---
title: Getting started with Shopware backend development | Shopware Community Hub
description: >-
  Create or clone a plugin with a storefront controller and understand the four
  parts that make it work.
canonical_url: >-
  https://hub.shopware.com/learn/unit/getting-started-with-shopware-backend-development
---

# Getting started with Shopware backend development

<LearningObjectives>

- Set up the `AcademyStorefrontController` example plugin.
- Explain why a storefront controller needs more than one file.
- Read the `ImageController` class and identify what each relevant part does.

</LearningObjectives>

# Getting Started With Shopware Backend Development

In the first learning unit, you created a minimal plugin named `AcademyFirstPlugin`. In the previous unit, you learned how services, controllers, subscribers, and dependency injection fit into a plugin.

Now you move from that overview to a focused example plugin named `AcademyStorefrontController`. You will use it to understand a storefront controller that loads a random cat or dog image from an external API and prepares it for a modal on the product page.

## Reminder: Prerequisites

Remember to have a **local Shopware 6.7** development environment with **PHP 8.3**.

## Target Result

By the end of this learning unit, you will have:

- Set up and activated the `AcademyStorefrontController` plugin.
- Located the `ImageController` class in the plugin.
- Understood which parts of the controller fetch data and return a storefront response.
- Seen why the controller class is only one part of the full storefront controller setup.

This learning unit focuses on the controller class. The next learning unit explains the route import, service definition, and Twig template that connect this class to the storefront.

## Plugins as the Entry Point

You already know that a plugin is the entry point for backend customization in Shopware. In this learning unit, the plugin gives Shopware a place for the storefront controller class.

![Plugin Folder example](assets/images/plugin-folder-example.jpg)

See the official guide for more detail: [Plugin base structure](https://developer.shopware.com/docs/guides/plugins/plugins/plugin-base-guide.html).

## Example Scenario

Many shops show extra content in a **modal** so the main shopping flow is not interrupted – for example, a newsletter prompt, login form, or product detail view. Here you fetch an image from an API and show it in a modal.

## Set Up the Example Plugin

Official reference: [adding a custom controller](https://developer.shopware.com/docs/guides/plugins/plugins/storefront/add-custom-controller.html).

### Option A: Clone the Example Plugin (Recommended)

For this course, the simplest path is to clone the prepared example plugin:

```shell
git clone https://github.com/ShopwareAcademy/AcademyStorefrontController.git custom/plugins/AcademyStorefrontController
```

This gives you the same plugin structure that the following units use. You can focus on understanding the controller flow instead of spending time on setup differences.

### Option B: Generate the Plugin Yourself

```shell
bin/console plugin:create AcademyStorefrontController
```

Choose **yes** for the example storefront controller. Rename `ExampleController` to `ImageController` if you follow this guide exactly. If you use the generator, verify **PSR-4 autoloading** in the plugin's `composer.json` and run `composer dump-autoload` in the shop root.

### Install and Activate

```bash
bin/console plugin:refresh
bin/console plugin:install AcademyStorefrontController --activate --clearCache
```

After this step, Shopware can load the plugin. In this learning unit, you focus on the controller class. The related routing, service configuration, and template are explained in the next learning unit.

## How a Storefront Controller Setup Fits Together

A storefront controller is not only one PHP class. The class needs a few supporting files so Shopware can find it, register it, and render a response.

| Part                   | Description                     | Covered in |
|------------------------|---------------------------------|------------|
| The controller         | A PHP class                     | This unit  |
| The route import       | `routes.xml`                    | Next unit  |
| The service definition | `services.xml`                  | Next unit  |
| The template           | A Twig file                     | Next unit  |

<Callout title="Tip for Beginners" type="info">

If you generate the plugin yourself, use `plugin:create` with the storefront controller option when possible. Wrong namespaces or paths are a common source of frustration.

</Callout>

## The Storefront Controller

Open the controller class in the example plugin:

```text
custom/plugins/AcademyStorefrontController/src/Storefront/Controller/ImageController.php
```

The `ImageController` class extends `StorefrontController`. It uses Shopware services to read plugin configuration, fetch an image URL from an external API, and pass that URL to a Twig template.

```php
<?php declare(strict_types=1);

namespace ShopwareAcademy\StorefrontController\Storefront\Controller;

use Shopware\Core\PlatformRequest;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Controller\StorefrontController;
use Shopware\Storefront\Framework\Routing\StorefrontRouteScope;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\HttpClient\HttpClientInterface;

#[Route(defaults: [PlatformRequest::ATTRIBUTE_ROUTE_SCOPE => [StorefrontRouteScope::ID], 'XmlHttpRequest' => true])]
class ImageController extends StorefrontController
{
    public function __construct(
        private readonly HttpClientInterface $client,
        private readonly SystemConfigService $systemConfigService
    ) {
    }

    #[Route(
        path: '/image',
        name: 'frontend.image.show',
        methods: ['GET']
    )]
    public function showImage(SalesChannelContext $context): Response
    {
        $apiAccessKey = $this->systemConfigService->get('AcademyStorefrontController.config.apiAccessKey', $context->getSalesChannelId());
        $apiProvider = $this->systemConfigService->get('AcademyStorefrontController.config.apiProvider', $context->getSalesChannelId());

        $response = $this->client->request('GET', 'https://api.'.$apiProvider.'.com/v1/images/search', [
            'headers' => [
                'x-api-key' => $apiAccessKey
            ]
        ]);

        $data = $response->toArray();
        $imageUrl = $data[0]['url'];

        return $this->renderStorefront('@AcademyStorefrontController/storefront/page/image.html.twig', [
            'imageUrl' => $imageUrl
        ]);
    }
}
```

### What This Code Does

Read the controller from top to bottom:

1. The `namespace` places the class inside the plugin's PHP structure.
2. `ImageController` extends `StorefrontController`, so it can use storefront helpers such as `renderStorefront()`.
3. The class-level route defaults put the controller into the storefront route scope and mark it as AJAX-only for modal loading.
4. The constructor asks the dependency injection container for `HttpClientInterface` and `SystemConfigService`.
5. `showImage()` handles a `GET` request for `/image` and uses the route name `frontend.image.show`.
6. `SystemConfigService` reads the configured API provider and optional API key from the plugin configuration.
7. The HTTP client requests one image from the selected provider.
8. `renderStorefront()` passes the image URL to the Twig template.

<Callout title="Expected Result (Partial)" type="success">

After this learning unit, the plugin is installed, and you can read the controller class. The browser-facing route, service registration, and Twig output are covered in the next learning unit.

</Callout>

<ArticleQuestionnaire>
  <ArticleQuestionnaireQuestion>How many main parts does a storefront controller setup consist of in this course?</ArticleQuestionnaireQuestion>
  <ArticleQuestionnaireAnswer>Two: controller and template</ArticleQuestionnaireAnswer>
  <ArticleQuestionnaireAnswer correct>Four: controller, route import, service definition, template</ArticleQuestionnaireAnswer>
  <ArticleQuestionnaireAnswer>One: only the PHP class</ArticleQuestionnaireAnswer>
</ArticleQuestionnaire>

## Summary

In this learning unit, you learned:

- How to set up and activate the `AcademyStorefrontController` example plugin.
- Where the `ImageController` class lives inside the plugin.
- How the controller uses injected services to read configuration, fetch data from an external API, and prepare a storefront response.
- Why the controller class is only one part of a complete storefront controller setup.

You now have the example plugin in place and understand the controller class itself.

**Next:** You will connect this controller to the storefront by adding the route import in `routes.xml`, registering the controller in `services.xml`, and rendering the output with a Twig template.
