Search Criteria no Magento 2
Tags: php, magento2, tutorial, braziliandevs
Published: 2021-12-10 12:57:07

## Contextualizando

### O que é Search Criteria?

O *Search Criteria* (critério de pesquisa) é literalmente um critério para pesquisar e/ou filtrar o resultado de um repositório desejado. É possível realizar um critério de pesquisa implementando uma interface para construir requisições personalizadas com diferentes condições que retornarão um vetor com os itens correspondentes a pesquisa.

Saiba como criar repositórios personalizados no post "[Como criar um Repositório personalizado no Magento](https://dev.to/santanaluc94/como-criar-um-repositorio-personalizado-no-magento-2926)".

Saiba como criar APIs personalizados no post "[Como criar APIs personalizadas no Magento 2](https://dev.to/santanaluc94/como-criar-apis-personalizadas-no-magento-2-2hon)".

---

## Código para criar o Search Criteria

Para utilizar o *Search Criteria* em uma entidade personalizada é necessário criar uma interface de repositório e implementar o seguinte código da interface em uma classe.

### API do Repositório

O *Search Criteria* (critério de pesquisa) deve ser criado dentro da classe de repositório da entidade com um método que implemente a classe `\Magento\Framework\Api\SearchCriteriaInterface`, que permite criar solicitações personalizadas com condições diferentes para executar filtros, ordenações, etc. 

A classe obriga a implementação do método `getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria)`, que define que o repositório deve retornar um objeto do resultado da pesquisa, através da coleção da entidade pesquisada. O objeto desta entidade deve implementar a interface `\Magento\Framework\Api\SearchResultsInterface`.

```php
<?php

namespace {Vendor}\{Module}\Api;

use {Vendor}\{Module}\Api\Data\{EntityName}Interface;
use Magento\Framework\Api\SearchCriteriaInterface;

interface {EntityName}RepositoryInterface
{
    // Other repository methods

    public function getList(SearchCriteriaInterface $searchCriteria): {EntityName}Interface;
}
```

### API dos Resultados da Pesquisa

O objeto desta entidade deve estender a interface `\Magento\Framework\Api\SearchResultsInterface`. Esta interface implementará os métodos `getItems()`, que retorna um array com os items correspondentes ao critério de busca do repositório, e o método `setItems(array $items)`, que deve receber um *array* com os itens a serem definidos para o critério de busca. 

```php
<?php

namespace {Vendor}\{Module}\Api\Data;

use Magento\Framework\Api\SearchResultsInterface;

interface {EntityName}SearchResultsInterface extends SearchResultsInterface
{
    public function getItems(): array;

    public function setItems(array $items): self;
}
```

### 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\Data\{EntityName}SearchResultsInterface" type="{Vendor}\{Module}\Model\{EntityName}SearchResults" />
```

### Resultados da Pesquisa

Esta classe deverá estender a classe `\Magento\Framework\Api\SearchResults` que implementará os métodos `getItems()` e `setItems(array $items)` da api personalizada dos resultados da pesquisa.

```php
<?php

namespace {Vendor}\{Module}\Model;

use Magento\Framework\Api\SearchResults;
use {Vendor}\{Module}\Api\Data\{EntityName}SearchResultsInterface;

class {EntityName}SearchResults extends SearchResults implements {EntityName}SearchResultsInterface
{
}
```

### Repositório

No repositório será implementado o método `getList(SearchCriteriaInterface $searchCriteria)` que retornará um objeto da entitdade da `\{Vendor}\{Module}\Api\Data\{EntityName}SearchResultsInterface`.

```php
<?php

namespace {Vendor}\{Module}\Model;

use {Vendor}\{Module}\Api\{EntityName}RepositoryInterface;
use {Vendor}\{Module}\Model\ResourceModel\{EntityName}\CollectionFactory;
use {Vendor}\{Module}\Model\{EntityName}SearchResultsFactory;
use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface;
use Magento\Framework\Api\SearchCriteriaInterface;
use {Vendor}\{Module}\Model\ResourceModel\{EntityName}\Collection;
use {Vendor}\{Module}\Api\Data\{EntityName}SearchResultsInterface;

class {EntityName}Repository implements {EntityName}RepositoryInterface
{
    public function __construct(
        // Other classes for dependency injection
        private CollectionFactory $collectionFactory,
        private {EntityName}SearchResultsFactory $entityNameSearchResultsFactory,
        private CollectionProcessorInterface $collectionProcessor
    ) {
    }

    // Implementation of other repository methods

    public function getList(SearchCriteriaInterface $searchCriteria): {EntityName}SearchResultsInterface
    {
        /** @var Collection $collection */
        $collection = $this->collectionFactory->create();

        $this->collectionProcessor->process($searchCriteria, $collection);

        /** @var {EntityName}SearchResultsInterface $searchResults */
        $searchResults = $this->entityNameSearchResultsFactory->create();
        $searchResults->setSearchCriteria($searchCriteria);
        $searchResults->setItems($collection->getItems());

        return $searchResults;
    }
}
```

Os objetos do resultado da pesquisa contêm o objeto de critério de pesquisa (que são as entidades retornadas) e as informações sobre a contagem total das entidades encontradas, independentemente de quaisquer limitações definidas nos critérios.

---

## Critérios de Busca nas APIs

Para pesquisas através de APIs que invocam a chamada do método `{EntityName}Repository::getList(SearchCriteriaInterface $searchCriteria)`. Os critérios de busca devem ser especificados na URL da requisição em APIs do método POST. O padrão básico para especificar o critério de busca deve seguir o modelo:

```
searchCriteria[filter_groups][{index}][filters][{index}][field]={field_name}
searchCriteria[filter_groups][{index}][filters][{index}][value]={search_value}
searchCriteria[filter_groups][{index}][filters][{index}][condition_type]={operator}
```

- **field**: é o nome do atributo pesquisado;
- **value**: valor especificado para pesquisa;
- **condition_type**: é a condição para busca. Caso o `condition_type` não seja especificado, eles assumirá o valor de `eq`.

O *index* `filter_groups` no *array* define um ou mais `filters`. Cada filtro define um termo de busca e o `field`, `value` e `condition_type` de cada termo de busca deve estar atribuído ao mesmo número do `index`, iniciando em `0`.

### Condição da Busca para Search Criteria

| Tipo    | Descrição                                                         |
|---------|-------------------------------------------------------------------|
| eq      | Igual ao valor passado                                            |
| finset  | O valor passado dentro de um conjunto                             |
| from    | O início de um intervalo. Deve ser usado com a condição to        |
| gt      | Maior que o valor passado                                         |
| gteq    | Maior ou igual ao valor passado                                   |
| in      | O valor passado pode ser separados por vírgula e estar dentro     |
| like    | O valor passado pode ter os caracteres especiais SQL              |
| lt      | Menor que o valor passado                                         |
| lteq    | Menor ou igual ao valor passado                                   |
| moreq   | Mais ou igual ao valor passado                                    |
| neq     | Não igual ao valor passado                                        |
| nfinset | O valor passado não está dentro de um conjunto                    |
| nin     | O valor passado pode ser separados por vírgula e não estar dentro |
| notnull | O valor passado não pode ser null                                 |
| null    | O valor passado for null                                          |
| to      | O fim de um intervalo. Deve ser usado com a condição from         |

- Para utilizar a pesquisa com uma condicional *OR* (ou), deve especificar múltiplos `filters` dentro do `filter_groups`. Condicionais do tipo *OR* não podem utilizar diferentes `filter_groups`
- Para utilizar a pesquisa com uma condicional *AND* (e), deve especificar múltiplos `filter_groups`

Outros critérios de busca:

- `searchCriteria[sortOrders][{index}][field]={field-name}`: especifica o campo que será ordenado. Por padrão, os resultados desta busca são retornados em ordem decrescente. É possível ordenar múltiplos campos especificando o valor com `ASC` ou `DESC`;
- `searchCriteria[pageSize]`: especifica o número máximo de itens para retornar. O valor deve ser um inteiro. Caso o valor não for passado, o sistema irá retornar todas os valores;
- `searchCriteria[currentPage]`: retorna a página atual da busca.

---

## 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) e para limpar todos os caches de armazenamento em cache do processos.

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

### 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
            - Data/
              - {EntityName}SearchResultsInterface.php
          - etc/
            - module.xml
            - {area}/
              - di.xml
          - Model/
            - {EntityName}Repository.php
            - {EntityName}SearchResults.php
          - registration.php
          - composer.json
```