spinitron/yii2-dynamic-ar

扩展 Yii ActiveRecord 以支持 Maria Dynamic Columns

安装数: 5,441

依赖项: 0

建议者: 0

安全: 0

星标: 57

关注者: 18

分支: 15

类型:yii2-extension

0.3.3 2019-02-17 01:48 UTC

README

yii2-dynamic-ar 扩展为 Yii 2 框架Active Record ORM 添加了类似 NoSQL 的文档。

Maria Dynamic Columns 和 PostgreSQL jsonb

Maria 10.0+ 中的 Dynamic Columns 以及 PostgreSQL 9.4+ 中的 jsonb 列类型和 函数 实际上为 SQL 表的每一行附加了一个 NoSQL 文档。这是一个强大的功能,允许你做一些在关系型数据库中难以完成的事情。可能会让你转向 Couch 或 Mongo,或者在模式中实施类似 EAV 的犯罪,现在突然变得容易了。

  • 记录可以有任意数量的属性,
  • 属性名称可以即时生成,
  • 动态属性名称不会出现在模式中,
  • 动态属性可以像关联数组一样结构化。

Dynamic AR 目前适用于 Maria,未来将支持 PostgreSQL。

示例

一个在线购物网站有一个表格,用于存储关于每个产品的信息。

CREATE TABLE product (
    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    sku VARCHAR(32),
    upc VARCHAR(32),
    title VARCHAR(255),
    price DECIMAL(9, 2),
    stock INT(11),
    details LONGBLOB NOT NULL
);

在这个(简化的)示例中,details 将包含 Maria 的 Dynamic Column blob,并通过模型类中的 dynamicColumn() 方法声明。Dynamic AR 类声明中的其他内容都是熟悉的 AR 内容。

class Product extends \spinitron\dynamicAr\DynamicActiveRecord
{
    public static function tableName()
    {
        return 'product';
    }

    public static function dynamicColumn()
    {
        return 'details';
    }
}

现在我们可以使用 Product 做所有正常的 AR 事情,但除此之外,我们还可以读取、写入和更新方案中未提及的属性。

$product = new Product([
    'sku' => 5463,
    'upc' => '234569',
    'price' => 4.99,
    'title' => 'Clue-by-four',
    'description' => 'Used for larting lusers or constructing things',
    'dimensions' => [
        'unit' => 'inch',
        'width' => 4,
        'height' => 2,
        'length' => 20,
    ],
    'material' => 'wood',
]);
$product->save();

details 表列视为包含序列化的关联数组。但与在文本字段中保存 JSON 文档不同,你可以在代码的任何地方使用动态属性,包括在查询中,就像使用方案属性一样。区别在于

  • 嵌套属性使用点表示法,例如 dimensions.length
  • 在模型实例上直接获取和设置嵌套属性使用 getAttribute()setAttribute() 方法,因为 PHP 不允许在标识符中使用点表示法。
  • 当动态属性出现在查询中时,用感叹号括号 (! … !) 包围它,例如 (! dimensions.length !)。(属性名称与其感叹号括号之间的空格是可选的,因此 (!material!) 也是可以的。)

例如

$model = new Product([
    'title' => 'Car',
    'specs.fuel.tank.capacity' => 50,
    'specs.fuel.tank.capacity.unit' => 'liter',
]);
$model->setAttribute('specs.wheels.count', 4);
$model = Product::find()->where(['(!dimensions.length!)' => 10]);
$section = Product::find()
    ->select('CONCAT((! dimensions.width !), " x ", (! dimensions.height !))')
    ->where(['id' => 11])
    ->one();

点表示法可以在 Yii 接受属性名称字符串的地方使用,例如

class Product extends \spinitron\dynamicAr\DynamicActiveRecord
{
    public function rules()
    {
        return [['dimensions.length', 'double', 'min' => 0.0]];
    }

    public function search($params)
    {
        $dataProvider = new \yii\data\ActiveDataProvider([
            'sort' => [
                'attributes' => [
                    'dimensions.length' => [
                        'asc' => ['(! dimensions.length !)' => SORT_DESC],
                        'desc' => ['(! dimensions.length !)' => SORT_ASC],
                    ],
                ],
            ],
            // ...
        ]);
    }
}

设计原则

DynamicActiveRecord 将第四个功能添加到读取和写入 AR 模型属性可以做的事情中

  1. $model->foo 如果存在,则访问实例变量 $foo
  2. 否则它将访问列属性 foo,如果模型的表中存在列“foo”,
  3. 否则它将访问虚拟属性 foo,如果模型的类有魔法 getFoo() / setFoo() 方法,
  4. 否则 $model->foo 将访问一个名为“foo”的动态属性。

所以任何不指向正常三种AR模型属性(实例变量、列属性、虚拟属性)之一的属性名,一旦使用,就自动成为动态属性。无法声明动态属性,只能通过写入来定义。

读取不存在的属性将返回null。

PHP null,SQL NULL 和 Maria

Maria不会对设置为SQL NULL的动态列进行编码

SELECT COLUMN_CREATE('a', 1, 'b', null) = COLUMN_CREATE('a', 1)
>> 1

因此,如果一个表记录当前有一个名为'b'的动态列,而Maria执行更新将其设置为NULL,那么Maria将从记录中删除'b'。(如果NULL具有数据库中传统意义上的“数据值不存在”,则这有意义。)因此,DynamicActiveRecord在从数据库读取回后不可能区分NULL值和不存在于动态列。

为了保持一致性,DynamicActiveRecord在读取尚未设置的动态属性时始终返回null,而ActiveRecord会抛出异常。但根据设计原则(如上所述),如果null表示“不存在”,则这也有道理。

进一步阅读

类参考

更多文档

有用的链接

在gh-pages分支中重新生成文档

vendor/bin/apidoc api . . --template="spinitron\dynamicAr\doc\template\ApiRenderer"

问题、评论、问题

使用问题跟踪器。或者如果您更喜欢,可以轻松找到我的电子邮件。

版权(c)2015 Spinitron LLC