ORM Eloquent: Factory
Tags: laravel, beginners, php
Published: 2022-11-29 21:08:34

Quando vamos realizar testes na aplicação, persistimos alguns registros para validações mais simples, tarefa árdua pois precisamos simular dados fictícios para inserir na aplicação.

Há serviços on-line onde podemos baixar esses dados em formato json, mas mesmo esses facilitadores apresentam limitações no schema, resultando em mais trabalho para adequar o schema ao contexto do projeto.

Felizmente, o ORM Eloquent disponível no Laravel possui uma classe com métodos para geração de diversos tipos de dados fictícios, onde a grande vantagem é poder utilizar os modelos da própria aplicação para persistir as informações.

Estou me referindo à classe abstrata `Illuminate\Database\Eloquent\Factories\Factory`. 

Ao longo deste artigo vou mostrar alguns métodos para criação de informações fictícias para cada modelo. Não haverá interação com a camada de persistência e todo o conteúdo deste artigo pode ser encontrado na documentação oficial [aqui](https://laravel.com/docs/9.x/eloquent-factories).

:warning: É recomendável conhecimento prévio sobre Laravel.

---
### Conteúdo

Este artigo está organizado de forma a facilitar a busca por informações. Se você quiser mais detalhes acerca do funcionamento da classe **Factory**, sugiro ler os itens 1 e 2.

Mas se você está buscando saber como gerar tipos específicos, então seu destino está entre os itens 3 e 8.

Boa leitura. :smile:

1. [Por onde começar](#beginning)
2. [Gerando informações fictícias](#howitworks)
3. [Dados pessoais](#personaldata)
4. [Endereço](#addressdata)
5. [Texto](#text)
6. [Números](#numbers)
7. [Data e hora](#datetime)
8. [Outros](#several)

---

### Por onde começar<a name="beginning"></a>

A maneira mais prática de criar uma classe que estenda de  **\Eloquent\Factories\Factory** é através do Artisan. Utilizando qualquer terminal, acesse o diretório raiz da aplicação e digite o seguinte comando:

```
php artisan make:factory <nome_da_factory>
```

Assim que o comando for executado um novo arquivo será criado no no diretório \database\factories\ com o conteúdo mostrado logo a seguir:

```php
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Model>
 */
class SampleFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition()
    {
        return [
            //
        ];
    }
}

```

A classe que acabamos de criar possui apenas um método, chamado `definition` onde toda mágica acontece e como podemos ver na assinatura desse método o retorno é um array de string/valor, ou algo como `'propriedade' => 'valor'`. 

Embora a declaração do método indique que ele retornará o estado padrão do modelo esta classe é totalmente desacoplada do modelo (**Illuminate\Database\Eloquent\Model**) dentro de aplicações Laravel.

Há duas formas de retornarmos informações para o método `definition`. A primeira é utilizar a propriedade protegida `faker` que extende de abastrata **Eloquent\Factories\Factory** ou através do helper `fake()`.

A principal diferença é que no helper `fake()` podemos passar o dialeto ($locale) para geração das informações, aumentando a assertividade dos dados.

Abaixo está a assinatura do método `fake()`.

```php
/**
 * Get a faker instance.
 *
 * @param  ?string  $locale
 * @return \Faker\Generator
 */
function fake($locale = null)
```

---

### Gerando informações fictícias<a name="howitworks"></a>

Para o mesmo tipo de dado o método fake() disponibiliza, quando disponível, duas formas de gerar informações. 

A primeira é consultando diretamente uma propriedade. 
Por exemplo, para criar nomes fictícios utilizamos o seguinte código:

```
fake()->name
```

E a segunda é chamando um método que retorna o nome, também fictício, conforme o código abaixo:

```
fake()->name()
```

A vantagem é no método `name()` é a existência do argumento opcional `$gender` que define o gênero do nome a ser criado.
 
A seguir vou listar vários tipos de dados que podem ser gerados, agrupando-os em categorias para facilitar a busca e utilização.

---

### Dados pessoais<a name="personaldata"></a>

Este grupo de métodos retorna diversas informações pessoais, de nomes a números de telefone. A tabela a seguir traz o nome da propriedade e qual retorno fornecido. 

| Propriedade       | Retorno                 |
| ----------------- | ----------------------- |
| `fake()->name` | nome completo |
| `fake()->lastName` | sobrenome |
| `fake()->firstNameMale` | primeiro nome masculino |
| `fake()->firstNameFemale` | primeiro nome feminino |
| `fake()->jobtitle` | título (profissão) |
| `fake()->phoneNumber` | número de telefone |
 

---

### Endereço<a name="addressdata"></a>

Esta categoria traz opções diversas opções para endereço como podemos ver na tabela a seguir.

| Propriedade       | Retorno                 |
| ------------------------ | ----------------------------- |
| `fake()->address` | endereço completo |
| `fake()->streetAddress` | logradouro com número |
| `fake()->streetName` | somente logradouro |
| `fake()->buildingNumber` | número do prédio |
| `fake()->city` | cidade |
| `fake()->country` | país |
| `fake()->postcode` | CEP |


---

### Texto<a name="text"></a>

"_...Lorem ipsum em design gráfico e editoração é um texto padrão em latim utilizado na produção gráfica para preencher os espaços de texto em publicações..._". Fonte: [Wikipedia](https://pt.wikipedia.org/wiki/Lorem_ipsum).

Esta categoria possibilita a geração de palavras únicas até parágrafos completos. 

Mas, diferentemente das categorias anteriores onde os retornos são sempre strings, algumas propriedades desta categoria retornam **array de strings**. 

Este comportamento pode ser evitado utilizando o método correspondente no lugar da propriedade.

Por exemplo, a propriedade `fake()->words` retornará um array com 3 strings diferentes, ao passo que o método `fake()-words(3, true)` também retornar 3 palavras mas em uma única string.

A tabela a seguir traz as propriedades com seus respectivos retornos e para cada propriedade há um método correspondente.

| Propriedade                   | Retorno                       |
| ------------------------ | ----------------------------- |
| `fake()->randomLetter` | uma letra |
| `fake()->word` | uma única palavra |
| `fake()->words` | array com 3 palavras |
| `fake()->sentence` | uma frase com até 6 palavras |
| `fake()->sentences` | array com 3 frases |
| `fake()->paragraph` | parágrafo com 3 frases |
| `fake()->paragraphs` | array com 3 parágrafos |
| `fake()->text` | texto com até 200 palavras |
 
---

### Números<a name="numbers"></a>

Este grupo destina-se a geração de números fictícios, sejam inteiros ou reais. Vamos à tabela com os métodos e os respectivos retornos.

:warning: Suprimi o `fake()->` para melhorar a visualização da tabela. 


| Método | Retorno                       |
| ----------------------------- | -------------------------- |
| `numberBetween($int1 = 0, $int2 = 2147483647)` | inteiro entre `$int1` e `$int2` |
| `randomDigit()` | inteiro entre 0 e 9 |
| `randomDigitNot($except)` | inteiro entre 0 e 9, exceto `$except` |
| `randomDigitNotZero()` | inteiro entre 1 e 9 |
| `randomFloat($nbMaxDecimals = null, $min = 0, $max = null)`| número real com `$nbMaxDecimals` casas decimais, maior ou igual a `$min` e menor ou igual a `$max` |

---

### Data e hora<a name="datetime"></a>

Esta categoria retorna informações de data e hora, fictícios. 

| Propriedade | Retorno                       |
| ----------------------------- | -------------------------- |
| `fake()->dateTime` | data e hora, até a atual |
| `fake()->date` | data no formato 'Y-m-d', até a atual |
| `fake()->time` | hora no formato 'H:i:s', até a atual |
| `fake()->dateTimeThisCentury` | data e hora do século corrente |
| `fake()->dateTimeThisDecade` | data e hora da década corrente |
| `fake()->dateTimeThisYear` | data e hora do ano corrente |
| `fake()->dateTimeThisMonth` | data e hora do mês corrente |
| `fake()->dayOfMonth` | dia do mês |
| `fake()->dayOfWeek` | dia da semana |
| `fake()->month` | mês (numeral) |
| `fake()->monthName` | mês (extenso) |
| `fake()->year` | ano |
| `fake()->century` | século |

---

### Outros<a name="several"></a>

Esta categoria traz propriedades bastante diversas e por isso, vou listar somente algumas.

| Propriedade | Retorno                       |
| ----------------------------- | -------------------------- |
| `fake()->hexColor` | cor em hexadecimal |
| `fake()->rgbColor` | cor em RGB |
| `fake()->rgbCssColor` | cor RGB em CSS |
| `fake()->colorName` | nome da cor |
| `fake()->userName` | nome de usuário |
| `fake()->password` | senha de 6 a 20 caracteres |
| `fake()->domainName` | nome de domínio |
| `fake()->url` | url |
| `fake()->ipv4` | endereço de rede IPV4 |
| `fake()->ipv6` | endereço de rede IPV6 |
| `fake()->macAddress` | endereço "mac" de placa de rede |


---

Muita coisa não é mesmo?!

Espero ter ajudado.

Até breve. :sunglasses: