Cakephp3:保存最大计数订购号

时间:2016-12-16 09:52:59

标签: cakephp

我在数据库表中使用了一个排序列。 每当我保存一个新的数据条目时,我想选择最大排序数,并用新条目保存这个新的排序号。

如何使用cakephp3进行此操作?

1 个答案:

答案 0 :(得分:0)

我前一段时间发现了这段代码(遗憾的是,我不记得原作者的所有内容)并根据我的需要进行了编辑

将此添加到您要在

上使用排序的table
$this->addBehavior('Sortable', [
        'field' => 'sort'
]);

并将其保存在/src/Model/Behaviour/SortableBehaviour.php

<?php

namespace App\Model\Behavior;

use Cake\Database\Expression\QueryExpression;
use Cake\Event\Event;
use Cake\ORM\Behavior;
use Cake\ORM\Entity;
use Cake\ORM\Exception\RecordNotFoundException;
use Cake\ORM\Table;
use Cake\ORM\Query;


class SortableBehavior extends Behavior {

    protected $_table;

/**
 * Default config
 *
 * These are merged with user-provided config when the behavior is used.
 *
 * field 
 * - the field in the DB-table that is doing the sorting
 * scope 
 * - one or more foreign_keys as array
 * - eg ['user_group_id'] in a table users would enabled sorting for each
 * - user_group separately
 * newEntries
 * - either `last` or `first`
 *
 * @var array
 */
    protected $_defaultConfig = [
        'field' => 'sort',
        'scope' => null,
        'newEntries' => 'last' 
    ];

/**
 * Constructor
 *
 * @param \Cake\ORM\Table $table The table this behavior is attached to.
 * @param array $config The config for this behavior.
 */
    public function __construct(Table $table, array $config = []) {
        parent::__construct($table, $config);
        $this->_table = $table;
    }   

/**
 * Before save listener
 * handles initial sorting for added entities
 * @param  \Cake\Event\Event $event The beforeSave event that was fired
 * @param  \Cake\ORM\Entity $entity the entity that is going to be saved
 * @return void
 */
    public function beforeSave(Event $event, Entity $entity) {
        $config = $this->config();
        if (!$entity->isNew()) {
            return;
        }
        if ($config['newEntries'] == 'last') {
            $scopeData = $this->_getScopeData($entity);
            $maxPosition = $this->_getMaxPosition($scopeData);
            $entity->set($config['field'], $maxPosition + 1);
        }
    }

/**
 * After delete listener
 *
 * makes sure the left over entities are sorted properly 
 * 
 * @param  \Cake\Event\Event $event The afterDelete event that was fired
 * @param  \Cake\ORM\Entity $entity the entity that was going to be deleted
 * @return void
 */
    public function afterDelete(Event $event, Entity $entity) {
        $config = $this->config();

        $expression = new QueryExpression($config['field'] . ' = ' . $config['field'] . ' - 1');
        $conditions = [
            $config['field'].' >' => $entity->get($config['field'])
        ];
        $conditions += $this->_getScopeData($entity);
        $this->_table->updateAll($expression, $conditions);
    }



/**
 * main move method
 *
 * 
 * 
 * @param  integer $id the id of the Entity that was moved
 * @param  array $newSortOrder all IDs of the current scope in the desired sort order (as provided by http://johnny.github.io/jquery-sortable/)
 * @return boolean
 * 
 */
    public function move($id, $newSortOrder) {
        return $this->_table->connection()->transactional(function() use ($id, $newSortOrder) {
            return $this->_move($id, $newSortOrder);
        });
    }



/**
 * helper method that contains the actual move code
 * 
 * @param  integer $id the id of the Entity that was moved
 * @param  array $newSortOrder all IDs of the current scope in the desired sort order (as provided by http://johnny.github.io/jquery-sortable/)
 * @return boolean
 * 
 */
    protected function _move($id, $newSortOrder) {
        $config = $this->config();

        $node = $this->_getNode($id);

        $current_position = $node[$config['field']];
        // might be faster to do array_flip?!
        $new_position = array_search($id, $newSortOrder) + 1;

        // no position change -> return
        if ($current_position == $new_position) {
            return true;
        }

        // build sql for updating affected entries
        if ($current_position < $new_position) {
            $expression = new QueryExpression($config['field'] . ' = ' . $config['field'] . ' - 1');
            $conditions = [
                'sort >' => $current_position,
                'AND' => [ $config['field'].' <=' => $new_position ],
            ];
        } else {
            $expression = new QueryExpression($config['field'] . ' = ' . $config['field'] . ' + 1');
            $conditions = [
                'sort <' => $current_position,
                'AND' => [ $config['field'].' >=' => $new_position ],
            ];
        }
        $conditions += $this->_getScopeData($node);

        $res = $this->_table->updateAll($expression, $conditions);

        // finally set the inital field to the new val
        $q = $this->_table->query();
        return $res && $q->update()
            ->set([$config['field']=>$new_position])
            ->where(['id'=>$id])
            ->execute();
    }

/**
 * returns a node and the scope params if set up in config
 * @param  integer $id the node id
 * @return Array|Object the result of query->first()
 * @throws Cake\ORM\Exception\RecordNotFoundException if no node with that id found
 */
    protected function _getNode($id) {
        $config = $this->config();
        // get current sort of `id`
        // if a context is set -> get that also while we are aclling this
        $query = $this->_table->find();
        $query
            ->select(array_merge(['id', $config['field']], (array)$config['scope']))
            ->where(['id'=>$id])
            ->contain();
        if (!$node = $query->first()) {
            throw new RecordNotFoundException(sprintf('Kein Eintrag mit ID %s gefunden', $id));
        }
        return $node;
    }


/**
 * returns the highest position within that scope
 *
 * @param array $scopeData the scope data
 * @return integer the currently highest positions in that scope
 */
    protected function _getMaxPosition($scopeData=null) {
        $config = $this->config();

        $query = $this->_table->find();
        $query
            ->select(array_merge([$config['field']], array_keys($scopeData)))
            ->where($scopeData)
            ->order([$config['field'] => 'DESC'])
            ->contain();
        $node = $query->first();
        return ($node[$config['field']] ?: 0);
    }


    protected function _getScopeData($node) {
        $config = $this->config();
        $conditions = [];
        foreach ((array)$config['scope'] as $scope) {
            $conditions[$scope] = $node[$scope];
        }
        return $conditions;
    }

}

这会自动添加递增的排序值,也可以提供排序(您需要对控制器类执行操作)

希望有所帮助