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

Getting Started Frustrations with Laravel 5.6 #40

Closed dhildreth closed 4 years ago

dhildreth commented 6 years ago

Having a lot of struggles getting this working with Laravel 5.6. I was able to get the installation going alright after adding "minimum-stability": "dev" to composer.json. I was also able to create a seeder to populate some attributes:

       use Rinvex\Attributes\Models\Attribute;

        Attribute::create([
            'type' => 'varchar',
            'name' => 'CPU',
            'entities' => ['App\Product'],
            'group' => 'Core Components',
        ]); 

I can verify the attribute is in the DB okay and the slug is set to 'cpu' (and group is set to 'core-components', which is another issue for another time).

In AppServiceProvider.php, I've pushed the entity...

        // Push your entity fully qualified namespace
        app('rinvex.attributes.entities')->push(\App\Product::class);

Now, when it comes time to actually set an attribute value for the product entity, it doesn't just work as it says in the documentation.

>>> $product = App\Product::find(14)
=> App\Product {#1007
     id: 14,
     ....
>>> $product->cpu = 'ARM';
=> "ARM"
>>> $product->save()
Illuminate\Database\QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'cpu' in 'field list' (SQL: update `products` set `updated_at` = 2018-04-27 11:06:21, `cpu` = ARM where `id` = 14)'
>>>

Assuming I get through this issue, the next issue is what happens when I need to set a field with a space in the name like "CPU Speed"? The slug comes out to be "cpu-speed". Does this mean I use $product->cpu_speed or $product->cpuSpeed or what?

Assuming I get through that issue, what about grouping? I need to be able to display the group in a human friendly way. For example "Core Components" instead of "core-components". I'll also need to provide a way for an admin to create new groups, set an order for each group, etc. Seems to me like another table such as "AttributeGroups" would be better, and set attributes.group to a foreign key instead of a slug. Documentation around grouping would be much appreciated.

But first, let's get through setting a value for the attribute please! What did I miss?

dhildreth commented 6 years ago

Okay, I tinkered around a little more and read through the documentation with a fine tooth comb and also kept it simple for now (instead of attempting to use groups). I was able to get somewhere. I was using morph classes, so changing things to this got everything working as expected:

AppServiceProvider.php:

Relation::morphMap([
            'product' => 'App\Product',
        ]);

app('rinvex.attributes.entities')->push('product');

ProductAttributeSeeder.php:

use Rinvex\Attributes\Models\Attribute;

        Attribute::create([
            'type' => 'varchar',
            'name' => 'CPU',
            'entities' => ['product'],
            //'group' => 'Core Components',
        ]);

At this point, I had to spend a bunch of time figuring out how to reference the attributes with spaces in them. I would suggest updating documentation with a quick example. Here's the setup:

ProductAttributeSeeder.php:

        Attribute::create([
            'type' => 'integer',
            'name' => 'CPU Speed',
            'entities' => ['product'],
            'slug' => 'cpu-speed,
        ]);

To set the attribute, you need to use $product->{'cpu-speed'}. Like so...

>>> $product = App\Product::find(14)
=> App\Product {#1007
     id: 14,
     ....
>>> $product->{'cpu-speed'} = '1000'
=> "1000"
>>> $product->save()
=> true
>>>

I'm going to leave this open for now, since there is still the issue of groups to handle. I'm not sure how to utilize this feature and I think there could be some documentation updates here as well.

dhildreth commented 6 years ago

And, another frustration. Attempting to use the special 'eav' rinvex attribute talked about in the documentation...

php artisan tinker

>>> $product = App\Product::find(14)
=> App\Product {#1007
     id: 14,
     ....
>>> $product->load('eav')
Illuminate\Database\Eloquent\RelationNotFoundException with message 'Call to undefined relationship [eav] on model [App\Product].'
>>>

Product.php

class Product extends Model
{
    use \Rinvex\Attributes\Traits\Attributable;

    // Eager loading all the registered attributes
    protected $with = ['eav'];
     ...

Good news I guess is that this does work:

>>> $product->load('cpu', 'cpu-speed')`
dhildreth commented 6 years ago

Sorry, I'm off to a rough start here, but I'm getting there I guess. I removed all but two attributes in my seeder model and tried again, this time with some success. I also cleared the cache (php artisan cache:clear). Now I can see the attributes on my Product model, but I'm still getting the nasty error when using $product->load('eav').

IsraelOrtuno commented 6 years ago

I am getting back to the project, will try to reproduce your case.

dhildreth commented 6 years ago

Thanks, that'd be great. I've moved onto other parts of the application for now, but I'll still need to get this part figured out sooner than later. ;-)

dhildreth commented 6 years ago

@IsraelOrtuno, were you able to get back to the project to reproduce the issues? I'm getting ready to come back on this portion of the app.

dhildreth commented 6 years ago

Any updates?

IsraelOrtuno commented 6 years ago

I have been testing it and it looks like a Laravel change on Eloquent in 5.5 or 5.6... Still digging into it

Omranic commented 6 years ago

Hello Dear @dhildreth, first of all thank you for your feedback and the detailed description, it's really helpful.

Let me address above issues one by one:

  1. Yes, you're right. This slug auto-generation with dashes is a real issue, let me see what's the best solution for that..
  2. Yes, I totally agree that grouping isn't intuitive and very limited, I've already though in your proposal before and I think it's time to take this into action, and refactor this part.
  3. For the $product->load('eav'), @IsraelOrtuno just notified me about this issue, I wasn't aware of, so I'll be checking with him to see what's the cause of this issue and try to fix it.

For now I'm working on first two issues, stay tuned for an upcoming update 🙂

Omranic commented 6 years ago

First issue fixed here https://github.com/rinvex/attributes/commit/f0f070c9bed253651b1df047d91b346f9f863a2f Now all auto-generated slugs will be underscore delimited, so you can use it normally like $product->cpu_speed

dhildreth commented 6 years ago

Thanks for your work on this. It's very appreciated. Let me know if I can help.

dhildreth commented 6 years ago

I figured I should mention, I got around the group attribute limitations by creating my own Attribute class which extends RinvexAttribute:

class Attribute extends RinvexAttribute
{
    /**
     * Un-enforce clean groups.
     *
     * @param string $value
     *
     * @return void
     */
    public function setGroupAttribute($value): void
    {
        $this->attributes['group'] = $value;
    }

It now behaves like I expect it to.

JackyWong88 commented 4 years ago

I'm currently using Laravel 7.x, and the $product->load('eav';) still does not work, but protected $with = ['eav']; does. It still returns the error message Call to undefined relationship [eav] on model.