derdida
derdida

Reputation: 14904

Laravel Mutators with Constructor?

Ill have a problem because my mutators never get called when ill use an constructor:

Like this:

function __construct() {
    $this->attributes['guid'] = Uuid::generate(4)->string;
}

public function setDateAttribute($date) {
    dd($date); // Never gets called
}

Ill already found out, that the mutators would ne be called when ill use an constructor, so i should use:

public function __construct(array $attributes = array()){
    parent::__construct($attributes);
    $this->attributes['guid'] = Uuid::generate(4)->string;
}

public function setDateAttribute($date) {
    dd($date); // now its getting called
}

But so ill get the following error:

array_key_exists() expects parameter 2 to be array, null given

But i dont know where? Can anyone help me out how to create a default value (like a UUID) for a specific column, and use mutators in the same class?

Edit: Thanks Martin Bean for your help, but i am now getting the following error:

Cannot declare class App\Uuid because the name is already in use

I have tried:

Creating a File called "Uuid.php" in /app/ -> /app/Uuid.php

With this content:

<?php namespace App;

use Webpatser\Uuid\Uuid;

trait Uuid
{
    public static function bootUuid()
    {
        static::creating(function ($model) {
            $model->uuid = Uuid::generate(4)->string();
        });
    }
}

Changed my Model to:

<?php namespace App;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;


class Task extends Model {

    use \App\Uuid;

Thank you very much!

Edit 2:

Ill tried it this way:

class Task extends Model {

    protected $table = 'tasks';

    protected $fillable = ['..... 'date', 'guid'];

    public function setGuidAttribute($first=false){
    if($first) $this->attributes['guid'] = Uuid::generate(4)->string;
}

TaskController:

public function store() {

    $input = Request::all();
    $input['guid'] = true;
    Task::create($input);

    return redirect('/');

}

Works fine, but when ill use:

public function setDateAttribute(){
    $this->attributes['date'] = date('Y-m-d', $date);
}

In Task.php ill get:

Undefined variable: date

Upvotes: 0

Views: 1023

Answers (2)

Martin Bean
Martin Bean

Reputation: 39389

EDIT: Whilst the below approach is still valid for adding “concerns” to Laravel models, Laravel since version 9.x has shipped with its own trait for generating UUIDs for models. Docs: https://laravel.com/docs/9.x/eloquent#uuid-and-ulid-keys

Mutators are called when you try and set a property on the model—they’re invoked via the __get magic method. If you manually assign a property in a method or constructor, then no mutators will ever be called.

Regardless, you should not be creating constructors on Eloquent model classes. This could interfere with how Eloquent models are “booted”.

If you need to set an UUID on a model then I’d suggest using a trait that has its own boot method:

namespace App\Models\Concerns;

trait HasUuid
{
    protected static function bootHasUuid(): void
    {
        static::creating(function (Model $model) {
            $model->uuid = Str::uuid()->toString();
        });
    }
}

You apply the trait to your model…

use App\Models\Concerns;

class SomeModel extends Model
{
    use HasUuid;
}

…and now each time a model is created, a UUID will be generated and stored in the database with your model in the uuid column.

Upvotes: 1

Emeka Mbah
Emeka Mbah

Reputation: 17545

EDITED:

based on your comment:

i would like to set a field on first insert

use Uuid; //please reference the correct namespace to Uuid 

class User extends Model{

   protected $fillable = [
      'first_name',
      'email',
      'guid' //add guid to list of your fillables
   ]

    public function setGuidAttribute($first=false){
        if($first) $this->attributes['guid'] = Uuid::generate(4)->string;
    }
 }

Later:

 $user = User::create([
    'guid' => true, //setAttribute will handle this
    'first_name' => 'Digitlimit',
    'email"  => [email protected]
 ]);

dd($user->guid); 

NB: Remove the __construct() method from your model

Upvotes: 2

Related Questions