antonyz89/yii2-many-to-many

Many-to-many ActiveRecord relation for Yii 2 framework. Created By Alexey Rogachev, forked by AntonyZ89

Installs: 997

Dependents: 1

Suggesters: 0

Security: 0

Stars: 0

Watchers: 3

Forks: 16

Type:yii2-extension

0.3.6 2023-08-12 18:07 UTC

This package is auto-updated.

Last update: 2024-04-12 19:32:48 UTC


README

Implementation of Many-to-many relationship for Yii 2 framework.

Created by arogachev, forked by AntonyZ89

Latest Stable Version Total Downloads Latest Unstable Version License

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">
    <!-- ... -->