Como criar um Repositório personalizado no Magento 2

Lucas Teixeira dos Santos Santana - Dec 7 '21 - - Dev Community

Contextualizando

Repositórios

A utilização do Repository contribui no isolamento da camada de acesso a dados (DAL) com a camada de negócio, impulsionando o uso da injeção de dependência (DI) e proporcionando uma visão mais orientada a objetos das interações com a camada de DAL, mais conhecida como camada de domínio. O padrão Repository faz a mediação entre o domínio e as camadas de mapeamento de dados usando uma interface semelhante a uma coleção para acessar os objetos de domínio, ou seja, o repositório fornece uma abstração de dados, para que sua aplicação possa trabalhar com uma abstração simples que tem uma interface próxima a de uma coleção.
Adicionar, remover, atualizar e selecionar itens dessa coleção é feito por meio de uma série de métodos simples, sem a necessidade de lidar com problemas de banco de dados como conexões, comandos, cursores ou leitores. Usar esse padrão pode ajudar a obter um acoplamento fraco e pode manter a persistência de objetos de domínio ignorante.
O repositório encapsula o conjunto de objetos persistentes em um armazenamento de dados e as operações realizadas sobre eles, fornecendo uma visão mais orientada a objetos da camada de persistência. O repositório também suporta o objetivo de alcançar uma separação limpa e dependência unilateral entre o domínio e as camadas de mapeamento de dados.
Com o uso desse padrão de projeto, aplicamos em nossa camada de domínio o princípio da persistência ignorante (PI), ou seja, nossas entidades da camada de negócio, não devem sofrer impactos pela forma em que são persistidas no banco de dados.


Código para criar um repositório

Interface

No Magento, primeiro criamos a interface do repositório no caminho \{Vendor}\{Module}\Api\{EntityName}RepositoryInterface. É recomendado que a interface da entidade esteja criada e sobrescrita na sua respectiva Model para que possa ser usada a tipagem na classe de repositório.

<?php

namespace {Vendor}\{Module}\Api;

use {Vendor}\{Module}\Model\{EntityName};

interface {EntityName}RepositoryInterface
{
    public function getById(int $id): {EntityName};

    public function save({EntityName} $object): {EntityName};

    public function delete({EntityName} $object): bool;

    public function deleteById(int $id): bool;
}
Enter fullscreen mode Exit fullscreen mode

di.xml

Após a criação da interface do repositório é necessário a sobrescrição através do arquivo di.xml, para que o arquivo fique devidamente implementado e possa descrever em como os métodos serão executados.

<preference for="{Vendor}\{Module}\Api\{EntityName}RepositoryInterface" type="{Vendor}\{Module}\Model\{EntityName}Repository" />
Enter fullscreen mode Exit fullscreen mode

Repositório

Criado a interface do repositório e a sobrescrição da interface através do arquivo di.xml, falta apenas implementar os métodos da interface na classe do repositório.

<?php

namespace {Vendor}\{Module}\Model;

use {Vendor}\{Module}\Api\{EntityName}RepositoryInterface;
use {Vendor}\{Module}\Model\{ModelName}Factory;
use {Vendor}\{Module}\Model\ResourceModel\{ResourceModelName};
use {Vendor}\{Module}\Model\{EntityName};
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\CouldNotDeleteException;

class {EntityName}Repository implements {EntityName}RepositoryInterface
{
    public function __construct(
        private {ModelName}Factory $modelNameFactory,
        private {ResourceModelName} $resourceModelName
    ) {
    }

    public function getById(int $id): {EntityName}
    {
        $entity = $this->modelNameFactory->create();
        $this->resourceModelName->load($entity, $id);

        if(!$entity->getId()) {
            throw NoSuchEntityException::singleField('{entity_column_id}', $id);
        }

        return $entity;
    }

    public function save({EntityName} $entity): {EntityName}
    {
        try {
            $entity->getResource()->save($entity);
        } catch (\Exception $exception) {
            throw new CouldNotSaveException(
                __('Unable to save object. Error: %1', $exception->getMessage())
            );
        }

        return $entity;
    }

    public function delete({EntityName} $entity): bool
    {
        try {
            $this->resourceModelName->delete($entity);
        } catch (\Exception $exception) {
            throw new CouldNotDeleteException(__(
                'Unable to remove object with ID %1. Error: %2',
                $entity->getId(),
                $exception->getMessage()
            ));
        }

        return true;
    }

    public function deleteById(int $id): bool
    {
        $entity = $this->getById($id);
        return $this->delete($entity);
    }
}
Enter fullscreen mode Exit fullscreen mode

Finalizando

Valores entre chaves ({test}) devem ser alterados na implementação do código.

Habilitando as alterações

Apague os arquivos que são gerados na compilação do Magento e execute o comando PHP para gerar a configuração das injeções de dependência e todas as classes ausentes que precisam ser geradas (proxys, interceptors, etc).

rm -rf var/generation/
rm -rf generated/
php bin/magento setup:di:compile
Enter fullscreen mode Exit fullscreen mode

Diretórios e Arquivos

Segue a a lista de diretórios e arquivos que devem ser criados.

- app/
  - code/
    - {Vendor}/
        - {Module}/
          - Api/
            - {EntityName}RepositoryInterface.php
          - etc/
            - di.xml
            - module.xml
          - Model/
            - {EntityName}Repository.php
            - {EntityName}.php
            - ResourceModel/
              - {EntityName}.php
              - {EntityName}/
                - Collection.php
          - registration.php
          - composer.json
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .