arogachev / yii2-sortable

Sortable ActiveRecord for Yii 2 framework
Other
17 stars 9 forks source link

Yii 2 Sortable

This extension allows to manage order of ActiveRecord models via different behaviors. Choose one to fit your needs.

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 arogachev/yii2-sortable

or add

"arogachev/yii2-sortable": "*"

to the require section of your composer.json file.

Features

Behaviors types

There are several behaviors to choose from:

The first two are numerical behaviors and they have one thing in common - they store position of each model as number.

ContinuousNumericalSortableBehavior:

Stored number is equal to exact position.

Advantages:

Disadvantages:

IntervalNumericalSortableBehavior:

The numbers are stored with certain intervals (initially with equal size). You can see the basic description of the used algorithm here.

Advantages:

Disadvantages:

Preparing table structure

In case of using numerical behaviors add this to migration:

$this->addColumn('table_name', 'sort', Schema::TYPE_INTEGER . ' NOT NULL');

Attaching behavior

Add this to your model for minimal setup:

use arogachev\sortable\behaviors\numerical\ContinuousNumericalSortableBehavior;
/**
 * @inheritdoc
 */
public function behaviors()
{
    return [
        [
            'class' => ContinuousNumericalSortableBehavior::className(),
        ],
    ];
}

Configuring behavior

Common properties for all behaviors:

scope - sortable scope. Specify it if you want to separate models by condition and manage order independently in each one. It expects closure returning ActiveQuery, but where part must be specified as array only. Example:

function () {
    return Question::find()->where(['test_id' => $this->test_id]);
}

You can use $model parameter to generate model related queries:

function ($model) {
    return $model->getNeighbors();
}

where getNeighbors() implementation can be like this:

/**
 * @return \yii\db\ActiveQuery
 */
public function getNeighbors()
{
    return static::find()->where(['parent_id' => $this->parent_id]);
}

If this property is not set, all models considered as one sortable scope.

sortableCondition - additional property to filter sortable models. You should specify it as conditional array:

[
    'is_active' => 1,
    'is_deleted' => 0,
],

prependAdded - insert added sortable model to the beginning of sortable scope. Defaults to false which means inserting to the end.

access - closure for checking access to sort for current user. Example:

function () {
    return Yii::$app->user->can('questions.sort');
}

Numerical behaviors properties:

sortAttribute - name of the sort attribute column. Defaults to sort.

IntervalNumericalSortableBehavior properties:

intervalSize - size of the interval. Defaults to 1000. When specifying bigger numbers, conflicts will happen less often.

increasingLimit - the number of times user can continuously move item to the end of the sortable scope. Used to prevent increasing of numbers. Defaults to 10.

Changing order of models inside sortable scope

The behavior provides few methods to change any sortable model order:

GUI for changing order

There is special SortableColumn for GridView.

Features:

Include once this to your application config:

'controllerMap' => [
    'sort' => [
        'class' => 'arogachev\sortable\controllers\SortController',
    ],
],

Then configure GridView:

use arogachev\sortable\grid\SortableColumn;
<div class="question-index" id="question-sortable">
    <?php Pjax::begin(); ?>

    <?= GridView::widget([
        // Other configuration
        'columns' => [
            [
                'class' => SortableColumn::className(),
                'gridContainerId' => 'question-sortable',
                'baseUrl' => '/sort/', // Optional, defaults to '/sort/'
                'confirmMove' => true, // Optional, defaults to true
            ],
            // Other columns
        ],
    ]) ?>

    <?php Pjax::end(); ?>
</div>

You can configure display through template and buttons properties (similar to ActionColumn).

The available tags are:

You can extend it with your own. Example of overriding:

'template' => '<div class="sortable-section">{moveWithDragAndDrop}</div>
<div class="sortable-section">{currentPosition}</div>
<div class="sortable-section">{moveForward} {moveBack}</div>',
'buttons' => [
    'moveForward' => function () {
        return Html::tag('i', '', [
            'class' => 'fa fa-arrow-circle-left',
            'title' => Yii::t('sortable', 'Move forward'),
        ]);
    },
    'moveBack' => function () {
        return Html::tag('i', '', [
            'class' => 'fa fa-arrow-circle-right',
            'title' => Yii::t('sortable', 'Move back'),
        ]);
    },
],

Custom GUI for changing order

If you want to write your own GUI for changing order without using GridView, you can use the SortController actions:

For all of the actions these two parameters must exist in POST: