Como devo salvar entidades novas ou atualizadas de modelos?

10

No Magento 2, temos classes de repositórios. O método clássico save()usado fortemente no Magento 1.9 está obsoleto, se eu estiver correto, de 2.04 ou 2.05. Eu estava usando fábricas para criar novo objeto e depois de definir propriedades de new, por exemplo, produto que chamei save():

$productFactory->create()->setName()...->save()

Por outro lado, temos repositórios também contendo method save. Estou usando em poucas palavras como este:

$product = $productFactory->create()->setName()... $productRepository->save($product)

No meu código, tenho classes trabalhando nos dois sentidos. Também notei que, às vezes, maneiras diferentes significam comportamentos diferentes. O repositório fornece alguma validação adicional de dados?

Qual o caminho que devo fazer?

Bartosz Kubicki
fonte

Respostas:

10

Vamos primeiro ver o que acontece se você usar o save()método diretamente em um productmodelo como

/**
 * @var Magento\Catalog\Model\Product $product
 */
$product->save();

A própria classe de modelo é

Magento\Catalog\Model\Product

Nessa classe, procure a definição do método save ().

Nenhum encontrado certo? Bem, há beforeSave () e afterSave (), mas não o save (). Interessante, não?

Então, precisamos olhar para as classes pai de Magento\Catalog\Model\Product.

Precisamos passar Magento\Catalog\Model\AbstractModele Magento\Framework\Model\AbstractExtensibleModel, finalmente, chegar Magento\Framework\Model\AbstractModel.

Com certeza, existe um método save () aqui e parece algo como

public function save()
{
    $this->_getResource()->save($this);
    return $this;
}

Vemos agora, sempre que save () é chamado em qualquer modelo, o método save () AbstractModelé chamado e a implementação é que o RESOURCE MODEL realmente faz o salvamento.

Este último não é surpreendente, uma vez que estamos sempre, desde o início do tempo no Magento 1.0, criando um modelo e um modelo de recurso para praticamente qualquer entidade.


Agora, vamos ver como isso ProductRepositoryfunciona.

Permite abrir arquivo

/vendor/magento/module-catalog/Api/ProductRepositoryInterface.php

Essa interface exige que exista um método save (), entre outros métodos.

Quem está realmente implementando essa interface?

Permite abrir arquivo

/etc/di.xml

e verifique a linha 10

<preference for="Magento\Catalog\Api\ProductRepositoryInterface" type="Magento\Catalog\Model\ProductRepository" />

Então, naturalmente, encontramos a implentação do método save () dentro

/vendor/magento/module-catalog/Model/ProductRepository

e começa na linha 444, parecendo algo como

public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveOptions = false)
{
    $tierPrices = $product->getData('tier_price');

    try {
    .... other code here ....

Esse método espera que um objeto $ product do tipo seja \Magento\Catalog\Api\Data\ProductInterfacepassado, mas, por padrão, isso resolve para Magento\Catalog\Model\Product.

Olhando para baixo na linha 500, em uma trydeclaração, vemos algo como

$this->resourceModel->save($product);

Você adivinhou bem! $this->resourceModelé do tipo \Magento\Catalog\Model\ResourceModel\Product, declarado como protectedpropriedade na linha 77.

Então, novamente, o que ResourceModelrealmente economiza.

Mas, entre as linhas 444 e 500, é realmente a resposta para sua pergunta. Todo o código executado aqui, de fato, eventualmente pode e levará a diferenças de comportamento entre o salvamento direto do modelo e essa maneira de salvar o repositório.

Por exemplo, o repositório do produto obterá e processará os links do produto, se ignore_links_flagestiver definido como 0, verifique se este é um produto existente, em primeiro lugar etc.

Provavelmente, precisamos concluir que, se houver necessidade de alterar no futuro como o produto é salvo, talvez a melhor maneira de fazê-lo seja substituindo o repositório do produto em vez do modelo do produto.

O mesmo vale para salvar e atualizar produtos. Prefiro usar o objeto de repositório do produto.

Também refiro a você /vendor/magento/module-cms/Model/PageRepository.php

É assim que uma página do CMS seria salva via repositório. Aqui, as coisas são mais simples. O ID da loja é definido e o modelo de recursos é chamado para salvar imediatamente.

Com este último aviso, você concluirá que, em alguns casos, pode não haver muitas diferenças entre o repositório e o modelo salvo, mas, de qualquer forma, espero que você esteja equipado agora para identificá-los sempre que precisar.

Marjan
fonte
1

É recomendável usar interfaces de dados (por exemplo \Magento\Catalog\Api\Data\ProductInterface) em vez do modelo diretamente e usar os repositórios para carregar e salvar modelos.

Veja a documentação do desenvolvedor Magento

ochnygosch
fonte
11
ok - esse é o caminho certo para toda a entidade - mas apenas para atualizar o valor de algum atributo - acho que carregar / salvar toda a entidade não é recomendado.
Bartosz Kubicki