nullref/yii2-eav

安装: 80

依赖: 0

建议者: 0

安全: 0

星标: 6

关注者: 4

分支: 3

开放问题: 3

类型:yii2-extension

dev-master 2021-10-16 00:03 UTC

This package is auto-updated.

Last update: 2024-09-16 06:38:02 UTC


README

Latest Stable Version Total Downloads Latest Unstable Version License

工作进度中

EAV (实体属性值) 反模式模块

安装

安装此扩展的首选方法是通过 composer

运行以下命令之一

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

或者

"nullref/yii2-eav": "*"

将以下内容添加到您的 composer.json 文件的 require 部分。

然后,运行控制台命令安装此模块并运行迁移

php yii module/install nullref/yii2-eav

请注意,如果您不使用我们的 应用程序模板,则需要更改配置文件结构以运行上述命令。

请查看此 文档部分

设置

向目标模型添加行为

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
                        ],
                    ]);
                },
            ],
        ];
    }
    //...
}

在管理面板中为它创建集合和属性

将属性小部件添加到实体编辑表单中

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

如果您需要模型的一些动态配置集,可以使用 afterFind() 方法

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();
}

在上面的示例中,我们有一个与具有 set_id 列的分类的多对多关系的商品模型。

请注意,此示例可能会导致 n+1 查询问题。为防止此问题,请使用查询缓存或记忆化。例如,将以下内容更改:

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

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

在搜索模型中使用

如果您需要通过 EAV 字段过滤记录,您需要修改 YourModelSearch::search() 方法,如下所示

    //...
    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;

要输出 gridview 中的列,请使用 nullref\eav\helpers\Grid::getGridColumns()

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

要配置要在网格中显示的列,请转到属性更新页面并选中 "在网格中显示" 复选框。

自定义

要添加自定义类型,您需要使用 \nullref\eav\components\TypesManager 类型。有关更多详细信息,请检查 \nullref\eav\Bootstrap::setupManager,它用作配置基本类型的示例。

您可以在引导阶段调用 \nullref\eav\components\TypesManager::registerType 并定义您自己的属性类型。

registerType 方法接受一个类型为 \nullref\eav\models\Type 的参数,该类包含有关特定类型的所有信息

  • 名称(唯一的字符串)
  • 标签
  • 值模型类(基于 \nullref\eav\widgets\AttributeInput
  • 表单输入类(基于 \nullref\eav\models\Value
TypesManager::get()->registerType(new Type(
    Types::TYPE_IMAGE, 
    Yii::t('eav', 'Image'), 
    JsonValue::class, 
    ImageInput::class)
);

过滤属性

如果您需要过滤 EAV 属性,您可以使用 filterAttributes 并将可调用的函数传递给它

'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;
            }
        ]);
    },
],

翻译

以及 翻译