yiiext/activerecord-relation-behavior

受到许多旨在提高相关记录保存功能的yii扩展的启发,整合了这些扩展的优秀之处。提供100%的测试覆盖率,代码结构良好且清晰,因此可以安全地在企业生产环境中使用。

安装: 34,461

依赖者: 0

建议者: 0

安全性: 0

星标: 92

关注者: 22

分支: 28

开放问题: 19

类型:yii-extension

1.1.3 2015-02-07 21:25 UTC

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或更高版本来运行单元测试。

如何安装

  1. 以下方式之一获取源代码
    • 下载最新版本,并将其文件放置在应用程序根目录下的extensions/yiiext/behaviors/activerecord-relation/中。
    • 通过调用git submodule add https://github.com/yiiext/activerecord-relation-behavior.git extensions/yiiext/behaviors/activerecord-relation将此存储库作为git子模块添加到您的存储库。
  2. 通过将其添加到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关系上的数组进行验证,以获得更清晰的语义

上述是提到的这些扩展

已审查但未做任何删除

非常感谢这些扩展的作者提供的灵感和想法。

运行单元测试

此行为由单元测试覆盖,代码覆盖率100%(由于复合主键尚未完全支持,ECompositeDbCriteria目前尚未覆盖)。要运行单元测试,您需要安装phpunit,并且测试类需要PHP 5.3或更高版本。

  1. 请确保yii框架位于./yii/framework下可用,您可以这样做:
    • 使用 git clone https://github.com/yiisoft/yii.git yii 克隆yii git存储库
    • 或通过 ln -s ../../path/to/yii yii 在此处链接现有的yii目录
  2. 运行 phpunit EActiveRecordRelationBehaviorTest.php,或者如果您想以HTML格式查看覆盖率信息,运行 phpunit --coverage-html tmp/coverage EActiveRecordRelationBehaviorTest.php

常见问题解答

当使用多对多关系时,不对其进行任何修改并调用save()方法,是否会重新保存关系?

它使用CActiveRecord::hasRelated()来检查关系是否已加载或设置,并且只有在这种情况才会保存。如果您加载但没有修改,它会重新保存,因为它无法检测到这一点。但是,重新保存并不意味着MANY_MANY表中的条目会被删除和重新插入。如果您没有修改记录,它将只执行一个不匹配任何行的删除查询,因此数据库中的任何行都不会受到影响。

是否可以只保存相关链接(n-m表记录)而不重新保存模型?

目前不可以,将来会添加这个功能:问题 #16

如何从多对多关系中删除特定的ID?我需要为此加载所有相关记录吗?

目前您必须加载所有并重新分配数组。将添加一个API来实现这个功能;《问题 #16