00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 class TreeBehavior extends ModelBehavior {
00038
00039 var $errors = array();
00040
00041 var $_defaults = array(
00042 'parent' => 'parent_id', 'left' => 'lft', 'right' => 'rght',
00043 'scope' => '1 = 1', 'type' => 'nested', '__parentChange' => false, 'recursive' => -1
00044 );
00045
00046 function setup(&$model, $config = array()) {
00047 if (!is_array($config)) {
00048 $config = array('type' => $config);
00049 }
00050 $settings = array_merge($this->_defaults, $config);
00051
00052 if (in_array($settings['scope'], $model->getAssociated('belongsTo'))) {
00053 $data = $model->getAssociated($settings['scope']);
00054 $parent =& $model->{$settings['scope']};
00055 $settings['scope'] = $model->alias . '.' . $data['foreignKey'] . ' = ' . $parent->alias . '.' . $parent->primaryKey;
00056 $settings['recursive'] = 0;
00057 }
00058 $this->settings[$model->alias] = $settings;
00059 }
00060
00061
00062
00063 function setScope(&$model, $scope) {
00064 trigger_error(__('(TreeBehavior::setScope) Deprecated - Use BehaviorCollection::attach() to re-attach with new settings', true), E_USER_WARNING);
00065 $this->settings[$model->alias]['scope'] = $scope;
00066 if ($this->settings[$model->alias]['recursive'] < 0) {
00067 $this->settings[$model->alias]['recursive'] = 0;
00068 }
00069 }
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 function afterSave(&$model, $created) {
00081 extract($this->settings[$model->alias]);
00082 if ($created) {
00083 if ((isset($model->data[$model->alias][$parent])) && $model->data[$model->alias][$parent]) {
00084 return $this->_setParent($model, $model->data[$model->alias][$parent], $created);
00085 }
00086 } elseif ($__parentChange) {
00087 $this->settings[$model->alias]['__parentChange'] = false;
00088 return $this->_setParent($model, $model->data[$model->alias][$parent]);
00089 }
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099 function beforeDelete(&$model) {
00100 extract($this->settings[$model->alias]);
00101 list($name, $data) = array($model->alias, $model->read());
00102 $data = $data[$name];
00103
00104 if (!$data[$right] || !$data[$left]) {
00105 return true;
00106 }
00107 $diff = $data[$right] - $data[$left] + 1;
00108
00109 if ($diff > 2) {
00110 if (is_string($scope)) {
00111 $scope = array($scope);
00112 }
00113 $scope[]["{$model->alias}.{$left} BETWEEN ? AND ?"] = array($data[$left] + 1, $data[$right] - 1);
00114 $model->deleteAll($scope);
00115 }
00116 $this->__sync($model, $diff, '-', '> ' . $data[$right]);
00117 return true;
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130 function beforeSave(&$model) {
00131 extract($this->settings[$model->alias]);
00132
00133 if (isset($model->data[$model->alias][$model->primaryKey])) {
00134 if ($model->data[$model->alias][$model->primaryKey]) {
00135 if (!$model->id) {
00136 $model->id = $model->data[$model->alias][$model->primaryKey];
00137 }
00138 }
00139 unset($model->data[$model->alias][$model->primaryKey]);
00140 }
00141
00142 $this->_addToWhitelist($model, array($left, $right));
00143 if (!$model->id) {
00144 if (array_key_exists($parent, $model->data[$model->alias]) && $model->data[$model->alias][$parent]) {
00145 $parentNode = $model->find('first', array(
00146 'conditions' => array($scope, $model->escapeField() => $model->data[$model->alias][$parent]),
00147 'fields' => array($model->primaryKey, $right), 'recursive' => $recursive
00148 ));
00149 if (!$parentNode) {
00150 return false;
00151 }
00152 list($parentNode) = array_values($parentNode);
00153 $model->data[$model->alias][$left] = 0;
00154 $model->data[$model->alias][$right] = 0;
00155 } else {
00156 $edge = $this->__getMax($model, $scope, $right, $recursive);
00157 $model->data[$model->alias][$left] = $edge + 1;
00158 $model->data[$model->alias][$right] = $edge + 2;
00159 }
00160 } elseif (array_key_exists($parent, $model->data[$model->alias])) {
00161 if ($model->data[$model->alias][$parent] != $model->field($parent)) {
00162 $this->settings[$model->alias]['__parentChange'] = true;
00163 }
00164 if (!$model->data[$model->alias][$parent]) {
00165 $model->data[$model->alias][$parent] = null;
00166 $this->_addToWhitelist($model, $parent);
00167 } else {
00168 list($node) = array_values($model->find('first', array(
00169 'conditions' => array($scope,$model->escapeField() => $model->id),
00170 'fields' => array($model->primaryKey, $parent, $left, $right ), 'recursive' => $recursive)
00171 ));
00172
00173 $parentNode = $model->find('first', array(
00174 'conditions' => array($scope, $model->escapeField() => $model->data[$model->alias][$parent]),
00175 'fields' => array($model->primaryKey, $left, $right), 'recursive' => $recursive
00176 ));
00177 if (!$parentNode) {
00178 return false;
00179 }
00180 list($parentNode) = array_values($parentNode);
00181
00182 if (($node[$left] < $parentNode[$left]) && ($parentNode[$right] < $node[$right])) {
00183 return false;
00184 } elseif ($node[$model->primaryKey] == $parentNode[$model->primaryKey]) {
00185 return false;
00186 }
00187 }
00188 }
00189 return true;
00190 }
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 function childcount(&$model, $id = null, $direct = false) {
00204 if (is_array($id)) {
00205 extract (array_merge(array('id' => null), $id));
00206 }
00207 if ($id === null && $model->id) {
00208 $id = $model->id;
00209 } elseif (!$id) {
00210 $id = null;
00211 }
00212 extract($this->settings[$model->alias]);
00213
00214 if ($direct) {
00215 return $model->find('count', array('conditions' => array($scope, $model->escapeField($parent) => $id)));
00216 }
00217
00218 if ($id === null) {
00219 return $model->find('count', array('conditions' => $scope));
00220 } elseif (!empty ($model->data)) {
00221 $data = $model->data[$model->alias];
00222 } else {
00223 list($data) = array_values($model->find('first', array('conditions' => array($scope, $model->escapeField() => $id), 'recursive' => $recursive)));
00224 }
00225 return ($data[$right] - $data[$left] - 1) / 2;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 function children(&$model, $id = null, $direct = false, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null) {
00245 if (is_array($id)) {
00246 extract (array_merge(array('id' => null), $id));
00247 }
00248 $overrideRecursive = $recursive;
00249
00250 if ($id === null && $model->id) {
00251 $id = $model->id;
00252 } elseif (!$id) {
00253 $id = null;
00254 }
00255 $name = $model->alias;
00256 extract($this->settings[$model->alias]);
00257
00258 if (!is_null($overrideRecursive)) {
00259 $recursive = $overrideRecursive;
00260 }
00261 if (!$order) {
00262 $order = $model->alias . '.' . $left . ' asc';
00263 }
00264 if ($direct) {
00265 $conditions = array($scope, $model->escapeField($parent) => $id);
00266 return $model->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
00267 }
00268
00269 if (!$id) {
00270 $conditions = $scope;
00271 } else {
00272 $result = array_values($model->find('first', array(
00273 'conditions' => array($scope, $model->escapeField() => $id),
00274 'fields' => array($left, $right),
00275 'recursive' => $recursive
00276 )));
00277
00278 if (empty($result) || !isset($result[0])) {
00279 return array();
00280 }
00281 $conditions = array($scope,
00282 $model->escapeField($right) . ' <' => $result[0][$right],
00283 $model->escapeField($left) . ' >' => $result[0][$left]
00284 );
00285 }
00286 return $model->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 function generatetreelist(&$model, $conditions = null, $keyPath = null, $valuePath = null, $spacer = '_', $recursive = null) {
00301 $overrideRecursive = $recursive;
00302 extract($this->settings[$model->alias]);
00303 if (!is_null($overrideRecursive)) {
00304 $recursive = $overrideRecursive;
00305 }
00306
00307 if ($keyPath == null && $valuePath == null && $model->hasField($model->displayField)) {
00308 $fields = array($model->primaryKey, $model->displayField, $left, $right);
00309 } else {
00310 $fields = null;
00311 }
00312
00313 if ($keyPath == null) {
00314 $keyPath = '{n}.' . $model->alias . '.' . $model->primaryKey;
00315 }
00316
00317 if ($valuePath == null) {
00318 $valuePath = array('{0}{1}', '{n}.tree_prefix', '{n}.' . $model->alias . '.' . $model->displayField);
00319
00320 } elseif (is_string($valuePath)) {
00321 $valuePath = array('{0}{1}', '{n}.tree_prefix', $valuePath);
00322
00323 } else {
00324 $valuePath[0] = '{' . (count($valuePath) - 1) . '}' . $valuePath[0];
00325 $valuePath[] = '{n}.tree_prefix';
00326 }
00327 $order = $model->alias . '.' . $left . ' asc';
00328 $results = $model->find('all', compact('conditions', 'fields', 'order', 'recursive'));
00329 $stack = array();
00330
00331 foreach ($results as $i => $result) {
00332 while ($stack && ($stack[count($stack) - 1] < $result[$model->alias][$right])) {
00333 array_pop($stack);
00334 }
00335 $results[$i]['tree_prefix'] = str_repeat($spacer,count($stack));
00336 $stack[] = $result[$model->alias][$right];
00337 }
00338 if (empty($results)) {
00339 return array();
00340 }
00341 return Set::combine($results, $keyPath, $valuePath);
00342 }
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 function getparentnode(&$model, $id = null, $fields = null, $recursive = null) {
00355 if (is_array($id)) {
00356 extract (array_merge(array('id' => null), $id));
00357 }
00358 $overrideRecursive = $recursive;
00359 if (empty ($id)) {
00360 $id = $model->id;
00361 }
00362 extract($this->settings[$model->alias]);
00363 if (!is_null($overrideRecursive)) {
00364 $recursive = $overrideRecursive;
00365 }
00366 $parentId = $model->read($parent, $id);
00367
00368 if ($parentId) {
00369 $parentId = $parentId[$model->alias][$parent];
00370 $parent = $model->find('first', array('conditions' => array($model->escapeField() => $parentId), 'fields' => $fields, 'recursive' => $recursive));
00371
00372 return $parent;
00373 } else {
00374 return false;
00375 }
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 function getpath(&$model, $id = null, $fields = null, $recursive = null) {
00388 if (is_array($id)) {
00389 extract (array_merge(array('id' => null), $id));
00390 }
00391 $overrideRecursive = $recursive;
00392 if (empty ($id)) {
00393 $id = $model->id;
00394 }
00395 extract($this->settings[$model->alias]);
00396 if (!is_null($overrideRecursive)) {
00397 $recursive = $overrideRecursive;
00398 }
00399 $result = $model->find('first', array('conditions' => array($model->escapeField() => $id), 'fields' => array($left, $right), 'recursive' => $recursive));
00400 if ($result) {
00401 $result = array_values($result);
00402 } else {
00403 return null;
00404 }
00405 $item = $result[0];
00406 $results = $model->find('all', array(
00407 'conditions' => array($scope, $model->escapeField($left) . ' <=' => $item[$left], $model->escapeField($right) . ' >=' => $item[$right]),
00408 'fields' => $fields, 'order' => array($model->escapeField($left) => 'asc'), 'recursive' => $recursive
00409 ));
00410 return $results;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 function movedown(&$model, $id = null, $number = 1) {
00424 if (is_array($id)) {
00425 extract (array_merge(array('id' => null), $id));
00426 }
00427 if (!$number) {
00428 return false;
00429 }
00430 if (empty ($id)) {
00431 $id = $model->id;
00432 }
00433 extract($this->settings[$model->alias]);
00434 list($node) = array_values($model->find('first', array(
00435 'conditions' => array($scope, $model->escapeField() => $id),
00436 'fields' => array($model->primaryKey, $left, $right, $parent), 'recursive' => $recursive
00437 )));
00438 if ($node[$parent]) {
00439 list($parentNode) = array_values($model->find('first', array(
00440 'conditions' => array($scope, $model->escapeField() => $node[$parent]),
00441 'fields' => array($model->primaryKey, $left, $right), 'recursive' => $recursive
00442 )));
00443 if (($node[$right] + 1) == $parentNode[$right]) {
00444 return false;
00445 }
00446 }
00447 $nextNode = $model->find('first', array(
00448 'conditions' => array($scope, $model->escapeField($left) => ($node[$right] + 1)),
00449 'fields' => array($model->primaryKey, $left, $right), 'recursive' => $recursive)
00450 );
00451 if ($nextNode) {
00452 list($nextNode)= array_values($nextNode);
00453 } else {
00454 return false;
00455 }
00456 $edge = $this->__getMax($model, $scope, $right, $recursive);
00457 $this->__sync($model, $edge - $node[$left] + 1, '+', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right]);
00458 $this->__sync($model, $nextNode[$left] - $node[$left], '-', 'BETWEEN ' . $nextNode[$left] . ' AND ' . $nextNode[$right]);
00459 $this->__sync($model, $edge - $node[$left] - ($nextNode[$right] - $nextNode[$left]), '-', '> ' . $edge);
00460
00461 if (is_int($number)) {
00462 $number--;
00463 }
00464 if ($number) {
00465 $this->moveDown($model, $id, $number);
00466 }
00467 return true;
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 function moveup(&$model, $id = null, $number = 1) {
00481 if (is_array($id)) {
00482 extract (array_merge(array('id' => null), $id));
00483 }
00484 if (!$number) {
00485 return false;
00486 }
00487 if (empty ($id)) {
00488 $id = $model->id;
00489 }
00490 extract($this->settings[$model->alias]);
00491 list($node) = array_values($model->find('first', array(
00492 'conditions' => array($scope, $model->escapeField() => $id),
00493 'fields' => array($model->primaryKey, $left, $right, $parent ), 'recursive' => $recursive
00494 )));
00495 if ($node[$parent]) {
00496 list($parentNode) = array_values($model->find('first', array(
00497 'conditions' => array($scope, $model->escapeField() => $node[$parent]),
00498 'fields' => array($model->primaryKey, $left, $right), 'recursive' => $recursive
00499 )));
00500 if (($node[$left] - 1) == $parentNode[$left]) {
00501 return false;
00502 }
00503 }
00504 $previousNode = $model->find('first', array(
00505 'conditions' => array($scope, $model->escapeField($right) => ($node[$left] - 1)),
00506 'fields' => array($model->primaryKey, $left, $right),
00507 'recursive' => $recursive
00508 ));
00509
00510 if ($previousNode) {
00511 list($previousNode) = array_values($previousNode);
00512 } else {
00513 return false;
00514 }
00515 $edge = $this->__getMax($model, $scope, $right, $recursive);
00516 $this->__sync($model, $edge - $previousNode[$left] +1, '+', 'BETWEEN ' . $previousNode[$left] . ' AND ' . $previousNode[$right]);
00517 $this->__sync($model, $node[$left] - $previousNode[$left], '-', 'BETWEEN ' .$node[$left] . ' AND ' . $node[$right]);
00518 $this->__sync($model, $edge - $previousNode[$left] - ($node[$right] - $node[$left]), '-', '> ' . $edge);
00519 if (is_int($number)) {
00520 $number--;
00521 }
00522 if ($number) {
00523 $this->moveUp($model, $id, $number);
00524 }
00525 return true;
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 function recover(&$model, $mode = 'parent', $missingParentAction = null) {
00544 if (is_array($mode)) {
00545 extract (array_merge(array('mode' => 'parent'), $mode));
00546 }
00547 extract($this->settings[$model->alias]);
00548 $model->recursive = $recursive;
00549 if ($mode == 'parent') {
00550 $model->bindModel(array('belongsTo' => array('VerifyParent' => array(
00551 'className' => $model->alias,
00552 'foreignKey' => $parent,
00553 'fields' => array($model->primaryKey, $left, $right, $parent,
00554 'actsAs' => '')
00555 ))));
00556 $missingParents = $model->find('list', array(
00557 'recursive' => 0,
00558 'conditions' => array($scope, array(
00559 'NOT' => array($model->escapeField($parent) => null), $model->VerifyParent->escapeField() => null
00560 ))
00561 ));
00562 $model->unbindModel(array('belongsTo' => array('VerifyParent')));
00563 if ($missingParents) {
00564 if ($missingParentAction == 'return') {
00565 foreach ($missingParents as $id => $display) {
00566 $this->errors[] = 'cannot find the parent for ' . $model->alias . ' with id ' . $id . '(' . $display . ')';
00567
00568 }
00569 return false;
00570 } elseif ($missingParentAction == 'delete') {
00571 $model->deleteAll(array($model->primaryKey => array_flip($missingParents)));
00572 } else {
00573 $model->updateAll(array($parent => $missingParentAction), array($model->escapeField($model->primaryKey) => array_flip($missingParents)));
00574 }
00575 }
00576 $count = 1;
00577 foreach ($model->find('all', array('conditions' => $scope, 'fields' => array($model->primaryKey), 'order' => $left)) as $array) {
00578 $model->{$model->primaryKey} = $array[$model->alias][$model->primaryKey];
00579 $lft = $count++;
00580 $rght = $count++;
00581 $model->save(array($left => $lft, $right => $rght), array('callbacks' => false));
00582 }
00583 foreach ($model->find('all', array('conditions' => $scope, 'fields' => array($model->primaryKey, $parent), 'order' => $left)) as $array) {
00584 $model->create();
00585 $model->id = $array[$model->alias][$model->primaryKey];
00586 $this->_setParent($model, $array[$model->alias][$parent]);
00587 }
00588 } else {
00589 foreach ($model->find('all', array('conditions' => $scope, 'fields' => array($model->primaryKey, $parent), 'order' => $left)) as $array) {
00590 $path = $this->getpath($model, $array[$model->alias][$model->primaryKey]);
00591 if ($path == null || count($path) < 2) {
00592 $parentId = null;
00593 } else {
00594 $parentId = $path[count($path) - 2][$model->alias][$model->primaryKey];
00595 }
00596 $model->updateAll(array($parent => $parentId), array($model->escapeField() => $array[$model->alias][$model->primaryKey]));
00597 }
00598 }
00599 return true;
00600 }
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613 function reorder(&$model, $options = array()) {
00614 $options = array_merge(array('id' => null, 'field' => $model->displayField, 'order' => 'ASC', 'verify' => true), $options);
00615 extract($options);
00616 if ($verify && !$model->verify()) {
00617 return false;
00618 }
00619 $verify = false;
00620 extract($this->settings[$model->alias]);
00621 $fields = array($model->primaryKey, $field, $left, $right);
00622 $sort = $field . ' ' . $order;
00623 $nodes = $model->children($id, true, $fields, $sort, null, null, $recursive);
00624
00625 if ($nodes) {
00626 foreach ($nodes as $node) {
00627 $id = $node[$model->alias][$model->primaryKey];
00628 $model->moveDown($id, true);
00629 if ($node[$model->alias][$left] != $node[$model->alias][$right] - 1) {
00630 $this->reorder($model, compact('id', 'field', 'order', 'verify'));
00631 }
00632 }
00633 }
00634 return true;
00635 }
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648 function removefromtree(&$model, $id = null, $delete = false) {
00649 if (is_array($id)) {
00650 extract (array_merge(array('id' => null), $id));
00651 }
00652 extract($this->settings[$model->alias]);
00653
00654 list($node) = array_values($model->find('first', array(
00655 'conditions' => array($scope, $model->escapeField() => $id),
00656 'fields' => array($model->primaryKey, $left, $right, $parent),
00657 'recursive' => $recursive
00658 )));
00659
00660 if ($node[$right] == $node[$left] + 1) {
00661 if ($delete) {
00662 $model->delete();
00663 } else {
00664 return false;
00665 }
00666 } elseif ($node[$parent]) {
00667 list($parentNode) = array_values($model->find('first', array(
00668 'conditions' => array($scope, $model->escapeField() => $node[$parent]),
00669 'fields' => array($model->primaryKey, $left, $right),
00670 'recursive' => $recursive
00671 )));
00672 } else {
00673 $parentNode[$right] = $node[$right] + 1;
00674 }
00675
00676 $model->updateAll(array($parent => $node[$parent]), array($parent => $node[$model->primaryKey]));
00677 $this->__sync($model, 1, '-', 'BETWEEN ' . ($node[$left] + 1) . ' AND ' . ($node[$right] - 1));
00678 $this->__sync($model, 2, '-', '> ' . ($node[$right]));
00679 $model->id = $id;
00680
00681 if ($delete) {
00682 $model->updateAll(
00683 array(
00684 $model->escapeField($left) => 0,
00685 $model->escapeField($right) => 0,
00686 $model->escapeField($parent) => null
00687 ),
00688 array($model->escapeField() => $id)
00689 );
00690 return $model->delete($id);
00691 } else {
00692 $edge = $this->__getMax($model, $scope, $right, $recursive);
00693 if ($node[$right] == $edge) {
00694 $edge = $edge - 2;
00695 }
00696 $model->id = $id;
00697 return $model->save(
00698 array($left => $edge + 1, $right => $edge + 2, $parent => null),
00699 array('callbacks' => false)
00700 );
00701 }
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714 function setparent(&$model, $parentId = null , $created = null) {
00715 trigger_error(
00716 __('(TreeBehavior::setParent) Deprecated - save the record with a parent ID instead', true),
00717 E_USER_ERROR
00718 );
00719 extract($this->settings[$model->alias]);
00720
00721 if ($created === false && $parentId == $model->field($parent)) {
00722 return true;
00723 }
00724 return $model->saveField($parent, $parentId, array('callbacks' => false));
00725 }
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736 function verify(&$model) {
00737 extract($this->settings[$model->alias]);
00738 if (!$model->find('count', array('conditions' => $scope))) {
00739 return true;
00740 }
00741 $min = $this->__getMin($model, $scope, $left, $recursive);
00742 $edge = $this->__getMax($model, $scope, $right, $recursive);
00743 $errors = array();
00744
00745 for ($i = $min; $i <= $edge; $i++) {
00746 $count = $model->find('count', array('conditions' => array(
00747 $scope, 'OR' => array($model->escapeField($left) => $i, $model->escapeField($right) => $i)
00748 )));
00749 if ($count != 1) {
00750 if ($count == 0) {
00751 $errors[] = array('index', $i, 'missing');
00752 } else {
00753 $errors[] = array('index', $i, 'duplicate');
00754 }
00755 }
00756 }
00757 $node = $model->find('first', array('conditions' => array($scope, $model->escapeField($right) . '< ' . $model->escapeField($left)), 'recursive' => 0));
00758 if ($node) {
00759 $errors[] = array('node', $node[$model->alias][$model->primaryKey], 'left greater than right.');
00760 }
00761
00762 $model->bindModel(array('belongsTo' => array('VerifyParent' => array(
00763 'className' => $model->alias,
00764 'foreignKey' => $parent,
00765 'fields' => array($model->primaryKey, $left, $right, $parent)
00766 ))));
00767
00768 foreach ($model->find('all', array('conditions' => $scope, 'recursive' => 0)) as $instance) {
00769 if (is_null($instance[$model->alias][$left]) || is_null($instance[$model->alias][$right])) {
00770 $errors[] = array('node', $instance[$model->alias][$model->primaryKey],
00771 'has invalid left or right values');
00772 } elseif ($instance[$model->alias][$left] == $instance[$model->alias][$right]){
00773 $errors[] = array('node', $instance[$model->alias][$model->primaryKey],
00774 'left and right values identical');
00775 } elseif ($instance[$model->alias][$parent]) {
00776 if (!$instance['VerifyParent'][$model->primaryKey]) {
00777 $errors[] = array('node', $instance[$model->alias][$model->primaryKey],
00778 'The parent node ' . $instance[$model->alias][$parent] . ' doesn\'t exist');
00779 } elseif ($instance[$model->alias][$left] < $instance['VerifyParent'][$left]) {
00780 $errors[] = array('node', $instance[$model->alias][$model->primaryKey],
00781 'left less than parent (node ' . $instance['VerifyParent'][$model->primaryKey] . ').');
00782 } elseif ($instance[$model->alias][$right] > $instance['VerifyParent'][$right]) {
00783 $errors[] = array('node', $instance[$model->alias][$model->primaryKey],
00784 'right greater than parent (node ' . $instance['VerifyParent'][$model->primaryKey] . ').');
00785 }
00786 } elseif ($model->find('count', array('conditions' => array($scope, $model->escapeField($left) . '< ' . $instance[$model->alias][$left], $right . '> ' . $instance[$model->alias][$right]), 'recursive' => 0))) {
00787 $errors[] = array('node', $instance[$model->alias][$model->primaryKey], 'The parent field is blank, but has a parent');
00788 }
00789 }
00790
00791 if ($errors) {
00792 return $errors;
00793 } else {
00794 return true;
00795 }
00796 }
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809 function _setParent(&$model, $parentId = null, $created = false) {
00810 extract($this->settings[$model->alias]);
00811 list($node) = array_values($model->find('first', array(
00812 'conditions' => array($scope, $model->escapeField() => $model->id),
00813 'fields' => array($model->primaryKey, $parent, $left, $right),
00814 'recursive' => $recursive
00815 )));
00816 $edge = $this->__getMax($model, $scope, $right, $recursive, $created);
00817
00818 if (empty ($parentId)) {
00819 $this->__sync($model, $edge - $node[$left] + 1, '+', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right], $created);
00820 $this->__sync($model, $node[$right] - $node[$left] + 1, '-', '> ' . $node[$left], $created);
00821 } else {
00822 $parentNode = array_values($model->find('first', array(
00823 'conditions' => array($scope, $model->escapeField() => $parentId),
00824 'fields' => array($model->primaryKey, $left, $right),
00825 'recursive' => $recursive
00826 )));
00827
00828 if (empty($parentNode) || empty($parentNode[0])) {
00829 return false;
00830 }
00831 $parentNode = $parentNode[0];
00832
00833 if (($model->id == $parentId)) {
00834 return false;
00835
00836 } elseif (($node[$left] < $parentNode[$left]) && ($parentNode[$right] < $node[$right])) {
00837 return false;
00838 }
00839 if (empty ($node[$left]) && empty ($node[$right])) {
00840 $this->__sync($model, 2, '+', '>= ' . $parentNode[$right], $created);
00841 $model->save(
00842 array($left => $parentNode[$right], $right => $parentNode[$right] + 1, $parent => $parentId),
00843 array('validate' => false, 'callbacks' => false)
00844 );
00845 } else {
00846 $this->__sync($model, $edge - $node[$left] +1, '+', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right], $created);
00847 $diff = $node[$right] - $node[$left] + 1;
00848
00849 if ($node[$left] > $parentNode[$left]) {
00850 if ($node[$right] < $parentNode[$right]) {
00851 $this->__sync($model, $diff, '-', 'BETWEEN ' . $node[$right] . ' AND ' . ($parentNode[$right] - 1), $created);
00852 $this->__sync($model, $edge - $parentNode[$right] + $diff + 1, '-', '> ' . $edge, $created);
00853 } else {
00854 $this->__sync($model, $diff, '+', 'BETWEEN ' . $parentNode[$right] . ' AND ' . $node[$right], $created);
00855 $this->__sync($model, $edge - $parentNode[$right] + 1, '-', '> ' . $edge, $created);
00856 }
00857 } else {
00858 $this->__sync($model, $diff, '-', 'BETWEEN ' . $node[$right] . ' AND ' . ($parentNode[$right] - 1), $created);
00859 $this->__sync($model, $edge - $parentNode[$right] + $diff + 1, '-', '> ' . $edge, $created);
00860 }
00861 }
00862 }
00863 return true;
00864 }
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874 function __getMax($model, $scope, $right, $recursive = -1, $created = false) {
00875 $db =& ConnectionManager::getDataSource($model->useDbConfig);
00876 if ($created) {
00877 if (is_string($scope)) {
00878 $scope .= " AND {$model->alias}.{$model->primaryKey} <> ";
00879 $scope .= $db->value($model->id, $model->getColumnType($model->primaryKey));
00880 } else {
00881 $scope['NOT'][$model->alias . '.' . $model->primaryKey] = $model->id;
00882 }
00883 }
00884 list($edge) = array_values($model->find('first', array(
00885 'conditions' => $scope,
00886 'fields' => $db->calculate($model, 'max', array($right)),
00887 'recursive' => $recursive
00888 )));
00889 return ife(empty ($edge[$right]), 0, $edge[$right]);
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900 function __getMin($model, $scope, $left, $recursive = -1) {
00901 $db =& ConnectionManager::getDataSource($model->useDbConfig);
00902 list($edge) = array_values($model->find('first', array(
00903 'conditions' => $scope,
00904 'fields' => $db->calculate($model, 'min', array($left)),
00905 'recursive' => $recursive
00906 )));
00907 return ife(empty($edge[$left]), 0, $edge[$left]);
00908 }
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921 function __sync(&$model, $shift, $dir = '+', $conditions = array(), $created = false, $field = 'both') {
00922 $modelRecursive = $model->recursive;
00923 extract($this->settings[$model->alias]);
00924 $model->recursive = $recursive;
00925
00926 if ($field == 'both') {
00927 $this->__sync($model, $shift, $dir, $conditions, $created, $left);
00928 $field = $right;
00929 }
00930 if (is_string($conditions)) {
00931 $conditions = array("{$model->alias}.{$field} {$conditions}");
00932 }
00933 if (($scope != '1 = 1' && $scope !== true) && $scope) {
00934 $conditions[] = $scope;
00935 }
00936 if ($created) {
00937 $conditions['NOT'][$model->alias . '.' . $model->primaryKey] = $model->id;
00938 }
00939 $model->updateAll(array($model->alias . '.' . $field => $model->alias . '.' . $field . ' ' . $dir . ' ' . $shift), $conditions);
00940 $model->recursive = $modelRecursive;
00941 }
00942 }
00943
00944 ?>