{"id":15698141,"url":"https://github.com/nullrefexcep/yii2-eav","last_synced_at":"2025-05-08T22:43:33.745Z","repository":{"id":57029275,"uuid":"115140710","full_name":"NullRefExcep/yii2-eav","owner":"NullRefExcep","description":"Module for entity attribute value anti-pattern","archived":false,"fork":false,"pushed_at":"2021-10-16T00:03:31.000Z","size":23628,"stargazers_count":6,"open_issues_count":3,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-08T22:43:25.482Z","etag":null,"topics":["eav","yii2","yii2-eav","yii2-extension"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NullRefExcep.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-22T18:29:13.000Z","updated_at":"2024-01-24T18:25:51.000Z","dependencies_parsed_at":"2022-08-23T17:40:52.216Z","dependency_job_id":null,"html_url":"https://github.com/NullRefExcep/yii2-eav","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NullRefExcep%2Fyii2-eav","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NullRefExcep%2Fyii2-eav/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NullRefExcep%2Fyii2-eav/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NullRefExcep%2Fyii2-eav/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NullRefExcep","download_url":"https://codeload.github.com/NullRefExcep/yii2-eav/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253160727,"owners_count":21863624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eav","yii2","yii2-eav","yii2-extension"],"created_at":"2024-10-03T19:23:37.127Z","updated_at":"2025-05-08T22:43:33.716Z","avatar_url":"https://github.com/NullRefExcep.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Yii2 EAV\n===============\n\n\n[![Latest Stable Version](https://poser.pugx.org/nullref/yii2-eav/v/stable)](https://packagist.org/packages/nullref/yii2-eav) [![Total Downloads](https://poser.pugx.org/nullref/yii2-eav/downloads)](https://packagist.org/packages/nullref/yii2-eav) [![Latest Unstable Version](https://poser.pugx.org/nullref/yii2-eav/v/unstable)](https://packagist.org/packages/nullref/yii2-eav) [![License](https://poser.pugx.org/nullref/yii2-eav/license)](https://packagist.org/packages/nullref/yii2-eav)\n\n\nWIP\n\nModule for EAV (entity attribute value) anti pattern\n\nInstallation\n------------\n\nThe preferred way to install this extension is through [composer](http://getcomposer.org/download/).\n\nEither run\n\n```\nphp composer.phar require --prefer-dist nullref/yii2-eav \"*\"\n```\n\nor add\n\n```\n\"nullref/yii2-eav\": \"*\"\n```\n\nto the require section of your `composer.json` file.\n\nThen You have run console command for install this module and run migrations:\n\n```\nphp yii module/install nullref/yii2-eav\n```\n\nPay attention that if you don't use our [application template](https://github.com/NullRefExcep/yii2-boilerplate) \nit needs to change config files structure to have ability run commands that show above.\n\nPlease check this [documentation section](https://github.com/NullRefExcep/yii2-core#config-structure)\n\nSetup\n-----\n\nAdd behavior to target model\n\n```php\nuse nullref\\eav\\behaviors\\Entity;\nuse nullref\\eav\\models\\attribute\\Set;\nuse nullref\\eav\\models\\Entity as EntityModel;\n\n/**\n * ...\n * @property EntityModel $eav\n * ...\n */\nclass Product extends \\yii\\db\\ActiveRecord\n    //...\n    public function behaviors()\n    {\n        return [\n            /** ... **/\n            'eav' =\u003e [\n                'class' =\u003e Entity::class,\n                'entity' =\u003e function () {\n                    return new EntityModel([\n                        'sets' =\u003e [\n                            Set::findOne(['code' =\u003e 'product']), //product -- set from db\n                        ],\n                    ]);\n                },\n            ],\n        ];\n    }\n    //...\n}\n```\n\nCreate set and attribute for it in admin panel\n\nAdd attributes widget to entity edit form\n\n```php\n\u003c?= \\nullref\\eav\\widgets\\Attributes::widget([\n    'form' =\u003e $form,\n    'model' =\u003e $model,\n]) ?\u003e\n```\n\nIf you need some dynamic configuration sets of your model you can use method `afterFind()`:\n\n```php\npublic function afterFind()\n{\n    $this-\u003eattachBehavior('eav', [\n        'class' =\u003e Entity::class,\n        'entity' =\u003e function () {\n            $setIds = $this-\u003egetCategories()-\u003eselect('set_id')-\u003ecolumn();\n            $setIds[] = Set::findOne(['code' =\u003e 'product'])-\u003eid;\n            return new EntityModel([\n                'sets' =\u003e Set::findAll(['id' =\u003e array_unique($setIds)]),\n            ]);\n        },\n    ]);\n    parent::afterFind();\n}\n```\n\nIn above example we have many-to-many relation product model with category which has set_id column.\n\nPay attention that this example could caused n+1 query problem. To prevent this problem use query caching or memoization.\nFor example, change:\n```php\n\\nullref\\eav\\models\\attribute\\Set::findOne(['code' =\u003e 'product']),\n```\nto\n```php\n\\nullref\\useful\\helpers\\Memoize::call([Set::class, 'findOne'],[['code' =\u003e 'product']]),\n```\n\nUsing in search model \n---------------------\n\nIf you need filtering your records by eav fields you need to modify `YourModelSearch::search()` method by following code:\n\n```php\n    //...\n    if (!$this-\u003evalidate()) {\n        return $dataProvider;\n    }\n    //...\n    foreach ($this-\u003eeav-\u003egetAttributes() as $key =\u003e $value) {\n\n        $valueModel = $this-\u003eeav-\u003egetAttributeModel($key)-\u003ecreateValue();\n\n        $valueModel-\u003esetScenario('search');\n        $valueModel-\u003eload(['value' =\u003e $value], '');\n        if ($valueModel-\u003evalidate(['value'])) {\n            $valueModel-\u003eaddJoin($query, self::tableName());\n            $valueModel-\u003eaddWhere($query);\n        }\n    }\n    //...\n    return $dataProvider;\n```\n\nTo output columns in gridview use `nullref\\eav\\helpers\\Grid::getGridColumns()`:\n\n```php\n\u003c?= GridView::widget([\n    'dataProvider' =\u003e $dataProvider,\n    'filterModel' =\u003e $searchModel,\n    'columns' =\u003e array_merge([\n    //... \n        'name',\n    ], \\nullref\\eav\\helpers\\Grid::getGridColumns($searchModel), [\n    //... \n        [\n            'class' =\u003e 'yii\\grid\\ActionColumn',\n        ],\n    ]),\n]); ?\u003e\n```\n\nTo configure which columns will be shown in grid go to attribute update page and select \"Show on grid\" checkbox.\n\n\nCustomization\n-------------\n\nTo add custom types you need to use type `\\nullref\\eav\\components\\TypesManager`.\nTo get more details please check `\\nullref\\eav\\Bootstrap::setupManager` as example of configuring base types.\n\nYou could call `\\nullref\\eav\\components\\TypesManager::registerType` at bootstrap phase and define you own types of attributes.\n\nMethod `registerType` takes one argument by type `\\nullref\\eav\\models\\Type` this class contains all info about particular type:\n\n- name (unique string)\n- label\n- value model class (based on `\\nullref\\eav\\widgets\\AttributeInput`)\n- form input class (based on `\\nullref\\eav\\models\\Value`)\n\n```php\nTypesManager::get()-\u003eregisterType(new Type(\n    Types::TYPE_IMAGE, \n    Yii::t('eav', 'Image'), \n    JsonValue::class, \n    ImageInput::class)\n);\n```\n\nFiltering attributes\n--------------------\n\nIf you need filter EAV attributes you could use `filterAttributes` and pass callable there:\n```php\n\n'eav' =\u003e [\n    'class' =\u003e Entity::class,\n    'entity' =\u003e function () {\n        return new EntityModel([\n            'sets' =\u003e [\n                Memoize::call([Set::class, 'findOne'], [['code' =\u003e 'product']]),\n            ],\n            'filterAttributes' =\u003e function ($attributes) {\n                $fieldCheckerService = Yii::$container-\u003eget(CheckerService::class);\n                $result = [];\n                foreach ($attributes as $code =\u003e $attr) {\n                    if ($fieldCheckerService-\u003eisAllowedForClass(self::class, $code)) {\n                        $result[$code] = $attr;\n                    }\n                }\n                return $result;\n            }\n        ]);\n    },\n],\n```\n\nTranslations\n------------\n\nAnd [translations](https://github.com/NullRefExcep/yii2-core#translation-overriding)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnullrefexcep%2Fyii2-eav","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnullrefexcep%2Fyii2-eav","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnullrefexcep%2Fyii2-eav/lists"}