Обострение DIC vs ServiceLocator

Redjik

Джедай-мастер
Где-то в контроллере.

ServiceLocator
PHP:
    public function actionRegister()
    {
        $sl = ServiceLocator::getServiceLocator();
        $user = User::getFromPost($sl->request->getPost('user'));
        if ($user->register())
        {
            $sl->mailer->sendMail('success',$user->email,'Congrats u ve registered');
        }
        $sl->response->setContent($sl->templating->render('success'));
       
        return $sl->response;        
    }
DIC
PHP:
    public function actionRegister(Request $request, Response $response, TwigClone $templating, MailService $mailService)
    {
        $user = User::getFromPost($request->getPost('user'));
        if ($user->register())
        {
            $mailService->mailer->sendMail('success',$user->email,'Congrats u ve registered');
        }
        $response->setContent($templating->render('success'));

        return $response;
    }
 
Последнее редактирование:

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
откуда там $user взялся в if()?

PS: псевдо код?
 

Adelf

Administrator
Команда форума
разумеется там часть кода.

З.Ы. мне больше импонирует второе. Типа круто. Попробую скоро ларавельку - ощутю все плюсы и минусы.
 

AmdY

Пью пиво
Команда форума
Redjik, автокомплит лучше, т.е. инъекция в метод, если это не добавит гемороя с вызовами и дополнительными слоями.
 

Вурдалак

Продвинутый новичок
Вообще-то во втором случае обычный DI. Дело в том, что контейнер не занимается такими вещами, как вызов action'ов, он резолвит зависимости. Должен быть какой-то конфиг, который маппит controller.action на список сервисов.

Хотя, конечно, можно рассматривать контроллер как фабрику response'ов. :rolleyes:
 

Вурдалак

Продвинутый новичок
О, а я только сейчас заметил, что там некий MailEvent, а не MailService. Содомия. :eek:
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
да, меня тоже заинтересовало что такое mailEvent - это что, обработчик почты?
 

Вурдалак

Продвинутый новичок
Событие само себя теребонькает. Выглядит ужасно. Центральным событием тут является «пользователь зарегистрировался».
PHP:
class UserController {
    public function actionRegister() {
        $this->eventDispatcher->dispatch(UserEvent::SIGNED_UP, new UserSignedUpEvent($user));
    }
}

class UserEventListener {
    public function onRegister(UserSignedUpEvent $event) {
        $this->mailer->send(...);
    }
}
 

Redjik

Джедай-мастер
Исправил вброс, не продумал изначально, крепко задумался про tell dont ask и DIC, и вот что мне не давало покоя:
1) Везде примеры с какими то элементарными действиями. (пример http://adamcod.es/2013/11/25/service-locator-vs-dependency-injection-container.html)
2) Как отправить почту и при этом заюзать lazy load по этим принципам. Всегда выходило, что, скажем, SwiftMailer инстанциировался при обращении к котнтроллеру, независимо от того, нужен он нам или нет.

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

И да, с одной стороны второй вариант сейчас выигрывает и выглядит кошерно, но вот, что меня смущает:
Как этот ад поддерживать в конфигах 0_о.
 

Redjik

Джедай-мастер
Вурдалак, eventDispatcher у тебя случаем не из ServiceLocator пришел? =)
Но твой вариант засчитываю, мой первый был ужасен, ага.
 

Redjik

Джедай-мастер
Вообще-то во втором случае обычный DI. Дело в том, что контейнер не занимается такими вещами, как вызов action'ов, он резолвит зависимости. Должен быть какой-то конфиг, который маппит controller.action на список сервисов.

Хотя, конечно, можно рассматривать контроллер как фабрику response'ов. :rolleyes:
Да, именно вариант конфига-маппера в вакууме и рассматриваю.
 

Вурдалак

Продвинутый новичок
А чем плохо, что сервис инстанцируется всегда? Есть какие-то реальные проблемы?

Если инициализация сервиса тяжёлая, то можно, например, обернуть сервис в прокси: http://symfony.com/doc/current/components/dependency_injection/lazy_services.html Тогда инстанс будет получен только в случае первого обращения.

Но скорее всего это экономия на спичках.
 

Redjik

Джедай-мастер
Не в спичках дело, просто мне не давал покоя именно пример, когда казалось, что почту дернуть можно только из SL, теперь все встало на место.
Yii головного мозга, ты был прав =(

ЗЫ. Если еще подскажешь best practice по мэпперу ну скажем на 10 контроллеров, в каждом по 5-6 экшенов, где в 1-2х экшенах нужна доп инъекция кроме Request, Response - буду благодарен.
Не понятно как этот зоопарк поддерживать.

ЗЫЫ. посмотрел ссылку, пилять, как раз пример с почтой ... как я это в доке пропустил =(
 

keltanas

marty cats
Redjik, в случае контроллера не надо передавать сервисы в экшен. Это по дефолту помойка. Достаточно наделать хелпер-методов в супер контроллере:
PHP:
abstract class SuperController extends ContainerAware
{
    /**
    * @return MailerInterface
    */
    protected function getMailerService()
    {
        return $this->container->get('mailer');
    }
}
Инъектировать надо в другие сервисы, чтобы удовлетворить их зависимости.

А это
PHP:
$user = User::getFromPost($request->getPost('user'));
явно не DIC, это бл**во какое-то.
 

Redjik

Джедай-мастер
keltanas, неа, ты не понял, http://symfony.com/doc/current/cookbook/controller/service.html
как раз контроллер как сервис, а не ContainerAware

Короче - ContainerAware, это старый добрый SL и нарушение инкапсуляции.
А controller as a service, это уже "православный" DIC =)

На самом деле все зависит от ситуации, просто до меня наконец дошло в чем разница и как делать "кошерный" Tell Dont Ask везде.
Но я не фанат, кошерного, правильного академического кода - "говнокод" порой намного проще понять, особенно в случае с SL.

А это
PHP:
$user = User::getFromPost($request->getPost('user'));
явно не DIC, это бл**во какое-то.
самый, штанинаесть, DIC

ЗЫ, хотя можно что нить типа User::getFromRequest($request)
 

Redjik

Джедай-мастер
Вот надо было привязаться к одной строчке псевдокода, да? когда про mail вообще речь шла.
PHP:
    public function actionRegister(TwigClone $templating, MailService $mailService, FormBuilder $formBuilder)
    {
        $user = new User();
        $form = $formBuilder->createFormBuilder($user)->getForm();
    
        if ($form->isValid() && $user->register())
        {
            $mailService->mailer->sendMail('success',$user->email,'Congrats u ve registered');
        }
        //response came from constructor
        $this->getResponse()->setContent($templating->render('success'));

        return $this->getResponse();
    }
так счастливы?
 
Последнее редактирование:

keltanas

marty cats
Redjik, не, можно конечно все контроллеры как сервисы регистрировать. Но, имхо, контроллер это последнее место в коде, над зависимостями которого надо думать ))

Чтобы заполнить объект данными из реквеста в православном стиле, надо что-то вроде этого использовать http://symfony.com/doc/current/book/forms.html#handling-form-submissions

ЗЫЖ ты пустую форму валидируешь ))
 
Сверху