2016-12-16 60 views
-2

我在我的数据库表中使用排序列。 每当我保存一个新的数据条目,我想选择排序的最大数量,并保存这个新的排序数字与新条目。CakePHP3:保存最大数量订购号

我该如何用cakephp3做到这一点?

回答

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

} 

这增加了全自动增加值排序,也可以提供排序(你需要动作到控制器类)

希望可以帮到