Pull to refresh
149
0
Игорь Миняйло @maghamed

Lead Architect, Magento an Adobe

Send message
CommandHandler-ы в вашем случае ничего не возвращают.

В типичном CQRS они и не должны, максимум, что они могут делать — бросать события, чтобы обновить Read БД


Типичный REST при создании чего-то должен вернуть идентификатор созданного ресурса.

Здесь вероятно может помочь перевод идентификаторов сущностей на UUID тогда айдишник будет известен еще в момент создания сущности.

Да, альтернативы коллекциям для реализации фильтрации сейчас нет. Но это попрежнему не значит, что ими можно пользоваться в коде бизнес логики.


Относительно первичного ключа — суррогатный ключ решает проблемы отношений.


Теперь самое важное — общий интерфейс. Разработчики Magento в данном вопросе считают правильно. А именно — что общий интерфейс BaseRepositoryInrerface вводить не нужно, более того это не правильно.


Взять, например интерфейс категории:


namespace Magento\Catalog\Api;

/**
 * @api
 */
interface CategoryRepositoryInterface
{
    /**
     * Create category service
     *
     * @param \Magento\Catalog\Api\Data\CategoryInterface $category
     * @return \Magento\Catalog\Api\Data\CategoryInterface
     * @throws \Magento\Framework\Exception\CouldNotSaveException
     */
    public function save(\Magento\Catalog\Api\Data\CategoryInterface $category);

    /**
     * Get info about category by category id
     *
     * @param int $categoryId
     * @param int $storeId
     * @return \Magento\Catalog\Api\Data\CategoryInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function get($categoryId, $storeId = null);

    /**
     * Delete category by identifier
     *
     * @param \Magento\Catalog\Api\Data\CategoryInterface $category category which will deleted
     * @return bool Will returned True if deleted
     * @throws \Magento\Framework\Exception\InputException
     * @throws \Magento\Framework\Exception\StateException
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function delete(\Magento\Catalog\Api\Data\CategoryInterface $category);

    ....

Как видите каждый из методов в своем контракте завязан на дата интерфейс категории \Magento\Catalog\Api\Data\CategoryInterface, т.е. все методы: get, getList, save, delete завязаны на контракт специфичного дата интерфейса.


Если представить, что последовать вашему примеру и ввести BaseRepositoryInrerface, то он должен в своих контрактах использовать BaseEntityInterface. Маркерный интерфейс, который расширят все Дата интерфейсы в системе. Это антиконцептуально с точки зрения доменного дизайна. Более того — это исключительно маркерный интерфейс, т.к. у нас нет ни одного метода, который бы мы могли туда положить. Даже getId не можем, потому что у сущностей с натуральным первичным ключем (например, продукт) в роли ID выступает SKU, который типа string, а не int. Естественно у такой BaseEntityInterface не можем быть реализации. Это просто маркерный интерфейс.
Поэтому Magento программисты решили договориться, и использовать во всех *RepositoryInterface одинаковый набор методов с одинаковыми параметрами, но завязанными на определенный тип сущности, как в моем примере выше на CategoryInterface

Окей, давайте по порядку.
Репозиторий это не «всего лишь обертка над коллекцией», репозиторий разделяет уровень доменных сущностей от слоя дата маппинга. Фактически это реализация классического Фаулеровского паттерна http://martinfowler.com/eaaCatalog/repository.html
Можно сказать, что репозитории представляют из себя коллекцию сущностей (Агрегейшен Рутов http://martinfowler.com/bliki/DDD_Aggregate.html в понятии DDD), которая агностична к тому, где эти сущности сохраняются и как.
Все репозитории являются частью публичного АПИ, предполагается, что репозитории будут выполнять роль Entry Point-a для работы с доменными сущностями. Поэтому именно репозитории будут плагинизироваться больше всего.

Сейчас для имплементации ф-ии getList практически все (вероятно даже все) репозитории используют механизм коллекций для реализации механизма фильтрации.
Более того, когда вы будете реализовывать АПИ для своего модуля, в реализации репозитория для сущности вашего модуля вы будете использовать коллекцию тоже. Потому что пока в Мадженто нет другого механизма, он должен появиться с версии 2.1
Но главное тут то, что код бизнес логики у вас (также как и в коде Мадженто) должен зависеть на RepositoryInterface, а не на коллекцию. Использование коллекции — это деталь реализации, которая постепенно будет меняться. Поэтому вы сами, как разработчик собственного модуля заинтересованы в том, чтобы изолировать код, который впоследствии станет деприкейтед и не плодить зависимости на него.

Композитный primary key не нужен, та же Доктрина не рекомендует использовать композитный составной ключ.

> Если исполнение «технического долга» со стороны Magento 2 Team сводится к оборачиванию коллекций в код,

Идея сводиться к тому, что нужно ввести стабильные АПИ, которые будут использовать и расширять. И иметь возможность безболезненно менять реализацию, которая кроется за этими АПИ. В данном случае Коллекции — реализация, и будет меняться на EntityManager который появится в версии 2.1

>EntityRepositoryInterface (которого, кстати, нет, хотя он просто обязан быть, если «разработчики мадженто за этим следят»)

Вот этого не понял. Почему в Мадженто должен быть общий интерфейс на репозитории? Его не должно быть и его нет.

>то все слова в отношении коллекций, сказанные коллегой Oxidant, верны также и для «обернутых коллекций».

Тут важно понимать следующее, основной посыл Oxidant сводился к тому, что программисты с недостаточным объемом знаний Мадженто, используют коллекции неправильно, когда пишут бизнес логику. Мой посыл в том, что эти программисты не должны использовать коллекции вообще. Они должны использовать репозитории, валидное использование коллекций сейчас может быть в реализации репозитория для собственного модуля, в остальном использования коллекций стоит избегать.
Сервис леер не плохо описан в документации, и если по нему есть открытые вопросы их всегда можно адресовать на Magento 2 Github или Magento stack exchange.
Также в самой системе он используется достаточно много, а те места где он не используется — можно считать техническим долгом, который постепенно будет рефакториться. Основная идея — модули могут «общаться» друг с другом только по средствам сервис контрактов.
Экстеншены, которые пишут партнеры используют сервис леер, и разработчики мадженто за этим следят.
Поэтому исходя из всего вышеперечисленного, Коллекции — это вынужденная необходимость, которую можно использовать, если нет необходимого сервис контракта. Но никак не рекомендованный механизм для разработчика.
Я же выше написал — везде где только можно. Потому что это АПИ, и Мадженто гарантирует, что она не сломает их PATCH и MINOR релизах, для коллекций и моделей такой гарантии нет.
А какие проблемы у вас возникают с фильтрацией, которые вы не можете решить с помощью SearchCriteriaBuilder?
Поэтому если кратко, то в вашем коде вы используете сервис леер везде. И только если вы не находите в нем нужного метода, тогда используете коллекцию или модель напрямую.
Ну так с этого нужно начинать, по-видимому вы не знакомы с концептом сервис леера. Поэтому я предлагаю вам почитать соответствующие статьи
Magento 2 Service Layer
Service Contracts in Magento
Magento 2 Service Contracts Patterns
Github What is the goal of the service layer in Magento 2

То, что в М2 есть коллекция — вас должно интересовать в самую последнюю очередь, если вы вдруг не найдете Сервис Контракта, удовлетворяющего ваши нужды. Во всех же обычных случаях вы будете использовать репозиторий сущности (EntityRepositoryInterface) и его метод getList(SearchCriteria $searchCriteria).
Потому что в противном случае вы зависите не на интерфейс, а на реализацию и соответственно fragility такого кода очень высока. С зависимостью на интерфейс, реализация может кастомизироваться и подменяться, но ваш код это не поломает.
я не говорю про копирование кода, я говорю про концептуальное различие. Для того, чтобы достать данные в М2 вы не используете коллекции, вы используете сервис леер Мадженто 2.
Единственный совет специфичный для Мадженто — это включите Flat вместо Eav
>но описанное так же подходит и для Magento 2.*

А почему вы это написали? Особенно то, что касается кода (кода коллекций в ваших примерах), я бы сказал, что не валидно по отношению к М2 чуть более чем полностью.

Ну и ваши рекомендации, они фактически не про Мадженто, они про Базу Данных.
Select * from table
работает медленней чем
select field from table

Поэтому не доставайте ненужные поля.
Считайте каунт не загружая записей из БД.
21 век, DDD шагает по планете, а я читаю статью про очередной квери билдер-обертку над ПДО
Я посмотрел ваш код и у меня с рота сигарета выпала.
Ваш код олицетворение шутки: "A piece of PHP code walks into a bar. The bartender informs it that they don't serve spaghetti there, so it turns around and leaves."
Просто для развлечения рекомендую вам посчитать цикломатическую сложность методов вашего года.
Ну и в целом это набор антипатерном и спагетти-кода, которое вы пафосно называете "идеальным решением". Мне кажется я вернулся в начало нулевых и посмотрел примеры кода на PHP 4.3
а чем "фигурка" не нравится?
устанавливаете через composer install?
Похоже на проблему с пермишенами в файловой системе
У вас картинка не правильная, если пост про Лисков, то картинка должна быть такой
image
По поводу repo.magento.com. Это репозиторий где хранятся Magento 2 компоненты, а также компоненты (Composer пакеты), разработанные разработчиками из комьюнити.
devdocs.magento.com/guides/v2.0/install-gde/prereq/connect-auth.html

Свои модули, как и раньше, предполагается распространять через Magento Connect
По поводу версионирования, здесь вы можете найти подробную статью о версионировании в Magento 2

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

Имеем МАЖОРНАЯ.МИНОРНАЯ.ПАТЧ у каждого модуля:

МАЖОРНУЮ версию, когда сделаны обратно несовместимые изменения API.
МИНОРНУЮ версию, когда мы добавляем новый функционал, не нарушая обратной совместимости.
ПАТЧ-версию, когда мы делаем обратно совместимые исправления.

Теперь относительно версии модуля и продуктовой версии:
Версия продукта и версии модулей независимы. Например, CE версия Magento была выпущена как 2.0, следующая будет 2.1, потому — 2.2 и т.д., но версионирование модулей началось с 100.0й версии. Такое разделение было сделано специально, чтобы упростить поддержку, и избежать ошибок и недопониманий в общении, когда мерчанты/программисты ссылаются на версию продукта вместо версии модуля и наоборот.
Ну и со временем версия продукта и версии модулей будут расходиться все больше.

Внизу вы можете видеть наглядную диаграмму развития продуктовой версии, а также версий модулей:

image
Если кого-то интересуют архитектурные темы связанные с Magento 2

  • Service Layer в Magento 2. Что это, зачем. Как использовать
  • Механизм Плагинизации
  • Как мы (команда Magento) видит правильную работу интеграторов с Magento 2
  • Кодогенерация в Magento 2


Может быть какие-то другие темы будут также интересны.
Напишите — буду рад осветить подробно в отдельном посте
DI контейнер и не должен никуда передаваться. Передаётся сервис локатор.


Когда я говорил про DI контейнер я имел в виду сущность, которая в Symfony называется Service Container. Т.е. сущность ответственная за создание сущностей в приложении.

Так вот, в Magento эта сущность называется ObjectManager и она НЕ передается (не должна передаваться) в создаваемые бизнес сущности. Классы имеют зависимости только на другие классы, которые им нужны для выполнения бизнес задач, и не имеют служебных зависимостей на сервис контейнер. Соответственно код бизнес сущностей написан так, что они не знают о существовании ObjectManager и DI в проекте.

Здесь можно подробней почитать про DI в Magento 2

Почему пишется про сервис локатор, и потом как следствие упоминаются проблемы в DI? И каким образом DI создаёт эти проблемы?


Вы не внимательно читаете мои ответы:

Более того, когда в Мадженто 1 данная модель содержала в себе все те же зависимости, но использовала внутри себя Service Locator для их инстанциации этого никто не замечал и все с этим жили. DI показал много проблем в зависимостях у классов и модулях, между которыми не должно быть этих зависимостей.


DI не создает эти проблемы — он их показывает. Проблема с лишними зависимостями в этом классе была всегда, т.е. со времен Мадженто 1, но это было не так очевидно. Потому что в каких-то местах (внутри тела класса) использовался ServiceLocator для создания нужных зависимостей, в других местах использовался Registry, для получения уже инстанциированных сущностей из регистра. В М2 появился DI и конструкторная иньекция. Соответственно все зависимости этой модели перешли в конструктор. И нарушение SRP стало очевидным.
Может имело бы смысл написать отдельный пост на Хабре, т.к. вчера зарелизилась Magento 2 GA
И осветить в нем отдельные вопросы, которые, как я вижу, вызывают много вопросов:
  • Service Layer в Magento 2. Что это, зачем. Как использовать
  • Механизм Плагинизации
  • Как мы (команда Magento) видит правильную работу интеграторов с Magento 2
  • Кодогенерация в Magento 2

Может быть какие-то другие темы будут также интересны. Потому что сам фреймворк М2 очень технологичен и современен, поэтому некоторые вещи на первый взгляд вызывают много вопросов и не всегда правильно поняты. Это как iPhone, которым по словам Стива Джобса не все правильно держали в руках, когда звонят, поэтому уровень сигнала падал :)

Information

Rating
Does not participate
Location
Киев, Киевская обл., Украина
Date of birth
Registered
Activity