Laravel-activitylog: Attribute does not capture value on model mutators.

Created on 5 Apr 2019  路  10Comments  路  Source: spatie/laravel-activitylog

As you can see, this is my code on Staff model:

use Spatie\Activitylog\Traits\LogsActivity;

class Staff extends Model
{
    use LogsActivity;

    protected $fillable = [
        'name',
    ];

    // activity log
    protected static $logName = 'staff';
    protected static $logAttributes = ['*'];

    public function setNameAttribute($value)
    {
        $this->attributes['name'] = strtoupper($value);
    }

This is my Activitylog table on database:
On Properties Column:

{
    "attributes":{
        "id":2,
        "name":"",
        "created_at":"2019-03-28 16:21:27",
        "updated_at":"2019-04-03 10:44:25"
    },
    "old":{
        "id":2,
        "name":"",
        "created_at":"2019-03-28 16:21:27",
        "updated_at":"2019-04-03 10:42:48"
    }
}

I'm using:

  • Laravel 5.8.8
  • ActivityLog v3

Can you help me get the value of name by using mutator?

question

Most helpful comment

All 10 comments

Hey,
I've added a specific unittest for this case and it's successful https://github.com/spatie/laravel-activitylog/pull/508

So far I also can't see a reason why it shouldn't work. We use the $model->getAttributes() method to resolve the * to all keys. In \Spatie\Activitylog\Traits\DetectsChanges::logChanges() we also rely on basic eloquent methods to get the values for each attribute.

Can you check if the name is set before the log entry is triggered?

@Gummibeer the value of name updated successfully in Staff table, However, the value does not capture on activity log table. If I remove the mutator, it works fine.

Did I missed something?

PS, I use oracle DB.

@nbsoo to be honest I have no idea what's going wrong. :/
The mutator itself isn't relevant for this package and like shown in the unittest it works - for create and update.
I would try to debug what happens in \Spatie\Activitylog\Traits\DetectsChanges::attributeValuesToBeLogged() and the order in which the mutator and the model event listener are called.

Thanks for your reply @Gummibeer , I have tried create a new project, it works fine. Maybe there is something missing with my project.
I'll try to investigate more, maybe try to reinstall the package.

Thanks for you help.

@Gummibeer I've found the culprit! The problem was not a mutators, it is cause by an accessors.
I have an accessor:

public function getNameAttribute($value) { return strtoupper($value); }

When I remove this accessor, the package works fine! :)
Can you add this accessor to your unittest? Is it okay on yours?

Hey, I will add a test and check it. But I think that it should work. We already have this in a similar test DetectsChangesTest::it_can_use_overloaded_as_loggable_attributes this test has a mutator and accessor for an overloaded/appended attribute.
Could it be that your value doesn't change like abc & aBc are both ABC following your accessor & mutator? Just the most stupid idea I have. 馃槄

@Gummibeer Haha,that's okay. My accessor works fine. The value does change from abc to ABC. However, logActivity does not capture the value when I used accessor.

I have try comment the accessor, suddenly logActivity works fine.

Do you have any idea regarding to this? 馃槄

Hi, I'm facing the same problem like @nbsoo.
I created new laravel 5.8.10 project and install only Activity Log package.
In User model I put simple mutator and accessor.

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Activitylog\Traits\LogsActivity;

class User extends Authenticatable
{
    use Notifiable;
    use LogsActivity;

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

    // activity log
    protected static $logName = 'user';
    protected static $logAttributes = ['*'];

    /**
     * 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 getNameAttribute($value)
    {
        return strtoupper($value);
    }

    public function setNameAttribute($value)
    {
        $this->attributes['name'] = strtoupper($value);
    }
}

and the result of user registration

{
    "attributes":{
        "id":1,
        "name":"",
        "email":"[email protected]",
        "email_verified_at":null,
        "password":"xyz",
        "remember_token":null,
        "created_at":"2019-04-09 03:57:58",
        "updated_at":"2019-04-09 03:57:58"
    }
}

I can confirm if I remove the accessor, the name will not empty.

{
    "attributes":{
        "id":2,
        "name":"SULTAN2",
        "email":"[email protected]",
        "email_verified_at":null,
        "password":"xyz",
        "remember_token":null,
        "created_at":"2019-04-09 08:36:58",
        "updated_at":"2019-04-09 08:36:58"
    }
}

Hey, I've added the new test and can reproduce it - the bug is that we had append all attributes that have an accessor. But these are called with a null value in \Illuminate\Database\Eloquent\Concerns\HasAttributes::attributesToArray(). So I've added an extra check that will only append attributes with an accessor and that aren't in $model->attributes.

PR will follow

Was this page helpful?
0 / 5 - 0 ratings

Related issues

BerendSpigt picture BerendSpigt  路  4Comments

federico-arona picture federico-arona  路  5Comments

hackel picture hackel  路  5Comments

ekandreas picture ekandreas  路  3Comments

DjKhireddine picture DjKhireddine  路  5Comments