¿Hay alguna razón para preferir $ model-> load () sobre los contratos de servicio?

24

Entiendo que la forma preferida de trabajar entre módulos en Magento 2 es usar los contratos de servicio.

Entonces, si quiero cargar un producto, uso el repositorio del producto:

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

que es por contrato devolviendo una instancia de Magento\Catalog\Api\Data\ProductInterface.

Pero también podría usar el método antiguo, llamando directamente a la capa de dominio:

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

¿Hay algún caso en el que esto sea necesario o útil?

Los devdocs dicen (resaltado agregado):

Un módulo puede llamar directamente a otro módulo. Esta solución estrechamente acoplada no se recomienda para la mayoría de las situaciones, pero a veces es inevitable .

[...]

Su estrategia para llamar al código de capa de dominio de otro módulo depende en gran medida de la configuración y las necesidades únicas de su sistema.

Fuente: http://devdocs.magento.com/guides/v2.0/architecture/archi_perspectives/domain_layer.html

Y un comentario sobre una pregunta relacionada declaró:

el uso del Repositorio le dará un modelo de datos del Producto ( Api/Data/Product), que es un modelo de Producto convertido en un DTO tonto. Algo a considerar, ya que son bastante diferentes.

Pero por lo que puedo ver, los objetos son los mismos en condiciones normales, solo los tipos de retorno por phpDoc difieren ( Magento\Catalog\Api\Data\ProductInterface/ Magento\Catalog\Model\Product)

Fabian Schmengler
fuente

Respuestas:

23

La razón para usar ProductRepository's get/ en getByIdlugar del load()método de ProductFatory es porque el primero es de un nivel más alto que el segundo.

A ProductRepository, al igual que un ProductFactory, podría devolver un Product modelo , pero eso no es lo que M2 quiere que tengas en cuenta. Eso no es lo que \Magento\Catalog\Api\ProductRepositoryInterface::getById()dice el bloque de documentos. Dice @return \Magento\Catalog\Api\Data\ProductInterface, que es una interfaz que está implementando un modelo de Producto .

Por lo tanto, debe usar la capa API siempre que sea posible, porque:

  • Api/Data la capa también se usa en la API web
  • los modelos pueden, y probablemente lo serán, refactorizarse en algún momento; Api/Data/ProductNo lo haré.
  • Para obtener un producto en sus clases, debe inyectar una fábrica de concreto ( ProductFactory) o una interfaz ( ProductRepository). No creo que quieras que tu módulo dependa de otra cosa que no sea una interfaz. Por lo tanto, no estoy de acuerdo con este tipo de inyección .

Considero que es solo otra pequeña capa de abstracción sobre los modelos, para atender a la API web (REST, SOAP, etc.).

Citando esta respuesta:

Con suerte, le encantarán los contratos de servicio cuando su módulo personalizado no se rompa después de las próximas versiones de Magento 2 (por supuesto, si no omite los contratos de servicio y utiliza modelos / colecciones / modelos de recursos directamente). Y cuando comienza a consumir / exponer la API web de Magento 2, que ahora se basa en los mismos contratos de servicio. Por lo tanto, debe realizar cambios solo en un lugar (por ejemplo, a través del complemento) y se aplicarán en todas partes. Esto fue imposible en Magento 1.

nevvermind
fuente
No es exactamente lo que estaba pidiendo, pero eso fue lo que pensé también, ¡gracias por la confirmación!
Fabian Schmengler
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?. Sí: cuando necesita llamar al método de un modelo y no al de Api/Data/Productuno. ¿Es esto mejor? :)
nevvermind
Sí, eso tiene sentido :)
Fabian Schmengler
14

Para mí, no hay ninguna razón para usar el loadmétodo sobre el método getById/ get.

No digo que tenga razón, pero así es como veo las cosas.

Ok, aquí está el getByIdmétodo (el getmétodo es similar pero usa el sku en lugar del id):

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];
}

Como puede notar el código que pegó:

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

Es parte de esta función.

Sin embargo, la condición adicional utiliza instancias almacenadas en caché para evitar una recarga adicional en caso de que haya utilizado previamente getByIdel getmétodo o para el mismo id (o sku en el caso del getmétodo) .

Puede pensar que una buena razón para usar loadpodría ser evitar usar esas instancias almacenadas en caché (en cuyo caso, ¿podría ser una buena razón? Eso no lo sé) pero getByIdlos getmétodos y tienen un $forceReloadparámetro que puede establecerse en verdadero a evite usar esas instancias de caché.

Por eso, para mí, no hay una buena razón para usar loadmétodo getByIdo getmétodos.

Raphael en Digital Pianism
fuente
2

Por favor, comprenda la diferencia entre repositorios y colecciones.

En su ejemplo, si usa repositorios, obtendrá una matriz Magento\Catalog\Api\Data\ProductInterfacediferente de la de una colección de Magento\Catalog\Model\Product.

Los repositorios y la interfaz de datos le brindan un alto nivel de interfaz que debería garantizarse como compatible en futuras versiones . Por eso es el enfoque sugerido.

Espero eso ayude.

Phoenix128_RiccardoT
fuente