Gerar CPF em Laravel: Service, Factory e Artisan
O gerador online de CPF resolve testes manuais, mas projetos Laravel pedem integração nativa: factories, seeders e comandos Artisan que produzam CPFs válidos sob demanda. A lógica segue o algoritmo de módulo 11 e o artigo foca na integração com o framework.
Service
<?php
namespace App\Services;
class CpfGenerator
{
public static function generate(): string
{
$digits = [];
for ($i = 0; $i < 9; $i++) {
$digits[] = rand(0, 9);
}
// Primeiro dígito verificador
$sum = 0;
for ($i = 0; $i < 9; $i++) {
$sum += $digits[$i] * (10 - $i);
}
$r = $sum % 11;
$digits[] = $r < 2 ? 0 : 11 - $r;
// Segundo dígito verificador
$sum = 0;
for ($i = 0; $i < 10; $i++) {
$sum += $digits[$i] * (11 - $i);
}
$r = $sum % 11;
$digits[] = $r < 2 ? 0 : 11 - $r;
return implode('', $digits);
}
public static function validate(string $cpf): bool
{
$cleaned = preg_replace('/[^\d]/', '', $cpf);
if (strlen($cleaned) !== 11) {
return false;
}
if (preg_match('/^(\d)\1{10}$/', $cleaned)) {
return false;
}
$digits = array_map('intval', str_split($cleaned));
// Verifica primeiro dígito
$sum = 0;
for ($i = 0; $i < 9; $i++) {
$sum += $digits[$i] * (10 - $i);
}
$r = $sum % 11;
$expected = $r < 2 ? 0 : 11 - $r;
if ($digits[9] !== $expected) {
return false;
}
// Verifica segundo dígito
$sum = 0;
for ($i = 0; $i < 10; $i++) {
$sum += $digits[$i] * (11 - $i);
}
$r = $sum % 11;
$expected = $r < 2 ? 0 : 11 - $r;
return $digits[10] === $expected;
}
}Factory
<?php
namespace Database\Factories;
use App\Models\User;
use App\Services\CpfGenerator;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
protected $model = User::class;
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'cpf' => CpfGenerator::generate(),
'email_verified_at' => now(),
'password' => Hash::make('password'),
'remember_token' => Str::random(10),
];
}
}Com essa factory configurada, basta chamar User::factory()->create() em seeders ou testes para obter um usuário com CPF válido. Para gerar múltiplos registros: User::factory()->count(50)->create().
Comando Artisan
<?php
namespace App\Console\Commands;
use App\Services\CpfGenerator;
use Illuminate\Console\Command;
class GenerateCpf extends Command
{
protected $signature = 'cpf:generate {quantidade=1 : Quantidade de CPFs a gerar}';
protected $description = 'Gera CPFs válidos para teste';
public function handle(): int
{
$quantidade = (int) $this->argument('quantidade');
if ($quantidade < 1) {
$this->error('A quantidade deve ser pelo menos 1.');
return Command::FAILURE;
}
$this->info("Gerando {$quantidade} CPF(s):");
$this->newLine();
for ($i = 0; $i < $quantidade; $i++) {
$cpf = CpfGenerator::generate();
$this->line($cpf);
}
return Command::SUCCESS;
}
}Uso: php artisan cpf:generate 10 gera dez CPFs válidos no terminal. Sem argumento, gera apenas um.
Análise do código
A classe CpfGenerator centraliza toda a lógica em métodos estáticos. O método generate() cria nove dígitos aleatórios com rand(0, 9), calcula o primeiro dígito verificador somando cada dígito multiplicado pelo peso correspondente (10 a 2) e aplicando módulo 11, depois repete o processo com dez dígitos (pesos de 11 a 2) para obter o segundo verificador. O método validate() faz o caminho inverso, recalculando os verificadores para confirmar a integridade do CPF.
A integração com Model Factory é direta: chamar CpfGenerator::generate() dentro do método definition() garante que cada registro criado por User::factory() receba um CPF válido. Isso é especialmente útil em testes de feature que dependem de validação de CPF no FormRequest, pois os dados de fábrica já passam nas regras de validação sem ajustes manuais.
O comando Artisan cpf:generate expõe a geração via terminal usando a mesma Service class. O argumento quantidade tem valor padrão 1, validação para evitar valores negativos e retorna Command::SUCCESS ou Command::FAILURE seguindo as convenções do Laravel. Isso permite gerar CPFs rapidamente durante o desenvolvimento sem precisar abrir o tinker ou criar scripts avulsos.
Testes
<?php
namespace Tests\Unit\Services;
use App\Services\CpfGenerator;
use PHPUnit\Framework\TestCase;
class CpfGeneratorTest extends TestCase
{
public function testGeradoDeveTer11DigitosValidos(): void
{
$cpf = CpfGenerator::generate();
$this->assertSame(11, strlen($cpf));
$this->assertMatchesRegularExpression('/^\d{11}$/', $cpf);
$this->assertTrue(CpfGenerator::validate($cpf));
}
public function testFactoryCriaUsuarioComCpfValido(): void
{
$cpf = CpfGenerator::generate();
$this->assertTrue(
CpfGenerator::validate($cpf),
"CPF gerado pela service deve ser válido: {$cpf}"
);
}
public function testMultiplosGeradosDevemDiferir(): void
{
$cpf1 = CpfGenerator::generate();
$cpf2 = CpfGenerator::generate();
$cpf3 = CpfGenerator::generate();
$this->assertFalse(
$cpf1 === $cpf2 && $cpf2 === $cpf3,
'Três CPFs gerados consecutivamente não devem ser todos iguais'
);
}
}O primeiro teste garante que o CPF gerado tem exatamente 11 caracteres numéricos e passa na validação da própria service. O segundo confirma que CPFs produzidos pelo mesmo método usado na factory são válidos. O terceiro gera três CPFs e verifica que não são todos idênticos, detectando falhas na aleatoriedade.
Veja também como validar CPF em Laravel com Custom Rule e FormRequest, ou volte à página inicial para gerar CPFs online.