antonyz89 / yii2-many-to-many
Many-to-many ActiveRecord relation for Yii 2 framework. Created By Alexey Rogachev, forked by AntonyZ89
Installs: 1 254
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 3
Forks: 16
Type:yii2-extension
Requires
- yiisoft/yii2: ~2.0.15
Requires (Dev)
- phpunit/dbunit: ~4.0
- phpunit/phpunit: ~7.1
README
Implementation of Many-to-many relationship for Yii 2 framework.
Created by arogachev, forked by AntonyZ89
Installation
The preferred way to install this extension is through composer.
Either run
php composer.phar require --prefer-dist antonyz89/yii2-many-to-many
or add
"antonyz89/yii2-many-to-many": "0.3.*"
to the require section of your composer.json
file.
Features
- Configuring using existing
hasMany
relations - Multiple relations
- No extra queries. For example, if initially model has 100 related records, after adding just one, exactly one row will be inserted. If nothing was changed, no queries will be executed.
- Auto filling of editable attribute
- Validator for checking if the received list is valid
Creating editable attribute
Simply add public property to your ActiveRecord
model like this:
/** @var int[] */ public $editableRoles = [];
It will store primary keys of related records during update.
Attaching and configuring behavior
First way is to explicitly specify all parameters:
namespace common\models; use antonyz89\ManyToMany\behaviors\ManyToManyBehavior; class User extends ActiveRecord { /** @var int[] */ public $editableRoles = []; /** * @inheritdoc */ public function behaviors() { return [ [ 'class' => ManyToManyBehavior::class, 'autoFill' => true # default is true. If false, you should fill manually with $model->fill() method 'relations' => [ [ // Editable attribute name 'editableAttribute' => 'editableRoles', // Model of the junction table 'modelClass' => UserRole::class, // Name of the column in junction table that represents current model 'ownAttribute' => 'user_id', // Related model class 'relatedModel' => Role::class, // Name of the column in junction table that represents related model 'relatedAttribute' => 'role_id', ], ], ], ]; } }
Attribute validation
Add editable attribute to model rules for massive assignment.
public function rules() { ['editableRoles', 'required'], ['editableRoles', 'integer'], ['editableRoles', 'each', 'skipOnEmpty' => false, 'rule' => [ 'exist', 'skipOnError' => true, 'targetClass' => Role::class, 'targetAttribute' => ['editableRoles' => 'id'] ]], }
Or use custom validator:
use antonyz89\ManyToMany\validators\ManyToManyValidator; public function rules() { ['editableRoles', ManyToManyValidator::class], }
Validator checks list for being array and containing only primary keys presented in related model.
It can not be used without attaching ManyToManyBehavior
.
Adding control to view
Add control to view for managing related list. Without extensions it can be done with multiple select:
<?= $form->field($model, 'editableRoles')->dropDownList(Role::getList(), ['multiple' => true]) ?>
Example of getList()
method contents (it needs to be placed in User
model):
use yii\helpers\ArrayHelper; /** * @return array */ public static function getList() { $models = static::find()->orderBy('name')->asArray()->all(); return ArrayHelper::map($models, 'id', 'name'); }
Global Auto Fill
By default, all ManyToMany relations are auto filled after trigger ActiveRecord::EVENT_AFTER_FIND
event, but if you want disable this feature and fill relations manually:
// common\config\bootstrap.php use antonyz89\ManyToMany\behaviors\ManyToManyBehavior; ManyToManyBehavior::$enableAutoFill = false;
And set autoFill
as true
on behaviors when you want enable auto fill on specific model
/** * @inheritdoc */ public function behaviors() { return [ [ 'class' => ManyToManyBehavior::class, 'autoFill' => true # default is true. If false, you should fill manually with $model->fill() method 'relations' => [ // ... ], ], ]; }
If $enableAutoFill
and autoFill
are false
, you should call $model->fill()
to fill relations manually
<?php // example/_form.php /* @var $this View */ /* @var $model Example */ // fill relations before load the form $model->fill(); ?> <div class="example-form"> <!-- ... -->