GithubHelp home page GithubHelp logo

yii2tech / ar-position Goto Github PK

View Code? Open in Web Editor NEW
115.0 10.0 15.0 22 KB

ActiveRecord behavior, which provides ability for custom records order setup

License: Other

PHP 100.00%
yii yii2 yii2-extension activerecord position custom order sort

ar-position's Introduction

ActiveRecord Position Extension for Yii2


This extension provides support for ActiveRecord custom records order setup.

For license information check the LICENSE-file.

Latest Stable Version Total Downloads Build Status

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist yii2tech/ar-position

or add

"yii2tech/ar-position": "*"

to the require section of your composer.json.

Usage

This extension provides support for custom records order setup via column-based position index.

This extension provides \yii2tech\ar\position\PositionBehavior ActiveRecord behavior for such solution support in Yii2. You may attach it to your model class in the following way:

<?php

use yii\db\ActiveRecord;
use yii2tech\ar\position\PositionBehavior;

class Item extends ActiveRecord
{
    public function behaviors()
    {
        return [
            'positionBehavior' => [
                'class' => PositionBehavior::className(),
                'positionAttribute' => 'position',
            ],
        ];
    }
}

Behavior uses the specific integer field of the database entity to set up position index. Due to this the database entity, which the model refers to, must contain field positionAttribute.

In order to display custom list in correct order you should sort it by positionAttribute in ascending mode:

<?php

$records = Item::find()->orderBy(['position' => SORT_ASC])->all();
foreach ($records as $record) {
    echo $record->position . ', ';
}
// outputs: 1, 2, 3, 4, 5,...

Position saving

Being attached, behavior automatically fills up positionAttribute value for the new record, placing it to the end of the list:

<?php

echo Item::find()->count(); // outputs: 4

$item = new Item();
$item->save();

echo $item->position; // outputs: 5

However, you may setup position for the new record explicitly:

<?php

echo Item::find()->count(); // outputs: 4

$item = new Item();
$item->position = 2; // enforce position '2'
$item->save();

echo $item->position; // outputs: 2 !!!

Position switching

Existing record can be moved to another position using following methods:

  • movePrev() - moves record by one position towards the start of the list.
  • moveNext() - moves record by one position towards the end of the list.
  • moveFirst() - moves record to the start of the list.
  • moveLast() - moves record to the end of the list.
  • moveToPosition() - moves owner record to the specific position.

You may as well change record position through the attribute, provided to positionAttribute directly:

<?php

$item = Item::find()->andWhere(['position' => 3])->one();
$item->position = 5; // switch position to '5'
$item->save();

Position in group

Sometimes single database entity contains several listings, which require custom ordering, separated logically by grouping attributes. For example: FAQ questions may be grouped by categories, while inside single category questions should be ordered manually. For this case \yii2tech\ar\position\PositionBehavior::$groupAttributes can be used:

<?php

use yii\db\ActiveRecord;
use yii2tech\ar\position\PositionBehavior;

class FaqQuestion extends ActiveRecord
{
    public function behaviors()
    {
        return [
            'positionBehavior' => [
                'class' => PositionBehavior::className(),
                'positionAttribute' => 'position',
                'groupAttributes' => [
                    'categoryId' // multiple lists varying by 'categoryId'
                ],
            ],
        ];
    }
}

In this case behavior will use owner values of groupAttributes as additional condition for position calculation and changing:

<?php

echo FaqQuestion::find()->andWhere(['categoryId' => 1])->count(); // outputs: '4'
echo FaqQuestion::find()->andWhere(['categoryId' => 2])->count(); // outputs: '7'

$record = new FaqQuestion();
$record->categoryId = 1;
$record->save();
echo $record->position; // outputs: '5'

$record = new FaqQuestion();
$record->categoryId = 2;
$record->save();
echo $record->position; // outputs: '8'

List navigation

Records with custom position order applied make a chained list, which you may navigate if necessary. You may use \yii2tech\ar\position\PositionBehavior::getIsFirst() and \yii2tech\ar\position\PositionBehavior::getIsLast() methods to determine if particular record is the first or last one in the list. For example:

<?php

echo Item::find()->count(); // outputs: 10

$firstItem = Item::find()->andWhere(['position' => 1])->one();
echo $firstItem->getIsFirst(); // outputs: true
echo $firstItem->getIsLast(); // outputs: false

$lastItem = Item::find()->andWhere(['position' => 10])->one();
echo $lastItem->getIsFirst(); // outputs: false
echo $lastItem->getIsLast(); // outputs: true

Having a particular record instance, you can always find record, which is located at next or previous position to it, using \yii2tech\ar\position\PositionBehavior::getNext() or \yii2tech\ar\position\PositionBehavior::getPrev() method. For example:

<?php

$item = Item::find()->andWhere(['position' => 5])->one();

$nextItem = $item->findNext();
echo $nextItem->position; // outputs: 6

$prevItem = $item->findPrev();
echo $prevItem->position; // outputs: 4

You may as well get the first and the last records in the list. For example:

<?php

echo Item::find()->count(); // outputs: 10
$item = Item::find()->andWhere(['position' => 5])->one();

$firstItem = $item->findFirst();
echo $firstItem->position; // outputs: 1

$lastItem = $item->findLast();
echo $lastItem->position; // outputs: 10

ar-position's People

Contributors

klimov-paul avatar ondrejvasicek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ar-position's Issues

Cant use method movePrev in "position in group"

model source:

public function movePre($position)
{
      $model = new PositionBehavior();
      $model->positionAttribute = $position;
      $model->groupAttributes = ['project_id'];
      $model->movePrev();
  }

controller source:

public function actionMove($id)
    {
        $position = $this->findModel($id)->position;
        $model = new Projectparts();
        $model->movePre($position);
        return $this->redirect(['projects/index']);
    }

return this: Call to a member function find() on null

[ENH] Add new property `insertDefaultPosition`

As I undestand all new records are appended to the end of list when positionAttribute is empty in insert scenario.
Is it a good idea to add a new property (for example insertDefaultPosition) when we can choose default inserting position (first or last or even exactly integer position).

Weird random positioning in group when categoryId is null

When trying to position in a null category group I'm getting the following result:

Initial position:
Item 1 -> position 1

After adding item 2:
Item 1 -> position 0
Item 2 -> position 1

Update item 2 for the first time:
Item 1 -> position 0
Item 2 -> position 2

Update item 2 for the second time:
Item 1 -> position 0
Item 2 -> position 0

Solved this issue by changing the line 256 of PositionBehavior.php to this code:

$condition[$attribute] = empty($this->owner->$attribute)?null:$this->owner->$attribute;

Allow to set group attribute value directry

We are facing problem when using PositionBehavior in couple with SoftDeleteBehavior.

We want to exclude deleted records from updateAllCounters update:

public function behaviors() {
    return [
        'softDelete' => [
            'class' => SoftDeleteBehavior::className(),
            'softDeleteAttributeValues' => [
                'isDeleted' => true,
            ],
        ],
        'position' => [
            'class' => PositionBehavior::className(),
            'positionAttribute' => 'position',
            'groupAttributes' => [
                'albumListId',
                'isDeleted',
            ],
        ],
    ];
}

But this causes that PositionBehavior updates only deleted records. Yes, I know that changing behaviors order may solve this problem, but this is not a good idea.

I propose adding ability to set a value into groupAttributes like that:

'groupAttributes' => [
    'albumListId',
    'isDeleted' => false,
]

Thank you.

Update groupAttribute

When I update groupAttribute behavior put old position to $this->positionOnSave in beforeUpdate event and then saves it in afterSave event instead of keeping the new calculated position (line 435).
I believe there is a wrong unnecessary line:

$this->positionOnSave = $this->owner->$positionAttribute;

Position is not updated when deleting the record

I have checked the code for PositionBehavior::beforeDelete and the idea (moveLast()) is great, but it seems not to be working.

What steps will reproduce the problem?

Delete a record

What is the expected result?

Position of other elementos to be updated

What do you get instead?

Elements that were after the deleted record keeps their position. I have elements in positions 1 to 10, if deleting the 2nd the third should become 2nd and the same for the rest.

Additional info

Q A
This Package Version "yii2tech/ar-position": "^1.0"
Yii Framework Version "yiisoft/yii2": "~2.0.6",
PHP version PHP 7.2.19-0ubuntu0.19.04.2 (cli) (built: Aug 13 2019 11:45:23) ( NTS )
Operating system Linux Ubuntu 19.04 5.3.0-050300rc7-generic #201909021831 SMP Mon Sep 2 18:33:34 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.