Проектирование сущностей, сервисов и репозиториев

Обсуждаем, как правильно строить приложения
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение sda »

samdark innodb в mysql появился в 2001. До этого момента поддержка транзакций отсутствовала.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение samdark »

Я про то, что ACID-транзакции были задолго до MySQL.
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение anton_z »

sda писал(а): 2017.11.14, 17:39 Но если посмотреть на реальный мир, то там все бизнес-процессы это eventual consistency, а не ACID. Потому что там нельзя сделать роллбек. Там конечный автомат. Бизнесмен решает, что ему делать если операция была неудачной. Например клиент съел заказ в ресторане, но оплатить его не в состоянии. Роллбек сделать невозможно. Можно лишь сделать какую-то компенсирующую операцию. Побить клиента например. Шутка. Я думаю, что в информационных системах мы также должны описывать бизнес-процессы в виде конечного автомата. ACID не работает в SOA архитектуре. ACID не существовал во времена доминирования MyISAM и я не смог найти как тогда решали проблему консистентности. Но очень интересно. Не думаю, что просто надеялись на лучшее :mrgreen:
Бесусловно, многие вещи в этом мире нетранзакционны, но не стоит натягивать жизнь на чисто технический критерий, которым является ACID.
Как правило rollback в РСУБД используется не для того, чтобы отменить уже совершенную операцию, а сделать атомарным выполнение какой-то конретной операции. У вас может быть и ACID и Eventual Consistency, это вещи не взаимоисключающие. Eventual Consistency - Immediate Consistency - вот антагонисты.

По поводу того, чем пользовались до появления транзакзакций - видимо чем-то не очень удобным, раз в итоге пришли к транзакциям.
Да с масштабированием проблемы, нужно их как-то решать (и то если один сервер РСУБД перестает справляться или проект изначально проектируется как высоконагруженный, заложены огромные деньги на рекламу) опираясь на специфику конкретного кейса. И здесь вам транзакции все равно пригодятся, только скорее всего выполняться они будут не в обработчике HTTP-запроса, а в воркере, который будет обрабатывать задания из очереди.
voodooism
Сообщения: 48
Зарегистрирован: 2018.11.12, 10:29

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение voodooism »

Дмитрий, спасибо большое вам за этот цикл статей, еще не полностью изучил, но уже реально очень много нового узнал!

У меня возник вопрос по поводу диспетчеризации:
Если мы рассматриваем большое приложение с кучей сущностей и сервисов, я боюсь представить каким адом в итоге может оказаться система работы с эвентами когда у нас их по 10 штук на сущность, и еще как минимум столько же эвентов и всё это нужно описать в DI контейнере. Существуют ли какие то готовые реализации этого паттерна ?

Так же хотелось бы уточнить - что должен принимать репозиторий в своих методах непосредственно сущность, или лишь только DTO? Я имею ввиду например методы save()/add()?

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

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение ElisDN »

voodooism писал(а): 2019.07.14, 18:38 ...и всё это нужно описать в DI контейнере. Существуют ли какие то готовые реализации этого паттерна ?
В проектах на Symfony вместо описания всего в контейнере достаточно слушатели оформить как EventSubscriber-классы и фреймворк сам обойдёт все папки и подключит их автоматически.

А в других случаях да, придётся всё прописывать.
voodooism писал(а): 2019.07.14, 18:38 Если мы рассматриваем большое приложение с кучей сущностей и сервисов, я боюсь представить каким адом в итоге может оказаться система работы с эвентами когда у нас их по 10 штук на сущность, и еще как минимум столько же эвентов...
Такова специфика размера, что чем проект крупнее, тем больше в нём становится контроллеров, сервисов, сущностей и событий.

Если вы лишь по некоторым событиям собираетесь рассылать уведомления, то для экономии можете делать только те эвенты, которые нужно обрабатывать, а не все подряд.
voodooism писал(а): 2019.07.14, 18:38 Так же хотелось бы уточнить - что должен принимать репозиторий в своих методах непосредственно сущность, или лишь только DTO? Я имею ввиду например методы save()/add()?
По своему определению репозиторий – это имитатор коллекции для хранения доменных сущностей.
voodooism писал(а): 2019.07.14, 18:38 И, еще , в одном из ваших интервью я слышал как вы говорили что потратили очень много времени на изучение различных проектов. Не могли бы вы поделится ссылками на проекты, в которых по вашему мнению хорошо реализуются описанные вами паттерны и техники?
Публично на GitHub реальные проекты не выкладывают. На Yii так делать либо никому не нужно, либо не умеют, либо неудобно. Так что ищите проекты на Symfony. Ссылки может выложу. А пока доделываю пример менеджера проектов.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение samdark »

Если вы лишь по некоторым событиям собираетесь рассылать уведомления, то для экономии можете делать только те эвенты, которые нужно обрабатывать, а не все подряд.
Здесь дело не в экономии производительности или чего-то такого, а в экономии ресурса мозга в попытке разобраться «как же эта хреновина работает». Чем больше событий, тем, как правило, хуже видно общую картину. Вводите события когда они действительно нужны. Это, конечно, часто, но если переборщить, будет худо.
voodooism
Сообщения: 48
Зарегистрирован: 2018.11.12, 10:29

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение voodooism »

Вот перешел к практике и сразу столкнулся с первыми вопросами.
Сначала кратко опишу вводные:
Есть сущность тикета. По каждому тикету могут быть разные типы коммуникации с клиентом (sms, email, телефон, соцсети и т.д.). Для каждого типа коммуникации был создан отдельный репозиторий, с целью того что бы обращаться к истории комуникации. Задача состоит в том, что во вьюхе тикета нужно отображать всю историю коммуникации всеми способами.

На данный момент, я реализовал следующим образом:
TicketService имеет метод getCommuincateLog($ticketId)
В этом методе я поочередно извлекаю из репозиториев нужные мне данные следующим образом:

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

$mailLog = $this->mailLogRepository->getLogByAppealId($idTicket);
$smsLog = $this->smsLogRepository->getLogByTicketId($idTicket);
Вопрос, как собрать это всё воедино для отображения на вьюхе? Дергать у каждой сущности пришедшей из репозитория нужные для отображения поля, и собирать их в DTO ?

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

        
        foreach ($mailLog as $log) {
            $objects[] = new HistoryDto();
            $dto->send_time = $log->send_time;
            $dto->send_email = $log->send_email;
            ...
        }
        
И так далее по каждому типу коммуникации. Получается если объект DTO будет один стандартный - то у него всегда будет куча лишних незаполненных полей, и это весьма усложнит рендеринг на вьюхе.

Второй вариант о котором я подумал, это отнаследовать отдельные классы для каждого типа коммуникации от абстрактного класса HistoryDto(), который будет содержать в себе абстрактный метод getView(). И каждый DTO будет содержать лишь необходимые ему поля, да ещё и уметь себя отрисовывать на вьюхе. Но тут возникает вопрос - на сколько это вообще сопоставимо с обсуждаемой тут концепцией? Ведь на сколько я понял DTO это должны быть простые объекты которые не содержат ничего кроме данных, а у меня тут есть еще и поведение.

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

И последний вопрос: т.к. в этом сервисе у меня используется несколько видов комуникаций, и вполне вероятно что в будущем их число будет увеличиваться, а кроме запроса истории сервис тикетов будет делать еще много операций. Получается что конструктор с кучей репозиториев и других зависимостей по итогу необратим? Имеет ли смысл сразу вынести запрос истории коммуникаций в отдельный сервис, типа TicketCommuicationsHistoryService ? Или это излишне?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение ElisDN »

voodooism писал(а): 2019.07.15, 10:45 Вопрос, как собрать это всё воедино для отображения на вьюхе? Дергать у каждой сущности пришедшей из репозитория нужные для отображения поля, и собирать их в DTO?
Соберите в контроллере всё в одну ленту:

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

$feed = new Feed($mails, $smses, $calls, ...);
где внутри присваивайте каждый элемент в одно из полей сборного DTO:

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

class Item
{
    /**
     * @var DateTimeImmutable
     */
    public $date;
    /**
     * @var MailMessage|null
     */
    public $mail;
    /**
     * @var SmsMessage|null
     */
    public $sms;
    /**
     * @var PhoneCall|null
     */
    public $call;
}
сортируя по дате. И в зависимости от заполненного поля выводите каждую строку своим представлением:

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

<p>Total: <?= $feed->getCount(): ?></p>

<?php foreach ($feed->getItems() as $item): ?>
    <?php if ($sms = $item->sms): ?>
        <?= $this->render('_sms', ['sms' => $sms]); ?>
    <?php elseif ($call = $item->call): ?>
        <?= $this->render('_call', ['call' => $call]); ?>
    <?php elseif ($mail = $item->mail): ?>
        <?= $this->render('_mail', ['mail' => $mail]); ?>
    <?php endif; ?>
<?php endfor; ?>
на основе своих DTO.
voodooism писал(а): 2019.07.15, 10:45 И последний вопрос: т.к. в этом сервисе у меня используется несколько видов комуникаций, и вполне вероятно что в будущем их число будет увеличиваться, а кроме запроса истории сервис тикетов будет делать еще много операций. Получается что конструктор с кучей репозиториев и других зависимостей по итогу необратим? Имеет ли смысл сразу вынести запрос истории коммуникаций в отдельный сервис, типа TicketCommuicationsHistoryService? Или это излишне?
Когда разрастётся, тогда объедините в один.
voodooism
Сообщения: 48
Зарегистрирован: 2018.11.12, 10:29

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение voodooism »

Дмитрий, я правильно понял, что в приведенном вашем примере Item - это и будет DTO в полях которого будут объекты коммуникаций?
Или же всё таки Item это сущность, которая в своих полях содержит непосредственно DTO отвечающие за разный виды коммуникаций?
voodooism
Сообщения: 48
Зарегистрирован: 2018.11.12, 10:29

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение voodooism »

Столкнулся вот еще с одним интересным кейсом: У меня прилетают по API различные типы тикетов, все прилетает в один экшн контроллера.
В зависимости от типа тикета, его должен обработать определенный метод в сервисе. Кто должен решить это?
Контроллер, что то типа такого:

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

switch ($ticketType) {
  case: TYPE_ONE:
    $this->ticketService->typeOne();
    break;
  case: TYPE_TWO:
    $this->ticketService->typeTwo();
    break;
  case: TYPE_THREE:
    $this->ticketService->typeThree();
    break;
}
или же это должно разруливаться уже непосредственно в самом сервисе как то так:

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

//Контроллер:
...
$this->ticketService->process($ticket);
...

//Сервис:
public function process(Ticket $tikcet) 
{
  switch ($ticketType) {
    case: TYPE_ONE:
      $this->typeOne($tikcet);
      break;
    case: TYPE_TWO:
      $this->typeTwo($tikcet);
      break;
    case: TYPE_THREE:
      $this->typeThree($tikcet);
      break;
  }
}
И вообще, имеется ли какое то более изящное решение? Потому как типов намечается много, и городить такой низкоуровневый код, как то не очень красиво.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение samdark »

Что-то типа TicketHandlerFactory:

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

class TicketHandlerFactory
{
     public function createTicketHandler(string $type): TicketHandlerInterface
     {
           // 
     }
}
Сами хендлеры распихиваем в отдельные реализации TicketHandlerInterface.
voodooism
Сообщения: 48
Зарегистрирован: 2018.11.12, 10:29

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение voodooism »

samdark писал(а): 2019.07.16, 15:34 Что-то типа TicketHandlerFactory:

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

class TicketHandlerFactory
{
     public function createTicketHandler(string $type): TicketHandlerInterface
     {
           // 
     }
}
Сами хендлеры распихиваем в отдельные реализации TicketHandlerInterface.
Идея ясна, но как то не получается её вписать в те концепции о которых я тут узнал.

Поясню: у меня есть TicketService(Dispatcher $dispatcher, Repoitory $repository, Notifier $notifier), соответственно со своими внедренными зависимостями.
Получается что хендлер тоже должен будет знать о всех внедренных в сервис зависимостях? Т.е. на сколько я понимаю - хэндлер, это прям непосредственный кусок самого сервиса, соответственно для полноценной работы, в него нужно внедрить всё тоже самое что и в сам сервис, или как то передовать это в метод handle() ?
voodooism
Сообщения: 48
Зарегистрирован: 2018.11.12, 10:29

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение voodooism »

Исходя из того что посоветовал samdark, пока что реализовал такое решение. Просьба оценить, на сколько вообще это номально смотрится? Задача: создать нужный тикет в зависимости от типа, и создать эвент.
Реализация:

Модель Ticket'a:

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

    public static function createTicket(TicketDto $dto)
    {
        $ticketFactory = TicketFactory::build($dto->type);
        return $ticketFactory::create($dto);
    }
TicketFactory :

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

abstract class TicketFactory
{
    public static function build($type)
    {
        switch (type) {
            case Ticket::TYPE_ONE:
                return new TypeOneTicket();
            case Ticket::TYPE_TWO:
                return new TypeTwoTicket();
            case Ticket::TYPE_THREE:
                return new TypeThreeTicket();
        }
    }
}
TicketDto:

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

abstract class TicketDto
{
    public $type;
}

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

class TypeOneTicketDto extends TicketDto
{
        ...
	public $field1;
	public $field2;
	...
	
}
TicketInterface

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

interface TicketInterface
{
    /**
     * @param TicketDto $dto
     * @return Ticket
     */
    public static function create(TicketDto $dto);
}
TypeOneTicket

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

class TypeOneTicket implements TicketInterface
{
    public static function create(TicketDto $dto)
    {
       $ticket = new Ticket();
       $ticket->field1 = $dto->field1;
       $ticket->addEvent(new EventTicketTypeOneCreated());
        return $ticket;
    }
}
Проблемы:
1) TypeOneTicket должен знать слишком много для того что бы создать тикет. Например, в зависимости от того, из какого источника пришло поле(я имею ввиду Yii::$app->user->identity), те или иные поля тикета будут обязательными.
2) т.к. метод recordEvent() является protected, и он находится в модели Ticket у класса TypeOneTicket нет возможности записать этот эвент в модель Ticket :(
uEhlO4a
Сообщения: 70
Зарегистрирован: 2017.08.12, 19:19

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение uEhlO4a »

если можно мои пару заметок и вопросов

voodooism

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

service->processTicket(ticket)
но если тебе пальцы не ломают использовать обертку в виде "service" и у тебя конкретно одно действие возможно и ты можешь сам создавать обьекты ticket, то лучше на каждый тип сделать свой класс и в нем

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

$ticket = Ticket::create($data) // тут будет mapper по типу вроде $mapper = [ type1 => class..]
$ticket->process()
и не парить себе мозги, будет у тебя папка с твоими N-типами вроде

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

Tickets\
    \Ticket.php <--- base
    \EmailTicket.php
    \SmsTicket.php

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

Область применения DDD - чистый C++ катафалк без фреймворков, область применения Doctrine - садомазохизм (иногда захожу сюда https://github.com/doctrine/orm/issues)


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

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

exception - исключение
bug - жук, ошибка
relation - связь
repository - хранилище
service - служба, услуга
domain - область
если будет такая статья - кинь ссылку я тоже почитаю

И еще, ElisDN я был бы признателен если бы ты показал какой-то реальный пример где это всё усложнение оправдано, не такое простое вроде https://github.com/ElisDN/yii2-demo-shop где можно всё было в контроллере засунуть и не париться (там кстати вместо 404 можно было сделать как ModelBinding actionShow(Post $post) но то такое, я не придираюсь) , может есть норм примеры, чтобы не вроде такого треша https://github.com/oroinc/platform , а где я смогу сказать, что оно работает и живет благодаря Doctrine и т.д. а не вопреки? Хотя возможно ты считаешь https://github.com/oroinc/platform произведением искуства, тогда обоснуй пожалуйста.


без обид, я просто привык о реальных вещах говорить.
реально скоро буду только английские источники читать, потому что это просто капец какой-то настал. через месяц может зайду. успехов
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение samdark »

Не, ну ORO — это та ещё треш-система. Всё очень гибко, но работать с этим решительно невозможно. Меняем конфиг и оно начинает компилить PHP в другой PHP компилятором на PHP. Минуты может компилить... Не знаю, как могла придти идея так сильно завязаться на compiler pass Symfony...
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение ElisDN »

uEhlO4a писал(а): 2019.08.15, 00:16 ElisDN я бы попросил научить пользователей сначала выучить значение слов, а то уже просто крышу сносит от этих "доменов" "багов" "эксепшенов" "рилейтов" "репозиториев" и другой х..еты значение которых можно за минуту узнать в переводчике, вроде такого...
За ту же минуту они также спокойно находятся на других сайтах вроде http://design-pattern.ru/patterns/
uEhlO4a писал(а): 2019.08.15, 00:16 И еще, ElisDN я был бы признателен если бы ты показал какой-то реальный пример где это всё усложнение оправдано, не такое простое вроде yii2-demo-shop где можно всё было в контроллере засунуть и не париться
Какой фрагмент кода из demo-shop вы считаете "усложнением"?

А так везде можно сначала "в контроллер засунуть и не париться". А потом дружно копипастить это всё в контроллеры для API и консоли.
uEhlO4a писал(а): 2019.08.15, 00:16 без обид, я просто привык о реальных вещах говорить.
Мы тоже о реальных вещах говорим.
uEhlO4a писал(а): 2019.08.15, 00:16 там кстати вместо 404 можно было сделать как ModelBinding actionShow(Post $post) но то такое, я не придираюсь
Yii в отличие от Laravel и Symfony так делать не умеет.
uEhlO4a писал(а): 2019.08.15, 00:16 может есть норм примеры, чтобы не вроде такого треша oroinc/platform , а где я смогу сказать, что оно работает и живет благодаря Doctrine и т.д. а не вопреки? Хотя возможно ты считаешь oroinc/platform произведением искуства, тогда обоснуй пожалуйста.
Чем вас именно Doctrine не устраивает? Это пока единственная Data Mapper ORM библиотека для проектов, которым не подходит ActiveRecord, но нет желания изобретать свой Data Mapper.

А касательно всяких oroinc/platform - любая публичная платформа/админка/система со временем переполняется оверхедом для универсальности. Поэтому универсальные решения сравнивать с кастомными некорректно.
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение anton_z »

ElisDN писал(а): 2019.08.15, 11:21
Чем вас именно Doctrine не устраивает? Это пока единственная Data Mapper ORM библиотека для проектов, которым не подходит ActiveRecord, но нет желания изобретать свой Data Mapper.
А как вы такие проекты отличаете? Есть какие-то объективные критерии? Честно, я без троллинга. По мне так здесь дело чисто в предпочтениях конкретных разработчиков. Для меня недостатки DataMapper перевешивают достоинства (обсуждали здесь). Я думаю, что Yii AR и Eloquent ORM подойдут для практически любых PHP проектов при грамотном подходе.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение ElisDN »

anton_z писал(а): 2019.08.15, 13:59 А как вы такие проекты отличаете? Есть какие-то объективные критерии? Честно, я без троллинга. По мне так здесь дело чисто в предпочтениях конкретных разработчиков. Я думаю, что Yii AR и Eloquent ORM подойдут для практически любых PHP проектов при грамотном подходе.
Для меня - любой, где нужны честные объекты с приватными полями, нативными конструкторами и объектами-значениями.

Yii AR и Eloquent так из коробки и без костылей не умеют. Только Yii более-менее научился в конструкторы после моего пулл-реквеста. Можно делать Mapping вручную тоннами кода в afterFind/beforeSave как в последней статье, превратив Yii AR или Eloquent в Doctrine. Но какой в этом смысл, если можно сразу взять Doctrine?
anton_z писал(а): 2019.08.15, 13:59 Для меня недостатки DataMapper перевешивают достоинства.
Как я понял, недостаток для вас в нём всего один: невозможность прямой работы с БД изнутри сущности.
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение anton_z »

ElisDN писал(а): 2019.08.15, 17:09
Как я понял, недостаток для вас в нём всего один: невозможность прямой работы с БД изнутри сущности.
Он главный. Есть еще проблемы поменьше, например внедрение зависимостей в сущности. В Yii я могу благодаря сервис-локатору Yii::$app в init() или конструкторе AR нужные зависимости получить. Нигде в AR кроме конструктора или Init() к SL не обращаюсь. Для БЛ зависимости почти всегда нужны какие-нибудь. Да, зависимость от Yii, но зато порой гораздо меньше приходится передавать через методы. Конечно, Yii::$app порождал много злоупотреблений как я погляжу, но не убирать его же из-за того, что кто-то им неправильно пользовался, а в Yii 3 его решили убрать как я понял. В Laravel тоже есть сервис-локатор.
ElisDN писал(а): 2019.08.15, 17:09 Можно делать Mapping вручную тоннами кода в afterFind/beforeSave как в последней статье, превратив Yii AR или Eloquent в Doctrine.
А я так не делаю, использую геттеры/сеттеры, внутри которых выполняю преобразование. Т.е. в атрибутах всегда записано в том виде, в котором оно пришло/пойдет в БД, кодирование/декодирование в геттерах/сеттерах.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Проектирование сущностей, сервисов и репозиториев

Сообщение samdark »

Если вам будет его нехватать, то сделать его самому в index.php — проще простого.
Закрыто