docs(articles): English translation of From Magento to Symfony
en/articles/magento-to-symfony/core/routing.md
new file +103
โ0
1
+
# Routing and controllers
2
+
3
+
**Magento** ยท routes.xml + Controller/Question/View.php
4
+
5
+
```xml
6
+
<router id="standard">
7
+
<route id="faq" frontName="faq">
8
+
<module name="Vendor_Faq"/>
9
+
</route>
10
+
</router>
11
+
```
12
+
```php
13
+
class View implements HttpGetActionInterface
14
+
{
15
+
public function __construct(
16
+
private RequestInterface $request,
17
+
private QuestionRepositoryInterface $questions,
18
+
private PageFactory $pageFactory,
19
+
) {}
20
+
21
+
public function execute(): ResultInterface
22
+
{
23
+
$id = (int) $this->request->getParam('id');
24
+
$question = $this->questions->getById($id);
25
+
$page = $this->pageFactory->create();
26
+
$page->getConfig()->getTitle()->set($question->getTitle());
27
+
return $page;
28
+
}
29
+
}
30
+
```
31
+
32
+
**Symfony** ยท src/Controller/FaqController.php
33
+
34
+
```php
35
+
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
36
+
use Symfony\Component\Routing\Attribute\Route;
37
+
38
+
final class FaqController extends AbstractController
39
+
{
40
+
#[Route('/faq', name: 'faq_index', methods: ['GET'])]
41
+
public function index(QuestionRepository $questions): Response
42
+
{
43
+
return $this->json($questions->findActive());
44
+
}
45
+
46
+
#[Route('/faq/{slug}', name: 'faq_show', methods: ['GET'])]
47
+
public function show(
48
+
#[MapEntity(mapping: ['slug' => 'slug'])]
49
+
Question $question,
50
+
): Response
51
+
{
52
+
return $this->json($question);
53
+
}
54
+
}
55
+
```
56
+
57
+
- The entity is resolved from the route parameter; if it doesn't exist, you get a 404 without writing any code. For `{id}` you don't need the `#[MapEntity]` attribute.
58
+
- You can request services directly in action arguments, not only in the constructor.
59
+
- URLs are generated by route name: `$this->generateUrl('faq_show', ['slug' => $q->getSlug()])`.
60
+
- `bin/console debug:router` lists all routes, `router:match /faq/returns` shows which route will match.
61
+
62
+
## JSON input: instead of getParam()
63
+
64
+
**Symfony** ยท DTO from the request body with validation
65
+
66
+
```php
67
+
final class CreateQuestion
68
+
{
69
+
public function __construct(
70
+
#[Assert\NotBlank, Assert\Length(max: 255)]
71
+
public readonly string $title,
72
+
#[Assert\NotBlank]
73
+
public readonly string $answer,
74
+
) {}
75
+
}
76
+
77
+
#[Route('/api/questions', methods: ['POST'])]
78
+
public function create(
79
+
#[MapRequestPayload]
80
+
CreateQuestion $input,
81
+
QuestionService $questions,
82
+
): JsonResponse
83
+
{
84
+
$question = $questions->create($input);
85
+
return $this->json(['id' => $question->getId()], 201);
86
+
}
87
+
```
88
+
89
+
Invalid JSON or violated constraints produce a 422 response with a list of errors. For the query string there are `#[MapQueryString]` and `#[MapQueryParameter]`, for the current user there is `#[CurrentUser]`.
90
+
91
+
## Area โ prefix and firewall
92
+
93
+
**Symfony** ยท config/routes.yaml
94
+
95
+
```yaml
96
+
admin:
97
+
resource: ../src/Controller/Admin/
98
+
type: attribute
99
+
prefix: /admin
100
+
name_prefix: admin_
101
+
```
102
+
103
+
Access to `/admin` is restricted in `security.yaml` (see the security section). There is no separate DI config per area: if the admin panel needs a different implementation of a service, those are two different services.