Laravel 8 firstOrCreate Not Working With $fillable

Viewed 361

I have this code in my controller:

$createAccreditorAccount = User::firstOrCreate(
    ['name' => "Accreditor"],
    ['nonofficial_category_id' => 0],
    ['role' => "accreditor"],
    ['email' => "accreditor@cvsucarmona.com"],
    ['password' => Hash::make('accreditor_cvsucarmona')],
    ['email_verified_at' => now()]
);

The error I get is this:

SQLSTATE[HY000]: General error: 1364 Field 'role' doesn't have a default value (SQL: insert into `users` (`name`, `nonofficial_category_id`, `updated_at`, `created_at`) values (Accreditor, 0, 2021-05-19 11:36:35, 2021-05-19 11:36:35))

Within the error display, it seems like the columns role, email and password do not fill my record. I am pretty sure that I have included those columns in my $fillable.

Below is my User model:

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'role',
        'subcategory',
        'email',
        'password',
        'nonofficial_category_id',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function nonOfficialsCategories()
    {
        return $this->belongsTo(NonOfficialsCategories::class, 'nonofficial_category_id');
    }
}

1 Answers

You don't need to specify each field value in it's own array and provide them as separate parameters, firstOrCreate() only takes 2 parameters, the first array is the unique fields to check against and the second param is the array of values to insert or update. It should be more like this...

$createAccreditorAccount = User::firstOrCreate(
    [ 'email' => "accreditor@cvsucarmona.com" ],    
    [
        'name' => "Accreditor",
        'nonofficial_category_id' => 0,
        'role' => "accreditor",
        'email' => "accreditor@cvsucarmona.com",
        'password' => Hash::make('accreditor_cvsucarmona'),
        'email_verified_at' => now()
    ]
);

To explain why you are getting the error that you are, the firstOrCreate() method is checking ['name' => "Accreditor"] to see if it's unique and then attempting to insert ['nonofficial_category_id' => 0], which only has the nonofficial_category_id column set, hence the complaint about role not having a default value, ergo, you need to provide a value.

Related