Skip to content

Commit d553f56

Browse files
committed
0.1.0 release
0 parents  commit d553f56

14 files changed

+1867
-0
lines changed

LICENSE.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Yii 2 Sortable extension for Yii 2 framework is free software.
2+
It is released under the terms of the following BSD License.
3+
4+
Copyright © 2015, Alexey Rogachev (https://github.com/arogachev)
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions are met:
9+
10+
* Redistributions of source code must retain the above copyright notice, this
11+
list of conditions and the following disclaimer.
12+
13+
* Redistributions in binary form must reproduce the above copyright notice,
14+
this list of conditions and the following disclaimer in the documentation
15+
and/or other materials provided with the distribution.
16+
17+
* Neither the name of test nor the names of its
18+
contributors may be used to endorse or promote products derived from
19+
this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
# Yii 2 Sortable
2+
3+
Sortable ActiveRecord for Yii 2 framework
4+
5+
- [Installation](#installation)
6+
- [Features](#features)
7+
- [Behaviors types](#behaviors-types)
8+
- [Preparing table structure](#preparing-table-structure)
9+
- [Attaching behavior](#attaching-behavior)
10+
- [Configuring behavior](#configuring-behavior)
11+
- [Changing order of models inside sortable scope](#changing-order-of-models-inside-sortable-scope)
12+
- [GUI for changing order](#gui-for-changing-order)
13+
- [Custom GUI for changing order](#custom-gui-for-changing-order)
14+
15+
## Installation
16+
17+
The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
18+
19+
Either run
20+
21+
```
22+
php composer.phar require --prefer-dist arogachev/yii2-sortable
23+
```
24+
25+
or add
26+
27+
```
28+
"arogachev/yii2-sortable": "*"
29+
```
30+
31+
to the require section of your `composer.json` file.
32+
33+
## Features
34+
35+
- Several implemented algorithms. Choose one to fit your needs.
36+
- Setting of sortable scope. In this case the order of models in each scope is managed separately.
37+
- Additional setting of sortable condition. For example, if the model can be marked as active or deleted,
38+
you can additionally specify that condition and it will be considered when changing these attributes values.
39+
- Order auto adjustment when adding new model, removing out of sortable scope,
40+
moving between the sortable scopes.
41+
- Changing order of models inside sortable scope.
42+
- GUI for managing order of models in `GridView` (`SortableColumn`).
43+
- Sort controller for simplifying writing of own GUI
44+
45+
## Behaviors types
46+
47+
There are several behaviors to choose from:
48+
49+
- `ContinuousNumericalSortableBehavior`
50+
- `IntervalNumericalSortableBehavior`
51+
- `LinkedListSortableBehavior` (currently not implemented)
52+
53+
The first two are numerical behaviors and they have one thing in common - they store position of each model as number.
54+
55+
`ContinuousNumericalSortableBehavior`:
56+
57+
Stored number is equal to exact position.
58+
59+
**Advantages:**
60+
61+
- You can get current position without additional queries
62+
63+
**Disadvantages:**
64+
65+
- Amount of `UPDATE` queries can be large depending on amount of sortable models and situation.
66+
It relates to adjustment order. For example no extra queries will be performed in case of switching models
67+
with 3 and 4 position (only 2 `UPDATE` queries). But if you have 1000 models and you move the last model
68+
to the very beginning there will be 1000 `UPDATE` queries (so it depends on interval length).
69+
70+
`IntervalNumericalSortableBehavior`:
71+
72+
The numbers are stored with certain intervals (initially with equal size).
73+
You can see the basic description of the used algorithm [here](http://stackoverflow.com/questions/6804166/what-is-the-most-efficient-way-to-store-a-sort-order-on-a-group-of-records-in-a/6804302#6804302).
74+
75+
**Advantages:**
76+
77+
- For adding or deletion there is no need to adjust order of other models. And for changing order for most of the times
78+
only few `SELECT` and one `UPDATE` query will be executed.
79+
The full adjustment of order of all models inside of sortable scope is only required in case of conflict.
80+
The conflicts don't happen often if you set interval size big enough
81+
and don't move models to the same position over and over again.
82+
83+
**Disadvantages:**
84+
85+
- For getting positions of models extra query is used.
86+
87+
### Preparing table structure
88+
89+
In case of using numerical behaviors add this to migration:
90+
91+
```php
92+
$this->addColumn('table_name', 'sort', Schema::TYPE_INTEGER . ' NOT NULL');
93+
```
94+
95+
## Attaching behavior
96+
97+
Add this to your model for minimal setup:
98+
99+
```php
100+
use arogachev\sortable\behaviors\numerical\ContinuousNumericalSortableBehavior;
101+
```
102+
103+
```php
104+
/**
105+
* @inheritdoc
106+
*/
107+
public function behaviors()
108+
{
109+
return [
110+
[
111+
'class' => ContinuousNumericalSortableBehavior::className(),
112+
],
113+
];
114+
}
115+
```
116+
117+
### Configuring behavior
118+
119+
**Common properties for all behaviors:**
120+
121+
`scope` - sortable scope. Specify it if you want to separate models by condition
122+
and manage order independently in each one. It expects closure returning `ActiveQuery`, but `where` part must be
123+
specified as array only. Example:
124+
125+
```php
126+
function () {
127+
return Question::find()->where(['test_id' => $this->test_id]);
128+
}
129+
```
130+
131+
If this property is not set, all models considered as one sortable scope.
132+
133+
`sortableCondition` - additional property to filter sortable models. You should specify it as conditional array:
134+
135+
```php
136+
[
137+
'is_active' => 1,
138+
'is_deleted' => 0,
139+
],
140+
```
141+
142+
`prependAdded` - insert added sortable model to the beginning of sortable scope. Defaults to `false` which means
143+
inserting to the end.
144+
145+
`access` - closure for checking access to sort for current user. Example:
146+
147+
```php
148+
function () {
149+
return Yii::$app->user->can('questions.sort');
150+
}
151+
```
152+
153+
**Numerical behaviors properties:**
154+
155+
`sortAttribute` - name of the sort attribute column. Defaults to `sort`.
156+
157+
**`IntervalNumericalSortableBehavior` properties:**
158+
159+
`intervalSize` - size of the interval. Defaults to `1000`. When specifying bigger numbers,
160+
conflicts will happen less often.
161+
162+
`increasingLimit` - the number of times user can continuously move item to the end of the sortable scope.
163+
Used to prevent increasing of numbers. Defaults to `10`.
164+
165+
## Changing order of models inside sortable scope
166+
167+
The behavior provides few methods to change any sortable model order:
168+
169+
- `moveToPosition($position)` - basic method for moving model to any position inside sortable scope
170+
- `moveBefore($pk = null)` - move model before another model of this sortable scope.
171+
If `$pk` is not specified it will be moved to the very end
172+
- `moveAfter($pk = null)` - move model after another model of this sortable scope
173+
If `$pk` is not specified it will be moved to the very beginning
174+
- `moveBack()` - move back by one position
175+
- `moveForward()` - move forward by one position
176+
- `moveAsFirst()` - move to the very beginning
177+
- `moveAsLast()` - move to the very end
178+
179+
## GUI for changing order
180+
181+
There is special `SortableColumn` for `GridView`.
182+
183+
**Features:**
184+
185+
- It doesn't force you to use the whole another `GridView`
186+
- No need to attach additional actions every time
187+
- Multiple `GridView` on one page support
188+
- Displaying current position
189+
- Inline editing of current position
190+
- Moving with drag and drop (with `jQuery UI Sortable`) with special handle icon,
191+
so you can interact with other data without triggering sort change
192+
- Moving back and forward by one position
193+
- Moving as first and last
194+
195+
Include once this to your application config:
196+
197+
```php
198+
'controllerMap' => [
199+
'sort' => [
200+
'class' => 'arogachev\sortable\controllers\SortController',
201+
],
202+
],
203+
```
204+
205+
Then configure `GridView`:
206+
207+
- Wrap it with `Pjax` widget for working without page reload
208+
- Add `id` for unchangeable root container
209+
- Include column in `columns` section
210+
211+
```php
212+
use arogachev\grid\SortableColumn;
213+
```
214+
215+
```php
216+
<div class="question-index" id="question-sortable">
217+
<?php Pjax::begin(); ?>
218+
219+
<?= GridView::widget([
220+
// Other configuration
221+
'columns' => [
222+
[
223+
'class' => SortableColumn::className(),
224+
'gridContainerId' => 'question-sortable',
225+
],
226+
// Other columns
227+
],
228+
]) ?>
229+
230+
<?php Pjax::end(); ?>
231+
</div>
232+
```
233+
234+
You can configure display through `template` and `buttons` properties (similar to [ActionColumn](http://www.yiiframework.com/doc-2.0/yii-grid-actioncolumn.html)).
235+
236+
The available tags are:
237+
238+
- `currentPosition`
239+
- `moveWithDragAndDrop`
240+
- `moveForward`
241+
- `moveBack`
242+
- `moveAsFirst`
243+
- `moveAsLast`
244+
245+
You can extend it with your own. Example of overriding:
246+
247+
```php
248+
'template' => '<div class="sortable-section">{moveWithDragAndDrop}</div>
249+
<div class="sortable-section">{currentPosition}</div>
250+
<div class="sortable-section">{moveForward} {moveBack}</div>',
251+
'buttons' => [
252+
'moveForward' => function () {
253+
return Html::tag('i', '', [
254+
'class' => 'fa fa-arrow-circle-left',
255+
'title' => Yii::t('sortable', 'Move forward'),
256+
]);
257+
},
258+
'moveBack' => function () {
259+
return Html::tag('i', '', [
260+
'class' => 'fa fa-arrow-circle-right',
261+
'title' => Yii::t('sortable', 'Move back'),
262+
]);
263+
},
264+
],
265+
```
266+
267+
## Custom GUI for changing order
268+
269+
If you want to write your own GUI for changing order without using `GridView`, you can use the `SortController` actions:
270+
271+
- `move-before` (requires `pk` of the next element after move sent via `POST`)
272+
- `move-after` (requires `pk` of the previous element after move sent via `POST`)
273+
- `move-back`
274+
- `move-forward`
275+
- `move-as-first`
276+
- `move-as-last`
277+
- `move-to-position` (requires `position` sent via `POST`)
278+
279+
For all of the actions these two parameters must exist in `POST`:
280+
281+
- `modelClass` - model full class name with namespace
282+
- `modelPk` - moved model primary key value (pass object in case of primary keys)

assets/SortableColumnAsset.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace arogachev\sortable\assets;
4+
5+
use yii\web\AssetBundle;
6+
7+
class SortableColumnAsset extends AssetBundle
8+
{
9+
/**
10+
* @inheritdoc
11+
*/
12+
public $sourcePath = '@vendor/arogachev/yii2-sortable/assets/src';
13+
14+
/**
15+
* @inheritdoc
16+
*/
17+
public $publishOptions = [
18+
'forceCopy' => YII_DEBUG,
19+
];
20+
21+
/**
22+
* @inheritdoc
23+
*/
24+
public $css = [
25+
'css/sortable-column.css',
26+
];
27+
28+
/**
29+
* @inheritdoc
30+
*/
31+
public $js = [
32+
'js/sortable-column.js',
33+
];
34+
35+
/**
36+
* @inheritdoc
37+
*/
38+
public $depends = [
39+
'yii\jui\JuiAsset',
40+
];
41+
}

assets/src/css/sortable-column.css

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.sortable-cell {
2+
min-width: 60px;
3+
}
4+
5+
.sortable-section {
6+
text-align: center;
7+
}
8+
9+
.sortable-section:not(:first-child) {
10+
margin: 5px 0 0 0;
11+
}
12+
13+
.sortable-section .label:empty {
14+
display: inline;
15+
}
16+
17+
.sortable-section .glyphicon {
18+
cursor: pointer;
19+
}
20+
21+
.sortable-section .glyphicon-sort {
22+
cursor: move;
23+
}
24+
25+
.sortable-section .glyphicon-fast-forward {
26+
margin: 0 0 0 5px;
27+
}

0 commit comments

Comments
 (0)