Я очень новичок в среде Symfony, и я пытаюсь повторить то, что я обычно делаю с другими языками (все еще следуя шаблону MVC)

Цель состоит в том, чтобы вызывать InitializeSomething() каждый раз, когда вызывается Fly(), непосредственно перед этим. Вот мой код:

<?php
// src/Controller/ExampleController.php
namespace App\Controller;

use App\Common\Utils;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ExampleController extends BaseController
{
    public function __construct()
    {
      // Initialize vars and so on...
    }

    /**
     * @Route("/example/fly")
     */
    public function Fly()
    {
      // This method is obviously called via the route
    }

    private function InitializeSomething()
    {
      // I would like to call this before Fly() is executed
    }
...

Конечно, самый простой способ достичь результата:

...
    /**
     * @Route("/example/fly")
     */
    public function Fly()
    {
      $this->InitializeSomething();
      ...
    }
...

Если нет другого элегантного способа сделать это, я выберу это решение, я просто хотел бы избежать распространения по всему моему коду одного и того же метода везде (конечный дом для метода InitializeSomething будет в базовом классе).

Обычно с другими языками я просто вызываю свой InitializeSomething внутри конструктора, потому что классы контроллера создаются каждый раз, когда вызывается метод, но здесь, кажется, Symfony работает по-другому, и когда вызывается конструктор, слишком рано выполнять мою инициализацию.

Ред.: Спасибо за советы! Вот несколько примеров того, что я собираюсь сделать.

    private function InitializeSomething()
    {
      // Add the connection to a local variable, just to have a shortcut and avoid boilerplate
      $this->dbconnection = $this->getEntityManager()->getConnection();
      $this->dbengine = $this->getDoctrine();

      // Engine start
      if($engine==false) {
        SwitchOnEngine();
      }

      if($engine->rpm < 1000) {
        WaitEngineStart();
      }

      // Other things like logging the event and so on

    }

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

1
Scare 14 Апр 2020 в 02:35
Конструктор может работать, почему вы думаете, что это слишком рано? событие контроллера — еще одна альтернатива (но все же раньше). См. также событие controller_arguments. Вы также можете вызвать метод после создания...
 – 
msg
14 Апр 2020 в 02:44
1
Конструктор не будет работать для контроллеров, так как локатор службы внедряется другим методом. С другой стороны, событие контроллера фактически отправляется после создания контроллера и предоставляет доступ к экземпляру контроллера. Поэтому, если OP действительно хочет вызвать свою процедуру инициализации, то хорошим выбором будет прослушиватель контроллера. Конечно, им не нужно инициализировать. Как только они наберутся опыта, они поймут, почему.
 – 
Cerad
14 Апр 2020 в 03:26
Нет никаких указаний на то, что он использует AbstractController, возможно, он вообще не использует локатор, поэтому я попросил больше подробностей и указал разные варианты. Но ваша точка зрения верна.
 – 
msg
14 Апр 2020 в 04:05
Что на самом деле должен делать InitializeSomething? Один-два примера были бы очень полезны. Также было бы полезно назвать один или два фреймворка/проекта MVC, которые применяют такой «трюк», чтобы мы могли провести небольшое целенаправленное исследование по этому вопросу. В любом случае инициализация/назначение должны происходить либо в конструкторе, либо в самом действии контроллера (Fly).
 – 
dakis
14 Апр 2020 в 08:11
- Основываясь на вашем примере с инициализацией, я бы предположил, что вы вкладываете слишком много бизнес-логики в свой контроллер. Однако, если вы действительно чувствуете, что вам нужна эта функциональность, сделайте себя прослушивателем событий ядра контроллера и вызовите ее там. Пользователь msg дал вам ссылку в своем первом комментарии.
 – 
Cerad
14 Апр 2020 в 16:17

1 ответ

В Symfony есть то, что мы называем Событиями. Вы можете проверить документацию, но это конкретное событие здесь вызывается прямо перед выполнением контроллера: https://symfony.com/doc/current/reference/ events.html#kernel-controller-arguments

Здесь у вас есть полная документация о компоненте событий Symfony, чтобы вы могли понять, как реализовать то, что вам нужно: https://symfony.com/doc/current/event_dispatcher.html

Вы получите что-то вроде:

class InitializerListener
{
    public function onKernelController(ControllerEvent $event)
    {
        [$controllerInstance, $actionName] = $this->getController();
        $controllerInstance->initializeSomething();
    }
}

И в вашем конфиге:

# config/services.yaml
services:
    App\EventListener\InitializerListener:
        tags:
            - { name: kernel.event_listener, event: kernel.controller }

PS.: Если ваш контроллер имеет более одного метода действия, getController возвращает массив в формате, показанном в приведенном выше коде. См.: https://symfony.com/doc/current/event_dispatcher/before_after_filters.html< /а>

Кроме того, не начинайте свои методы с заглавных букв в PHP: https://www.php-fig.org/psr/psr-12/< /а>

1
Vinicius Dias 15 Апр 2020 в 23:43