Como criar um Repositório personalizado no Magento 2
Tags: php, magento2, tutorial, braziliandevs
Published: 2021-12-07 12:31:03

## 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
<?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;
}
```

### 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.

```xml
<preference for="{Vendor}\{Module}\Api\{EntityName}RepositoryInterface" type="{Vendor}\{Module}\Model\{EntityName}Repository" />
```

### 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
<?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);
    }
}
```

---

## 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).

```bash
rm -rf var/generation/
rm -rf generated/
php bin/magento setup:di:compile
```

### 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
```