Trait luya\admin\traits\SortableTrait
Available since version | 1.0.0 |
---|---|
Source Code | https://github.com/luyadev/luya-module-admin/blob/master/src/traits/SortableTrait.php |
Sortable Trait provides orderBy clause and re-index when update, delete or create rows.
By default the field sortindex
is taken, change this by override the sortableField
method.
public static function sortableField()
{
return 'sortfield';
}
The SortableTrait is commonly used with the {{luya\admin\ngrest\plugins\Sortable}} Plugin. By default the {{luya\admin\ngrest\base\NgRestModel::ngRestListOrder}} is set to false which disables the ability to sort the GRID by the end-user.
Public Methods
Method | Description | Defined By |
---|---|---|
find() | Overrides the find() method of the ActiveRecord | luya\admin\traits\SortableTrait |
init() | luya\admin\traits\SortableTrait | |
ngRestFind() | Overrides the ngRestFind() method of the ActiveRecord | luya\admin\traits\SortableTrait |
ngRestListOrder() | Disable the list ordering. | luya\admin\traits\SortableTrait |
sortableField() | The field which should by used to sort. | luya\admin\traits\SortableTrait |
Protected Methods
Method | Description | Defined By |
---|---|---|
deleteItemIndex() | Update the index when deleting an item | luya\admin\traits\SortableTrait |
newItemIndex() | Update the index for a new item | luya\admin\traits\SortableTrait |
updateItemIndex() | Update the index for a given event. | luya\admin\traits\SortableTrait |
Method Details
Update the index when deleting an item
protected void deleteItemIndex ( yii\base\Event $event ) | ||
$event | yii\base\Event |
protected function deleteItemIndex(Event $event)
{
$transaction = Yii::$app->db->beginTransaction();
try {
$pkName = current($event->sender->primaryKey());
$this->reIndex($event, self::sortableField(), $pkName);
$transaction->commit();
} catch (\Exception|\Throwable $e) {
$transaction->rollBack();
throw $e;
}
}
Overrides the find() method of the ActiveRecord
public static yii\db\ActiveQuery find ( ) |
public static function find()
{
return parent::find()->orderBy([self::tableName().'.'.self::sortableField() => SORT_ASC]);
}
public void init ( ) |
public function init()
{
parent::init();
$this->on(NgRestModel::EVENT_AFTER_INSERT, [$this, 'newItemIndex']);
$this->on(NgRestModel::EVENT_AFTER_UPDATE, [$this, 'updateItemIndex']);
$this->on(NgRestModel::EVENT_AFTER_DELETE, [$this, 'deleteItemIndex']);
}
Update the index for a new item
protected void newItemIndex ( yii\db\AfterSaveEvent $event ) | ||
$event | yii\db\AfterSaveEvent |
protected function newItemIndex(AfterSaveEvent $event)
{
$this->updateItemIndex($event, true);
}
Overrides the ngRestFind() method of the ActiveRecord
public static yii\db\ActiveQuery ngRestFind ( ) |
public static function ngRestFind()
{
return parent::ngRestFind()->orderBy([self::tableName().'.'.self::sortableField() => SORT_ASC]);
}
Disable the list ordering.
public boolean ngRestListOrder ( ) |
public function ngRestListOrder()
{
return false;
}
The field which should by used to sort.
public static string sortableField ( ) |
public static function sortableField()
{
return 'sortindex';
}
Update the index for a given event.
Either
- set the highest index available (if a row is created but no value has been given)
- swap index for high to low position
- swap index for low to hight position
protected void updateItemIndex ( yii\db\AfterSaveEvent $event, $isNewRecord = false ) | ||
$event | yii\db\AfterSaveEvent | |
$isNewRecord | boolean |
protected function updateItemIndex(AfterSaveEvent $event, $isNewRecord = false)
{
$attributeName = self::sortableField();
$oldPosition = array_key_exists($attributeName, $event->changedAttributes) ? $event->changedAttributes[$attributeName] : false;
$newPosition = $event->sender[$attributeName];
// nothing has changed, skip further updates
if ($oldPosition == $newPosition && !$isNewRecord) {
return;
}
$transaction = Yii::$app->db->beginTransaction();
try {
$findQuery = $event->sender->find();
if ($findQuery instanceof NgRestActiveQuery && Yii::$app instanceof Application) {
$findQuery->inPool(Yii::$app->request->get('pool'));
}
$pkName = current($event->sender->primaryKey());
// no index has been set, set max value (last position)
if ($isNewRecord && empty($newPosition)) {
$event->sender->updateAttributes([$attributeName => $findQuery->max($attributeName) + 1]);
} elseif ($oldPosition && $newPosition && $oldPosition != $newPosition) {
$i = 1;
if ($newPosition > $oldPosition) {
// when the new position is highter then the old one: (old position - 1) + *1
foreach ($findQuery->andWhere(['and', ['!=', $pkName, $event->sender->primaryKey], ['>', $attributeName, $oldPosition], ['<=', $attributeName, $newPosition]])->all() as $item) {
$item->updateAttributes([$attributeName => ($oldPosition - 1) + $i]);
$i++;
}
} else {
// when the new position is higher then the old one: (new position + *1)
foreach ($findQuery->andWhere(['and', ['!=', $pkName, $event->sender->primaryKey], ['>=', $attributeName, $newPosition], ['<', $attributeName, $oldPosition]])->all() as $item) {
$item->updateAttributes([$attributeName => $newPosition + $i]);
$i++;
}
}
} elseif (!empty($newPosition) && empty($oldPosition)) {
// its a new record where the user entered a position, lets move all the other higher indexes
$i = 1;
foreach ($findQuery->andWhere(['and', ['!=', $pkName, $event->sender->primaryKey], ['>=', $attributeName, $newPosition]])->all() as $item) {
$item->updateAttributes([$attributeName => $newPosition + $i]);
$i++;
}
}
$this->reIndex($event, $attributeName, $pkName);
$transaction->commit();
} catch (\Exception|\Throwable $e) {
$transaction->rollBack();
throw $e;
}
}