Как использовать slug в Symfony?

Как настроить Symfony роутер для передачи ```{slug}``` вместо ```Id``` и правильно связать сущность ```Page``` с контроллером, чтобы не возникало ошибок "Cannot autowire argument $page of "App\Controller\PageController::show()""?
  • 24 марта 2024 г. 19:39
Ответы на вопрос 2
Для использования slug в Symfony, сначала необходимо настроить роутер для передачи slug вместо id. Для этого нужно в конфигурации маршрутов routes.yaml указать параметр {slug} вместо {id}. Например:

```yaml
page_show:
    path: /page/{slug}
    controller: App\Controller\PageController::show
    defaults:
        _controller: 'App\Controller\PageController::show'
```

Далее, необходимо в контроллере PageController правильно связать сущность Page с полученным slug. Для этого можно воспользоваться Doctrine EntityManager для получения записи Page по slug. Например:

```php
namespace App\Controller;

use App\Entity\Page;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;

class PageController extends AbstractController
{
    public function show(Page $page): Response
    {
        // Ваш код для отображения страницы
    }
}
```

При этом не забудьте добавить аннотацию ```@ParamConverter``` к параметру метода show, чтобы Symfony могла автоматически преобразовать slug в объект Page.

```php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

/**
 * @ParamConverter("page", options={"mapping": {"slug": "slug"}})
 */
public function show(Page $page): Response
{
    // Ваш код для отображения страницы
}
```

Таким образом, можно использовать slug в Symfony и правильно связать сущность Page с контроллером, чтобы избежать ошибок "Cannot autowire argument $page of "App\Controller\PageController::show()"".
public function show(Request $request, Page $page): Response

Здесь symfony пытается заполнить атрибуты объекта Page, основываясь на значениях из запроса. В запросе есть только slug. Если бы в Page остальные атрибуты были необязательные у них были заполнены значения по умолчанию, то сущность Page заполнялась бы slug'ом из запроса и этими значениями по умолчанию, и именно этот объект был бы в контроллере, без ошибок.

Очевидно, что такое поведение не ожидается при попытке найти сущность по slug.

Правильный подход:

В методах контроллера ожидают DTO запроса и на основе этого DTO получают сущность
class ShowPageRequestDTO
{
    public function __construct(
        public readonly string $slug,
    ) {}
}

class PageController
{
    public function __construct(
        private readonly PageRepository $repository,
    ) {}

    public function show(ShowPageRequestDTO $request)
    {
        return $this->render('/page/show.html.twig', [
            'slug' => $request->slug,
            'page' => $this->repository->findBySlug($request->slug),
        ]);
    }
}


В данном примере опущена валидация запроса, т.к. ее можно осуществить по-разному, а так же указан некий PageRepository с методом findBySlug для получения сущности из базы по slug, но это тоже можно реализовать по-разному.
Похожие вопросы