Jonjie's avatar
Level 12

Why field _created_by is not included when using $guarded

Why field _created_by is not included when using protected $guarded = []; and when using Model::create();?

But when I use $fillable, it works perfectly fine.

0 likes
10 replies
azimidev's avatar

$fillable and $guarded are related to mass assignment protection. When you use Model::create(); or similar mass assignment methods, Laravel uses these properties to determine which attributes should be allowed or denied for mass assignment.

Its whitelisting using $fillable vs blacklisting using $guarded. Laravel defaults to whitelisting for your own benefit. You might want to research whitelisting vs blacklisting.

Jonjie's avatar
Level 12

@azimidev yup, $guarded = [] means whitelisting all the fields. But why the _created_by is the only field that is not working?

Merklin's avatar

If you want to populate '_created_by' when it is defined as guarded, you cannot assign it from a form, as stated above. Instead, you have to write a code to assign a default value. For example, if _created_by is ALWAYS the currently authenticated user, you can do this:

Create a trait named CreatedByTrait with following content:

<?php

declare(strict_types=1);

namespace App\Traits;

trait CreatedByTrait
{
    /**
     * Boot the trait for a model.
     *
     */
    public static function bootCreatedByTrait(): void
    {
        if (auth()->check()) {
            static::creating(function ($model): void {
                $model->created_by = auth()->id();
            });
        }
    }
}

Then, in the model where you have defined _created_by as guarded, include the trait in the beginning:

<?php

declare(strict_types=1);

namespace App\Models;

use App\Traits\CreatedByTrait;

class SomeModel extends Model
{
	use CreatedByTrait;
}

With the above code, every time when you create a new record for SomeModel the field for _created_by will be auto-populated with the ID of the currently authenticated user.

If you are suing Livewire, same code can be used for #[Locked] properties.

amitsolanki24_'s avatar

$guarded = []; and $fillable are opposite to eachother When you are use fillable its checking columns are exists in fillable array But when you use guarded its allow all columns that are not exists in guarded

azimidev's avatar

yep again whitelisting vs blacklisting! you need to include them in the $fillable property or set $guarded to an empty array if you want all fields to be mass-assignable. If you want to guard specific fields, you should list them in the $guarded property. Whether a field name starts with an underscore or not doesn't change the default behavior in Laravel's Eloquent.

Jonjie's avatar
Level 12

@azimidev Nope. underscore does matter in laravel eloquent, please check my answer so you'll have a reference in the future when you face this issue.

Tray2's avatar

@Jonjie I would venture as far as to ask why would you ever want to have a column name that starts with an underscore, that is just plain bad practice.

1 like
Jonjie's avatar
Level 12

@Tray2 yep I agree with that. This is actually an old database that I am currently maintaining. So I really need to adjust 😅

Please or to participate in this conversation.