rinvex / laravel-attributes

⚠️ [ABANDONED] Rinvex Attributable is a robust, intelligent, and integrated Entity-Attribute-Value model (EAV) implementation for Laravel Eloquent, with powerful underlying for managing entity attributes implicitly as relations with ease. It utilizes the power of Laravel Eloquent, with smooth and seamless integration.
MIT License
433 stars 104 forks source link

setEntitiesAttribute (Attribute.php) creates model listener #126

Closed viewpnt1 closed 2 years ago

viewpnt1 commented 4 years ago

I noticed huge performance issues with using this library when running tests. After some research, I've found that the root cause is insane number of queries when registering around 30 attributes with 3 different entities. What happens is that this method is actually in a very bad place. Whenever during the runtime an entity is attached to an attribute, this creates a new listener for a model which will be called when any other model after that gets saved.

Example: Have 30 attributes created. Attach 3 entities using:

foreach ($attributes as $attribute) {
$attribute->fill(
     ['entities' => ['App\Models\...', 'App\Models\...', 'App\Models\...']]
)->save();
}

1st iteration of foreach: Attribute 1 gets new entities (delete old, create new) 2nd iteration of foreach: Attribute 1 gets new entities (delete old, create new), Attribute 2 gets new entities (delete old, create new) 3rd iteration of foreach: Attribute 1 gets new entities (delete old, create new), Attribute 2 gets new entities (delete old, create new), Attribute 3 gets new entities (delete old, create new)

... and so on.

This creates over 2000 queries for specified example, which happened for every test I created since seeding is done in setUp method.

Any suggestions how this should be handled, so I maybe add a PR?

viewpnt1 commented 4 years ago

At the moment I use another method of adding entities as a workaround:

$attribute->entities()->createMany(
                [['entity_type' => 'App\Models\...'], ['entity_type' => 'App\Models\...'], ['entity_type' => 'App\Models\Competitive\...']]
            );

Which works as expected.

Omranic commented 2 years ago

Thank you for your patience, I'm glad you found a workaround. You're correct, this was mentioned in the documentation under Performance Loss, and initially this package was built with support for another caching package (which is no longer supported due to changes in the underlying Eloquent and other reasons).

However, I did a complete rewrite for the whole package and changed how collections work. In the new refactor, it actually uses normal relationships, and should be easy and straightforward like default Laravel relationships. Although, that refactor is incomplete.

I'm still not happy with the overall performance (I believe we can reduce number of executed queries), if you want to check it out, see https://github.com/rinvex/laravel-attributes/tree/refactor-to-native-laravel-relationships

Currently no plans to merge that rewrite, but hopefully sometime I can get it to a stable state, improve performance and release it. Any help with that branch would be much appreciated! 🙂