To create a database seeder in Laravel it is best to work with several model factories and one seeder file. In this blog post I will talk about how you can set this up and the usage of it and all the potential issues you may run into to get this all to run smoothly.
Seeder File
To create a seeder file use
php artisan make:seeder DatabaseSeeder
A seeder class only contains one method by default: run
. This method is called when the db:seed
Artisan command is executed.
Model Factories
There is a default user factory in Laravel already on which you can base your own model factories. An example of a factory for posts could be
<?php use Faker\Generator as Faker; /* |-------------------------------------------------------------------------- | Model Factories |-------------------------------------------------------------------------- | | This directory should contain each of the model factory definitions for | your application. Factories provide a convenient way to generate new | model instances for testing / seeding your application's database. | */ $factory->define(App\Models\Post::class, function (Faker $faker) { return [ 'meta_description' => $faker->sentence($nbWords = 6, $variableNbWords = true), 'meta_keywords' => implode(',', $faker->words($nb = 3, $asText = false)), 'excerpt' => $faker->paragraph($nbSentences = 4, $variableNbSentences = true), 'body' => $faker->paragraphs($nb = 8, $asText = true), 'active' => true, ]; });
Running the Seeder
Run the database seeder is easy once all is set up neatly. Just run the following command:
php artisan db:seed
Update Migrations
Sometimes the seeder fails because you did not run the migrations yet or because tables are missing columns. Running your migrations can be done using
php artisan migrate
Add Column to existing Table
Writing this blog post the issue we had using an existing code base was that we were missing a role column in the user table. So new column needed ? No issue with Laravel using column modifier in a new migration:
php artisan make:migration add_role_to_user_table
It then creates this for you:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class AddRoleToUserTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('user', function (Blueprint $table) { // }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('user', function (Blueprint $table) { // }); } }
Which is a great starting point to add the missing column so we can run the database seeder without issues. Where the comment is we added
$table->string('role')->after('password');
as we needed the column role after password column as we saw in the seeder error. And we also realized we had the table users
, not user so adjusted that as well.
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class AddRoleToUserTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { $table->string('role')->after('password'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { $table->string('role')->after('password'); }); } }
That we ran without issues:
Created Migration: 2020_08_01_061408_add_role_to_user_table laradock@75e4f7d90899:/var/www$ php artisan migrate Migrating: 2020_08_01_061408_add_role_to_user_table Migrated: 2020_08_01_061408_add_role_to_user_table (0.03 seconds)
This should then solve our issue and we tried
php artisan db:seed
once more. We however realized the existing seeder was still missing valid
and confirmed
columns. So we did a
php artisan make:migration add_valid_and_confirmed_to_users_table
Then I modified it some and ran this file contents:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class AddValidAndConfirmedToUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { $table->string('valid')->after('role'); $table->string('confirmed')->after('valid'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { $table->string('valid')->after('role'); $table->string('confirmed')->after('valid'); }); } }
New Migrations
Then I still had a lot of missing columns, so decided to load all migrations and Seeder anew from https://github.com/EamonKeane/laravel5-5-example and ran a
php artisan migrate:fresh --seed
to drop all tables and rerun all.
NB Added use Illuminate\Support\Facades\Schema;
to most to have Schema
work properly. Also had to tweak database/seeds/DatabaseSeeder.php
some.
Baum Nested Trees
I did unfortunately ran into another error on a missing makeChildof
method which is part of the Baum Nested Pattern package:
BadMethodCallException Call to undefined method App\Models\Comment::makeChildOf() at vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php:50 46| * @throws \BadMethodCallException 47| */ 48| protected static function throwBadMethodCallException($method) 49| { 50| throw new BadMethodCallException(sprintf( 51| 'Call to undefined method %s::%s()', static::class, $method 52| )); 53| } 54| } • Bad Method Call: Did you mean App\Models\Comment::makeHiddenIf() ?+2 vendor frames
3 database/seeds/DatabaseSeeder.php:301 Illuminate\Database\Eloquent\Model::__call()+37 vendor frames
41 artisan:37 Illuminate\Foundation\Console\Kernel::handle()
A nested set is a smart way to implement an ordered tree that allows for fast, non-recursive queries. For example, you can fetch all descendants of a node in a single query, no matter how deep the tree. The drawback is that insertions/moves/deletes require complex SQL, but that is handled behind the curtains by this package!
Nested sets are appropriate for ordered trees (e.g. menus, commercial categories) and big trees that must be queried efficiently (e.g. threaded posts).
I had to install the version 2 developer version
"baum/baum": "v2.x-dev#a5944ebfd605688213954fd19e1aff0e8fafb132"
to make it work with Laravel 7 but somehow the provider did not get added properly.. which should be done automatically in Laravel. Did Google some and found https://github.com/etrepat/baum/issues/230 for example.
Tried composer dump autoload and updating
laradock@e70f2daa5db5:/var/www$ composer dump-autoload Generating optimized autoload files Illuminate\Foundation\ComposerScripts::postAutoloadDump @php artisan package:discover --ansi Discovered Package: barryvdh/laravel-ide-helper Discovered Package: baum/baum Discovered Package: facade/ignition Discovered Package: fideloper/proxy Discovered Package: fruitcake/laravel-cors Discovered Package: laravel/tinker Discovered Package: laravel/ui Discovered Package: nesbot/carbon Discovered Package: nunomaduro/collision Package manifest generated successfully. Generated optimized autoload files containing 5110 classes laradock@e70f2daa5db5:/var/www$ composer update Loading composer repositories with package information Updating dependencies (including require-dev) ....
But still the same error on php artisan migrate:fresh --seed
. So I checked database/seeds/DatabaseSeeder.php:301
and that is the final line of this block:
// Comments second level $comment3 = factory(Comment::class)->create([ 'post_id' => 2, 'user_id' => 4, //'parent_id' => $nbrComments - 1, ])->makeChildOf($comment1);
Did add the missing Illuminate\Support\Facades\DB;
but that was not related.
Then I did a big models and general app
data migration from the Laravel 5.5 example made by bestmomo and forked by EamonKeane . That allowed for the seeder to run with just some elements like
// Uncheck new for these users // foreach(User::all() as $user) { // $user->ingoing->delete(); // }
commented out.
laradock@e70f2daa5db5:/var/www$ php artisan migrate:fresh --seed Dropped all tables successfully. Migration table created successfully. Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.05 seconds) Migrating: 2017_02_01_233219_create_users_table Migrated: 2017_02_01_233219_create_users_table (0.05 seconds) Migrating: 2017_03_10_233219_create_categories_table Migrated: 2017_03_10_233219_create_categories_table (0.05 seconds) Migrating: 2017_03_10_233219_create_posts_table Migrated: 2017_03_10_233219_create_posts_table (0.04 seconds) Migrating: 2017_03_10_233220_create_comments_table Migrated: 2017_03_10_233220_create_comments_table (0.08 seconds) Migrating: 2017_03_10_233220_create_contacts_table Migrated: 2017_03_10_233220_create_contacts_table (0.02 seconds) Migrating: 2017_03_10_233220_create_ingoings_table Migrated: 2017_03_10_233220_create_ingoings_table (0.06 seconds) Migrating: 2017_03_10_233220_create_notifications_table Migrated: 2017_03_10_233220_create_notifications_table (0.08 seconds) Migrating: 2017_03_10_233220_create_post_tag_table Migrated: 2017_03_10_233220_create_post_tag_table (0.02 seconds) Migrating: 2017_03_10_233220_create_tags_table Migrated: 2017_03_10_233220_create_tags_table (0.04 seconds) Migrating: 2017_03_18_145906_create_category_post_table Migrated: 2017_03_18_145906_create_category_post_table (0.02 seconds) Migrating: 2017_03_18_145916_create_foreign_keys Migrated: 2017_03_18_145916_create_foreign_keys (0.39 seconds)
Well, there you have it. We successfully ran new migrations AND added dummy data to the database to work with. Allowed all to see what we all tried with building up our own models and migrations to tweaking existing models and migrations to implement them in our Laravel 7 setup.
Now we will see what controllers and routes we will use to query data and how can add some need views for backend and frontend views. But that is for some potential follow up block posts.
Current Code @ https://github.com/smart48/smt-demo