| 1 | <?php | 
|---|
| 2 | # -- BEGIN LICENSE BLOCK --------------------------------------- | 
|---|
| 3 | # | 
|---|
| 4 | # This file is part of Dotclear 2. | 
|---|
| 5 | # | 
|---|
| 6 | # Copyright (c) 2003-2010 Olivier Meunier & Association Dotclear | 
|---|
| 7 | # Licensed under the GPL version 2.0 license. | 
|---|
| 8 | # See LICENSE file or | 
|---|
| 9 | # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html | 
|---|
| 10 | # | 
|---|
| 11 | # -- END LICENSE BLOCK ----------------------------------------- | 
|---|
| 12 | if (!defined('DC_RC_PATH')) { return; } | 
|---|
| 13 |  | 
|---|
| 14 | # nestedTree class is based on excellent work of Kuzma Feskov | 
|---|
| 15 | # (http://php.russofile.ru/ru/authors/sql/nestedsets01/) | 
|---|
| 16 | # | 
|---|
| 17 | # One day we'll move nestedTree to Clearbricks. | 
|---|
| 18 |  | 
|---|
| 19 | class dcCategories extends nestedTree | 
|---|
| 20 | { | 
|---|
| 21 |      protected $f_left = 'cat_lft'; | 
|---|
| 22 |      protected $f_right = 'cat_rgt'; | 
|---|
| 23 |      protected $f_id = 'cat_id'; | 
|---|
| 24 |       | 
|---|
| 25 |      protected $core; | 
|---|
| 26 |      protected $blog_id; | 
|---|
| 27 |       | 
|---|
| 28 |      public function __construct($core) | 
|---|
| 29 |      { | 
|---|
| 30 |           $this->core =& $core; | 
|---|
| 31 |           $this->con =& $core->con; | 
|---|
| 32 |           $this->blog_id = $core->blog->id; | 
|---|
| 33 |           $this->table = $core->prefix.'category'; | 
|---|
| 34 |           $this->add_condition = array('blog_id' => "'".$this->con->escape($this->blog_id)."'"); | 
|---|
| 35 |      } | 
|---|
| 36 |       | 
|---|
| 37 |      public function getChildren($start=0,$id=null,$sort='asc',$fields=array()) | 
|---|
| 38 |      { | 
|---|
| 39 |           $fields = array_merge(array('cat_title','cat_url','cat_desc'),$fields); | 
|---|
| 40 |           return parent::getChildren($start,$id,$sort,$fields); | 
|---|
| 41 |      } | 
|---|
| 42 |       | 
|---|
| 43 |      public function getParents($id,$fields=array()) | 
|---|
| 44 |      { | 
|---|
| 45 |           $fields = array_merge(array('cat_title','cat_url','cat_desc'),$fields); | 
|---|
| 46 |           return parent::getParents($id,$fields); | 
|---|
| 47 |      } | 
|---|
| 48 |       | 
|---|
| 49 |      public function getParent($id,$fields=array()) | 
|---|
| 50 |      { | 
|---|
| 51 |           $fields = array_merge(array('cat_title','cat_url','cat_desc'),$fields); | 
|---|
| 52 |           return parent::getParent($id,$fields); | 
|---|
| 53 |      } | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | abstract class nestedTree | 
|---|
| 57 | { | 
|---|
| 58 |      protected $con; | 
|---|
| 59 |       | 
|---|
| 60 |      protected $table; | 
|---|
| 61 |      protected $f_left; | 
|---|
| 62 |      protected $f_right; | 
|---|
| 63 |      protected $f_id; | 
|---|
| 64 |       | 
|---|
| 65 |      protected $add_condition = array(); | 
|---|
| 66 |       | 
|---|
| 67 |      protected $parents; | 
|---|
| 68 |       | 
|---|
| 69 |      public function __construct($con) | 
|---|
| 70 |      { | 
|---|
| 71 |           $this->con =& $con; | 
|---|
| 72 |      } | 
|---|
| 73 |       | 
|---|
| 74 |      public function getChildren($start=0,$id=null,$sort='asc',$fields=array()) | 
|---|
| 75 |      { | 
|---|
| 76 |           $fields = count($fields) > 0 ? ', C2.'.implode(', C2.',$fields) : ''; | 
|---|
| 77 |            | 
|---|
| 78 |           $sql = 'SELECT C2.'.$this->f_id.', C2.'.$this->f_left.', C2.'.$this->f_right.', COUNT(C1.'.$this->f_id.') AS level ' | 
|---|
| 79 |           . $fields.' '   | 
|---|
| 80 |           . 'FROM '.$this->table.' AS C1, '.$this->table.' AS C2 %s ' | 
|---|
| 81 |           . 'WHERE C2.'.$this->f_left.' BETWEEN C1.'.$this->f_left.' AND C1.'.$this->f_right.' ' | 
|---|
| 82 |           . ' %s ' | 
|---|
| 83 |           . $this->getCondition('AND','C2.') | 
|---|
| 84 |           . $this->getCondition('AND','C1.') | 
|---|
| 85 |           . 'GROUP BY C2.'.$this->f_id.', C2.'.$this->f_left.', C2.'.$this->f_right.' '.$fields.' ' | 
|---|
| 86 |           . ' %s ' | 
|---|
| 87 |           . 'ORDER BY C2.'.$this->f_left.' '.($sort == 'asc' ? 'ASC' : 'DESC').' '; | 
|---|
| 88 |            | 
|---|
| 89 |           $from = $where = ''; | 
|---|
| 90 |           if ($start > 0) { | 
|---|
| 91 |                $from = ', '.$this->table.' AS C3'; | 
|---|
| 92 |                $where = 'AND C3.'.$this->f_id.' = '.(integer) $start.' AND C1.'.$this->f_left.' >= C3.'.$this->f_left.' AND C1.'.$this->f_right.' <= C3.'.$this->f_right; | 
|---|
| 93 |                $where .= $this->getCondition('AND','C3.'); | 
|---|
| 94 |           } | 
|---|
| 95 |            | 
|---|
| 96 |           $having = ''; | 
|---|
| 97 |           if ($id !== null) { | 
|---|
| 98 |                $having = ' HAVING C2.'.$this->f_id.' = '.(integer) $id; | 
|---|
| 99 |           } | 
|---|
| 100 |            | 
|---|
| 101 |           $sql = sprintf($sql,$from,$where,$having); | 
|---|
| 102 |            | 
|---|
| 103 |           return $this->con->select($sql); | 
|---|
| 104 |      } | 
|---|
| 105 |       | 
|---|
| 106 |      public function getParents($id,$fields=array()) | 
|---|
| 107 |      { | 
|---|
| 108 |           $fields = count($fields) > 0 ? ', C1.'.implode(', C1.',$fields) : ''; | 
|---|
| 109 |            | 
|---|
| 110 |           return $this->con->select( | 
|---|
| 111 |                'SELECT C1.'.$this->f_id.' '.$fields.' ' | 
|---|
| 112 |                . 'FROM '.$this->table.' C1, '.$this->table.' C2 ' | 
|---|
| 113 |                . 'WHERE C2.'.$this->f_id.' = '.(integer) $id.' ' | 
|---|
| 114 |                . 'AND C1.'.$this->f_left.' < C2.'.$this->f_left.' ' | 
|---|
| 115 |                . 'AND C1.'.$this->f_right.' > C2.'.$this->f_right.' ' | 
|---|
| 116 |                . $this->getCondition('AND','C2.') | 
|---|
| 117 |                . $this->getCondition('AND','C1.') | 
|---|
| 118 |                . 'ORDER BY C1.'.$this->f_left.' ASC ' | 
|---|
| 119 |           ); | 
|---|
| 120 |      } | 
|---|
| 121 |       | 
|---|
| 122 |      public function getParent($id,$fields=array()) | 
|---|
| 123 |      { | 
|---|
| 124 |           $fields = count($fields) > 0 ? ', C1.'.implode(', C1.',$fields) : ''; | 
|---|
| 125 |            | 
|---|
| 126 |           return $this->con->select( | 
|---|
| 127 |                'SELECT C1.'.$this->f_id.' '.$fields.' ' | 
|---|
| 128 |                . 'FROM '.$this->table.' C1, '.$this->table.' C2 ' | 
|---|
| 129 |                . 'WHERE C2.'.$this->f_id.' = '.(integer) $id.' ' | 
|---|
| 130 |                . 'AND C1.'.$this->f_left.' < C2.'.$this->f_left.' ' | 
|---|
| 131 |                . 'AND C1.'.$this->f_right.' > C2.'.$this->f_right.' ' | 
|---|
| 132 |                . $this->getCondition('AND','C2.') | 
|---|
| 133 |                . $this->getCondition('AND','C1.') | 
|---|
| 134 |                . 'ORDER BY C1.'.$this->f_left.' DESC ' | 
|---|
| 135 |                . $this->con->limit(1) | 
|---|
| 136 |           ); | 
|---|
| 137 |      } | 
|---|
| 138 |       | 
|---|
| 139 |      /* ------------------------------------------------ | 
|---|
| 140 |       * Tree manipulations | 
|---|
| 141 |       * ---------------------------------------------- */ | 
|---|
| 142 |      public function addNode($data,$target=0) | 
|---|
| 143 |      { | 
|---|
| 144 |           if (!is_array($data) && !($data instanceof cursor)) { | 
|---|
| 145 |                throw new Exception('Invalid data block'); | 
|---|
| 146 |           } | 
|---|
| 147 |            | 
|---|
| 148 |           if (is_array($data)) | 
|---|
| 149 |           { | 
|---|
| 150 |                $D = $data; | 
|---|
| 151 |                $data = $this->con->openCursor($this->table); | 
|---|
| 152 |                foreach ($D as $k => $v) { | 
|---|
| 153 |                     $data->{$k} = $v; | 
|---|
| 154 |                } | 
|---|
| 155 |                unset($D); | 
|---|
| 156 |           } | 
|---|
| 157 |            | 
|---|
| 158 |           # We want to put it at the end | 
|---|
| 159 |           $this->con->writeLock($this->table); | 
|---|
| 160 |           try | 
|---|
| 161 |           { | 
|---|
| 162 |                $rs = $this->con->select('SELECT MAX('.$this->f_id.') as n_id FROM '.$this->table); | 
|---|
| 163 |                $id = $rs->n_id; | 
|---|
| 164 |                 | 
|---|
| 165 |                $rs = $this->con->select( | 
|---|
| 166 |                     'SELECT MAX('.$this->f_right.') as n_r '. | 
|---|
| 167 |                     'FROM '.$this->table. | 
|---|
| 168 |                     $this->getCondition('WHERE') | 
|---|
| 169 |                ); | 
|---|
| 170 |                $last = $rs->n_r == 0 ? 1 : $rs->n_r; | 
|---|
| 171 |                 | 
|---|
| 172 |                $data->{$this->f_id} = $id+1; | 
|---|
| 173 |                $data->{$this->f_left} = $last+1; | 
|---|
| 174 |                $data->{$this->f_right} = $last+2; | 
|---|
| 175 |                 | 
|---|
| 176 |                $data->insert(); | 
|---|
| 177 |                $this->con->unlock(); | 
|---|
| 178 |                try { | 
|---|
| 179 |                     $this->setNodeParent($id+1,$target); | 
|---|
| 180 |                     return $data->{$this->f_id}; | 
|---|
| 181 |                } catch (Exception $e) {} # We don't mind error in this case | 
|---|
| 182 |           } | 
|---|
| 183 |           catch (Exception $e) | 
|---|
| 184 |           { | 
|---|
| 185 |                $this->con->unlock(); | 
|---|
| 186 |                throw $e; | 
|---|
| 187 |           } | 
|---|
| 188 |      } | 
|---|
| 189 |       | 
|---|
| 190 |      public function deleteNode($node,$keep_children=true) | 
|---|
| 191 |      { | 
|---|
| 192 |           $node = (integer) $node; | 
|---|
| 193 |            | 
|---|
| 194 |           $rs = $this->getChildren(0,$node); | 
|---|
| 195 |           if ($rs->isEmpty()) { | 
|---|
| 196 |                throw new Exception('Node does not exist.'); | 
|---|
| 197 |           } | 
|---|
| 198 |           $node_left = (integer) $rs->{$this->f_left}; | 
|---|
| 199 |           $node_right = (integer) $rs->{$this->f_right}; | 
|---|
| 200 |            | 
|---|
| 201 |           try | 
|---|
| 202 |           { | 
|---|
| 203 |                $this->con->begin(); | 
|---|
| 204 |                 | 
|---|
| 205 |                if ($keep_children) | 
|---|
| 206 |                { | 
|---|
| 207 |                     $this->con->execute('DELETE FROM '.$this->table.' WHERE '.$this->f_id.' = '.$node); | 
|---|
| 208 |                      | 
|---|
| 209 |                     $sql = 'UPDATE '.$this->table.' SET ' | 
|---|
| 210 |                     . $this->f_right.' = CASE ' | 
|---|
| 211 |                     .    'WHEN '.$this->f_right.' BETWEEN '.$node_left.' AND '.$node_right.' ' | 
|---|
| 212 |                     .         'THEN '.$this->f_right.' - 1 ' | 
|---|
| 213 |                     .    'WHEN '.$this->f_right.' > '.$node_right.' ' | 
|---|
| 214 |                     .         'THEN '.$this->f_right.' - 2 ' | 
|---|
| 215 |                     .    'ELSE '.$this->f_right.' ' | 
|---|
| 216 |                     .    'END, ' | 
|---|
| 217 |                     . $this->f_left.' = CASE ' | 
|---|
| 218 |                     .    'WHEN '.$this->f_left.' BETWEEN '.$node_left.' AND '.$node_right.' ' | 
|---|
| 219 |                     .         'THEN '.$this->f_left.' - 1 ' | 
|---|
| 220 |                     .    'WHEN '.$this->f_left.' > '.$node_right.' ' | 
|---|
| 221 |                     .         'THEN '.$this->f_left.' - 2 ' | 
|---|
| 222 |                     .    'ELSE '.$this->f_left.' ' | 
|---|
| 223 |                     .    'END ' | 
|---|
| 224 |                     . 'WHERE '.$this->f_right.' > '.$node_left | 
|---|
| 225 |                     . $this->getCondition(); | 
|---|
| 226 |                      | 
|---|
| 227 |                     $this->con->execute($sql); | 
|---|
| 228 |                } | 
|---|
| 229 |                else | 
|---|
| 230 |                { | 
|---|
| 231 |                     $this->con->execute('DELETE FROM '.$this->table.' WHERE '.$this->f_left.' BETWEEN '.$node_left.' AND '.$node_right); | 
|---|
| 232 |                      | 
|---|
| 233 |                     $node_delta = $node_right - $node_left + 1; | 
|---|
| 234 |                     $sql = 'UPDATE '.$this->table.' SET ' | 
|---|
| 235 |                     . $this->f_left.' = CASE ' | 
|---|
| 236 |                     .    'WHEN '.$this->f_left.' > '.$node_left.' ' | 
|---|
| 237 |                     .         'THEN '.$this->f_left.' - ('.$node_delta.') ' | 
|---|
| 238 |                     .    'ELSE '.$this->f_left.' ' | 
|---|
| 239 |                     .    'END, ' | 
|---|
| 240 |                     . $this->f_right.' = CASE ' | 
|---|
| 241 |                     .    'WHEN '.$this->f_right.' > '.$node_left.' ' | 
|---|
| 242 |                     .         'THEN '.$this->f_right.' - ('.$node_delta.') ' | 
|---|
| 243 |                     .    'ELSE '.$this->f_right.' ' | 
|---|
| 244 |                     .    'END ' | 
|---|
| 245 |                     . 'WHERE '.$this->f_right.' > '.$node_right | 
|---|
| 246 |                     . $this->getCondition(); | 
|---|
| 247 |                } | 
|---|
| 248 |                 | 
|---|
| 249 |                $this->con->commit(); | 
|---|
| 250 |           } | 
|---|
| 251 |           catch (Exception $e) | 
|---|
| 252 |           { | 
|---|
| 253 |                $this->con->rollback(); | 
|---|
| 254 |                throw $e; | 
|---|
| 255 |           } | 
|---|
| 256 |      } | 
|---|
| 257 |       | 
|---|
| 258 |      public function resetOrder() | 
|---|
| 259 |      { | 
|---|
| 260 |           $rs = $this->con->select( | 
|---|
| 261 |                'SELECT '.$this->f_id.' ' | 
|---|
| 262 |                .'FROM '.$this->table.' ' | 
|---|
| 263 |                .$this->getCondition('WHERE') | 
|---|
| 264 |                .'ORDER BY '.$this->f_left.' ASC ' | 
|---|
| 265 |           ); | 
|---|
| 266 |            | 
|---|
| 267 |           $lft = 2; | 
|---|
| 268 |           $this->con->begin(); | 
|---|
| 269 |           try | 
|---|
| 270 |           { | 
|---|
| 271 |                while ($rs->fetch()) { | 
|---|
| 272 |                     $this->con->execute( | 
|---|
| 273 |                          'UPDATE '.$this->table.' SET ' | 
|---|
| 274 |                          .$this->f_left.' = '.($lft++).', ' | 
|---|
| 275 |                          .$this->f_right.' = '.($lft++).' ' | 
|---|
| 276 |                          .'WHERE '.$this->f_id .' = '.(integer) $rs->{$this->f_id}.' ' | 
|---|
| 277 |                          .$this->getCondition() | 
|---|
| 278 |                     ); | 
|---|
| 279 |                } | 
|---|
| 280 |                $this->con->commit(); | 
|---|
| 281 |           } | 
|---|
| 282 |           catch (Exception $e) | 
|---|
| 283 |           { | 
|---|
| 284 |                $this->con->rollback(); | 
|---|
| 285 |                throw $e; | 
|---|
| 286 |           } | 
|---|
| 287 |      } | 
|---|
| 288 |       | 
|---|
| 289 |      public function setNodeParent($node,$target=0) | 
|---|
| 290 |      { | 
|---|
| 291 |           if ($node == $target) { | 
|---|
| 292 |                return; | 
|---|
| 293 |           } | 
|---|
| 294 |           $node = (integer) $node; | 
|---|
| 295 |           $target = (integer) $target; | 
|---|
| 296 |            | 
|---|
| 297 |           $rs = $this->getChildren(0,$node); | 
|---|
| 298 |           if ($rs->isEmpty()) { | 
|---|
| 299 |                throw new Exception('Node does not exist.'); | 
|---|
| 300 |           } | 
|---|
| 301 |           $node_left = (integer) $rs->{$this->f_left}; | 
|---|
| 302 |           $node_right = (integer) $rs->{$this->f_right}; | 
|---|
| 303 |           $node_level = (integer) $rs->level; | 
|---|
| 304 |            | 
|---|
| 305 |           if ($target > 0) | 
|---|
| 306 |           { | 
|---|
| 307 |                $rs = $this->getChildren(0,$target); | 
|---|
| 308 |           } | 
|---|
| 309 |           else | 
|---|
| 310 |           { | 
|---|
| 311 |                $rs = $this->con->select( | 
|---|
| 312 |                     'SELECT MIN('.$this->f_left.')-1 AS '.$this->f_left.', MAX('.$this->f_right.')+1 AS '.$this->f_right.', 0 AS level '. | 
|---|
| 313 |                     'FROM '.$this->table.' '. | 
|---|
| 314 |                     $this->getCondition('WHERE') | 
|---|
| 315 |                ); | 
|---|
| 316 |           } | 
|---|
| 317 |           $target_left = (integer) $rs->{$this->f_left}; | 
|---|
| 318 |           $target_right = (integer) $rs->{$this->f_right}; | 
|---|
| 319 |           $target_level = (integer) $rs->level; | 
|---|
| 320 |            | 
|---|
| 321 |           if ($node_left == $target_left | 
|---|
| 322 |                || ($target_left >= $node_left && $target_left <= $node_right) | 
|---|
| 323 |                || ($node_level == $target_level+1 && $node_left > $target_left && $node_right < $target_right) | 
|---|
| 324 |           ) | 
|---|
| 325 |           { | 
|---|
| 326 |                throw new Exception('Cannot move tree'); | 
|---|
| 327 |           } | 
|---|
| 328 |            | 
|---|
| 329 |           if ($target_left < $node_left && $target_right > $node_right && $target_level < $node_level -1) | 
|---|
| 330 |           { | 
|---|
| 331 |                $sql = 'UPDATE '.$this->table.' SET ' | 
|---|
| 332 |                . $this->f_right.' = CASE ' | 
|---|
| 333 |                .    'WHEN '.$this->f_right.' BETWEEN '.($node_right+1).' AND '.($target_right-1).' ' | 
|---|
| 334 |                .         'THEN '.$this->f_right.'-('.($node_right-$node_left+1).') ' | 
|---|
| 335 |                .    'WHEN '.$this->f_left.' BETWEEN '.$node_left.' AND '.$node_right.' ' | 
|---|
| 336 |                .         'THEN '.$this->f_right.'+'.((($target_right-$node_right-$node_level+$target_level)/2)*2+$node_level-$target_level-1).' ' | 
|---|
| 337 |                .    'ELSE ' | 
|---|
| 338 |                .         $this->f_right.' ' | 
|---|
| 339 |                .    'END, ' | 
|---|
| 340 |                . $this->f_left.' = CASE ' | 
|---|
| 341 |                .    'WHEN '.$this->f_left.' BETWEEN '.($node_right+1).' AND '.($target_right-1).' ' | 
|---|
| 342 |                .         'THEN '.$this->f_left.'-('.($node_right-$node_left+1).') ' | 
|---|
| 343 |                .    'WHEN '.$this->f_left.' BETWEEN '.$node_left.' AND '.$node_right.' ' | 
|---|
| 344 |                .         'THEN '.$this->f_left.'+'.((($target_right-$node_right-$node_level+$target_level)/2)*2+$node_level-$target_level-1).' ' | 
|---|
| 345 |                .    'ELSE '.$this->f_left.' ' | 
|---|
| 346 |                .    'END ' | 
|---|
| 347 |                . 'WHERE '.$this->f_left.' BETWEEN '.($target_left+1).' AND '.($target_right-1).''; | 
|---|
| 348 |           } | 
|---|
| 349 |           elseif ($target_left < $node_left) | 
|---|
| 350 |           { | 
|---|
| 351 |                $sql = 'UPDATE '.$this->table.' SET ' | 
|---|
| 352 |                . $this->f_left.' = CASE ' | 
|---|
| 353 |                .    'WHEN '.$this->f_left.' BETWEEN '.$target_right.' AND '.($node_left-1).' ' | 
|---|
| 354 |                .         'THEN '.$this->f_left.'+'.($node_right-$node_left+1).' ' | 
|---|
| 355 |                .    'WHEN '.$this->f_left.' BETWEEN '.$node_left.' AND '.$node_right.' ' | 
|---|
| 356 |                .         'THEN '.$this->f_left.'-('.($node_left-$target_right).') ' | 
|---|
| 357 |                .    'ELSE '.$this->f_left .' ' | 
|---|
| 358 |                .    'END, ' | 
|---|
| 359 |                . $this->f_right.' = CASE ' | 
|---|
| 360 |                .    'WHEN '.$this->f_right.' BETWEEN '.$target_right.' AND '.$node_left.' ' | 
|---|
| 361 |                .         'THEN '.$this->f_right.'+'.($node_right-$node_left+1).' ' | 
|---|
| 362 |                .    'WHEN '.$this->f_right.' BETWEEN '.$node_left.' AND '.$node_right.' ' | 
|---|
| 363 |                .         'THEN '.$this->f_right.'-('.($node_left-$target_right).') ' | 
|---|
| 364 |                .    'ELSE '.$this->f_right.' ' | 
|---|
| 365 |                .    'END ' | 
|---|
| 366 |                . 'WHERE ('.$this->f_left.' BETWEEN '.$target_left.' AND '.$node_right. ' ' | 
|---|
| 367 |                .    'OR '.$this->f_right.' BETWEEN '.$target_left.' AND '.$node_right.')'; | 
|---|
| 368 |           } | 
|---|
| 369 |           else | 
|---|
| 370 |           { | 
|---|
| 371 |                $sql = 'UPDATE '.$this->table.' SET ' | 
|---|
| 372 |                . $this->f_left.' = CASE ' | 
|---|
| 373 |                .    'WHEN '.$this->f_left.' BETWEEN '.$node_right.' AND '.$target_right.' ' | 
|---|
| 374 |                .         'THEN '.$this->f_left.'-'.($node_right-$node_left+1).' ' | 
|---|
| 375 |                .    'WHEN '.$this->f_left.' BETWEEN '.$node_left.' AND '.$node_right.' ' | 
|---|
| 376 |                .         'THEN '.$this->f_left.'+'.($target_right-1-$node_right).' ' | 
|---|
| 377 |                .    'ELSE '.$this->f_left.' ' | 
|---|
| 378 |                .    'END, ' | 
|---|
| 379 |                . $this->f_right.' = CASE ' | 
|---|
| 380 |                .    'WHEN '.$this->f_right.' BETWEEN '.($node_right+1).' AND '.($target_right-1).' ' | 
|---|
| 381 |                .         'THEN '.$this->f_right.'-'.($node_right-$node_left+1).' ' | 
|---|
| 382 |                .    'WHEN '.$this->f_right.' BETWEEN '.$node_left.' AND '.$node_right.' ' | 
|---|
| 383 |                .         'THEN '.$this->f_right.'+'.($target_right-1-$node_right).' ' | 
|---|
| 384 |                .    'ELSE '.$this->f_right.' ' | 
|---|
| 385 |                .    'END ' | 
|---|
| 386 |                . 'WHERE ('.$this->f_left.' BETWEEN '.$node_left.' AND '.$target_right.' ' | 
|---|
| 387 |                .    'OR '.$this->f_right.' BETWEEN '.$node_left.' AND '.$target_right.')'; | 
|---|
| 388 |           } | 
|---|
| 389 |            | 
|---|
| 390 |           $sql .= ' '.$this->getCondition(); | 
|---|
| 391 |            | 
|---|
| 392 |           $this->con->execute($sql); | 
|---|
| 393 |      } | 
|---|
| 394 |       | 
|---|
| 395 |      public function setNodePosition($nodeA,$nodeB,$position='after') | 
|---|
| 396 |      { | 
|---|
| 397 |           $nodeA = (integer) $nodeA; | 
|---|
| 398 |           $nodeB = (integer) $nodeB; | 
|---|
| 399 |            | 
|---|
| 400 |           $rs = $this->getChildren(0,$nodeA); | 
|---|
| 401 |           if ($rs->isEmpty()) { | 
|---|
| 402 |                throw new Exception('Node does not exist.'); | 
|---|
| 403 |           } | 
|---|
| 404 |           $A_left = $rs->{$this->f_left}; | 
|---|
| 405 |           $A_right = $rs->{$this->f_right}; | 
|---|
| 406 |           $A_level = $rs->level; | 
|---|
| 407 |            | 
|---|
| 408 |           $rs = $this->getChildren(0,$nodeB); | 
|---|
| 409 |           if ($rs->isEmpty()) { | 
|---|
| 410 |                throw new Exception('Node does not exist.'); | 
|---|
| 411 |           } | 
|---|
| 412 |           $B_left = $rs->{$this->f_left}; | 
|---|
| 413 |           $B_right = $rs->{$this->f_right}; | 
|---|
| 414 |           $B_level = $rs->level; | 
|---|
| 415 |            | 
|---|
| 416 |           if ($A_level != $B_level) { | 
|---|
| 417 |                throw new Exception('Cannot change position'); | 
|---|
| 418 |           } | 
|---|
| 419 |            | 
|---|
| 420 |           $rs = $this->getParents($nodeA); | 
|---|
| 421 |           $parentA = $rs->isEmpty() ? 0 : $rs->{$this->f_id}; | 
|---|
| 422 |           $rs = $this->getParents($nodeB); | 
|---|
| 423 |           $parentB = $rs->isEmpty() ? 0 : $rs->{$this->f_id}; | 
|---|
| 424 |            | 
|---|
| 425 |           if ($parentA != $parentB) { | 
|---|
| 426 |                throw new Exception('Cannot change position'); | 
|---|
| 427 |           } | 
|---|
| 428 |            | 
|---|
| 429 |           if ($position == 'before') | 
|---|
| 430 |           { | 
|---|
| 431 |                if ($A_left > $B_left) { | 
|---|
| 432 |                     $sql = 'UPDATE '.$this->table.' SET ' | 
|---|
| 433 |                     . $this->f_right.' = CASE WHEN '.$this->f_left.' BETWEEN '.$A_left.' AND '.$A_right.' THEN '.$this->f_right.' - ('.($A_left - $B_left).') ' | 
|---|
| 434 |                     . 'WHEN '.$this->f_left.' BETWEEN '.$B_left.' AND '.($A_left - 1).' THEN '.$this->f_right.' +  '.($A_right - $A_left + 1).' ELSE '.$this->f_right.' END, ' | 
|---|
| 435 |                     . $this->f_left.' = CASE WHEN '.$this->f_left.' BETWEEN '.$A_left.' AND '.$A_right.' THEN '.$this->f_left.' - ('.($A_left - $B_left).') ' | 
|---|
| 436 |                     . 'WHEN '.$this->f_left.' BETWEEN '.$B_left.' AND '.($A_left - 1).' THEN '.$this->f_left.' + '.($A_right - $A_left + 1).' ELSE '.$this->f_left.' END ' | 
|---|
| 437 |                     . 'WHERE '.$this->f_left.' BETWEEN '.$B_left.' AND '.$A_right; | 
|---|
| 438 |                } else { | 
|---|
| 439 |                     $sql = 'UPDATE '.$this->table.' SET ' | 
|---|
| 440 |                     . $this->f_right.' = CASE WHEN '.$this->f_left.' BETWEEN '.$A_left.' AND '.$A_right.' THEN '.$this->f_right.' + '.(($B_left - $A_left) - ($A_right - $A_left + 1)).' ' | 
|---|
| 441 |                     . 'WHEN '.$this->f_left.' BETWEEN '.($A_right + 1).' AND '.($B_left - 1).' THEN '.$this->f_right.' - ('.(($A_right - $A_left + 1)).') ELSE '.$this->f_right.' END, ' | 
|---|
| 442 |                     . $this->f_left.' = CASE WHEN '.$this->f_left.' BETWEEN '.$A_left.' AND '.$A_right.' THEN '.$this->f_left.' + '.(($B_left - $A_left) - ($A_right - $A_left + 1)).' ' | 
|---|
| 443 |                     . 'WHEN '.$this->f_left.' BETWEEN '.($A_right + 1).' AND '.($B_left - 1).' THEN '.$this->f_left.' - ('.($A_right - $A_left + 1).') ELSE '.$this->f_left.' END ' | 
|---|
| 444 |                     . 'WHERE '.$this->f_left.' BETWEEN '.$A_left.' AND '.($B_left - 1); | 
|---|
| 445 |                } | 
|---|
| 446 |           } | 
|---|
| 447 |           else | 
|---|
| 448 |           { | 
|---|
| 449 |                if ($A_left > $B_left) { | 
|---|
| 450 |                     $sql = 'UPDATE '.$this->table.' SET ' | 
|---|
| 451 |                     . $this->f_right.' = CASE WHEN '.$this->f_left.' BETWEEN '.$A_left.' AND '.$A_right.' THEN '.$this->f_right.' - ('.($A_left - $B_left - ($B_right - $B_left + 1)).') ' | 
|---|
| 452 |                     . 'WHEN '.$this->f_left.' BETWEEN '.($B_right + 1).' AND '.($A_left - 1).' THEN '.$this->f_right.' +  '.($A_right - $A_left + 1).' ELSE '.$this->f_right.' END, ' | 
|---|
| 453 |                     . $this->f_left.' = CASE WHEN '.$this->f_left.' BETWEEN '.$A_left.' AND '.$A_right.' THEN '.$this->f_left.' - ('.($A_left - $B_left - ($B_right - $B_left + 1)).') ' | 
|---|
| 454 |                     . 'WHEN '.$this->f_left.' BETWEEN '.($B_right + 1).' AND '.($A_left - 1).' THEN '.$this->f_left.' + '.($A_right - $A_left + 1).' ELSE '.$this->f_left.' END ' | 
|---|
| 455 |                     . 'WHERE '.$this->f_left.' BETWEEN '.($B_right + 1).' AND '.$A_right; | 
|---|
| 456 |                } else { | 
|---|
| 457 |                     $sql = 'UPDATE '.$this->table.' SET ' | 
|---|
| 458 |                     . $this->f_right.' = CASE WHEN '.$this->f_left.' BETWEEN '.$A_left.' AND '.$A_right.' THEN '.$this->f_right.' + '.($B_right - $A_right).' ' | 
|---|
| 459 |                     . 'WHEN '.$this->f_left.' BETWEEN '.($A_right + 1).' AND '.$B_right.' THEN '.$this->f_right.' - ('.(($A_right - $A_left + 1)).') ELSE '.$this->f_right.' END, ' | 
|---|
| 460 |                     . $this->f_left.' = CASE WHEN '.$this->f_left.' BETWEEN '.$A_left.' AND '.$A_right.' THEN '.$this->f_left.' + '.($B_right - $A_right).' ' | 
|---|
| 461 |                     . 'WHEN '.$this->f_left.' BETWEEN '.($A_right + 1).' AND '.$B_right.' THEN '.$this->f_left.' - ('.($A_right - $A_left + 1).') ELSE '.$this->f_left.' END ' | 
|---|
| 462 |                     . 'WHERE '.$this->f_left.' BETWEEN '.$A_left.' AND '.$B_right; | 
|---|
| 463 |                } | 
|---|
| 464 |           } | 
|---|
| 465 |            | 
|---|
| 466 |           $sql .= $this->getCondition(); | 
|---|
| 467 |           $this->con->execute($sql); | 
|---|
| 468 |      } | 
|---|
| 469 |       | 
|---|
| 470 |      protected function getCondition($start='AND',$prefix='') | 
|---|
| 471 |      { | 
|---|
| 472 |           if (empty($this->add_condition)) { | 
|---|
| 473 |                return ''; | 
|---|
| 474 |           } | 
|---|
| 475 |            | 
|---|
| 476 |           $w = array(); | 
|---|
| 477 |           foreach ($this->add_condition as $c => $n) { | 
|---|
| 478 |                $w[] = $prefix.$c.' = '.$n; | 
|---|
| 479 |           } | 
|---|
| 480 |           return ' '.$start.' '.implode(' AND ',$w).' '; | 
|---|
| 481 |      } | 
|---|
| 482 | } | 
|---|
| 483 | ?> | 
|---|