Database Seeding Gone Wild

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

Jasper Frumau

Jasper has been working with web frameworks and applications such as Laravel, Magento and his favorite CMS WordPress including Roots Trellis and Sage for more than a decade. He helps customers with web design and online marketing. Services provided are web design, ecommerce, SEO, content marketing. When Jasper is not coding, marketing a website, reading about the web or dreaming the internet of things he plays with his son, travels or run a few blocks.