dfware/ar-dynattribute

提供动态ActiveRecord属性,以序列化状态存储在单个字段中

资助包维护!
klimov-paul
Patreon

安装: 49

依赖: 0

建议者: 0

安全: 0

星标: 0

观察者: 0

分支: 12

开放问题: 0

类型:yii2-extension

1.0.0 2023-09-27 17:48 UTC

This package is auto-updated.

Last update: 2024-09-27 19:57:36 UTC


README

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

运行以下命令之一:

composer require dfware/ar-dynattribute

或添加

"dfware/ar-dynattribute": "*"

到您的composer.json文件的require部分。

用法

此扩展提供动态ActiveRecord属性,存储在单个字段中以序列化状态。例如:假设我们创建了一个网站,登录用户可以自定义其外观,如更改颜色方案或启用/禁用侧边栏等。为了使这种定制持久化,所有用户的选择都应该存储在数据库中。通常,每个视图设置都应该在'user'表中有一个自己的列。然而,在您的应用程序正在开发中且新设置快速出现的情况下,这不是很实际。因此,使用单个文本字段是有意义的,该字段将存储所有选择的视图参数的序列化字符串。如果引入了新选项,则无需更改'user'表的架构。创建'user'表的迁移可能看起来如下:

class m??????_??????_create_user extends \yii\db\Migration
{
    public function up()
    {
        $this->createTable('User', [
            'id' => $this->primaryKey(),
            'username' => $this->string()->notNull(),
            'email' => $this->string()->notNull(),
            'passwordHash' => $this->string()->notNull(),
            // ...
            'viewParams' => $this->text(), // field, which stores view parameters in serialized state
        ]);
    }

    public function down()
    {
        $this->dropTable('User');
    }
}

注意!总的来说,这种数据存储方法是一种 不良 实践,不建议使用。其主要缺点是在搜索查询中无法使用动态属性。它仅适用于直接设置和读取单个记录的属性,并且永远不会用于筛选查询。

提示:如果您正在使用具有内置JSON支持的现代数据库管理系统(例如MySQL >= 5.5或PostgreSQL),则可以将动态属性存储在'JSON'类型列中而不是纯文本,但是您必须自己处理可能出现的搜索条件组合 - 此扩展不提供对此的明确支持。

此扩展提供了支持动态属性的ActiveRecord行为 [[\yii2tech\ar\dynattribute\DynamicAttributeBehavior]]。例如

use yii\db\ActiveRecord;
use yii2tech\ar\dynattribute\DynamicAttributeBehavior;

class User extends ActiveRecord
{
    public function behaviors()
    {
        return [
            'dynamicAttribute' => [
                'class' => DynamicAttributeBehavior::className(),
                'storageAttribute' => 'viewParams', // field to store serialized attributes
                'dynamicAttributeDefaults' => [ // default values for the dynamic attributes
                    'bgColor' => 'green',
                    'showSidebar' => true,
                ],
            ],
        ];
    }

    public static function tableName()
    {
        return 'User';
    }

    // ...
}

一旦附加 [[\yii2tech\ar\dynattribute\DynamicAttributeBehavior]],它允许其所有者像常规属性一样操作动态属性。在模型保存时,它们将被序列化并存储在持有字段中。在从数据库中检索记录后,第一次尝试读取动态属性将反序列化它们并准备使用。例如

$model = new User();
// ...
$model->bgColor = 'red';
$model->showSidebar = false;
$model->save(); // 'bgColor' and 'showSidebar' are serialized and stored at 'viewParams'
echo $model->viewParams; // outputs: '{"bgColor": "red", "showSidebar": false}'

$refreshedModel = User::findOne($model->getPrimaryKey());
echo $refreshedModel->bgColor; // outputs 'red'
echo $refreshedModel->showSidebar; // outputs 'false'

您可以使用动态属性作为常规ActiveRecord属性。例如:您可以指定它们的验证规则,并通过网页表单获取它们的值。

注意:请记住,动态属性与ActiveRecord实体字段不对应,因此某些特定的ActiveRecord方法(如 updateAttributes())对它们不起作用。

默认值设置

如您从上述示例中注意到的,您可以通过 [[\yii2tech\ar\dynattribute\DynamicAttributeBehavior::$dynamicAttributeDefaults]] 提供动态属性的默认值。因此,一旦您需要为模型添加额外的动态属性,您只需更新相应的值,而无需对数据库执行任何更新。

class User extends ActiveRecord
{
    public function behaviors()
    {
        return [
            'dynamicAttribute' => [
                'class' => DynamicAttributeBehavior::className(),
                'storageAttribute' => 'viewParams',
                'dynamicAttributeDefaults' => [
                    'bgColor' => 'green',
                    'showSidebar' => true,
                    'fontColor' => 'black', // newly added attribute
                ],
            ],
        ];
    }

    // ...
}

$newModel = new User();
echo $newModel->bgColor; // outputs 'green'
echo $newModel->showSidebar; // outputs 'true'

$oldModel = User::find()->orderBy(['id' => SORT_ASC])->limit(1)->one();
echo $oldModel->viewParams; // outputs: '{"bgColor": "red", "showSidebar": false}'
echo $oldModel->fontColor; // outputs: 'black'

注意:您可以通过禁用 [[\yii2tech\ar\dynattribute\DynamicAttributeBehavior::$saveDynamicAttributeDefaults]] 选项来排除具有默认值的动态属性,从而禁用其保存。

限制动态属性列表

动态属性默认值设置不仅有用,而且在一般情况下是必要的。此列表对可能的动态属性名称施加了限制。只有指定了默认值的属性才能从模型中设置或读取。这可以防止由代码中的拼写错误引起的可能错误。例如

$newModel = new User();
$newModel->bgColor = 'blue'; // works fine
$newModel->unExistingAttribute = 10; // throws an exception!

然而,有时有必要存储无法预测的属性列表。例如,保存来自某些外部服务的响应字段。在这种情况下,您可以使用 [[\yii2tech\ar\dynattribute\DynamicAttributeBehavior::$allowRandomDynamicAttribute]] 禁用对属性设置器进行的检查。如果将其设置为 true,您将能够在 dynamicAttributeDefaults 中设置任何动态属性,无论它们是否已声明。

注意:您还可以使用 [[\yii2tech\ar\dynattribute\DynamicAttributeBehavior::setDynamicAttributes()]] 方法绕过命名限制。此方法将设置提供的所有属性而无需任何检查。

您还可以使用 [[\yii2tech\ar\dynattribute\DynamicAttributeBehavior::$dynamicAttributeSaveFilter]] 控制要实际保存的动态属性列表。如果设置为 true,它将排除任何不在 dynamicAttributeDefaults 选项中列出的属性。您还可以将其指定为 PHP 回调,该回调将执行一些自定义过滤。此选项允许您删除过去存在的但不再有效的旧动态属性。

序列化设置

默认情况下,[[\yii2tech\ar\dynattribute\DynamicAttributeBehavior]] 以 JSON 格式保存动态属性。但是,您可以通过 [[\yii2tech\ar\dynattribute\DynamicAttributeBehavior::$serializer]] 设置为它们设置另一个序列化程序。此扩展中可用以下序列化程序

  • [[\yii2tech\ar\dynattribute\JsonSerializer]] - 以 JSON 格式存储数据
  • [[\yii2tech\ar\dynattribute\PhpSerializer]] - 使用 PHP 的 serialize()/unserialize() 函数存储数据
  • [[\yii2tech\ar\dynattribute\CallbackSerializer]] - 通过自定义序列化 PHP 回调存储数据
  • [[\yii2tech\ar\dynattribute\JsonExpressionSerializer]] - 处理 [[yii\db\JsonExpression]] 实例,支持使用 'JSON' 数据库列类型。

请参阅特定序列化程序类以获取更多详细信息。