2017 © Pedro Peláez
 

yii2-extension yii2-eav

image

nullref/yii2-eav

  • Tuesday, June 5, 2018
  • by ZAYEC77
  • Repository
  • 3 Watchers
  • 2 Stars
  • 22 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 2 Forks
  • 3 Open issues
  • 1 Versions
  • 16 % Grown

The README.md

Yii2 EAV

Latest Stable Version Total Downloads Latest Unstable Version License, (*1)

WIP, (*2)

Module for EAV (entity attribute value) anti pattern, (*3)

Installation

The preferred way to install this extension is through composer., (*4)

Either run, (*5)

php composer.phar require --prefer-dist nullref/yii2-eav "*"

or add, (*6)

"nullref/yii2-eav": "*"

to the require section of your composer.json file., (*7)

Then You have run console command for install this module and run migrations:, (*8)

php yii module/install nullref/yii2-eav

Pay attention that if you don't use our application template it needs to change config files structure to have ability run commands that show above., (*9)

Please check this documentation section, (*10)

Setup

Add behavior to target model, (*11)

use nullref\eav\behaviors\Entity;
use nullref\eav\models\attribute\Set;
use nullref\eav\models\Entity as EntityModel;

/**
 * ...
 * @property EntityModel $eav
 * ...
 */
class Product extends \yii\db\ActiveRecord
    //...
    public function behaviors()
    {
        return [
            /** ... **/
            'eav' => [
                'class' => Entity::class,
                'entity' => function () {
                    return new EntityModel([
                        'sets' => [
                            Set::findOne(['code' => 'product']), //product -- set from db
                        ],
                    ]);
                },
            ],
        ];
    }
    //...
}

Create set and attribute for it in admin panel, (*12)

Add attributes widget to entity edit form, (*13)

<?= \nullref\eav\widgets\Attributes::widget([
    'form' => $form,
    'model' => $model,
]) ?>

If you need some dynamic configuration sets of your model you can use method afterFind():, (*14)

public function afterFind()
{
    $this->attachBehavior('eav', [
        'class' => Entity::class,
        'entity' => function () {
            $setIds = $this->getCategories()->select('set_id')->column();
            $setIds[] = Set::findOne(['code' => 'product'])->id;
            return new EntityModel([
                'sets' => Set::findAll(['id' => array_unique($setIds)]),
            ]);
        },
    ]);
    parent::afterFind();
}

In above example we have many-to-many relation product model with category which has set_id column., (*15)

Pay attention that this example could caused n+1 query problem. To prevent this problem use query caching or memoization. For example, change:, (*16)

\nullref\eav\models\attribute\Set::findOne(['code' => 'product']),

to, (*17)

\nullref\useful\helpers\Memoize::call([Set::class, 'findOne'],[['code' => 'product']]),

Using in search model

If you need filtering your records by eav fields you need to modify YourModelSearch::search() method by following code:, (*18)

    //...
    if (!$this->validate()) {
        return $dataProvider;
    }
    //...
    foreach ($this->eav->getAttributes() as $key => $value) {

        $valueModel = $this->eav->getAttributeModel($key)->createValue();

        $valueModel->setScenario('search');
        $valueModel->load(['value' => $value], '');
        if ($valueModel->validate(['value'])) {
            $valueModel->addJoin($query, self::tableName());
            $valueModel->addWhere($query);
        }
    }
    //...
    return $dataProvider;

To output columns in gridview use nullref\eav\helpers\Grid::getGridColumns():, (*19)

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => array_merge([
    //... 
        'name',
    ], \nullref\eav\helpers\Grid::getGridColumns($searchModel), [
    //... 
        [
            'class' => 'yii\grid\ActionColumn',
        ],
    ]),
]); ?>

To configure which columns will be shown in grid go to attribute update page and select "Show on grid" checkbox., (*20)

Customization

To add custom types you need to use type \nullref\eav\components\TypesManager. To get more details please check \nullref\eav\Bootstrap::setupManager as example of configuring base types., (*21)

You could call \nullref\eav\components\TypesManager::registerType at bootstrap phase and define you own types of attributes., (*22)

Method registerType takes one argument by type \nullref\eav\models\Type this class contains all info about particular type:, (*23)

  • name (unique string)
  • label
  • value model class (based on \nullref\eav\widgets\AttributeInput)
  • form input class (based on \nullref\eav\models\Value)
TypesManager::get()->registerType(new Type(
    Types::TYPE_IMAGE, 
    Yii::t('eav', 'Image'), 
    JsonValue::class, 
    ImageInput::class)
);

Filtering attributes

If you need filter EAV attributes you could use filterAttributes and pass callable there:, (*24)


'eav' => [ 'class' => Entity::class, 'entity' => function () { return new EntityModel([ 'sets' => [ Memoize::call([Set::class, 'findOne'], [['code' => 'product']]), ], 'filterAttributes' => function ($attributes) { $fieldCheckerService = Yii::$container->get(CheckerService::class); $result = []; foreach ($attributes as $code => $attr) { if ($fieldCheckerService->isAllowedForClass(self::class, $code)) { $result[$code] = $attr; } } return $result; } ]); }, ],

Translations

And translations, (*25)

The Versions