Skip to content

Commit b252858

Browse files
committed
Module AdminControllers for back office documentation has to be adjusted for PS9
1 parent 927bd82 commit b252858

File tree

1 file changed

+188
-42
lines changed
  • modules/concepts/controllers/admin-controllers

1 file changed

+188
-42
lines changed

modules/concepts/controllers/admin-controllers/_index.md

Lines changed: 188 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,75 +9,179 @@ Using modern pages, you will have access to the PrestaShop debug toolbar, the se
99

1010
## How to declare a new Controller
1111

12-
Somewhere in your module declare a new class that will act as a Controller:
12+
{{% notice warning %}}
13+
**PrestaShop 9.0+**: The `FrameworkBundleAdminController` is **deprecated** and will be removed in PrestaShop 10.0. Use `PrestaShopAdminController` instead for new controllers.
14+
{{% /notice %}}
15+
16+
In your module, create a new controller class in the `src/Controller/` directory:
17+
1318
```php
1419
<?php
1520
// modules/your-module/src/Controller/DemoController.php
1621

1722
namespace MyModule\Controller;
1823

19-
use Doctrine\Common\Cache\CacheProvider;
20-
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
24+
use PrestaShopBundle\Controller\Admin\PrestaShopAdminController;
25+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
26+
use Symfony\Component\HttpFoundation\Request;
27+
use Symfony\Component\HttpFoundation\Response;
2128

22-
class DemoController extends FrameworkBundleAdminController
29+
class DemoController extends PrestaShopAdminController
2330
{
24-
private $cache;
25-
26-
// you can use symfony DI to inject services
27-
public function __construct(CacheProvider $cache)
31+
/**
32+
* Inject services via constructor for services used across multiple actions
33+
*/
34+
public function __construct(
35+
private readonly MyCustomService $myCustomService,
36+
) {
37+
}
38+
39+
/**
40+
* You can also inject services directly in action methods
41+
*/
42+
public function demoAction(AnotherService $anotherService): Response
2843
{
29-
$this->cache = $cache;
44+
// Use injected services
45+
$data = $this->myCustomService->getData();
46+
$moreData = $anotherService->getMoreData();
47+
48+
return $this->render('@Modules/your-module/templates/admin/demo.html.twig', [
49+
'data' => $data,
50+
'moreData' => $moreData,
51+
]);
3052
}
3153

32-
public function demoAction()
54+
/**
55+
* You can also use the #[Autowire] attribute to inject services by their ID
56+
*/
57+
public function advancedAction(
58+
Request $request,
59+
ShopRepository $shopRepository,
60+
#[Autowire(service: 'my_module.custom_service')] $customService,
61+
): Response
3362
{
34-
return $this->render('@Modules/your-module/templates/admin/demo.html.twig');
63+
// Use the injected service
64+
$customService->execute();
65+
66+
return $this->render('@Modules/your-module/templates/admin/advanced.html.twig');
3567
}
68+
69+
/**
70+
* Use helper methods provided by PrestaShopAdminController
71+
*/
72+
public function anotherAction(): Response
73+
{
74+
// PrestaShopAdminController provides helper methods for common services
75+
$config = $this->getConfiguration()->get('my_config');
76+
77+
return $this->render('@Modules/your-module/templates/admin/another.html.twig',[
78+
'my_config' => $config,
79+
]);
80+
}
81+
}
82+
```
83+
84+
The example above demonstrates a complete controller implementation with:
85+
- **Constructor injection** for services used across multiple actions (`MyCustomService`)
86+
- **Method parameter injection** for services used in specific actions (`AnotherService`)
87+
- **Autowire attribute** for injecting services by their ID (`#[Autowire(service: 'my_module.custom_service')]`)
88+
- **Helper methods** provided by `PrestaShopAdminController` for accessing common PrestaShop services
89+
90+
You have access to Twig as rendering engine and everything from the Symfony framework ecosystem.
91+
Note that you must return a `Response` object, but this can be a `JsonResponse` if you plan to make a single page application (or "SPA").
92+
93+
{{% notice note %}}
94+
This controller works exactly the same as the Core Back Office ones.
95+
{{% /notice %}}
96+
97+
{{% notice info %}}
98+
**Accessing PrestaShop services:**
99+
100+
The `PrestaShopAdminController` provides helper methods to access common PrestaShop services:
101+
- `$this->getConfiguration()` - Configuration service
102+
- `$this->getTranslator()` or `$this->trans()` - Translation service
103+
- `$this->getRouter()` - Router service
104+
- `$this->getEmployeeContext()` - Employee context
105+
- `$this->getShopContext()` - Shop context
106+
- `$this->getLanguageContext()` - Language context
107+
- `$this->getCurrencyContext()` - Currency context
108+
- `$this->getCountryContext()` - Country context
109+
- `$this->dispatchCommand()` - Execute CQRS commands
110+
- `$this->dispatchQuery()` - Execute CQRS queries
111+
- `$this->dispatchHookWithParameters()` - Dispatch hooks
112+
- `$this->presentGrid()` - Present grid data
113+
114+
See the complete list in the [PrestaShopAdminController source code](https://github.com/PrestaShop/PrestaShop/blob/9.0.0/src/PrestaShopBundle/Controller/Admin/PrestaShopAdminController.php).
115+
{{% /notice %}}
116+
117+
{{% notice warning %}}
118+
**Doctrine repositories must be injected:**
119+
120+
Doctrine ORM is not directly accessible via `$this->getDoctrine()` or similar methods. All Doctrine repositories and entity managers must be injected as dependencies in your controller's constructor or action methods.
121+
122+
Example:
123+
```php
124+
use Doctrine\ORM\EntityManagerInterface;
125+
use App\Repository\ProductRepository;
126+
127+
public function __construct(
128+
private readonly EntityManagerInterface $entityManager,
129+
private readonly ProductRepository $productRepository,
130+
) {
36131
}
37132
```
133+
{{% /notice %}}
134+
135+
## Service Configuration
136+
137+
In PrestaShop 9.0, controllers must be defined as services. You have two main approaches to configure your controller service:
138+
139+
### Option 1: Explicit service configuration with tags
38140

39-
If you want Symfony Dependency Injection to inject services into your controller, you need to use specific YAML service declaration:
40141
```yaml
142+
# modules/your-module/config/services.yml
41143
services:
42-
# The name of the service must match the full namespace class
43144
MyModule\Controller\DemoController:
44-
class: MyModule\Controller\DemoController
45-
arguments:
46-
- '@doctrine.cache.provider'
145+
autowire: true
146+
autoconfigure: true
147+
tags:
148+
- { name: controller.service_arguments }
47149
```
48150
49-
You can also retrieve services with the container available in symfony controllers ->
50-
```php
51-
<?php
52-
// modules/your-module/src/Controller/DemoController.php
151+
### Option 2: Using service defaults
53152
54-
namespace MyModule\Controller;
153+
```yaml
154+
# modules/your-module/config/services.yml
155+
services:
156+
_defaults:
157+
public: false
158+
autowire: true
159+
autoconfigure: true
160+
161+
MyModule\Controller\DemoController: ~
162+
```
55163
56-
use Doctrine\Common\Cache\CacheProvider;
57-
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
164+
{{% notice warning %}}
165+
**Service configuration is mandatory:**
58166
59-
class DemoController extends FrameworkBundleAdminController
60-
{
61-
public function demoAction()
62-
{
63-
// you can also retrieve services directly from the container
64-
$cache = $this->container->get('doctrine.cache');
65-
66-
return $this->render('@Modules/your-module/templates/admin/demo.html.twig');
67-
}
68-
}
69-
```
167+
One of the two service configuration options above is **essential and required** for your controller to work properly. Without this configuration:
168+
- **The controller will not function** and will throw errors
169+
- Helper methods from `PrestaShopAdminController` will not be accessible
170+
- Services like Twig, Form, Router, and other Symfony components will not be available
70171

71-
You have access to the Container, to Twig as rendering engine, the Doctrine ORM, everything from Symfony framework ecosystem.
72-
Note that you must return a `Response` object, but this can be a `JsonResponse` if you plan to make a single page application (or "SPA").
172+
**Important:** The service name (e.g., `MyModule\Controller\DemoController`) **must exactly match** the fully qualified class name (FQCN) of your controller. If the service name doesn't match the class name, Symfony and PrestaShop will not be able to identify and instantiate the controller, resulting in errors.
73173

74-
{{% notice note %}}
75-
This controller works exactly the same as the Core Back Office ones.
76-
{{% /notice %}}
174+
**Understanding the configuration:**
175+
- `autowire: true` - Automatically injects services in constructors and method parameters
176+
- `autoconfigure: true` - Automatically configures the controller as a service and enables all controller features
177+
- `controller.service_arguments` tag - Required if your controller doesn't extend `AbstractController` to enable method parameter injection
178+
{{% /notice %}}
179+
180+
## Autoloading Configuration
77181

78182
You must enable the autoloading for this Controller. For example using a `composer.json` file for your module.
79183

80-
#### Example using PSR-4 namespacing
184+
### Example using PSR-4 namespacing
81185

82186
1. Use namespace for your Controller file
83187

@@ -87,7 +191,7 @@ You must enable the autoloading for this Controller. For example using a `compos
87191
88192
namespace MyModule\Controller;
89193
90-
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
194+
use PrestaShopBundle\Controller\Admin\PrestaShopAdminController;
91195
```
92196

93197
2. Configure composer to autoload this namespace
@@ -98,7 +202,7 @@ You must enable the autoloading for this Controller. For example using a `compos
98202
"description": "...",
99203
"autoload": {
100204
"psr-4": {
101-
"MyModule\\Controller\\": "src/Controller/"
205+
"MyModule\\": "src/"
102206
}
103207
},
104208
"config": {
@@ -182,6 +286,48 @@ In order to generate the valid URI of a controller you created from inside the m
182286
```
183287

184288

289+
## Key Changes in PrestaShop 9.0 (Symfony 6.4)
290+
291+
### Controllers as Services
292+
293+
In Symfony 6.4, controllers must be defined as services. The container passed to controllers is no longer the "global container" but a dedicated, optimized container based on the services injected into it.
294+
295+
**Important implications:**
296+
297+
- The `$this->get('service_name')` method is no longer available in modern controllers
298+
- `FrameworkBundleAdminController` maintains backward compatibility but is **deprecated** and will be removed in PrestaShop 10.0
299+
- New controllers should extend `PrestaShopAdminController` which follows Symfony best practices
300+
301+
### Dependency Injection Methods
302+
303+
You have three main ways to inject services:
304+
305+
1. **Constructor injection** - For services used across multiple actions
306+
2. **Method injection** - For services used in a single action (more optimized)
307+
3. **Autowire attribute** - Use `#[Autowire(service: 'service_id')]` to inject services by their ID
308+
309+
### PrestaShopAdminController Helper Methods
310+
311+
The new base controller provides convenient helper methods for commonly used services:
312+
313+
- `$this->getConfiguration()` - Access configuration service
314+
- `$this->getTranslator()` - Access translator service
315+
- `$this->getRouter()` - Access router service
316+
- `$this->getFlashBag()` - Access flash messages
317+
318+
See the [full list of helper methods](https://github.com/PrestaShop/PrestaShop/blob/9.0.0/src/PrestaShopBundle/Controller/Admin/PrestaShopAdminController.php) in the class.
319+
320+
{{% notice info %}}
321+
**Learn more about Symfony controllers:**
322+
- [Controllers as services](https://symfony.com/doc/6.4/controller/service.html)
323+
- [Service Subscribers & Locators](https://symfony.com/doc/6.4/service_container/service_subscribers_locators.html)
324+
- [Service container](https://symfony.com/doc/6.4/service_container.html)
325+
{{% /notice %}}
326+
185327
## Secure your controller
186328

187329
It is safer to define permissions required to use your controller, this can be configured using the `#[AdminSecurity]` attribute and some configuration in your routing file. You can read this documentation if you need more details about [Controller Security]({{< ref "/9/development/architecture/migration-guide/controller-routing.md#security" >}}).
330+
331+
{{% notice note %}}
332+
**PrestaShop 9.0+**: The `@AdminSecurity` annotation has been replaced with the `#[AdminSecurity]` attribute following PHP 8 standards.
333+
{{% /notice %}}

0 commit comments

Comments
 (0)