my6uot9 / yii2-dynamic-ar
扩展 Yii ActiveRecord 以支持 Maria 动态列
Requires
- ext-json: *
- ext-mbstring: *
- yiisoft/yii2: ~2.0
Requires (Dev)
- phpunit/phpunit: ^8.5 || ^9.2
- yidas/yii2-bower-asset: ~2.0.5
- yiisoft/yii2-coding-standards: ~2.0.2
- yiisoft/yii2-dev: ~2.0
This package is auto-updated.
Last update: 2024-09-29 05:29:20 UTC
README
这是 Tom Worster 版本的分支:Tom Worster's version.
yii2-dynamic-ar 扩展为 Yii 2 框架 的 Active Record ORM 添加了类似 NoSQL 的文档。
Maria 动态列和 PostgreSQL jsonb
在 Maria 10.0+ 和 jsonb 列类型 以及 函数 在 PostgreSQL 9.4+ 中提供了,实际上每个 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 的 动态列 blob,并在模型类中通过 dynamicColumn() 方法声明。Dynamic AR 类声明中的其他一切都是熟悉的 AR 内容。
class Product extends \my6uot9\dynamicAr\DynamicActiveRecord { public static function tableName() { return 'product'; } public static function dynamicColumn() : string { 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 \my6uot9\dynamicAr\DynamicActiveRecord { public function rules() { return [['dimensions.length', 'double', 'min' => 0.0]]; } public function search($params) { $dataProvider = new ActiveDataProvider([ 'sort' => [ 'attributes' => [ 'dimensions.length' => [ 'asc' => ['(! dimensions.length !)' => SORT_DESC], 'desc' => ['(! dimensions.length !)' => SORT_ASC], ], ], ], // ... ]); } public static function dynamicColumn() : string { return 'details'; } }
设计原则
DynamicActiveRecord 为读取和写入 AR 模型属性可以做的三件事情增加了第四件
$model->foo如果存在,将访问实例变量$foo,- 否则,如果模型的表中有列 "foo",则访问列属性
foo, - 否则,如果模型的类有魔法方法
getFoo()/setFoo(),则访问虚拟属性foo, - 否则
$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 相比。但这也符合设计原则(如上所述)。
进一步阅读
类参考
更多文档
- PHP、SQL 和 JSON 中的数据类型并不相同。
- 设计历史 – 项目原始的 README。
有用的链接
在 gh-pages 分支中重新生成文档
vendor/bin/apidoc api . . --template="spinitron\dynamicAr\doc\template\ApiRenderer"
问题、评论、问题
使用 问题跟踪器。
版权(c)2015 Spinitron LLC
版权 2021 My6UoT9