Сервисный слой, как правильно?

Обсуждаем, как правильно строить приложения
nootropil
Сообщения: 46
Зарегистрирован: 2015.11.21, 18:45

Re: Сервисный слой, как правильно?

Сообщение nootropil »

zelenin писал(а): ... либо публичные поля и констуктор в виде __construct(array $attributes) ...
Вообще думаю использовать массивы как основу для конструкторов сущности, иначе слишком они монструозно выглядят при большом количестве полей и запутаться с порядком легко.
https://bitbucket.org/nootropil/studyin ... ew-default
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Сервисный слой, как правильно?

Сообщение zelenin »

типа того.
лайфхак: чтобы не плодить длинные конструкторы, можно оставить только обязательные поля, а необязательные сеттить через сеттеры.
https://bitbucket.org/nootropil/studyin ... ser.php-62
Аватара пользователя
SiZE
Сообщения: 2813
Зарегистрирован: 2011.09.21, 12:39
Откуда: Perm
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение SiZE »

zelenin писал(а):типа того.
лайфхак: чтобы не плодить длинные конструкторы, можно оставить только обязательные поля, а необязательные сеттить через сеттеры.
https://bitbucket.org/nootropil/studyin ... ser.php-62
В код как раз то, что я хотел спросить :))) Я так же сделал.

Код: Выделить всё

public function activate()
{
        $this->isActive = UserStatuses::STATUS_ACTIVE;
}
А это нормально использовать, так константы?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Сервисный слой, как правильно?

Сообщение zelenin »

то есть?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение ElisDN »

SiZE писал(а):

Код: Выделить всё

public function activate()
{
        $this->isActive = UserStatuses::STATUS_ACTIVE;
} 
А это нормально использовать, так константы?
Если статусов много, то логичнее константами:

Код: Выделить всё

$this->status = UserStatuses::STATUS_ACTIVE; 
А если просто true/false, то константы ни к чему:

Код: Выделить всё

$this->isActive = true; 
Аватара пользователя
SiZE
Сообщения: 2813
Зарегистрирован: 2011.09.21, 12:39
Откуда: Perm
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение SiZE »

Не знаю к месту ли вопрос. А если меняем статус, где должно быть логирование изменения статусов? И откуда вызываться заполнение лога?
ElisDN писал(а):Если статусов много, то логичнее константами
Спасибо
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Сервисный слой, как правильно?

Сообщение zelenin »

SiZE писал(а):Не знаю к месту ли вопрос. А если меняем статус, где должно быть логирование изменения статусов? И откуда вызываться заполнение лога?
смотря в рамках какой парадигмы. Но в целом - не в модели. В рамках ddd есть понятие доменных событий, например. В рамках сервисного слоя логировать нужно непосредственно в сервисе (или шине, если используется некая сервисная шина, и глобальный логгер), которым меняется статус. При event sourcing у вас собственно весь поток эвентов, из которых строится модель, и есть лог.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение ElisDN »

SiZE писал(а):А если меняем статус, где должно быть логирование изменения статусов? И откуда вызываться заполнение лога?
Если просто записывать всё в системе, то предпочитаю логировать Event-ы на уровне Event Dispatcher. Для выборочного логгирования делаю интерфейс LoggedEvent с методом getLogMessage() и помечаю им нужные события:

Код: Выделить всё

class LoggedEventDispatcher implements EventDispatcherInterface
{
    private $next;
    private $logger;

    public function __construct(EventDispatcherInterface $next, LoggerInterface $logger)
    {
        $this->next = $next;
        $this->logger = $logger;
    }

    public function dispatch(Event $event)
    {
        $this->next->dispatch($event);
        if ($event instanceof LoggedEvent) {
            $this->logger->log($event->getLogMessage());
        }
    }
} 
ShNURoK
Сообщения: 168
Зарегистрирован: 2012.04.12, 05:44
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение ShNURoK »

zelenin, можете сказать или показать в какую сторону копать, как быть в ситуации, когда допустим вызывается actionLogin и в зависимости от ситуации, мы либо рендирим страницу с ошибкой, либо дополнительную форму, либо редиректим.
Может вопрос не про DDD, но хотелось бы всю логику из контроллера перенести в сервисный слой, что мы должны вызвать в контроллере, что должно вернуться, что должен делать контроллер? С тем учетом, что контроллер должен быть тонким.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Сервисный слой, как правильно?

Сообщение zelenin »

Код: Выделить всё

try {
    $userDto = UserDto::createFromRequest(Yii::$app->getRequest()->getPost('User')); // или модель формы
    (new AuthService)->login($userDto);
} catch (ValidationException $e) {

} catch (AuthException $e) {

}
это?
ShNURoK
Сообщения: 168
Зарегистрирован: 2012.04.12, 05:44
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение ShNURoK »

zelenin писал(а):это?
Да, спасибо, а что если нам надо каждого, например 10 пользователя поздравлять с этим и отправлять на секретную страницу. Мне интересно как вырезать логику подсчета из контроллера. Тоже через исключения?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Сервисный слой, как правильно?

Сообщение zelenin »

ShNURoK писал(а):
zelenin писал(а):это?
Да, спасибо, а что если нам надо каждого, например 10 пользователя поздравлять с этим и отправлять на секретную страницу. Мне интересно как вырезать логику подсчета из контроллера. Тоже через исключения?

Код: Выделить всё

if($userService->validForSmallSecret($userDto) { 
ShNURoK
Сообщения: 168
Зарегистрирован: 2012.04.12, 05:44
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение ShNURoK »

zelenin писал(а):
ShNURoK писал(а):
zelenin писал(а):

Код: Выделить всё

if($userService->validForSmallSecret($userDto) {
Понял, то есть нормально для контроллера такие проверки устраивать? Кроме проверки, еще и данные может быть надо какие получить для view.

А не знаете, где можно почитать, что можно размещать в контроллере, а что не следует? Я тут посмотрел ларакаст, но там аналог исключений и выходит по 1 строке на экшен, что тоже считаю плохо, получается другая крайность.

Контроллер

Код: Выделить всё

public function actionLogin()
{
    $userService = new UserService($this);
    return $this->userService->login($_POST);
}
public function renderLogin($params)
{
    return $this->render('login', $params);
}
...
 
Сервис

Код: Выделить всё

public function __construct($listener)
{
    $this->listener = $listener;
}

public function login($params)
{
    // все что обычно бывает в контреллере
    $this->listener->renderLogin($params);
}
...
 
Это плохой вариант?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Сервисный слой, как правильно?

Сообщение zelenin »

ShNURoK писал(а):Понял, то есть нормально для контроллера такие проверки устраивать?
это такой же метод как и login
ShNURoK писал(а):Кроме проверки, еще и данные может быть надо какие получить для view.
$userService->findById($id);
ShNURoK писал(а):А не знаете, где можно почитать, что можно размещать в контроллере, а что не следует?
бизнес-логику не размещайте и все.
ShNURoK писал(а):$userService = new UserService($this);
сервис не обязательно вызывается только в контроллере - не надо его туда передавать.
ShNURoK писал(а):$this->userService->login($_POST);
а вот вы проверяете входящий массив на состав всех полей? а зачем вообще передавать массив неизвестного состава? Передавайте объект с известной структурой.
ShNURoK писал(а):Сервис

Код: Выделить всё

public function __construct($listener)
{
    $this->listener = $listener;
}

public function login($params)
{
    // все что обычно бывает в контреллере
    $this->listener->renderLogin($params);
}
...
 
Это плохой вариант?
сервис не используется только в контроллере. В нем не должно быть рендера.
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение slavcodev »

ElisDN писал(а):1. В сущности User у Вас практически только геттеры и сеттеры. Из-за этого сами работаете с ней процедурно, а не как с объектом. Сеттеров в сущности быть практически не должно.
zelenin писал(а):лайфхак: чтобы не плодить длинные конструкторы, можно оставить только обязательные поля, а необязательные сеттить через сеттеры.
https://bitbucket.org/nootropil/studyin ... ser.php-62
Так все таки можно геттеры и сеттеры или нет? :)
Жду Yii 3!
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Сервисный слой, как правильно?

Сообщение zelenin »

сеттеры не в плохом смысле слова) не setStatus($statusId), а activize()
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение slavcodev »

zelenin писал(а):сеттеры не в плохом смысле слова) не setStatus($statusId), а activize()
Хмм. А в чем отличие?

тут defineAsUser, defineAsAdmin, defineCreateTime и тд, все это ИМХО обычные сеттеры анемичной модели. До ДДД тут далеко.
Жду Yii 3!
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Сервисный слой, как правильно?

Сообщение slavcodev »

уже не говоря о нарушении инкапсуляции, что любой может взять и вызвать изменение даты создания, даты обновления, статуса пользователя и другие нехороши вещи.
Жду Yii 3!
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Сервисный слой, как правильно?

Сообщение zelenin »

slavcodev писал(а):
zelenin писал(а):сеттеры не в плохом смысле слова) не setStatus($statusId), а activize()
Хмм. А в чем отличие?

тут defineAsUser, defineAsAdmin, defineCreateTime и тд, все это ИМХО обычные сеттеры анемичной модели. До ДДД тут далеко.
если это вписывается в его бизнес-кейс (есть фича смены активации юзера), то пыжься не пыжься, а только просто сеттер и будет. Можно только переименовать в рамках Ubiquitous Language (что и сделано).
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Сервисный слой, как правильно?

Сообщение zelenin »

slavcodev писал(а):уже не говоря о нарушении инкапсуляции, что любой может взять и вызвать изменение даты создания, даты обновления, статуса пользователя и другие нехороши вещи.
с этим согласен, оговариваясь, что вполне может быть у него есть такие бизнес-процессы (что вряд ли).
Закрыто