Trait luya\admin\traits\SortableTrait

Available since version1.0.0

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

Hide inherited 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

Hide inherited 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

Hide inherited methods

deleteItemIndex() protected method (available since version 4.4.0)

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;
    }
}

            
find() public static method

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]);
}

            
init() public method (available since version 4.4.0)

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']);
}

            
newItemIndex() protected method (available since version 4.4.0)

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);
}

            
ngRestFind() public static method

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]);
}

            
ngRestListOrder() public method

Disable the list ordering.

public boolean ngRestListOrder ( )

                public function ngRestListOrder()
{
    return false;
}

            
sortableField() public static method

The field which should by used to sort.

public static string sortableField ( )

                public static function sortableField()
{
    return 'sortindex';
}

            
updateItemIndex() protected method (available since version 4.4.0)

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;
    }
}