symfony service -- Вызов контроллера в других контроллерах (использование одинаковых участков кода)

Для того чтобы можно было вызвать Контроллер из другого Контроллера, необходимо создать для него Сервис.

В чём проблема

При создании экземпляра контроллера Symfony создаёт контейнер, в который помещает стандартные сервисы (например, doctrine). Проблема в том, что, когда мы хотим обратиться к методу контроллера из другого класса, мы не можем просто создать его объект (в нём не будет контейнера).

Решение

Лучшей практикой будет вынос всех функциональных участков кода, в том числе и многократно используемых, из контроллера в сервисы.
Создать сервис можно так.

Как вариант решения проблемы - создание объекта контроллера и одновременно запуск метода setConteiner(), устанавливающего свойство conteiner. Чтобы не делать это каждый раз вручную, принято создавать сервис, который является по сути инстансом своего класса с определёнными свойствами.

Вот так будет выглядеть код:

  1. Вызываемый контроллер:
    <?php
    
    namespace AppBundle\Controller;
    
    use AppBundle\Entity\Category;
    use Doctrine\ORM\EntityNotFoundException;
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    
    class CategoryController extends Controller
    {
        protected $container;
    
        /**
         * @param ContainerInterface $container
         * 
         * @return self
         */
        public function setContainer(ContainerInterface $container = null): self
        {
            $this->container = $container;
            
            return $this;
        }
    
        /**
         * @return array
         */
        public function getCategories(): array
        {
            // какой-то метод, который нужно вызвать из другого класса
    
            return $categories;
        }
    }
  2. Сервисservices.yml):
    categories.for.menu:
            class: AppBundle\Controller\CategoryController
            calls:
                - method: setContainer
                  arguments:
                      - "@service_container"
    
     # aliases:
        AppBundle\Controller\CategoryController: '@categories.for.menu'
  3. Вызывающий контроллер:
    $this->get('categories.for.menu')->getCategories();

Источники

vedro-compota's picture

по-хорошему надо всё общее выносить куда-то ещё, а если нужен прям другой контроллер то делать переадресацию. Разве нет?

Хотя, наверное бывают исключения)

_____________
матфак вгу и остальная классика =)

melisa's picture

а если нужен прям другой контроллер то делать переадресацию

нет, речь идёт об одном методе, реализующем какой-то функционал

Хотя, наверное бывают исключения

При создании экземпляра контроллера Symfony создаёт контейнер, в который помещает стандартные сервисы (например, doctrine). Проблема в том, что, когда мы хотим обратиться к методу контроллера из другого класса, мы не можем просто создать его объект (в нём не будет контейнера).
Решением проблемы является создание объекта контроллера и одновременно запуск метода seConteiner(), устанавливающего свойство conteiner. Чтобы не делать это каждый раз вручную, принято создавать сервис, который является по сути инстансом своего класса с определёнными свойствами.

vedro-compota's picture

и всё равно надо добавить, что повторно используемый код нельзя держать непосредственно в контроллере.

_____________
матфак вгу и остальная классика =)