Есть ли причина предпочитать $ model-> load () контрактам на обслуживание?

24

Я понимаю, что предпочтительным способом работы между модулями в Magento 2 является использование сервисных контрактов.

Поэтому, если я хочу загрузить продукт, я использую репозиторий продукта:

$product = $productRepository->getById($id);

который по контракту возвращает экземпляр Magento\Catalog\Api\Data\ProductInterface.

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

$product = $productFactory->create()->load($id);

Есть ли случай, когда это было бы необходимо или полезно?

Девдоки говорят (выделение добавлено):

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

[...]

Ваша стратегия вызова кода уровня домена другого модуля сильно зависит от уникальной конфигурации и потребностей вашей системы.

Источник: http://devdocs.magento.com/guides/v2.0/architecture/archi_perspectives/domain_layer.html

И комментарий по связанному вопросу заявил:

использование репозитория даст вам модель данных Product ( Api/Data/Product), которая представляет собой модель Product, преобразованную в неработающий DTO. Что-то, чтобы рассмотреть, поскольку они довольно разные

Но, насколько я вижу, объекты одинаковы при нормальных условиях, отличаются только типы возвращаемых данных для phpDoc ( Magento\Catalog\Api\Data\ProductInterface/ Magento\Catalog\Model\Product)

Фабиан Шменглер
источник

Ответы:

23

Причина использования метода ProductRepositorys get/ getByIdвместо метода ProductFatory заключается в том load(), что первый имеет более высокий уровень, чем последний.

A ProductRepository- как и ProductFactory- может вернуть Product модель , но это не то, что M2 хочет, чтобы вы рассмотрели. Это не то, что \Magento\Catalog\Api\ProductRepositoryInterface::getById()говорит блок документации. Он говорит @return \Magento\Catalog\Api\Data\ProductInterface, что это интерфейс, который реализует модель продукта .

Итак, вы должны использовать уровень API, когда это возможно, потому что:

  • Api/Data слой используется и в Web Api
  • модели могут - и, вероятно, будут - подвергаться рефакторингу в определенный момент; Api/Data/Productне будет.
  • Чтобы получить продукт в ваших классах, вам нужно ввести либо конкретную фабрику ( ProductFactory), либо интерфейс ( ProductRepository). Я не думаю, что вы хотите, чтобы ваш модуль опирался ни на что, кроме интерфейса. Следовательно, я не согласен с этим типом инъекции .

Я считаю, что это просто еще один крошечный уровень абстракции над моделями для обслуживания веб-API (REST, SOAP и т. Д.).

Цитирую этот ответ:

Надеемся, вам понравятся сервисные контракты, когда ваш пользовательский модуль не будет нарушен после следующих выпусков Magento 2 (конечно, если вы не обходите сервисные контракты и напрямую используете модели / коллекции / модели ресурсов). И когда вы начинаете использовать / раскрывать веб-API Magento 2, который теперь основан на тех же контрактах на обслуживание. Таким образом, вы должны вносить изменения только в одном месте (например, с помощью плагина), и они будут применяться везде. Это было невозможно в Magento 1.

nevvermind
источник
Не совсем то, о чем я просил, но я тоже так думал, спасибо за подтверждение!
Фабиан Шменглер
1
But I could also use the old way instead, calling the domain layer directly: (use factory). Is there any case where this would be necessary or useful?, Да: когда вам нужно вызвать метод модели , а не метод Api/Data/Product. Это лучше? :)
nevvermind
Да, это имеет смысл :)
Фабиан Шменглер
14

Для меня нет причин использовать loadметод над getById/ getметодом.

Я не говорю, что я прав, но вот как я вижу вещи.

Итак, вот getByIdметод ( getметод похож, но использует идентификатор вместо идентификатора):

public function getById($productId, $editMode = false, $storeId = null, $forceReload = false)
{
    $cacheKey = $this->getCacheKey(func_get_args());
    if (!isset($this->instancesById[$productId][$cacheKey]) || $forceReload) {
        $product = $this->productFactory->create();
        if ($editMode) {
            $product->setData('_edit_mode', true);
        }
        if ($storeId !== null) {
            $product->setData('store_id', $storeId);
        }
        $product->load($productId);
        if (!$product->getId()) {
            throw new NoSuchEntityException(__('Requested product doesn\'t exist'));
        }
        $this->instancesById[$productId][$cacheKey] = $product;
        $this->instances[$product->getSku()][$cacheKey] = $product;
    }
    return $this->instancesById[$productId][$cacheKey];
}

Как вы можете заметить код, который вы вставили:

$productFactory->create()->load($id);

Является частью этой функции.

Однако дополнительное условие использует кэшированные экземпляры, чтобы избежать дополнительной перезагрузки в случае, если вы ранее использовали метод getByIdили getдля того же идентификатора (или sku в случае getметода) .

Вы можете подумать, что хорошей причиной для использования loadможет быть отказ от использования этих кэшированных экземпляров (в таком случае это может быть веской причиной? Я не знаю), но getByIdу getметодов и есть $forceReloadпараметр, для которого можно установить значение true, равное true. Избегайте использования этих экземпляров кэша.

Вот почему для меня нет веской причины использовать loadметод getByIdили getметоды.

Рафаэль в цифровом пианизме
источник
2

Пожалуйста, поймите разницу между хранилищами и коллекциями.

В вашем примере, если вы используете репозитории, вы получите массив, Magento\Catalog\Api\Data\ProductInterfaceкоторый отличается от получения коллекции Magento\Catalog\Model\Product.

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

Надеюсь, это поможет.

Phoenix128_RiccardoT
источник