Existe alguma razão para preferir $ model-> load () sobre contratos de serviço?

24

Entendo que a maneira preferida de trabalhar entre os módulos no Magento 2 é usando os contratos de serviço.

Portanto, se eu quiser carregar um produto, eu uso o repositório do produto:

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

que é por contrato retornando uma instância de Magento\Catalog\Api\Data\ProductInterface.

Mas eu também poderia usar a maneira antiga, chamando a camada de domínio diretamente:

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

Existe algum caso em que isso seria necessário ou útil?

Os devdocs dizem (destaque adicionado):

Um módulo pode chamar diretamente em outro módulo. Essa solução fortemente acoplada não é recomendada para a maioria das situações, mas às vezes é inevitável .

[...]

Sua estratégia para chamar o código da camada de domínio de outro módulo depende muito da configuração e necessidades exclusivas do seu sistema.

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

E um comentário sobre uma pergunta relacionada afirmou:

usar o Repositório fornecerá um modelo de dados do Produto ( Api/Data/Product), que é um modelo do Produto convertido em um DTO simplificado. Algo a considerar, pois são bem diferentes

Mas, tanto quanto posso ver, os objetos são os mesmos em condições normais, apenas os tipos de retorno por phpDoc diferem ( Magento\Catalog\Api\Data\ProductInterface/ Magento\Catalog\Model\Product)

Fabian Schmengler
fonte

Respostas:

23

O motivo para usar o método ProductRepositorys get/ em getByIdvez do load()método ProductFatory é porque o primeiro possui um nível mais alto que o segundo.

A ProductRepository- assim como a ProductFactory- pode retornar um Product modelo , mas não é isso que M2 quer que você considere. Não é isso que \Magento\Catalog\Api\ProductRepositoryInterface::getById()o bloco de documentos diz. Diz @return \Magento\Catalog\Api\Data\ProductInterface, que é uma interface que um modelo de Produto está implementando.

Portanto, você deve usar a camada API sempre que possível, porque:

  • Api/Data camada é usada na API da Web, também
  • modelos podem - e provavelmente serão - ser refatorados em algum momento; Api/Data/Productnão vou.
  • Para obter um produto em suas aulas, você precisa injetar uma fábrica de concreto ( ProductFactory) ou uma interface ( ProductRepository). Eu não acho que você deseja que seu módulo dependa de nada além de uma interface. Por isso, discordo deste tipo de injeção .

Considero que é apenas mais uma pequena camada de abstração acima dos modelos, para atender à API da Web (REST, SOAP etc.).

Citando esta resposta:

Felizmente, você vai adorar contratos de serviço quando seu módulo personalizado não for quebrado após os próximos lançamentos do Magento 2 (é claro se você não ignorar os contratos de serviço e usar modelos / coleções / modelos de recursos diretamente). E quando você começa a consumir / expor a API da web Magento 2, que agora é baseada nos mesmos contratos de serviço. Então você tem que fazer alterações apenas em um lugar (por exemplo, via plugin) e elas serão aplicadas em qualquer lugar. Isso era impossível no Magento 1.

nevvermind
fonte
Não é exatamente o que eu estava pedindo, mas era o que eu pensava também, obrigado pela confirmação!
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?. Sim: quando você precisar chamar o método de um modelo e não o método de Api/Data/Productum. Isso é melhor? :)
nevvermind 18/04/19
Sim, isso faz sentido :)
Fabian Schmengler
14

Para mim, não há razão para usar o loadmétodo sobre o getById/ getmétodo.

Não digo que estou certo, mas eis como vejo as coisas.

Ok, então aqui está o getByIdmétodo (o getmétodo é semelhante, mas usa o sku em vez do 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 você pode observar o código que você colou:

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

Faz parte desta função.

No entanto, a condição extra usa instâncias em cache para evitar uma recarga extra caso você tenha usado anteriormente getByIdo getmétodo ou para o mesmo ID (ou sku no caso do getmétodo) .

Você pode pensar que um bom motivo para usar loadpoderia ser evitar o uso dessas instâncias em cache (nesse caso, poderia ser um bom motivo? Que eu não sei), mas getByIdos getmétodos e têm um $forceReloadparâmetro que pode ser definido como verdadeiro para evite usar essas instâncias de cache.

É por isso que, para mim, não há uma boa razão para usar loadmétodos getByIdou getmétodos.

Raphael na Digital Pianism
fonte
2

Por favor, entenda a diferença entre repositórios e coleções.

No seu exemplo, se estiver usando repositórios, você obterá uma matriz Magento\Catalog\Api\Data\ProductInterfacediferente da obtenção de uma coleção de Magento\Catalog\Model\Product.

Repositórios e interface de dados oferecem um alto nível de interface que deve ser garantido como compatível em futuras versões . É por isso que é a abordagem sugerida.

Espero que ajude.

Phoenix128_RiccardoT
fonte