la-haute-societe/yii2-save-relations-behavior

此软件包已弃用且不再维护。没有建议替代包。

自动验证并保存相关 Active Record 模型。

安装次数: 400 109

依赖项: 18

建议者: 0

安全: 0

星标: 134

关注者: 11

分支: 30

开放问题: 18

类型:yii2-extension

1.7.2 2019-06-22 13:36 UTC

This package is auto-updated.

Last update: 2022-07-19 20:31:43 UTC


README

自动验证和保存相关 Active Record 模型。

Latest Stable Version Total Downloads Code Coverage Build Status Latest Unstable Version License

功能

  • 支持 hasMany()hasOne() 关系
  • 与现有以及新相关模型一起工作
  • 支持复合主键
  • 仅使用纯 Active Record API,因此它应与任何数据库驱动程序一起工作
  • 从 1.5.0 版本开始,现在可以与主模型一起删除相关记录
  • ⚠️ 从 2.0.0 版本开始,关系属性现在遵守 safe 验证规则

安装

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

运行以下命令之一:

php composer.phar require --prefer-dist la-haute-societe/yii2-save-relations-behavior "*"

"la-haute-societe/yii2-save-relations-behavior": "*"

将其添加到您的 composer.json 文件的 require 部分。

配置

按如下方式配置模型

use lhs\Yii2SaveRelationsBehavior\SaveRelationsBehavior;

class Project extends \yii\db\ActiveRecord
{
    use SaveRelationsTrait; // Optional

    public function behaviors()
    {
        return [
            'timestamp'     => TimestampBehavior::className(),
            'blameable'     => BlameableBehavior::className(),
            ...
            'saveRelations' => [
                'class'     => SaveRelationsBehavior::className(),
                'relations' => [
                    'company',
                    'users',
                    'projectLinks' => ['cascadeDelete' => true],
                    'tags'  => [
                        'extraColumns' => function ($model) {
                            /** @var $model Tag */
                            return [
                                'order' => $model->order
                            ];
                        }
                    ]
                ],
            ],
        ];
    }

    public function rules()
    {
        return [
            [['name', 'company_id'], 'required'],
            [['name'], 'unique', 'targetAttribute' => ['company_id', 'name']],
            [['company', 'users', 'projectLinks', 'tags'], 'safe']
        ];
    }

    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => self::OP_ALL,
        ];
    }

    ...


    /**
     * @return ActiveQuery
     */
    public function getCompany()
    {
        return $this->hasOne(Company::className(), ['id' => 'company_id']);
    }

    /**
     * @return ActiveQuery
     */
    public function getProjectUsers()
    {
        return $this->hasMany(ProjectUser::className(), ['project_id' => 'id']);
    }

    /**
     * @return ActiveQuery
     */
    public function getUsers()
    {
        return $this->hasMany(User::className(), ['id' => 'user_id'])->via('ProjectUsers');
    }

    /**
     * @return ActiveQuery
     */
    public function getProjectLinks()
    {
        return $this->hasMany(ProjectLink::className(), ['project_id' => 'id']);
    }

    /**
     * @return ActiveQuery
     */
    public function getTags()
    {
        return $this->hasMany(Tag::className(), ['id' => 'tag_id'])->viaTable('ProjectTags', ['project_id' => 'id']);
    }
}

虽然不是必需的,但强烈建议激活拥有者模型的交易。⚠️ 为了保存,关系属性必须在拥有者模型验证规则中定义为 safe

使用

现在可以按照以下方式设置和保存声明在 relations 行为参数中的每个关系

$project = new Project();
$project->name = "New project";
$project->company = Company::findOne(2);
$project->users = User::findAll([1,3]);
$project->save();

您可以通过仅指定其主键来设置相关模型

$project = new Project();
$project->name = "Another project";
$project->company = 2;
$project->users = [1,3];
$project->save();

您甚至可以将相关模型设置为如下这样的关联数组

$project = Project::findOne(1);
$project->company = ['name' => 'GiHub', 'description' => 'Awesome']; // Will create a new company record
// $project->company = ['id' => 3, 'name' => 'GiHub', 'description' => 'Awesome']; // Will update an existing company record
$project->save();

将使用 `load()` 方法大量分配相关模型的属性。因此,请记住在相关模型的规则中声明相应的属性为 safe。

注意: 只有新创建或更改的相关模型将被保存。请参阅 PHPUnit 测试以获取更多示例。

在多对多关系中填充额外的连接表列

在涉及连接表的许多多关系的情况下,可以保存每个模型的额外列值到连接表。有关示例,请参阅配置部分。

注意: 如果为关系配置了连接表属性,则每次保存时都会删除与连接表中相关模型关联的行并重新插入,以确保保存连接表属性更改。

验证

在保存之前将对每个声明相关模型进行验证。如果任何验证失败,对于每个出错的关联模型属性,将向拥有者模型添加与命名关系关联的错误。

对于 hasMany() 关系,将使用相关模型的索引来标识关联的错误消息。

可以声明一个关联数组来指定每个关系的验证场景,其中必须包含 scenario 键所需的场景值。例如,在以下配置中,将使用 Link::SOME_SCENARIO 场景验证 links 相关记录

...
    public function behaviors()
    {
        return [
            'saveRelations' => [
                'class'     => SaveRelationsBehavior::className(),
                'relations' => ['company', 'users', 'links' => ['scenario' => Link::SOME_SCENARIO]]
            ],
        ];
    }
...

还可以在运行时使用setRelationScenario设置关系场景,如下所示:

$model->setRelationScenario('relationName', 'scenarioName');

提示:对于不涉及连接表的关联,使用via()viaTable()方法时,应从‘必需’验证规则中删除指向拥有者模型的属性,以便能够通过验证。

注意:如果在保存相关记录的afterSave事件过程中发生任何错误,将抛出第一个发生的错误上的yii\db\Exception。错误信息将附加到拥有者模型的关系属性上。为了能够以用户友好的方式处理这些情况,必须捕获yii\db\Exception异常。

当主模型被删除时删除相关记录

对于没有内置关系约束的DBMs,从1.5.0版本开始,现在可以指定在删除主模型时一起删除的关系。

为此,应将关系声明为具有将cascadeDelete属性设置为true的属性。例如,当主模型将被删除时,相关的projectLinks记录将自动被删除。

...
'saveRelations' => [
    'class'     => SaveRelationsBehavior::className(),
    'relations' => [
        'projectLinks' => ['cascadeDelete' => true]
    ],
],
...

注意:将删除定义在它们的ActiveQuery语句中与主模型相关的所有记录。

使用输入数据填充模型及其关系

此行为添加了一个方便的方法,以加载关系模型的属性,就像load()方法一样。只需使用相应的输入数据调用loadRelations()即可。

例如

$project = Project::findOne(1);
/**
 * $_POST could be something like:
 * [
 *     'Company'     => [
 *         'name' => 'YiiSoft'
 *     ],
 *     'ProjectLink' => [
 *         [
 *             'language' => 'en',
 *             'name'     => 'yii',
 *             'link'     => 'https://yiiframework.cn'
 *         ],
 *         [
 *             'language' => 'fr',
 *             'name'     => 'yii',
 *             'link'     => 'http://www.yiiframework.fr'
 *         ]
 *     ]
 * ];
 */
$project->loadRelations(Yii::$app->request->post());

您还可以通过将SaveRelationsTrait添加到您的模型来进一步简化此过程。在这种情况下,调用load()方法将自动使用相同的数据触发对loadRelations()方法的调用,因此您基本上不需要更改您的控制器。

可以使用relationKeyName属性来决定如何从数据参数中检索关系数据。

可能的常量值是

  • SaveRelationsBehavior::RELATION_KEY_FORM_NAME(默认):键名将使用模型的formName()方法计算得出
  • SaveRelationsBehavior::RELATION_KEY_RELATION_NAME:使用在行为声明中定义的关系名称

获取旧关系值

要检索模型保存之前最近修改的关联值,可以使用以下方法:

  • getOldRelation($name):获取具有指定名称的旧关系值。
  • getOldRelations():获取一个数组,其中包含以名称索引的关联及其旧值。

注意

  • 如果关系尚未被修改,则将返回其初始值。
  • 仅返回在行为参数中定义的关联。

获取脏关系

要处理自模型加载以来已修改的脏(修改)关系,可以使用以下方法:

  • getDirtyRelations():获取自加载以来已修改的关联(键值对)。
  • markRelationDirty($name):即使关系尚未被修改,也将关系标记为脏。