Seeders i Factories

Com poblar la base de dades amb dades de prova: seeders, model factories i Faker.

Seeders#

Els seeders permeten inserir dades a la base de dades de manera automatitzada. Són útils per crear dades inicials que l'aplicació necessita per funcionar (com rols, categories o un usuari administrador) i per generar dades de prova durant el desenvolupament.

Per crear un seeder, utilitza la comanda Artisan:

php artisan make:seeder UserSeeder

Això genera un fitxer a database/seeders/UserSeeder.php amb un mètode run() on defineixes les dades a inserir:

namespace Database\Seeders;
 
use App\Models\User;
use Illuminate\Database\Seeder;
 
class UserSeeder extends Seeder
{
    public function run(): void
    {
        // Crear un usuari administrador específic
        User::create([
            'name' => 'Admin',
            'email' => 'admin@laravelandorra.com',
            'password' => bcrypt('password'),
            'is_admin' => true,
        ]);
 
        // Crear 50 usuaris amb dades fictícies
        User::factory()->count(50)->create();
    }
}

El DatabaseSeeder#

El fitxer database/seeders/DatabaseSeeder.php és el seeder principal que s'executa per defecte. Des d'aquí pots cridar altres seeders per organitzar la generació de dades:

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([
            UserSeeder::class,
            CategorySeeder::class,
            ArticleSeeder::class,
            CommentSeeder::class,
        ]);
    }
}

Els seeders s'executen en l'ordre en què els llistes. Això és important quan les dades tenen dependències: els usuaris s'han de crear abans que els articles, perquè els articles referencien un user_id.

Executar seeders#

# Executar el DatabaseSeeder (que crida els altres)
php artisan db:seed
 
# Executar un seeder específic
php artisan db:seed --class=UserSeeder
 
# Esborrar la BD, executar migracions i seeders
php artisan migrate:fresh --seed

Model Factories#

Les factories generen dades fictícies realistes per als teus models. Utilitzen la llibreria Faker, que pot generar noms, correus, adreces, textos, dates i molts altres tipus de dades en múltiples idiomes.

Per crear una factory:

php artisan make:factory ArticleFactory

Això genera un fitxer a database/factories/ArticleFactory.php. El mètode definition() retorna un array amb els atributs del model i els seus valors generats:

namespace Database\Factories;
 
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
 
class ArticleFactory extends Factory
{
    public function definition(): array
    {
        return [
            'title' => fake()->sentence(),
            'slug' => fake()->unique()->slug(),
            'body' => fake()->paragraphs(5, true),
            'user_id' => User::factory(),
            'published' => fake()->boolean(70),
            'published_at' => fake()->dateTimeBetween('-1 year'),
        ];
    }
}

El helper fake() proporciona accés a tots els generadors de Faker. Fixa't que user_id utilitza User::factory() en lloc d'un valor estàtic. Això significa que, quan crees un article, Laravel crearà automàticament un usuari associat si no n'especifiques un.

Generadors de Faker habituals#

Faker ofereix una gran varietat de generadors:

fake()->name();                          // 'Joan Garcia'
fake()->firstName();                     // 'Maria'
fake()->lastName();                      // 'Martínez'
fake()->email();                         // 'joan.garcia@exemple.com'
fake()->unique()->safeEmail();           // Email únic
fake()->phoneNumber();                   // '+34 612 345 678'
fake()->address();                       // Adreça completa
fake()->city();                          // 'Barcelona'
fake()->country();                       // 'Andorra'
fake()->sentence();                      // Frase curta
fake()->paragraph();                     // Paràgraf
fake()->paragraphs(3, true);             // 3 paràgrafs com a string
fake()->text(200);                       // Text de 200 caràcters
fake()->url();                           // 'https://www.exemple.com'
fake()->boolean(70);                     // true (70% probabilitat)
fake()->numberBetween(1, 100);           // Número aleatori
fake()->randomFloat(2, 0, 1000);         // 342.57
fake()->dateTimeBetween('-1 year');       // Data de l'últim any
fake()->imageUrl(640, 480);              // URL d'imatge

Estats (States)#

Els estats permeten definir variacions d'una factory. Això és molt útil per crear models en estats concrets sense repetir codi:

class ArticleFactory extends Factory
{
    public function definition(): array
    {
        return [
            'title' => fake()->sentence(),
            'slug' => fake()->unique()->slug(),
            'body' => fake()->paragraphs(5, true),
            'user_id' => User::factory(),
            'published' => false,
            'published_at' => null,
        ];
    }
 
    public function published(): static
    {
        return $this->state(fn (array $attributes) => [
            'published' => true,
            'published_at' => fake()->dateTimeBetween('-6 months'),
        ]);
    }
 
    public function draft(): static
    {
        return $this->state(fn (array $attributes) => [
            'published' => false,
            'published_at' => null,
        ]);
    }
 
    public function byAuthor(User $user): static
    {
        return $this->state(fn (array $attributes) => [
            'user_id' => $user->id,
        ]);
    }
}

Ara pots combinar estats per crear models amb característiques específiques:

// 10 articles publicats
Article::factory()->count(10)->published()->create();
 
// 5 esborranys d'un autor concret
Article::factory()->count(5)->draft()->byAuthor($admin)->create();

Utilitzar factories#

Les factories es poden fer servir de moltes maneres:

// Crear un model i desar-lo a la BD
$user = User::factory()->create();
 
// Crear múltiples models
$users = User::factory()->count(10)->create();
 
// Crear sense desar (útil per a tests)
$user = User::factory()->make();
 
// Sobreescriure atributs concrets
$user = User::factory()->create([
    'name' => 'Joan',
    'email' => 'joan@exemple.com',
]);

Factories amb relacions#

Les factories poden crear models amb les seves relacions automàticament:

// Crear un usuari amb 5 articles
$user = User::factory()
    ->has(Article::factory()->count(5))
    ->create();
 
// Sintaxi curta (Laravel infereix el nom de la relació)
$user = User::factory()
    ->hasArticles(5)
    ->create();
 
// Crear un article amb un usuari específic
$article = Article::factory()
    ->for(User::factory()->state(['name' => 'Admin']))
    ->create();
 
// Sintaxi curta
$article = Article::factory()
    ->forUser(['name' => 'Admin'])
    ->create();

Exemple complet d'un seeder#

Un seeder ben organitzat combina dades fixes amb dades generades per factories:

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        // Usuari admin (sempre el mateix)
        $admin = User::factory()->create([
            'name' => 'Admin',
            'email' => 'admin@laravelandorra.com',
            'is_admin' => true,
        ]);
 
        // 20 usuaris normals
        $users = User::factory()->count(20)->create();
 
        // 30 articles publicats de l'admin
        Article::factory()
            ->count(30)
            ->published()
            ->byAuthor($admin)
            ->create();
 
        // 50 articles aleatoris d'usuaris normals
        Article::factory()
            ->count(50)
            ->create();
 
        // 10 esborranys
        Article::factory()
            ->count(10)
            ->draft()
            ->create();
    }
}

Ara, amb php artisan migrate:fresh --seed, tens una base de dades completa amb dades realistes per desenvolupar i testejar l'aplicació.