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