replaced group with cluster as group is already used in cake core since RC2
[my_behaviors.git] / models / behaviors / sortable.php
blob1e6108aed35e3c359945f7c8026c031811935274
1 <?php
2 /**
3 * Copyright (c) 2008, Dardo Sordi
5 * Licensed under The MIT License
6 * Redistributions of files must retain the above copyright notice.
8 * @copyright Copyright (c) 2008, Dardo Sordi
9 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
10 * @author Dardo Sordi
13 class SortableBehavior extends ModelBehavior {
15 var $__config = array();
17 function setup(&$model, $config = array()) {
18 $default = array('field' => 'order', 'enabled' => true, 'cluster' => false);
19 $this->__config[$model->name] = array_merge($default, (array)$config);
22 function _config(&$model, $config = array()) {
23 if (is_array($config)) {
24 if (!empty($config)) {
25 $this->__config[$model->name] = array_merge($this->__config[$model->name], $config);
27 } else {
28 return $this->__config[$model->name][$config];
31 return $this->__config[$model->name];
34 function _fullField(&$model) {
35 return $model->name . '.' . $this->_config($model, 'field');
38 function beforeFind(&$model, $conditions = array()) {
39 extract($this->_config($model));
40 if (!$enabled) {
41 return $conditions;
43 if (is_string($conditions['fields']) && strpos($conditions['fields'], 'COUNT') === 0) {
44 return $conditions;
46 $order = $conditions['order'];
47 if (is_array($conditions['order'])) {
48 $order = current($conditions['order']);
50 if (empty($order)) {
51 $conditions['order'] = array(array($this->_fullField($model) => 'ASC'));
53 if ($cluster !== false) {
54 $conditions['order'] = array_merge(array($cluster => 'ASC'), $conditions['order']);
57 return $conditions;
60 function beforeSave(&$model) {
61 extract($this->_config($model));
62 if ($enabled) {
63 $fixPosition = false;
64 $isInsert = !$model->id;
65 if (isset($model->data[$model->name][$field]) && !empty($model->data[$model->name][$field])) {
66 $newPosition = $model->data[$model->name][$field];
67 } else {
68 $newPosition = null;
70 $clusterId = $this->_clusterId($model);
71 $model->data[$model->name][$field] = $this->lastPosition($model, $clusterId) + 1;
72 $model->__fixPosition = $newPosition;
74 return true;
77 function afterSave(&$model, $created) {
78 extract($this->_config($model));
79 if (!$enabled) {
80 return true;
82 $position = $model->data[$model->name][$field];
83 if ($model->__fixPosition) {
84 $position = $model->__fixPosition;
85 $model->__fixPosition = null;
86 $this->setPosition($model, $model->id, $position);
90 function beforeDelete(&$model) {
91 extract($this->_config($model));
92 if ($enabled) {
93 $model->__fixPosition = $this->position($model);
95 return true;
98 function afterDelete(&$model) {
99 extract($this->_config($model));
100 if (!$enabled) {
101 return true;
103 $fullField = $this->_fullField($model);
104 $position = $model->__fixPosition;
105 $model->__fixPosition = null;
106 $model->updateAll(array($fullField => "$fullField - 1"), array("$fullField >=" => $position));
109 function moveTop(&$model, $id = null) {
110 $this->disableSortable($model);
111 if ($id) {
112 $model->id = $id;
114 extract($this->_config($model));
115 $position = $this->position($model);
116 $clusterId = $this->_clusterId($model);
117 $fullField = $this->_fullField($model);
119 if ($position > 1) {
120 $newPosition = 1;
121 $conditions = $this->_conditions($model, $clusterId, array("$fullField <=" => $position, "$fullField >=" => $newPosition));
122 $model->updateAll(array($fullField => "$fullField + 1"), $conditions);
123 $model->saveField($field, $newPosition);
125 $this->enableSortable($model);
126 return true;
129 function moveUp(&$model, $id = null, $step = 1) {
130 $this->disableSortable($model);
131 if ($id) {
132 $model->id = $id;
134 extract($this->_config($model));
135 $position = $this->position($model);
136 $clusterId = $this->_clusterId($model);
137 $fullField = $this->_fullField($model);
139 if ($position > 1) {
140 $newPosition = $position - $step;
141 if ($newPosition < 1) {
142 $newPosition = 1;
144 $conditions = $this->_conditions($model, $clusterId, array("$fullField <=" => $position, "$fullField >=" => $newPosition));
145 $model->updateAll(array($fullField => "$fullField + 1"), $conditions);
146 $model->saveField($field, $newPosition);
148 $this->enableSortable($model);
149 return true;
152 function moveDown(&$model, $id = null, $step = 1) {
153 $this->disableSortable($model);
154 if ($id) {
155 $model->id = $id;
157 extract($this->_config($model));
158 $position = $this->position($model);
159 $clusterId = $this->_clusterId($model);
160 $id = $model->id;
161 $model->id = null;
162 $last = $this->lastPosition($model, $clusterId);
163 $fullField = $this->_fullField($model);
165 if ($position < $last) {
166 $newPosition = $position + $step;
167 if ($newPosition > $last) {
168 $newPosition = $last;
170 $conditions = $this->_conditions($model, $clusterId, array("$fullField >=" => $position, "$fullField <=" => $newPosition));
171 $model->updateAll(array($fullField => "$fullField - 1"), $conditions);
172 $model->id = $id;
173 $model->saveField($field, $newPosition);
175 $this->enableSortable($model);
176 return true;
179 function moveBottom(&$model, $id = null) {
180 $this->disableSortable($model);
181 if ($id) {
182 $model->id = $id;
184 extract($this->_config($model));
186 $position = $this->position($model);
187 $clusterId = $this->_clusterId($model);
188 $id = $model->id;
189 $model->id = null;
190 $last = $this->lastPosition($model, $clusterId);
191 $fullField = $this->_fullField($model);
193 if ($position < $last) {
194 $newPosition = $last;
195 $conditions = $this->_conditions($model, $clusterId, array("$fullField >=" => $position, "$fullField <=" => $newPosition));
196 $model->updateAll(array($fullField => "$fullField - 1"), $conditions);
197 $model->id = $id;
198 $model->saveField($field, $newPosition);
200 $this->enableSortable($model);
201 return true;
204 function setPosition(&$model, $id = null, $destination) {
205 $this->disableSortable($model);
206 if ($id) {
207 $model->id = $id;
209 extract($this->_config($model));
210 $position = $this->position($model);
211 $id = $model->id;
212 $model->id = null;
213 $delta = $position - $destination;
215 if ($position > $destination) {
216 $this->moveUp($model, $id, $delta);
217 } elseif ($position < $destination) {
218 $this->moveDown($model, $id, -$delta);
220 $this->enableSortable($model);
221 return true;
224 function disableSortable(&$model) {
225 $this->_config($model, array('enabled' => false));
228 function enableSortable(&$model) {
229 $this->_config($model, array('enabled' => true));
232 function position(&$model, $id = null) {
233 if ($id) {
234 $model->id = $id;
236 return $model->field($this->_config($model, 'field'));
239 function _clusterId(&$model, $id = null) {
240 $cluster = $this->_config($model, 'cluster');
242 if ($cluster === false) {
243 return null;
245 if ($id) {
246 $model->id = $id;
248 return $model->field($cluster);
251 function lastPosition(&$model, $clusterId = null) {
252 $id = $model->id;
253 $model->id = null;
254 $field = $this->_config($model, 'field');
255 $fields = array($field);
256 $order = array($field => 'DESC');
257 $conditions = $this->_conditions($model, $clusterId);
258 $last = $model->find('first', compact('fields', 'order', 'conditions'));
259 $model->id = $id;
261 if (!empty($last)) {
262 return current(current($last));
265 return false;
268 function _conditions(&$model, $clusterId = null, $conditions = array()) {
269 $cluster = $this->_config($model, 'cluster');
271 if (($cluster !== false) && !is_null($clusterId)) {
272 $conditions = array_merge($conditions, array($cluster => $clusterId));
275 return $conditions;
278 function findByPosition(&$model, $position, $clusterId = null) {
279 $field = $this->_fullField($model);
280 return $model->find($this->_conditions($model, $clusterId, array($field => $position)));