curtisupshall
curtisupshall

Reputation: 396

Laravel factory using custom create method

I'm overriding the create method on a few of my models, like in this question. The problem I'm finding is that factories for these models fail because they aren't calling my custom create method.

Model code:

class Teacher extends Model {
  public static function create(array $attributes)
  {
    $user = User::create(['name' => $attributes['name']);
    return static::query()->create(['budget' => $attributes['budget', 'user_id' => $user->id]);
  }

Factory code:

$factory->define(App\Teacher::class, function(Faker $faker) {
  return [
    'name' => $faker->firstName(),
    'budget' => $faker->numberBetween(100, 1000)
  ];
}

I get the following error:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'name' in 'field list' (SQL: insert into `teachers` (`name`, `budget`, `updated_at`, `created_at`) values (Audreanne, 600, 2020-04-07 16:43:54, 2020-04-07 16:43:54))

Any help is greatly appreciated!

Upvotes: 1

Views: 2980

Answers (1)

Dan Mason
Dan Mason

Reputation: 2327

Answer

Factories do not use the model create method to create the model it uses the save method. You should change your factory to be like the below:

$factory->define(App\Teacher::class, function(Faker $faker) {
  return [
    'user_id' => function () {
        return factory(App\User::class)->create()->id;
    },
    'budget' => $faker->numberBetween(100, 1000)
  ];
});

You should have a UserFactory.php already that will generate a name for the associated user.

Additional Advice

As for overriding the create function on your model I strongly do not recommend this approach.

And where you are creating your teacher in code I would recommend taking this approach:

// For example in TeacherController::store
$budget = 500;
$user_id = User::create(['name' => 'Peter Griffin'])->id;
$teacher = Teacher::create(compact('budget', 'user_id'));

If you find that you are needing to do this code in multiple places then I would suggest implementing a new method on your model (see below) or create a service class to handle it:

class Teacher extends Model {
    public static function createWithUser($name, $budget): Teacher
    {
        $user_id = User::create(compact('name'))->id;
        return Teacher::create(compact('budget', 'user_id'));          
    }
}

// For example
$teacher = Teacher::createWithUser('Peter Griffin', 500);

Upvotes: 3

Related Questions