O que e por que é a maneira correta de carregar um modelo

9

Tenho muita experiência com o Magento, mas percebi que não entendo qual a maneira de carregar um modelo é a correta e por quê. Eu li tudo o que pude sobre o tópico, mas as pessoas que explicam coisas como essa nunca são suficientemente profundas para explicar, por que usar esse método específico em vez de outro. Vamos supor que não há repositório para o modelo que eu quero carregar.

Até agora, eu estava sempre usando o modelo no construtor e, em seguida, simplesmente carregá-lo.

public function __construct(
    \Vendor\Module\Model\Something $somethingModel
) {
    $this->somethingModel = $somethingModel;
}

public function getTestById($id) {
    return $this->somethingModel->load($id);
}

E sempre funcionou como planejado, também tenho certeza de que é ou pelo menos foi usado normalmente no núcleo.

Mas então eu vi um dos meus colegas usando

modelFactory->create()->load($id)

Tanto quanto eu entendo as fábricas estão sendo usadas para criar uma nova entidade, por exemplo, se eu quiser criar um novo produto, posso criar a fábrica, preenchê-la com dados e salvá-la. Mas, novamente, comecei a pesquisar o tópico e vi exemplos de Fabian Schmengler ( quando devemos usar um repositório e uma fábrica no Magento 2? ) Que estava carregando o modelo dessa maneira e também desencorajava outros a simplesmente carregá-los, ele não ' Não explique por que, além de dizer que "não faz parte do contrato de serviço". Pelo que entendi, os repositórios fazem parte dos contratos de serviço, portanto, não vejo nenhuma conexão aqui quando se trata de carregar modelos que não estão disponíveis através de um repositório.

Para adicionar mais confusão, eu também encontrei uma maneira de carregar o modelo, obtendo o resourceModel do modelFactory criado, foi apresentado por Vinai Kopp ( Como implementar o contrato de serviço para um módulo personalizado no Magento 2? ) E agora estou completamente perdido, pois sempre li que não deveria usar modelos de recursos diretamente.

Então, sim, alguém poderia me dizer qual é a maneira correta e por que eu deveria usá-la em vez de todos os outros métodos?

czs
fonte
Estou literalmente vinculando este tópico como contendo um exemplo confuso, você leu meu post?
Czs
11
Boa pergunta, tentarei encontrar tempo para responder em detalhes mais tarde. Já posso lhe dizer isso: é um caso diferente se você carregar seus próprios modelos (exemplo da Vinai) ou modelos dos módulos principais ou de terceiros (minha resposta). Além disso, a injeção do modelo via construtor fornecerá sempre a mesma instância, o que pode levar a efeitos colaterais indesejados.
Fabian Schmengler 10/10

Respostas:

12

Bem, a primeira etapa que você deve verificar para o modelo em questão é: Existe um contrato de serviço de repositório? Nesse caso, use isso, porque os Contratos de Serviço estão vinculados ao controle de versão semântico e continuarão a se comportar como deveriam até o Magento 3.x ser lançado. Desnecessário dizer que, ao criar seus próprios módulos com modelos que requerem persistência, você também deve escrever o repositório para isso.

public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
) {
    $this->productRepository = $productRepository;
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $this->productRepository->save($product);
}

Se não houver nenhum repositório presente, use o modelo de recursos . Observe que os modelos de recursos não contêm um estado: eles estão utilizando persistência para seus modelos "regulares". Portanto, você não precisa incluí-los usando uma fábrica:

public function __construct(
    \Magento\Catalog\Model\ResourceModel\Product $productResource,
    \Magento\Catalog\Model\ProductFactory $productFactory
) {
    $this->productResource = $productResource;
    $this->productFactory = $productFactory;
    ...
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $product = $this->productFactory->create();
    $this->productResource->save($product);
}

"Então, qual benefício traz um Contrato / Repositório de Serviços sobre um Modelo de Recursos?" você pode perguntar. Bem, em teoria, um Modelo de Recursos deve ser responsável apenas pela persistência de um Modelo de Dados , enquanto um Repositório também leva em consideração as tarefas adicionais envolvidas ao salvar uma entidade. Pense em atualizar índices, criar relações com outras entidades, etc. Essa é a teoria, embora na vida real essas linhas tendam a embaçar com bastante frequência. Mas é bom para você manter isso em mente.

Você não deve usar o modelo direto save(), load()etc. -Métodos. Eles estão obsoletos porque é semântico incorreto. Pense nisso de uma maneira SOLID:

  • Os modelos (dados) devem ser responsáveis ​​apenas por conter dados.
  • Os modelos de recursos devem ser responsáveis ​​pela persistência de tais dados.
  • Os repositórios devem ser responsáveis ​​pela comunicação dentro e fora do módulo para ações de persistência.

E é esse último ponto que faz a diferença: ao se comunicar com outros módulos, em um mundo ideal, nunca se deve confiar na lógica persistente interna desses módulos (ou em qualquer um de seus métodos públicos, mas essa é outra discussão), mas use apenas a funcionalidade fornecida pelos contratos de serviço dos módulos .

Em conclusão

Para responder à sua pergunta: em ordem de preferência. A maneira correta de carregar um modelo é:

  • Se houver um Repositório, carregue-o usando o Repositório.
  • Somente se não houver repositório, use o Modelo de Recursos (em combinação com uma fábrica).
Giel Berkers
fonte
11
Ok, então se eu seguir corretamente - quando eu quiser modificar / adicionar novos dados e salvá-los no banco de dados, devo usar o Modelo de Recursos e, quando desejar carregar dados na memória, devo usar o Factory? Existe alguma situação em que eu deveria usar Model diretamente diretamente (como no uso de uma classe Model no construtor)?
CZS
@czs Você está correto, adicionei um exemplo mais descritivo para o carregamento de modelos para o mesmo.
Milind Singh
2
  • ModelsA Interface de dados é usada para manter apenas os dados em objetos, ou seja, para sete getdados para uma linha.
  • ResourceModelssão um mecanismo responsável pela persistência de tais dados, ou seja, executar a consulta SQL para realmente saveou loaddados no Modelobjeto.

A maneira correta de loade savedeve ser criando um repositório ou carregando de um recurso da seguinte maneira:

namespace MyVendor\MyModule\Model;

class QueueRepository impliments \MyVendor\MyModule\Api\QueueRepositoryInterface
{

    /** @var \MyVendor\MyModule\Model\ResourceModel\Queue  */
    public $resource;

    /** @var \MyVendor\MyModule\Model\QueueFactory  */
    public $modelFactory;

    public function __construct(
        \MyVendor\MyModule\Model\ResourceModel\Queue $resource,
        \MyVendor\MyModule\Model\QueueFactory $modelFactory
    ) {
        $this->resource = $resource;
        $this->modelFactory = $modelFactory;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @return $queue
     * @throws \Exception
     */
    public function save(\MyVendor\Integrator\Api\Data\QueueInterface $queue)
    {
        $this->resource->save($queue);
        return $queue;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @param int $id
     * @return $queue
     * @throws \Exception
     */
    public function load(\MyVendor\MyModule\Api\Data\QueueInterface $queue, $id)
    {
        $this->resource->load($queue, $id);
        return $queue;
    }

    public function getById($id)
    {
        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
    }
}

Aqui, \MyVendor\MyModule\Api\Data\QueueInterfaceé implementado pelo QueueModel.

Então, nos bastidores, estamos realmente criando um Modelobjeto e depois loadingpelo ResourceModelobjeto. Essa é a maneira correta de carregar ou salvar.

        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
Milind Singh
fonte