Search code examples
phplaravel-5eloquent

Laravel 5 Model Factories Null Error


This is the error I am receiving when I try to use a Model factory for only my Message model. Other model factories are working just fine and I have tracked this down to the applyStates method in laravel's FactoryBuilder and it is in-fact null, I am just not sure why. I have the model class defined, I have the table created, the code in my method to add seed data for messages is working but this error is thrown after the first record is inserted keeping it from adding a bunch of seed data for me.

[2016-12-23 20:24:04] local.ERROR: Symfony\Component\Debug\Exception\FatalThrowableError: Type error: Argument 1 passed to Illuminate\Database\Eloquent\FactoryBuilder::applyStates() must be of the type array, null given, called in /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php on line 168 in /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:180
Stack trace:

- 0 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php(168): Illuminate\Database\Eloquent\FactoryBuilder->applyStates(NULL, Array)
- 1  /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(2282): Illuminate\Database\Eloquent\FactoryBuilder->Illuminate\Database\Eloquent\{closure}()
- 2 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php(170): Illuminate\Database\Eloquent\Model::unguarded(Object(Closure))
- 3 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php(143): Illuminate\Database\Eloquent\FactoryBuilder->makeInstance(Array)
- 4 [internal function]: Illuminate\Database\Eloquent\FactoryBuilder->Illuminate\Database\Eloquent\{closure}(1)
- 5 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php(144): array_map(Object(Closure), Array)
- 6 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php(113): Illuminate\Database\Eloquent\FactoryBuilder->make(Array)
- 7 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/database/seeds/MessagesTableSeeder.php(15): Illuminate\Database\Eloquent\FactoryBuilder->create()
- 8 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/SeedCommand.php(63): MessagesTableSeeder->run()
- 9 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(2288): Illuminate\Database\Console\Seeds\SeedCommand->Illuminate\Database\Console\Seeds\{closure}()
- 10 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/SeedCommand.php(64): Illuminate\Database\Eloquent\Model::unguarded(Object(Closure))
- 11 [internal function]: Illuminate\Database\Console\Seeds\SeedCommand->fire()
- 12 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Container/Container.php(508): call_user_func_array(Array, Array)
- 13 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Console/Command.php(169): Illuminate\Container\Container->call(Array)
- 14 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/symfony/console/Command/Command.php(254): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
- 15 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Console/Command.php(155): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
- 16 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/symfony/console/Application.php(821): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
- 17 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/symfony/console/Application.php(187): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Database\Console\Seeds\SeedCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
- 18 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/symfony/console/Application.php(118): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
- 19 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(121): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
- 20 /Users/jcrawford/Dropbox/Work/RYNO/htdocs/artisan(35): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
- 21 {main}

// Model Factory

$factory->define(Message::class, function(Faker\Generator $faker) {
$userIds = User::all()->pluck('id')->toArray();
$postIds = Post::all()->pluck('id')->toArray();

$post = Post::find($faker->randomElement($postIds));

$user1 = User::find($faker->randomElement($userIds));
$user2 = User::find($faker->randomElement($userIds));

$message1 = new Message([
    'post_id' => $post->id,
    'to_user_id' => $user1->id,
    'from_user_id' => $user2->id,
    'message' => $faker->sentence()
]);
$message1->save();

if(mt_rand(0,1) === 1) {
    // add message reply
    $message2 = new Message([
        'message_id' => $message1->id,
        'post_id' => $post->id,
        'to_user_id' => $user2->id,
        'from_user_id' => $user1->id,
        'message' => $faker->sentence()
    ]);

    $message2->save();
}
});

// Using Model Factory

<?php

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

class MessagesTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        factory(Message::class, 200)->create();
    }
}

Solution

  • You get the error because a Model Factory definition needs to return an array containing the attributes of the Model instance that you are creating.

    With your current code you'll always end up with at least 1 or eventually 2 new Message (if the mt_rand(0,1) equals to true). But your factory() call will always fail after the first execution. Try this:

    Model Factory:

    $factory->define(App\Message::class, function(Faker\Generator $faker) {
    
        $userIds = App\User::all()->pluck('id')->toArray();
        $postIds = App\Post::all()->pluck('id')->toArray();
        $post = App\Post::find($faker->randomElement($postIds));
        $user1 = App\User::find($faker->randomElement($userIds));
        $user2 = App\User::find($faker->randomElement($userIds));
    
        return [
            'message_id' => null, // default NULL
            'post_id' => $post->id,
            'to_user_id' => $user1->id,
            'from_user_id' => $user2->id,
            'message' => $faker->sentence()
        ];
    });
    

    MessagesTableSeeder:

    class MessagesTableSeeder extends Seeder
    {
        /**
         * Run the database seeds.
         *
         * @return void
         */
        public function run()
        {
            factory(App\Message::class, 200)
                ->create()
                ->each(function ($m) {
                    if(mt_rand(0,1) === 1) {
                        factory(App\Message::class)
                            ->create([
                                'message_id' => $m->id, // Overrides NULL attribute
                                'post_id' => $m->post_id, // Ensures same post
                                'to_user_id' => $m->from_user_id, // Switch from & to from relation
                                'from_user_id' => $m->to_user_id,
                            ]);
                    }
                });
        }
    }