Inicio
Artículos
Categorias
Etiquetas
Inserción de datos de prueba con seeders y factories - II
publicado el: 2021-1-28   actualizado el: 2021-1-28   incluido en: Proyecto blog laravel
palabras totales: 1610   tiempo de lectura: 8 mins  

Inserción de datos de prueba en la base de datos

Voy a crear un factory para cada una de las entidades/tablas de mi base de datos, salvo para User que ya se creo con el proyecto.

UserFactory.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

namespace Database\Factories;

use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class UserFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = User::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'name' => $this->faker->name,
            'email' => $this->faker->unique()->safeEmail,
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
}

Empiezo a crealos.

1
2
3
4
5
6
7
8
enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:factory CategoryFactory
Factory created successfully.
enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:factory PostFactory
Factory created successfully.
enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:factory TagFactory
Factory created successfully.
enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:factory ImageFactory
Factory created successfully.

Ahora abro cada uno de los factories creados y los edito. Debo de indicar en cada uno de ellos que campos de la tabla quiero que se llenen y con que tipo de datos.

CategoryFactory.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

namespace Database\Factories;

use App\Models\Category;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class CategoryFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Category::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        $name = $this->faker->unique()->word(20); //genera una palabra aleatorioa y única

        return [
            'name' => $name,
            'slug' => Str::slug($name) // Uso Str para que me genere el slug de $name
        ];
    }
}

PostFactory.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php

namespace Database\Factories;

use App\Models\Category;
use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class PostFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Post::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        $name = $this->faker->unique()->sentence(); // Para el titulo del post

        return [
            'name' => $name,
            'slug' => Str::slug($name),
            'extract' => $this->faker->text(250), //Expecifico que el texto sea de 250 caracteres
            'body' => $this->faker->text(2000), //Expecifico que el texto sea de 250 caracteres
            'category_id' => Category::all()->random()->id, // Llamo al modelo Category, traigo todos los registros, elijo uno al azar y pido su id.
            'user_id' => User::all()->random()->id // Llamo al modelo User, traigo todos los registros, elijo uno al azar y pido su id.
        ];

TagFactory.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

namespace Database\Factories;

use App\Models\Tag;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class TagFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Tag::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        $name = $this->faker->unique()->word(20);

        return [
            'name' => $name,
            'slug' => Str::slug($name),
            'color' => $this->faker->randomElement(['red', 'yellow', 'green', 'blue', 'indigo', 'purple', 'pink'])
        ];
    }
}

cuando subimos una imagen al servidor esta se almacena en la carpeta var/www/laravel/blog_laravel/storage/app

1
2
3
4
5
6
enrique@enrique-server:/var/www/laravel/blog_laravel$ ls -la storage/app/
total 16
drwxrwsr-x 3 enrique www-data 4096 Dec  8 15:51 .
drwxrwsr-x 5 enrique www-data 4096 Dec  8 15:51 ..
-rw-rw-r-- 1 enrique www-data   23 Dec  8 15:51 .gitignore
drwxrwsr-x 2 enrique www-data 4096 Dec  8 15:51 public

Pero a la única carpeta a la que podemos acceder desde el navegador es a la carpeta public

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
enrique@enrique-server:/var/www/laravel/blog_laravel$ ls -la public/
total 36
drwxrwsr-x  4 enrique www-data 4096 Dec  9 22:58 .
drwxrwsr-x 13 enrique www-data 4096 Dec  9 22:57 ..
-rw-rw-r--  1 enrique www-data  603 Dec  8 15:51 .htaccess
drwxr-sr-x  2 enrique www-data 4096 Dec  9 22:30 css
-rw-rw-r--  1 enrique www-data    0 Dec  8 15:51 favicon.ico
-rw-rw-r--  1 enrique www-data 1731 Dec  8 15:51 index.php
drwxrwsr-x  2 enrique www-data 4096 Dec  9 22:58 js
-rw-rw-r--  1 enrique www-data   71 Dec  9 22:58 mix-manifest.json
-rw-rw-r--  1 enrique www-data   24 Dec  8 15:51 robots.txt
lrwxrwxrwx  1 enrique www-data   48 Dec  9 22:30 storage -> /var/www/laravel/blog_laravel/storage/app/public
-rw-rw-r--  1 enrique www-data 1194 Dec  8 15:51 web.config

En esta carpeta public hay un acceso directo a una carpeta llamada storage, pero esta carpeta storage no es la misma que var/www/laravel/blog_laravel/storage/app, sino a /var/www/laravel/blog_laravel/storage/app/public.

Entonces lo que debo lograr es que las imágenes se suban a la carpeta /var/www/laravel/blog_laravel/storage/app/public para conseguirlo voy a la carpeta config y abro el archivo /var/www/laravel/blog_laravel/config/filesystems.php donde cambio el valor de la variable FILESYSTEM_DRIVER de local a public.

filesystems.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Default Filesystem Disk
    |--------------------------------------------------------------------------
    |
    | Here you may specify the default filesystem disk that should be used
    | by the framework. The "local" disk, as well as a variety of cloud
    | based disks are available to your application. Just store away!
    |
    */

    //'default' => env('FILESYSTEM_DRIVER', 'local'),
    'default' => env('FILESYSTEM_DRIVER', 'public'),

ImageFactory.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php

namespace Database\Factories;

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

class ImageFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Image::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'url' => 'posts/'.$this->faker->image('public/storage/posts', 640, 480, null, false) //lo almacena en posts/imagen.jpg
        ];
    }
}

Para que estos factories puedan rellenar la base de datos con valores falsos debo de llamarlos desde databaseSeeders.php

Creo un seeder para meter mis usuarios junto con datos aleatorios creados por el UserFactory.php

1
2
enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:seeder UserSeeder
Seeder created successfully.

UserSeeder.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

namespace Database\Seeders;

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

class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        User::create([
            'name' => 'Enrique Saborit Crespo',
            'email' => 'esaborit@gmail.com',
            'password' => bcrypt('esaborit')
        ]);
        
        User::factory(99)->create();
    }
}

Debo llamar este UserSeeder desde el DatabaseSeederya que es el único documento que se va a leer a la hora de ejecutar los seeders.

DatabaseSeeder.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UserSeeder::class); // Llamo al UserSeeder
        Category::factory(4)->create(); // Para que me cree 4 categorias
        Tag::factory(8)->create(); // me crea 8 etiquetas
    }
}

Para crear los posts falsos necesito que me cree a la vez una imagen con cada uno por lo que los voy a crear con u seeder a parte que incluiré después en DaabaseSeeder.php

enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:seeder PostSeeder
Seeder created successfully.

PostSeeder.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

namespace Database\Seeders;

use App\Models\Image;
use App\Models\Post;
use Illuminate\Database\Seeder;

class PostSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $posts = Post::factory(100)->create();

        foreach ($posts as $post) {
            // añado una imagen a cada post (como el ImageFactory solo añade la url el resto lo añado aqui)
            Image::factory(1)->create([
                'imageable_id' => $post->id,
                'imageable_type' => Post::class
            ]);
            // Añado 2 etiquetas a cada post
            $post->tags()->attach([ // attach() rellena la tabla post_tag
                rand(1, 4),
                rand(5, 8)
            ]);
        }
    }
}

Llamo a este seeder desde DatabaseSeeder.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php

namespace Database\Seeders;

use App\Models\Category;
use App\Models\Tag;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Storage;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
         // \App\Models\User::factory(10)->create();
        
        Storage::deleteDirectory('posts'); // Elimina el directorio cada vez que hago un seed
        Storage::makeDirectory('posts');
        $this->call(UserSeeder::class);
        Category::factory(4)->create();
        Tag::factory(8)->create();
        $this->call(PostSeeder::class);
    }
}

Ejecuto los seeders

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan migrate:fresh --seed
Dropped all tables successfully.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (7,283.34ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (3,186.33ms)
Migrating: 2014_10_12_200000_add_two_factor_columns_to_users_table
Migrated:  2014_10_12_200000_add_two_factor_columns_to_users_table (4,433.22ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (3,505.14ms)
Migrating: 2019_12_14_000001_create_personal_access_tokens_table
Migrated:  2019_12_14_000001_create_personal_access_tokens_table (6,432.68ms)
Migrating: 2020_12_09_223020_create_sessions_table
Migrated:  2020_12_09_223020_create_sessions_table (11,400.94ms)
Migrating: 2020_12_10_151428_create_categories_table
Migrated:  2020_12_10_151428_create_categories_table (2,110.62ms)
Migrating: 2020_12_10_152625_create_posts_table
Migrated:  2020_12_10_152625_create_posts_table (14,110.12ms)
Migrating: 2020_12_10_154814_create_tags_table
Migrated:  2020_12_10_154814_create_tags_table (2,421.83ms)
Migrating: 2020_12_10_155345_create_post_tag_table
Migrated:  2020_12_10_155345_create_post_tag_table (17,809.01ms)
Migrating: 2020_12_10_182248_create_images_table
Migrated:  2020_12_10_182248_create_images_table (2,946.20ms)
Seeding: Database\Seeders\UserSeeder
Seeded:  Database\Seeders\UserSeeder (47,335.58ms)
Seeding: Database\Seeders\PostSeeder
Seeded:  Database\Seeders\PostSeeder (172,518.66ms)
Database seeding completed successfully.

Desde phpmyadmin puedo ver las tablas de mi proyecto con los registros falsos creados.

ESC
«No se puede enseñar nada a un hombre; sólo se le puede ayudar a encontrar la respuesta dentro de sí mismo». Galileo Galilei (1564 - 1642)
Tabla de contenidos
Artículos relacionados
Creando el crud de posts - IX
Creando un crud para los post del blog Creo el controlador con los siete métodos 1 2 enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:controller Admin/PostController -r Controller created successfully. Lo modifico para recibir objetos post y las vistas a los métodos correspondientes. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 <?
2021-2-3
Creando el crud de etiquetas - VIII
Creando un crud para las etiquetas del blog Sigo los mismos pasos que para las categorias. Desde la consola de comandos y situado dentro del proyecto creo el controlador con sus 7 métodos para administrar las etiquetas desde el backend. 1 2 enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:controler Admin/TagController -r Controller created successfully.
2021-1-31
Creando el crud de categorías - VII
Creando un crud para las categorías del blog Genero en admin.php una ruta de tipo resources que me genere las rutas para el crud de las categorías. Antes creo un controlador para categorías que me genere ya los 7 métodos. 1 2 enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:controller Admin/CategoryController -r Controller created successfully.
2021-1-30
Creando el backend del blog -VI
Integrando AdminLTE en el proyecto Para la gestión de la parte administrativa voy a usar el paquete AdminLTE 3 Voy a generar una url llamada admin que utilizaré para desarrollar la parte de administración del blog. Esta url no la voy a declarar en el fichero web.php sino que creo uno nuevo llamado routes/admin.
2021-1-29
Mostrando y filtrando posts - V
Mostrando el detalle de un post Creo una ruta en web.php para mostrar el detalle de un post. web.php 1 Route::get('posts/{post}', [PostController::class, 'show'])->name('posts.show'); Creo en método show en el controllador PostController.php al que le paso como parámetro un objeto post. Dentro de el recupero los post que pertenecen a la misma categoría que el en la variable $similares y se los paso junto con la variable $post a la vista posts.
2021-1-28