yiiext / activerecord-relation-behavior
受到许多旨在提高相关记录保存功能的yii扩展的启发,整合了这些扩展的优秀之处。提供100%的测试覆盖率,代码结构良好且清晰,因此可以安全地在企业生产环境中使用。
Requires
- php: >=5.1.0
- yiisoft/yii: >=1.1.6
Requires (Dev)
- phpunit/php-invoker: *
- phpunit/phpunit: 4.0.*
This package is auto-updated.
Last update: 2024-09-05 18:28:27 UTC
README
此扩展受到所有旨在提高相关记录保存功能的yii扩展的启发。它允许您更轻松地分配相关记录,特别是对于MANY_MANY关系。它整合了以下提到的所有扩展的优秀之处(请参阅“功能比较”部分)。它提供100%的测试覆盖率,代码结构良好且清晰,因此可以安全地在企业生产环境中使用。
要求
- Yii 1.1.6或更高版本
- 与Yii框架一样,此行为与所有高于5.1.0版本的PHP兼容。我尽量保持与Yii相同的向后兼容性,即PHP 5.1.0。如果有任何与PHP版本相关的问题,请报告问题!
- 行为仅适用于具有主键定义的ActiveRecord类。确保在您的表没有定义主键时重写primaryKey()方法。
- 需要php 5.3.x或更高版本来运行单元测试。
如何安装
- 以下方式之一获取源代码
- 下载最新版本,并将其文件放置在应用程序根目录下的
extensions/yiiext/behaviors/activerecord-relation/
中。 - 通过调用
git submodule add https://github.com/yiiext/activerecord-relation-behavior.git extensions/yiiext/behaviors/activerecord-relation
将此存储库作为git子模块添加到您的存储库。
- 下载最新版本,并将其文件放置在应用程序根目录下的
- 通过将其添加到
behaviors()
方法中,将其添加到您想要使用的模型。
<?php public function behaviors() { return array( 'activerecord-relation'=>array( 'class'=>'ext.yiiext.behaviors.activerecord-relation.EActiveRecordRelationBehavior', ), ); }
魔法开始...
我们有两个ActiveRecord类(来自Yii definitive guide)
<?php class Post extends CActiveRecord { // ... public function relations() { return array( 'author' => array(self::BELONGS_TO, 'User', 'author_id'), 'categories' => array(self::MANY_MANY, 'Category', 'tbl_post_category(post_id, category_id)'), ); } } class User extends CActiveRecord { // ... public function relations() { return array( 'posts' => array(self::HAS_MANY, 'Post', 'author_id'), 'profile' => array(self::HAS_ONE, 'Profile', 'owner_id'), ); } }
在我们的应用程序代码的某个地方,我们可以这样做
<?php $user = new User(); $user->posts = array(1,2,3); $user->save(); // user is now author of posts 1,2,3 // this is equivalent to the last example: $user = new User(); $user->posts = Post::model()->findAllByPk(array(1,2,3)); $user->save(); // user is now author of posts 1,2,3 $user->posts = array_merge($user->posts, array(4)); $user->save(); // user is now also author of post 4 $user->posts = array(); $user->save(); // user is not related to any post anymore $post = Post::model()->findByPk(2); $post->author = User::model()->findByPk(1); $post->categories = array(2, Category::model()->findByPk(5)); $post->save(); // post 2 has now author 1 and belongs to categories 2 and 5 // adding a profile to a user: $user->profile = new Profile(); $user->profile->save(); // need this to ensure profile got a primary key $user->save();
你还可以...
启用/禁用/重置要保存的关系。为此,您可以使用
$model->withoutRelations('relation name 1', 'relation name 2',…)->save()
…将保存所有$model
关系,除了传递到作用域中的那些。
$model->withRelations('relation name 1', 'relation name 2',…)->save()
…将只保存传递到作用域中的$model
关系
$model->resetRelations()->save()
…将清除以前的范围,并保存$model
的所有关系
一些你应该关心的事情...
- 一旦你使用了这个行为,你不能再通过设置外键属性来设置关系了。例如,如果你设置
$model->author_id
,它将没有任何效果,因为ARRelationBehavior会在没有相关记录时将其覆盖为null,或者在设置相关记录的主键时将其设置为主键。相反,只需将值分配给关系本身:$model->author = 1;
/$model->author = null;
- 在保存后,关系不会被刷新,因此如果你只设置了主键,还没有对象。调用
$model->reload()
强制重新加载相关记录。或者,使用强制重新加载加载相关记录:$model->getRelated('relationName',true)
。 - 此行为仅适用于没有定义额外条件、连接、分组等的关系,因为设置和保存它们之后的预期结果并不总是明确的。
- 如果您将一条记录分配给了一个“属于”关系,例如
$post->author = $user;
,则不会自动更新$user->posts
(将来可能添加此功能)。
异常说明
"无法保存具有新相关记录的记录!"
您已将一条记录分配给了尚未保存的关系(它还没有在数据库中)。由于ActiveRecord关系行为需要主键才能将其保存到关系表中,这将不起作用。您必须在保存相关记录之前对所有新记录调用 ->save()
。
"HAS_MANY/MANY_MANY关系必须是记录数组的或主键!"
您只能将数组分配给HAS_MANY和MANY_MANY关系,无法将单个记录分配给_MANY关系。
"主键为“X”的相关记录不存在!"
您尝试将主键值 X 分配给一个关系,但 X 在您的数据库中不存在。
功能比较
受到以下yii扩展的启发,并整合了它们的强大功能
- 可以像cadvancedarbehavior、eadvancedarbehavior、esaverelatedbehavior和advancedrelationsbehavior一样保存MANY_MANY关系
- 当记录被删除时,会关心关系,类似于eadvancedarbehavior(尚未实现,请参阅github 问题 #7)
- 可以保存BELONGS_TO、HAS_MANY、HAS_ONE,类似于eadvancedarbehavior、esaverelatedbehavior和advancedrelationsbehavior
- 使用事务保存,并可以处理外部事务,类似于with-related-behavior、esaverelatedbehavior和saverbehavior
- 不接触MANY_MANY表中的其他数据(cadvancedarbehavior已删除)
- 对HAS_MANY和MANY_MANY关系上的数组进行验证,以获得更清晰的语义
上述是提到的这些扩展
- cadvancedarbehavior https://yiiframework.cn/extension/cadvancedarbehavior/
- eadvancedarbehavior https://yiiframework.cn/extension/eadvancedarbehavior
- advancedrelationsbehavior https://yiiframework.cn/extension/advancedrelationsbehavior
- saverbehavior https://yiiframework.cn/extension/saverbehavior
- with-related-behavior https://github.com/yiiext/with-related-behavior
- CSaveRelationsBehavior http://code.google.com/p/yii-save-relations-ar-behavior/
- esaverelatedbehavior https://yiiframework.cn/extension/esaverelatedbehavior
已审查但未做任何删除
- xrelationbehavior https://yiiframework.cn/extension/xrelationbehavior
- save-relations-ar-behavior https://yiiframework.cn/extension/save-relations-ar-behavior
非常感谢这些扩展的作者提供的灵感和想法。
运行单元测试
此行为由单元测试覆盖,代码覆盖率100%(由于复合主键尚未完全支持,ECompositeDbCriteria目前尚未覆盖)。要运行单元测试,您需要安装phpunit,并且测试类需要PHP 5.3或更高版本。
- 请确保yii框架位于./yii/framework下可用,您可以这样做:
- 使用
git clone https://github.com/yiisoft/yii.git yii
克隆yii git存储库 - 或通过
ln -s ../../path/to/yii yii
在此处链接现有的yii目录
- 使用
- 运行
phpunit EActiveRecordRelationBehaviorTest.php
,或者如果您想以HTML格式查看覆盖率信息,运行phpunit --coverage-html tmp/coverage EActiveRecordRelationBehaviorTest.php
常见问题解答
当使用多对多关系时,不对其进行任何修改并调用save()方法,是否会重新保存关系?
它使用CActiveRecord::hasRelated()
来检查关系是否已加载或设置,并且只有在这种情况才会保存。如果您加载但没有修改,它会重新保存,因为它无法检测到这一点。但是,重新保存并不意味着MANY_MANY表中的条目会被删除和重新插入。如果您没有修改记录,它将只执行一个不匹配任何行的删除查询,因此数据库中的任何行都不会受到影响。
是否可以只保存相关链接(n-m表记录)而不重新保存模型?
目前不可以,将来会添加这个功能:问题 #16。
如何从多对多关系中删除特定的ID?我需要为此加载所有相关记录吗?
目前您必须加载所有并重新分配数组。将添加一个API来实现这个功能;《问题 #16。