arogachev / yii2-many-to-many
为 Yii 2 框架提供的多对多 ActiveRecord 关系
Requires
- yiisoft/yii2: >=2.0.14
Requires (Dev)
- phpunit/dbunit: ~1.4
- phpunit/phpunit: ~5.2
This package is not auto-updated.
Last update: 2024-09-19 14:06:34 UTC
README
实现 Yii 2 框架的多对多关系。
安装
安装此扩展的首选方式是通过 composer。
运行以下命令之一:
php composer.phar require --prefer-dist arogachev/yii2-many-to-many
或添加
"arogachev/yii2-many-to-many": "0.2.*"
到您的 composer.json
文件的 require 部分中。
功能
- 使用现有的
hasMany
关系配置 - 多个关系
- 无需额外查询。例如,如果最初模型有 100 个相关记录,添加一个后,恰好插入一行。如果没有变化,则不会执行查询。
- 自动填充可编辑属性
- 用于检查接收到的列表是否有效的验证器
创建可编辑属性
只需在您的 ActiveRecord
模型中添加公共属性即可,例如
/** * @var array */ public $editableUsers = [];
它将存储更新期间相关记录的主键。
附加和配置行为
第一种方法是显式指定所有参数
use arogachev\ManyToMany\behaviors\ManyToManyBehavior; /** * @inheritdoc */ public function behaviors() { return [ [ 'class' => ManyToManyBehavior::className(), 'relations' => [ [ 'editableAttribute' => 'editableUsers', // Editable attribute name 'table' => 'tests_to_users', // Name of the junction table 'ownAttribute' => 'test_id', // Name of the column in junction table that represents current model 'relatedModel' => User::className(), // Related model class 'relatedAttribute' => 'user_id', // Name of the column in junction table that represents related model ], ], ], ]; }
但更常见的是我们需要显示相关模型,因此最好为该模型定义关系,并用于显示和行为配置。两种方式(via
和 viaTable
)都认为是有效的
使用 viaTable
/** * @return \yii\db\ActiveQuery */ public function getUsers() { return $this->hasMany(User::className(), ['id' => 'user_id']) ->viaTable('tests_to_users', ['test_id' => 'id']) ->orderBy('name'); }
使用 via
(需要额外的模型来处理连接表)
/** * @return \yii\db\ActiveQuery */ public function getTestUsers() { return $this->hasMany(TestUser::className(), ['test_id' => 'id']); } /** * @return \yii\db\ActiveQuery */ public function getUsers() { return $this->hasMany(User::className(), ['id' => 'user_id']) ->via('testUsers') ->orderBy('name'); }
顺序不是必需的。
然后只需传递此关系的名称,所有其他参数将自动获取。
/** * @inheritdoc */ public function behaviors() { return [ [ 'class' => ManyToManyBehavior::className(), 'relations' => [ [ 'name' => 'users', // This is the same as in previous example 'editableAttribute' => 'editableUsers', ], ], ], ]; }
可以通过完全相同的方式添加额外的多对多关系。请注意,即使对于单个关系,也应将其声明为 relations
部分的一部分。
填充关系
默认情况下,每个找到的模型的 editableAttribute
将用相关模型 id 填充(使用预加载)。如果您想有更多的手动控制,防止额外的查询,禁用 autoFill
选项
'autoFill' => false,
并仅在需要时填充它,例如在控制器的 update
动作中。这是推荐的使用方式。
public function actionUpdate($id) { $model = $this->findModel($id); $model->getManyToManyRelation('users')->fill(); // ... }
或者您可以在闭包中指定填充条件
'autoFill' => function ($model) { return $model->scenario == Test::SCENARIO_UPDATE; // boolean value }
甚至可以这样做
'autoFill' => function ($model) { return Yii::$app->controller->route == 'tests/default/update'; }
但出于某种原因,这不建议使用,因为模型不是处理路由的合适位置。
在不进行大量赋值的情况下保存关系
在创建模型时
$model = new Test; $model->editableUsers = [1, 2]; $model->save();
在更新模型('autoFill' => true
)时
$model = new Test; $model->editableUsers = [1, 2]; $model->save();
在更新模型('autoFill' => false
,手动填充)时
$model = new Test; $model->getManyToManyRelation('users')->fill(); var_dump($model->editableUsers) // [1, 2] $model->editableUsers = [1, 2, 3]; $model->save();
在更新模型('autoFill' => false
,不手动填充)时
$model = new Test; var_dump($model->editableUsers) // empty array $model->save();
在这种情况下,多对多关系将保持不变。
将属性添加为安全
将可编辑属性添加到模型规则中,以进行大量赋值。
至少将其标记为安全
public function rules() { ['editableUsers', 'safe'], }
或使用自定义验证器
use arogachev\ManyToMany\validators\ManyToManyValidator; public function rules() { ['editableUsers', ManyToManyValidator::className()], }
验证器检查列表是否为数组,并且仅包含在相关模型中呈现的主键。它不能在没有附加 ManyToManyBehavior
的情况下使用。
将控件添加到视图
将控件添加到视图以管理相关列表。没有扩展,可以使用多选列表完成此操作
<?= $form->field($model, 'editableUsers')->dropDownList(User::getList(), ['multiple' => true]) ?>
示例 getList()
方法内容(需要放置在 User
模型中)
use yii\helpers\ArrayHelper; /** * @return array */ public static function getList() { $models = static::find()->orderBy('name')->all(); return ArrayHelper::map($models, 'id', 'name'); }
关系功能
您可以像这样访问多对多关系
$relation = $model->getManyToManyRelation('users');
users
可以是配置中指定的 name
或 table
关系属性之一的值。
您可以这样用相关记录的 id 填充 editableAttribute
$model->getManyToManyRelation('users')->fill();
您可以如此获取特定关系的相关模型的添加和删除主键。
$addedPrimaryKeys = $model->getManyToManyRelation('users')->getAddedPrimaryKeys(); $deletedPrimaryKeys = $model->getManyToManyRelation('users')->getDeletedPrimaryKeys();
注意,它们仅在模型保存后可用,因此您可以在调用$model->save()
后或afterSave()
事件处理器中访问它们。
运行测试
安装依赖项
composer install
添加数据库配置(tests/config/db-local.php
文件)如下内容
<?php return [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=yii2_many_to_many', 'username' => 'root', 'password' => '', ];
您可以按需更改dbname
、username
和password
。确保在运行测试之前创建数据库和用户。
运行测试
vendor/bin/phpunit