docs(articles): From Magento to Symfony, a requalification guide grouped into sections
uk/articles/magento-to-symfony/core/routing.md
новий файл +103
−0
1
+
# Роутинг і контролери
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
+
- Сутність підставляється за параметром маршруту; якщо її немає, буде 404 без жодного коду. Для `{id}` атрибут `#[MapEntity]` не потрібен.
58
+
- Сервіси можна просити прямо в аргументах дії, а не лише в конструкторі.
59
+
- URL генерують за іменем маршруту: `$this->generateUrl('faq_show', ['slug' => $q->getSlug()])`.
60
+
- `bin/console debug:router` — усі маршрути, `router:match /faq/returns` — який маршрут спрацює.
61
+
62
+
## JSON на вході: замість getParam()
63
+
64
+
**Symfony** · DTO з тіла запиту з валідацією
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
+
Невалідний JSON або порушені обмеження дають відповідь 422 зі списком помилок. Для query string є `#[MapQueryString]` і `#[MapQueryParameter]`, для поточного користувача — `#[CurrentUser]`.
90
+
91
+
## Area → префікс і 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
+
Доступ до `/admin` закривають у `security.yaml` (див. розділ про безпеку). Окремого DI-конфігу для area немає: якщо в адмінці потрібна інша реалізація сервісу, це два різні сервіси.