9: Generando e insertando datos de prueba para tu portafolio con Laravel

 

9: Generando e insertando datos de prueba para tu portafolio con Laravel

Introducción

En este tutorial vamos a crear y ejecutar Factories y Seeders para poblar nuestra base de datos con información de prueba. Lo interesante de esta clase es que implementaremos un enfoque particular para manejar los colores e iconos que funcionan con Tailwind CSS, asegurando que los estilos se apliquen correctamente en el frontend.


¿Qué son los Factories y Seeders?

  • Factories: Clases que generan datos ficticios para tus modelos usando la librería Faker

  • Seeders: Clases que ejecutan los factories para insertar datos en la base de datos


Paso 1: Crear los Factories

Primero, crearemos los factories para nuestros modelos:

bash
php artisan make:factory ProjectFactory --model=Project
php artisan make:factory SkillFactory --model=Skill

Paso 2: Configurar el Factory de Skills

Abre database/factories/SkillFactory.php y define la estructura:

php
<?php

namespace Database\Factories;

use App\Models\Skill;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\File;

class SkillFactory extends Factory
{
    protected $model = Skill::class;

    // Método estático para obtener colores de fondo disponibles
    public static function getAvailableBackgroundColors()
    {
        $path = resource_path('json/customization.json');
        $content = File::get($path);
        $data = json_decode($content, true);
        
        return $data['background'] ?? [];
    }

    public function definition(): array
    {
        $backgroundColors = self::getAvailableBackgroundColors();
        
        return [
            'name' => $this->faker->unique()->word(),
            'color' => $this->faker->randomElement($backgroundColors),
            'category' => $this->faker->randomElement(['Frontend', 'Backend', 'DevOps', 'Database', 'Mobile']),
            'level' => $this->faker->numberBetween(30, 100),
            'is_featured' => $this->faker->boolean(30), // 30% de probabilidad
            'order' => $this->faker->numberBetween(0, 10),
        ];
    }
}

Paso 3: Crear el archivo de configuración JSON

Ahora crearemos el archivo que contendrá los colores e iconos disponibles. Este archivo es crucial porque Tailwind CSS necesita conocer las clases que se van a utilizar en el frontend.

Crea la carpeta y el archivo:

bash
mkdir -p resources/json
touch resources/json/customization.json

Abre resources/json/customization.json y agrega:

json
{
    "background": [
        "indigo",
        "green",
        "yellow",
        "blue",
        "pink",
        "red",
        "purple",
        "orange",
        "teal",
        "cyan",
        "rose",
        "amber",
        "lime",
        "emerald",
        "violet",
        "fuchsia"
    ],
    "text": [
        "indigo",
        "green",
        "yellow",
        "blue",
        "pink",
        "red",
        "purple",
        "orange",
        "teal",
        "cyan",
        "rose",
        "amber",
        "lime",
        "emerald",
        "violet",
        "fuchsia"
    ],
    "icons": [
        "code",
        "database",
        "server",
        "cloud",
        "mobile",
        "desktop",
        "puzzle",
        "rocket",
        "star",
        "heart",
        "camera",
        "music",
        "book",
        "coffee",
        "laptop",
        "globe",
        "shield",
        "lock",
        "key",
        "github",
        "linkedin",
        "twitter"
    ]
}

Paso 4: Configurar el Factory de Projects

Abre database/factories/ProjectFactory.php:

php
<?php

namespace Database\Factories;

use App\Models\Project;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\File;

class ProjectFactory extends Factory
{
    protected $model = Project::class;

    // Método estático para obtener colores de texto disponibles
    public static function getAvailableTextColors()
    {
        $path = resource_path('json/customization.json');
        $content = File::get($path);
        $data = json_decode($content, true);
        
        return $data['text'] ?? [];
    }

    // Método estático para obtener iconos disponibles
    public static function getAvailableIcons()
    {
        $path = resource_path('json/customization.json');
        $content = File::get($path);
        $data = json_decode($content, true);
        
        return $data['icons'] ?? [];
    }

    public function definition(): array
    {
        $textColors = self::getAvailableTextColors();
        $icons = self::getAvailableIcons();

        return [
            'title' => $this->faker->words(3, true),
            'description' => $this->faker->sentence(),
            'content' => $this->faker->paragraphs(3, true),
            'image_url' => $this->faker->imageUrl(800, 600, 'tech', true, 'Project'),
            'github_url' => 'https://github.com/' . $this->faker->userName() . '/' . $this->faker->word(),
            'demo_url' => 'https://' . $this->faker->domainName(),
            'technologies' => $this->faker->randomElements(['Laravel', 'Vue.js', 'React', 'Tailwind', 'MySQL', 'Docker', 'AWS', 'Python'], 3),
            'start_date' => $this->faker->dateTimeBetween('-2 years', 'now'),
            'end_date' => $this->faker->optional()->dateTimeBetween('-1 year', 'now'),
            'is_featured' => $this->faker->boolean(20),
            'is_published' => $this->faker->boolean(90),
            'order' => $this->faker->numberBetween(0, 10),
        ];
    }
}

Paso 5: Crear los Seeders

Seeder de Skills

bash
php artisan make:seeder SkillSeeder

Abre database/seeders/SkillSeeder.php:

php
<?php

namespace Database\Seeders;

use App\Models\Skill;
use Illuminate\Database\Seeder;

class SkillSeeder extends Seeder
{
    public function run(): void
    {
        // Crear 6 habilidades usando el factory
        Skill::factory()
            ->count(6)
            ->create();
    }
}

Seeder de Projects

bash
php artisan make:seeder ProjectSeeder

Abre database/seeders/ProjectSeeder.php:

php
<?php

namespace Database\Seeders;

use App\Models\Project;
use Illuminate\Database\Seeder;

class ProjectSeeder extends Seeder
{
    public function run(): void
    {
        // Crear 5 proyectos usando el factory
        Project::factory()
            ->count(5)
            ->create();
    }
}

Seeder de Experiences

bash
php artisan make:seeder ExperienceSeeder

Abre database/seeders/ExperienceSeeder.php:

php
<?php

namespace Database\Seeders;

use App\Models\Experience;
use Illuminate\Database\Seeder;

class ExperienceSeeder extends Seeder
{
    public function run(): void
    {
        Experience::factory()
            ->count(4)
            ->create();
    }
}

Paso 6: Actualizar DatabaseSeeder

Abre database/seeders/DatabaseSeeder.php y agrega los seeders:

php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([
            SkillSeeder::class,
            ProjectSeeder::class,
            ExperienceSeeder::class,
        ]);
    }
}

Paso 7: Crear el Factory de Experiences (Opcional)

Si deseas también tener datos de prueba para experiencias:

bash
php artisan make:factory ExperienceFactory --model=Experience

Abre database/factories/ExperienceFactory.php:

php
<?php

namespace Database\Factories;

use App\Models\Experience;
use Illuminate\Database\Eloquent\Factories\Factory;

class ExperienceFactory extends Factory
{
    protected $model = Experience::class;

    public function definition(): array
    {
        $startDate = $this->faker->dateTimeBetween('-5 years', '-1 year');
        $isCurrent = $this->faker->boolean(30);

        return [
            'company' => $this->faker->company(),
            'position' => $this->faker->jobTitle(),
            'logo_url' => $this->faker->imageUrl(100, 100, 'logo', true, 'Company'),
            'description' => $this->faker->paragraph(),
            'start_date' => $startDate,
            'end_date' => $isCurrent ? null : $this->faker->dateTimeBetween($startDate, 'now'),
            'is_current' => $isCurrent,
            'location' => $this->faker->city() . ', ' . $this->faker->country(),
            'achievements' => $this->faker->sentences(3),
            'order' => $this->faker->numberBetween(0, 10),
        ];
    }
}

Paso 8: Ejecutar los Seeders

Ahora ejecutaremos los seeders para poblar la base de datos:

Opción 1: Ejecutar todos los seeders

bash
php artisan db:seed

Opción 2: Ejecutar un seeder específico

bash
php artisan db:seed --class=SkillSeeder
php artisan db:seed --class=ProjectSeeder

Opción 3: Refrescar la base de datos y ejecutar seeders

bash
php artisan migrate:fresh --seed

Nota: El comando migrate:fresh elimina todas las tablas y las vuelve a crear, ejecutando luego los seeders.


Paso 9: Verificar los datos insertados

Usando Tinker

bash
php artisan tinker
php
// Ver todas las habilidades
App\Models\Skill::all();

// Ver todos los proyectos
App\Models\Project::all();

// Ver todas las experiencias
App\Models\Experience::all();

// Ver proyectos destacados
App\Models\Project::where('is_featured', true)->get();

Usando el navegador

Si tienes configuradas las rutas, puedes visitar:

  • /projects - Ver todos los proyectos

  • /skills - Ver todas las habilidades

  • /experience - Ver toda la experiencia


El misterio del archivo JSON

¿Por qué estamos usando un archivo JSON para los colores e iconos?

La razón: Tailwind CSS utiliza un compilador JIT (Just-In-Time) que solo incluye las clases que encuentra en tu código fuente. Si los colores e iconos se guardan directamente en la base de datos y se insertan dinámicamente, Tailwind no los detectará y no generará los estilos correspondientes.

La solución: Al mantener estos valores en un archivo JSON que se encuentra en el código fuente, Tailwind puede escanearlo y generar todas las clases necesarias. Además, esto nos permite:

  1. Mantener consistencia: Los mismos colores se usan en todo el sitio

  2. Configuración centralizada: Cambios en un lugar afectan todo el sistema

  3. Optimización: Tailwind solo genera las clases que realmente se usan

  4. Flexibilidad: Fácil de modificar o extender


Posibles errores y soluciones

Error: "Method is not static"

Solución: Asegúrate de que los métodos en los factories sean estáticos:

php
public static function getAvailableBackgroundColors()

Error: "Class not found"

Solución: Verifica los namespaces e imports:

php
use Illuminate\Support\Facades\File;
use App\Models\Skill;

Error: "Cannot redeclare unique()"

Solución: El método unique() de Faker asegura que no haya valores duplicados. Si obtienes este error, aumenta el límite de intentos:

php
$this->faker->unique($maxRetries = 100)->word()

Resumen

✅ Creamos Factories para generar datos de prueba
✅ Configuramos la lectura de colores e iconos desde un archivo JSON
✅ Creamos Seeders para poblar la base de datos
✅ Ejecutamos los seeders correctamente
✅ Verificamos que los datos estén insertados

¡Excelente trabajo! Ahora tenemos datos de prueba en nuestra base de datos que nos permitirán construir y probar las interfaces de usuario. La base de datos está poblada con proyectos, habilidades y experiencia que muestran el potencial de nuestro portafolio.

En la próxima sección comenzaremos a trabajar con las vistas y componentes Vue.js para mostrar esta información de manera atractiva.


Recursos adicionales


¿Tienes dudas sobre el enfoque del archivo JSON? No te preocupes, en las próximas clases veremos por qué es tan importante y cómo se integra con Tailwind CSS para que los estilos funcionen correctamente

Comentarios

Entradas más populares de este blog

Tareas con Laravel + Inertia + Jetstream

HACER CAMBIOS-AL EJEMPLO POR DEFECTO

Laravel + Inertia - ejemplo