spatie / activitylog

A very simple activity logger to monitor the users of your website or application
https://spatie.be/opensource/laravel
MIT License
582 stars 75 forks source link

Logging Old and New Values on Update #29

Closed frederikvdbe closed 8 years ago

frederikvdbe commented 8 years ago

I've seen a past post with the same title, but the answer there didn't help me, probably cause im very new to laravel...

-> https://github.com/spatie/activitylog/issues/21

So this package works great for logging standard messages like 'Model created', 'Model updated', and so on, but how can I log the previous values of the changes? Example, model 'Product' price changes from 150 to 160, or Product title changes..

I tried a couple of things, working with events/handlers, creating a new trait, but nothing worked so far for me...

Btw im using laravel 5.0

Can anyone assist me with this please? Thanks in advance!

sebastiandedeyne commented 8 years ago

I'll clarify on my old post you just referenced—

The easiest way to achieve this would be to register and event in the boot method of your model. The updating event will be called whenever you save an existing product with updated values. The getOriginal function allows you to retrieve the original value of the price (which would have been 150).

use Activity;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected static function boot()
    {
        static::updating(function ($product) {
            Activity::log("{$product->price} just updated to {$product->getOriginal('price')}");
        }
    }
}

More on model events: https://laravel.com/docs/master/eloquent#events

frederikvdbe commented 8 years ago

Ok, for some reason this works now, I probably made some syntax error in the past.. But now how do I tackle the fact my model has serveral fields? Do I use a large is/else statement checking each property for change? or does laravel has some helpers for this?

Thanks for the help so far :)

sebastiandedeyne commented 8 years ago

If you're going to log multiple fields, what would your message look like? Or would you log one message per field?

frederikvdbe commented 8 years ago

I think one message would suffice, ofcourse the field should be specified in the activity log.. Maybe something like "$product->name $field has been updated from getOriginal('price') to $product->price".. Is this possible?

Btw this is only for the updating message.. The messages for created and deleted are fine the way they are...

frederikvdbe commented 8 years ago

I found the isDirty and getDirty methods which returns boolean and array of changed values, perfect for this.

Thanks for the help!

frederikvdbe commented 8 years ago

Me again. For some reason the default methods from your package doesn't work anymore when I use the updated event..

This works (in my Product.php model)

public function getActivityDescriptionForEvent($eventName)
{
    if ($eventName == 'created')
    {
        return 'Product "' . $this->name . '" was created';
    }

    if ($eventName == 'updated')
    {

        return 'Product "' . $this->name . '" was updated';
    }

    if ($eventName == 'deleted')
    {
        return 'Product "' . $this->name . '" was deleted';
    }

    return '';
}

But when I add this at the top

protected static function boot(){

        static::updated(function ($product) {

            $changes = $product->isDirty() ? $product->getDirty() : false;

            if($changes)
            {
                foreach($changes as $attr => $value)
                {

                    Activity::log("updated product $attr from {$product->getOriginal($attr)} to {$product->$attr}");

                }
            }

        });

    }

It loggs only when updating..

Anyone knows going on here? Thanks in advance!

sebastiandedeyne commented 8 years ago

The LogsActivity trait registers events via Eloquent's boot method, which you're overriding. You'll need to add parent::boot() to your own method.

frederikvdbe commented 8 years ago

That makes sense.. Thanks for the help, it works :)

Cheers!