Skip to content

7 - Seeder, Factory y Faker

Índice

  1. Introducción1.1 Autoría 1.2 Enlaces otros tutoriales
  2. Proyecto base
  3. Seeders
  4. Factory
  5. Faker

1. Introducción

Recapitulamos

  1. La estructuración del sistema de base de datos -> Migraciones
  2. Esto nos da la base para el ORM
  3. Todo es la estructura
  4. En los sistemas necesitaremos poblar con datos necesarios, usarios, roles...
  5. Al instalar debería llevar al menos un admin/admin, o los productos, categoría... de la tienda

Para todo lo anterior, usaremos los seeders.

  • Además, necesitamos añadir cientos de usuarios, miles de productos.... mediante los FACTORIES,
  • Los Factories llevarán un FAKER que nos incluirán datos falsos que tengan sentido para pruebas

2. Proyecto base

Para ello lo primero que vamos a hacer es crear una nuevo proyecto Laravel al que vamos a llamar databases, y lo hacemos de la siguiente manera:

composer create-project laravel/laravel databases
laravel new databases >> cd databases

Una vez creado nuestro proyecto en Laravel vamos a crear nuestro sistema de persistencia, en mi caso lo he creado dentro de HeidiSQL y le vamos a llamar databases.

Mysql en lugar de SQLite

En el caso de cambiar a mysql, deberíamos editar nuestro archivo.env para darle la información necesaria de nuestra base de datos:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=databases
DB_USERNAME=root
DB_PASSWORD=root

Una vez hecho esto nos iremos a nuestra carpeta databases/database y veremos que tenemos tres carpetas factories, migrations y seeders, sobre la carpeta migrations ya hemos trabajado anteriormente, en cambion los otros no, esos son los que voy a explicar en esta presentación.

1738064717922

Yo voy a empezar por los seeders, los cuales nos van a servir para dar un poblado inicial a nuestra estructura de datos, lo que vamos a hacer es generar un modelo que nos sirva de ejemplo para poblar el contenido, para ello vamos a realizar el siguiente comando:

Model Product

php artisan make:model Product --migration

Ahora si nos vamos a app/models podremos ver que dentro de la carpeta models se nos ha generado el modelo Product al cual le vamos a indicar el comando protected guarded =[] para que podamos guardar todo tipo de información ya que ningún dato va a estar protegido en nuesktro modelo, quedaría de la siguiente manera:

Has Factory en Laravel 11

Hay que tener en cuenta que Laravel 11 no incorpora por defecto la clase HasFactory, hay que incluirla

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Product extends Model
{
    //
    use HasFactory;
    protected $guarded =[];
}

Migración

Ya podemos acudir a las migraciones de nuestro modelo que se encuentran en database/migrations y desde ahí le añadiremos los datos que queremos crear en nuestro modelo Products desde su archivo correspondiente:

 public function up(): void
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name', 50);
            $table->string('short_description', 100);
            $table->text('description', 500);
            $table->float('price')->default(20);
            $table->timestamps();
        });
    }

Vista

A continuación voy a preparar una vista en la que vaya a mostrar un lsitado del contenido del seeder para poder visualizarlos el contenido mientras trabajamos con ellos

Pero antes vamos a crear un controlador:

php artisan make:controller ProductController

El controlador se nos habrá creado dentro de la carpeta:

app/Http/Controllers

Una vez hecho esto nos iremos al controlador y crearemos una función index en la que llamaremos a la vista que nos mostrará el listado de productos:

class ProductController extends Controller
{
    public function index():View{
        $products = Product::all();
        return view('product.index', compact('products'));
    }
}

Ya nos queda crear el archivo de la vista, que haremos dentro de app/resources/view, para ello dentro de esta carpeta creamos otra carpeta llamada product en la cual vamos a incluir la vista de productos a la que llamaremos index.blade.php en el que incluiremos la información de la vista:

<body>
    @forelse($products as $product)
        <div>
            <h3>{{$product->name}}</h3>
            <p>{{$product->short_description}}</p>
            <p>{{$product->price}}USD</p>
        </div>
    @empty
        <h5>No data.</h5>
    @endforelse
</body>

Lo siguiente que hacemos es ir a nuestro archivo de rutas wep.php e importamos nuestro controlador de producto:

use App\Http\Controllers\ProductController;

Le indicamos a nuestra ruta principal raiz que queremos utilizar como dupla el ProductController:

Route::get('/',[ProductController::class,'index'])->name('product.index');//Ruta principal

Migramos el contenido de la base de datos que se me había olvidado migrar antes:

php artisan migrate 

Una vez hecho todo esto si nos vamos a la página web de nuestro servicio veremos que nos muestra el texto "No data" porque actualmente no tenemos datos en nuestra base de datos.

Desde la consola de comandos levantamos nuestro servicio para comprobar que está todo correcto:

php artisan serve

Y ya tendríamos nuestro proyecto configurado para seguir con los seeders, factory y fakers

3. Seeders

Para crear nuestro primer *seeder que nos permita poblar la estructura lo que haremos es desde la consola de comandos, creamos el Seeder:

php artisan make:seeder ProductSeeder

De esta manera se nos habrá creado un seeder dentro de database/seeders que en nuestro caso se llamará ProductSeeder, dentro de la carpeta seeders nos encontraremos siempre por defecto el archivo DatabaseSeeder, este es el encargado principal de generar todos los seeders, por lo que debemos de hacer siempre es generar un seeder por cada una de los elementos/recursos y posteriormente al DatabaseSeeder le vamos a indicar cual de todos los seeders vamos a estar utilizando.

De manera que lo primero que vamos a hacer es un seeder sencillo, para poblar nuestra base de datos con datos que nuestro proyecto necesita.

Para ello dentro del seeder generado añadimos los datos del seeder:

 public function run(): void
    {
        Product::create([
            'name'=> 'Example',
            'short_description' => 'Lorem Ipsum',
            'description' => 'Lorem ipsum dolor set aimet',
            'price'=> 42
        ]);

        Product::create([
            'name'=> 'Example 2',
            'short_description' => 'Lorem Ipsum',
            'description' => 'Lorem ipsum dolor set aimet',
            'price'=> 25
        ]);

        Product::create([
            'name'=> 'Example 3',
            'short_description' => 'Lorem Ipsum',
            'description' => 'Lorem ipsum dolor set aimet',
            'price'=> 60
        ]);
    }

Nuestro seeder está aislado, es decir que cuando usemos el comando para poblar la base de datos, este comando no va a ser ejecutado, por lo que dentro del DatabaseSeeder.php debemos de indicar cual de nuestros seeders queremos utilizar:

public function run(): void
    {
        $this->call([
            ProductSeeder::class
        ]);
    }

A continuación cuando ejecutemos las instrucciones de poblado se crearán los 3 productos del seeder, así que desde la carpeta databases vamos a ejecutar el sigueinte comando:

php artisan db:seed

1738065816770

Y volvemos a lanzar nuestro servidor:

php artisan serve

Y ya nos debería de aparecer los datos insertados en el seeder, para poder visualizarlo mejor desde la carpeta databases/public he creado un archivo que se va a llamar style.css, el cual va a contener dentro de él los siguientes estilos:

.row {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem; /* Espacio entre las tarjetas */
}

.card {
    flex: 1 1 30%; /* Cada card ocupará un 30% del contenedor */
    box-sizing: border-box;
    padding: 1rem;
    border: 1px solid #ddd;
    border-radius: 8px;
}

@media (max-width: 768px) {
    .card {
        flex: 1 1 45%; /* En pantallas pequeñas, las tarjetas ocupan el 45% */
    }
}

@media (max-width: 480px) {
    .card {
        flex: 1 1 100%; /* En pantallas aún más pequeñas, las tarjetas ocupan el 100% */
    }
}

Luego nos iremos a nuestro archivo de vistas *index.blade.php y le vincularemos el elemento anterior:

<link rel="stylesheet" href="{{ asset('style.css')}}">

Y dentro del body añadimos dos div, uno con la clase container y otro con la clase card:

<div class="container">
    @forelse($products as $product)
        <div class="card">
            <h3>{{$product->name}}</h3>
            <p>{{$product->short_description}}</p>
            <p>{{$product->price}}USD</p>
        </div>
    @empty
        <h5>No data.</h5>
    @endforelse
    </div>

Una vez hecho esto ya podemos visualizar nuestros datos con estilos.

1738066125765

Ejecutar un seeder específico

Debemos saber que no siempre vamos a llamar a los seeders desde un seedergeneral, a veces nos interesa llamar a un solo seeder, por ejemplo si tenemos 4 tipos de seeders distintos solo ejecutar uno con:

php artisan db:seed --class=ProductSeeder

4. Factory

Vamos a utilizar los Factories para generar diferentes datos de prueba, porque si queremos probar la aplicación cuando tiene 2000 productos no vamos a estar haciendo seeders con datos de prueba 1 a 1.

Para ello debemos generar nuestro factory desde la consola de comandos, para ello vamos a poner:

php artisan make:factory ProductFactory

Una vez hecho esto, dentro de nuestra carpeta databases/database/factories nos vamos a poder encontrar nuestro ProductFactory.php también por defecto tenemos el UserFactory.php.

El factory se va a encargar de establecer como se debe de crear el dato de prueba, de manera que no tengamos que crear el dato por completo a mano, haciendo que nos genere un dato aleatoria siguiendo algunas reglas las cuales nosotros mismos vamos a indicar.

Note

Si te has fijado, en el DatabaseSeeder viene una factoria de usuarios por defecto, esto es algo nuevo de Laravel 11

Vamos a generar factories para nuestros modelos los cuales van a tener el trait use HasFactory (Qué es un trait en PHP?) y la importación del mismo.

A continuación vamos a generar nuestro primer Factory, para ello nos iremos a nuestro ProductFactory.php y ponemos:

public function definition(): array
    {
        return [
            'name'=>Str::random(25),//Cadena random de 25 caracteres
            'short_description'=>Str::random(45),//Cadena random de 45 caracteres
            'description'=>Str::random(150),//Cadena random de 150 caracteres
            'price'=>random_int(1,125),//Genera un número aleatorio entre 1 y 125
        ];
    }

Lo ideal es que los datos de prueba que introduzcamos sean lo más reales posibles, ya sea incluyendo comas, puntos o mayúsculas, para eso ya lo veremos más adelante voy a utilizar los Faker.

Método factory()

Ahora lo que queremos es indicar en nuestro seeder que queremos generar estos datos de prueba, para ello vamos a indicarle que queremos exactamente generar ciertos datos de prueba apoyándonos en el factory que hemos generado anteriormente

Nos iremos a nuestro ProductSeeder.php

  • Comentamos o eliminamos el anterior código creado directamente con create
  • Product::create([ 'name'=> 'Example 3', 'short_description' => 'Lorem Ipsum', 'description' => 'Lorem ipsum dolor set aimet', 'price'=> 60 ]);
  • y haremos uso del método factory() siguiente:
public function run(): void
    {
        Product::factory()->count(150)->create();//Indicamos que queremos crear un producto a través del factory
    }

Nos apoyamos en el ORM dede Eloquent para poder encadenar métodos y no tener que poner todo el rato la función create o realizar bucles for innecesarios para crear tantos productos con sus datos como queramos.

Para ver el resultado de todo lo realizado vamos a hacer desde la consola de comandos:

php artisan db:seed

Y si todo ha ido bien se nos generará los productos utilizando el factory

Opcional: Mejorar código index.blade.php

1738068227691

Añado aquí un ejemplo de código modificado para que no haya desbordamiento con muchas tarjetas:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Seeder</title>
    <link rel="stylesheet" href="{{ asset('style.css')}}">
</head>
<body>
    <div class="container">
        @php
    $counter = 0;
@endphp

<div class="row">
    @forelse($products as $product)
        @if($counter % 3 == 0 && $counter != 0)
            </div>
            <div class="row">
        @endif

        <div class="card">
            <h3>{{$product->name}}</h3>
            <p>{{$product->short_description}}</p>
            <p>{{$product->price}} USD</p>
        </div>

        @php
            $counter++;
        @endphp

    @empty
        <h5>No data.</h5>
    @endforelse
</div>
     </div>
</body>

</html>

5. Faker

Como hemos visto antes con Faker lo que vamos a conseguir es generar datos pero para que tengan más sentido y estén más claros a la hora de que los visualicemos.

Entonces desde nuestro Factories Nos vamos a apoyar en la utilización de la clase Faker para generar estos elementos:

public function definition(): array
    {
        return [
            'name'=>fake()->name,//Con name se nos generará un nombre aleatorio
            'short_description'=>fake()->sentence,//Con sentence una frase
            'description'=>fake()->paragraph(3),//Con paragraph generaremos un párrafo, en mi caso he seleccionado que sean 3
            'price'=>fake()->numberBetween(1,125),//con numberBetween generaremos un número aleatorio entre 1 y 125 
        ];
    }

No solo tenemos esas funciones, dependiendo del tipo de dato hay muchas otras que deberemos de utilizar, pero esas serían como las más básicas.

A continuación voy a borrar todos los datos de las migraciones realizadas anteriormente con:

php artisan migrate:rollback

Migramos de nuevo el contenido:

php artisan migrate

Y a continuación utilizamos los seeders para poblar nuestra base de datos:

php artisan db:seed

Nos quedaría levantar de nuevo el servicio:

php artisan serve

Conclusiones

Importante: Practicar y llevarlos al proyecto personal o de equipo

Hasta aqui, debemos saber:

  1. CRUD Completo
  2. Acciones necesarias MVC
  3. Seeder /Factory / Faker para poblar las bases de datos.

Veremos lo siguiente las relaciones.

  • Las normales 1:1, 1:N, N:M...
  • Datos de pivotaje
  • O Polimórficoas, que tienen datos que no son del mismo modelo