Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Activity logs twice when extending Trait from LogsActivity #392

Closed
thc1967 opened this issue Jun 9, 2018 · 6 comments
Closed

Activity logs twice when extending Trait from LogsActivity #392

thc1967 opened this issue Jun 9, 2018 · 6 comments

Comments

@thc1967
Copy link

thc1967 commented Jun 9, 2018

I've probably done something wrong, and I can stop the double logging as I describe below. But I'd like to use my own Trait as an extension of the LogsActivity Trait to keep my code just a bit cleaner.

I've extended my own Trait from Spatie\Activitylog\Traits\LogsActivity as follows:

namespace App\Traits;

use Spatie\Activitylog\Traits\LogsActivity as SpatieLogsActivity;

trait LogsActivity
{
    use SpatieLogsActivity;

    /**
     * Log only changed properties
     *
     * @var boolean
     */
    protected static $logOnlyDirty = true;

    /**
     * The custom log name for the model
     *
     * @param string $eventName
     * @return string
     */
    public function getLogNameToUse(string $eventName = ''): string
    {
        return str_plural(strtolower(class_basename($this)));
    }
}

When I apply this Trait to any Model class, the system puts two rows in the activity_log table for each change to a Model record.

If, on the other hand, I don't use my extended Trait and instead apply the Spatie LogsActivity Trait to my Model class, I get only one entry in the activity_log table for each change to a Model record.

This seems to mean that there's something in the way I've extended the Trait, or in PHP's Trait handling, that causes the double logging. If it were something happening in the Model, I would expect to get two log entries regardless which Trait I associated to the Model.

The repo here https://github.com/thc1967/SpatieSortableExtendTraitDemo is a barebones demo of the issue.

I use Tinker to create and save a "Widget" object and poof, two entries in the activity_log table. Switch the Widget model to use the core Spatie LogsActivity trait instead of the extended one and we get one log entry.

// Tinker
$w = new Widget();
$w->name = 'foo';
$w->save();

Result is either 1 or 2 entries in activity_log depending on whether we're using the core Trait or extended Trait.

@thc1967
Copy link
Author

thc1967 commented Jun 9, 2018

This issue can be closed.

If I rename the extended Trait to anything else, even if I alias it in my use statement, it only logs one entry. PHP issue, perhaps? Definitely not Spatie's problem though.

@thc1967 thc1967 closed this as completed Jun 9, 2018
@Gummibeer
Copy link
Collaborator

Gummibeer commented Jun 10, 2018

Just an idea - the trait is booted by the special bootXyzTrait method. This is generated done by a reflection class and so on. If you have two traits with the same name it could be that the method is executed two times. If so it will add the observer two times.

So if I'm right this is a laravel core issue. Could you try to verify this with a simple dump in the boot method for example?

Here is the core method: https://github.com/laravel/framework/blob/4f7b2760aefea06d4860af6ee2b0d52b2e93b78b/src/Illuminate/Database/Eloquent/Model.php#L189-L198

@thc1967
Copy link
Author

thc1967 commented Jun 10, 2018

I've inserted a dump into the Laravel code's Model bootTraits() method as follows:

    protected static function bootTraits()
    {
        $class = static::class;

        foreach (class_uses_recursive($class) as $trait) {
            if (method_exists($class, $method = 'boot'.class_basename($trait))) {
                dump('booting ' . $trait);
                forward_static_call([$class, $method]);
            }
        }
    }

When I Tinker and type $w = new Widget();, I get the following dump. Notice the two LogsActivity traits.

"booting App\Traits\LogsActivity"
"booting Spatie\Activitylog\Traits\LogsActivity"
"booting Spatie\Activitylog\Traits\DetectsChanges"

When I rename my Trait to MyLogsActivity and alias that as LogsActivity in my Model class, I get the following with the same action:

use App\Traits\MyLogsActivity as LogsActivity;
class Widget extends Model
{
    use LogsActivity;
"booting Spatie\Activitylog\Traits\LogsActivity"
"booting Spatie\Activitylog\Traits\DetectsChanges"

Given my relative inexperience with PHP and Laravel, I'm not sure what to make of the difference. There's a simple, public Github project referenced in the original post that makes this easily reproducible.

@Gummibeer
Copy link
Collaborator

Ok, this is just the prove that laravel executes the same bootXyzTrait method multiple times if the base class name of multiple traits are the same.
As a solution for you I recommend to rename your trait to AppLogsActivity or `LogsActivityTrait or something like this to prevent this error.

laravel/framework#24548

@Gummibeer
Copy link
Collaborator

It's fixed in laravel/framework#24556

@eduarguz
Copy link
Contributor

eduarguz commented Dec 7, 2018

Thank you guys for the well explained issue and the given updates, fixed the same issue in no time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants