22
33namespace Gedmo \Tree \Strategy \ORM ;
44
5+ use Doctrine \Common \Collections \ArrayCollection ;
6+ use Doctrine \Common \Collections \Criteria ;
57use Doctrine \ORM \EntityManagerInterface ;
68use Doctrine \ORM \Mapping \ClassMetadata ;
79use Gedmo \Exception \UnexpectedValueException ;
@@ -123,7 +125,9 @@ public function processScheduledInsertion($em, $node, AdapterInterface $ea)
123125 if (isset ($ config ['level ' ])) {
124126 $ meta ->getReflectionProperty ($ config ['level ' ])->setValue ($ node , 0 );
125127 }
126- if (isset ($ config ['root ' ]) && !$ meta ->hasAssociation ($ config ['root ' ])) {
128+ if (isset ($ config ['root ' ]) && !$ meta ->hasAssociation ($ config ['root ' ]) && !$ config ['rootIdentifierMethod ' ]) {
129+ $ meta ->getReflectionProperty ($ config ['root ' ])->setValue ($ node , 0 );
130+ } else if (isset ($ config ['rootIdentifierMethod ' ]) && is_null ($ meta ->getReflectionProperty ($ config ['root ' ])->getValue ($ node ))) {
127131 $ meta ->getReflectionProperty ($ config ['root ' ])->setValue ($ node , 0 );
128132 }
129133 }
@@ -203,18 +207,17 @@ public function processScheduledDelete($em, $node)
203207 $ qb = $ em ->createQueryBuilder ();
204208 $ qb ->select ('node ' )
205209 ->from ($ config ['useObjectClass ' ], 'node ' )
206- ->where ($ qb ->expr ()->between ('node. ' .$ config ['left ' ], '?1 ' , '?2 ' ))
207- ->setParameters (array (1 => $ leftValue , 2 => $ rightValue ))
208- ;
210+ ->where ($ qb ->expr ()->between ('node. ' . $ config ['left ' ], '?1 ' , '?2 ' ))
211+ ->setParameters (array (1 => $ leftValue , 2 => $ rightValue ));
209212
210213 if (isset ($ config ['root ' ])) {
211- $ qb ->andWhere ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
214+ $ qb ->andWhere ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
212215 $ qb ->setParameter ('rid ' , $ rootId );
213216 }
214217 $ q = $ qb ->getQuery ();
215218 // get nodes for deletion
216219 $ nodes = $ q ->getResult ();
217- foreach ((array ) $ nodes as $ removalNode ) {
220+ foreach ((array )$ nodes as $ removalNode ) {
218221 $ uow ->scheduleForDelete ($ removalNode );
219222 }
220223 }
@@ -311,7 +314,7 @@ public function updateNode(EntityManagerInterface $em, $node, $parent, $position
311314 $ level = 0 ;
312315 $ treeSize = $ right - $ left + 1 ;
313316 $ newRoot = null ;
314- if ($ parent ) {
317+ if ($ parent ) { // || (!$parent && isset($config['rootIdentifierMethod']))
315318 $ wrappedParent = AbstractWrapper::wrap ($ parent , $ em );
316319
317320 $ parentRoot = isset ($ config ['root ' ]) ? $ wrappedParent ->getPropertyValue ($ config ['root ' ]) : null ;
@@ -342,10 +345,15 @@ public function updateNode(EntityManagerInterface $em, $node, $parent, $position
342345 $ level ++;
343346 } else {
344347 $ newParent = $ wrappedParent ->getPropertyValue ($ config ['parent ' ]);
345- if (is_null ($ newParent ) && (isset ($ config ['root ' ]) || $ isNewNode )) {
348+
349+ if (is_null ($ newParent ) && ((isset ($ config ['root ' ]) && $ config ['root ' ] == $ config ['parent ' ]) || $ isNewNode )) {
346350 throw new UnexpectedValueException ("Cannot persist sibling for a root node, tree operation is not possible " );
351+ } else if (is_null ($ newParent ) && (isset ($ config ['root ' ]) || $ isNewNode )) {
352+ // root is a different column from parent (pointing to another table?), do nothing
353+ } else {
354+ $ wrapped ->setPropertyValue ($ config ['parent ' ], $ newParent );
347355 }
348- $ wrapped -> setPropertyValue ( $ config [ ' parent ' ], $ newParent );
356+
349357 $ em ->getUnitOfWork ()->recomputeSingleEntityChangeSet ($ meta , $ node );
350358 $ start = $ parentLeft ;
351359 }
@@ -358,10 +366,14 @@ public function updateNode(EntityManagerInterface $em, $node, $parent, $position
358366 $ level ++;
359367 } else {
360368 $ newParent = $ wrappedParent ->getPropertyValue ($ config ['parent ' ]);
361- if (is_null ($ newParent ) && (isset ($ config ['root ' ]) || $ isNewNode )) {
369+ if (is_null ($ newParent ) && (( isset ($ config ['root ' ]) && $ config [ ' root ' ] == $ config [ ' parent ' ]) || $ isNewNode )) {
362370 throw new UnexpectedValueException ("Cannot persist sibling for a root node, tree operation is not possible " );
371+ } else if (is_null ($ newParent ) && (isset ($ config ['root ' ]) || $ isNewNode )) {
372+ // root is a different column from parent (pointing to another table?), do nothing
373+ } else {
374+ $ wrapped ->setPropertyValue ($ config ['parent ' ], $ newParent );
363375 }
364- $ wrapped -> setPropertyValue ( $ config [ ' parent ' ], $ newParent );
376+
365377 $ em ->getUnitOfWork ()->recomputeSingleEntityChangeSet ($ meta , $ node );
366378 $ start = $ parentRight + 1 ;
367379 }
@@ -445,8 +457,23 @@ public function updateNode(EntityManagerInterface $em, $node, $parent, $position
445457 }
446458 } else {
447459 $ start = 1 ;
448-
449- if ($ meta ->isSingleValuedAssociation ($ config ['root ' ])) {
460+ if (isset ($ config ['rootIdentifierMethod ' ])) {
461+ $ method = $ config ['rootIdentifierMethod ' ];
462+ $ newRoot = $ node ->$ method ();
463+ $ repo = $ em ->getRepository ($ config ['useObjectClass ' ]);
464+
465+ $ criteria = new Criteria ();
466+ $ criteria ->andWhere (Criteria::expr ()->notIn ($ wrapped ->getMetadata ()->identifier [0 ], [$ wrapped ->getIdentifier ()]));
467+ $ criteria ->andWhere (Criteria::expr ()->eq ($ config ['root ' ], $ node ->$ method ()));
468+ $ criteria ->andWhere (Criteria::expr ()->isNull ($ config ['parent ' ]));
469+ $ criteria ->andWhere (Criteria::expr ()->eq ($ config ['level ' ], 0 ));
470+ $ criteria ->orderBy ([$ config ['right ' ] => Criteria::ASC ]);
471+ $ roots = $ repo ->matching ($ criteria )->toArray ();
472+ $ last = array_pop ($ roots );
473+
474+ $ start = ($ last ) ? $ meta ->getFieldValue ($ last , $ config ['right ' ]) + 1 : 1 ;
475+
476+ } else if ($ meta ->isSingleValuedAssociation ($ config ['root ' ])) {
450477 $ newRoot = $ node ;
451478 } else {
452479 $ newRoot = $ wrapped ->getIdentifier ();
@@ -472,28 +499,28 @@ public function updateNode(EntityManagerInterface $em, $node, $parent, $position
472499 $ qb = $ em ->createQueryBuilder ();
473500 $ qb ->update ($ config ['useObjectClass ' ], 'node ' );
474501 if (isset ($ config ['root ' ])) {
475- $ qb ->set ('node. ' . $ config ['root ' ], ':rid ' );
502+ $ qb ->set ('node. ' . $ config ['root ' ], ':rid ' );
476503 $ qb ->setParameter ('rid ' , $ newRoot );
477504 $ wrapped ->setPropertyValue ($ config ['root ' ], $ newRoot );
478505 $ em ->getUnitOfWork ()->setOriginalEntityProperty ($ oid , $ config ['root ' ], $ newRoot );
479506 }
480507 if (isset ($ config ['level ' ])) {
481- $ qb ->set ('node. ' . $ config ['level ' ], $ level );
508+ $ qb ->set ('node. ' . $ config ['level ' ], $ level );
482509 $ wrapped ->setPropertyValue ($ config ['level ' ], $ level );
483510 $ em ->getUnitOfWork ()->setOriginalEntityProperty ($ oid , $ config ['level ' ], $ level );
484511 }
485512 if (isset ($ newParent )) {
486513 $ wrappedNewParent = AbstractWrapper::wrap ($ newParent , $ em );
487514 $ newParentId = $ wrappedNewParent ->getIdentifier ();
488- $ qb ->set ('node. ' . $ config ['parent ' ], ':pid ' );
515+ $ qb ->set ('node. ' . $ config ['parent ' ], ':pid ' );
489516 $ qb ->setParameter ('pid ' , $ newParentId );
490517 $ wrapped ->setPropertyValue ($ config ['parent ' ], $ newParent );
491518 $ em ->getUnitOfWork ()->setOriginalEntityProperty ($ oid , $ config ['parent ' ], $ newParent );
492519 }
493- $ qb ->set ('node. ' . $ config ['left ' ], $ left + $ diff );
494- $ qb ->set ('node. ' . $ config ['right ' ], $ right + $ diff );
520+ $ qb ->set ('node. ' . $ config ['left ' ], $ left + $ diff );
521+ $ qb ->set ('node. ' . $ config ['right ' ], $ right + $ diff );
495522 // node id cannot be null
496- $ qb ->where ($ qb ->expr ()->eq ('node. ' . $ identifierField , ':id ' ));
523+ $ qb ->where ($ qb ->expr ()->eq ('node. ' . $ identifierField , ':id ' ));
497524 $ qb ->setParameter ('id ' , $ nodeId );
498525 $ qb ->getQuery ()->getSingleScalarResult ();
499526 $ wrapped ->setPropertyValue ($ config ['left ' ], $ left + $ diff );
@@ -522,12 +549,11 @@ public function max(EntityManagerInterface $em, $class, $rootId = 0)
522549 $ meta = $ em ->getClassMetadata ($ class );
523550 $ config = $ this ->listener ->getConfiguration ($ em , $ meta ->name );
524551 $ qb = $ em ->createQueryBuilder ();
525- $ qb ->select ($ qb ->expr ()->max ('node. ' .$ config ['right ' ]))
526- ->from ($ config ['useObjectClass ' ], 'node ' )
527- ;
552+ $ qb ->select ($ qb ->expr ()->max ('node. ' . $ config ['right ' ]))
553+ ->from ($ config ['useObjectClass ' ], 'node ' );
528554
529555 if (isset ($ config ['root ' ]) && $ rootId ) {
530- $ qb ->where ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
556+ $ qb ->where ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
531557 $ qb ->setParameter ('rid ' , $ rootId );
532558 }
533559 $ query = $ qb ->getQuery ();
@@ -539,6 +565,10 @@ public function max(EntityManagerInterface $em, $class, $rootId = 0)
539565 /**
540566 * Shift tree left and right values by delta
541567 *
568+ * @param EntityManager $em
569+ * @param string $class
570+ * @param integer $first
571+ * @param integer $delta
542572 * @param EntityManagerInterface $em
543573 * @param string $class
544574 * @param integer $first
@@ -554,22 +584,20 @@ public function shiftRL(EntityManagerInterface $em, $class, $first, $delta, $roo
554584 $ absDelta = abs ($ delta );
555585 $ qb = $ em ->createQueryBuilder ();
556586 $ qb ->update ($ config ['useObjectClass ' ], 'node ' )
557- ->set ('node. ' .$ config ['left ' ], "node. {$ config ['left ' ]} {$ sign } {$ absDelta }" )
558- ->where ($ qb ->expr ()->gte ('node. ' .$ config ['left ' ], $ first ))
559- ;
587+ ->set ('node. ' . $ config ['left ' ], "node. {$ config ['left ' ]} {$ sign } {$ absDelta }" )
588+ ->where ($ qb ->expr ()->gte ('node. ' . $ config ['left ' ], $ first ));
560589 if (isset ($ config ['root ' ])) {
561- $ qb ->andWhere ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
590+ $ qb ->andWhere ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
562591 $ qb ->setParameter ('rid ' , $ root );
563592 }
564593 $ qb ->getQuery ()->getSingleScalarResult ();
565594
566595 $ qb = $ em ->createQueryBuilder ();
567596 $ qb ->update ($ config ['useObjectClass ' ], 'node ' )
568- ->set ('node. ' .$ config ['right ' ], "node. {$ config ['right ' ]} {$ sign } {$ absDelta }" )
569- ->where ($ qb ->expr ()->gte ('node. ' .$ config ['right ' ], $ first ))
570- ;
597+ ->set ('node. ' . $ config ['right ' ], "node. {$ config ['right ' ]} {$ sign } {$ absDelta }" )
598+ ->where ($ qb ->expr ()->gte ('node. ' . $ config ['right ' ], $ first ));
571599 if (isset ($ config ['root ' ])) {
572- $ qb ->andWhere ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
600+ $ qb ->andWhere ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
573601 $ qb ->setParameter ('rid ' , $ root );
574602 }
575603
@@ -618,7 +646,7 @@ public function shiftRL(EntityManagerInterface $em, $class, $first, $delta, $roo
618646 * @param integer $delta
619647 * @param integer|string $root
620648 * @param integer|string $destRoot
621- * @param integer $levelDelta
649+ * @param integer $levelDelta
622650 */
623651 public function shiftRangeRL (EntityManagerInterface $ em , $ class , $ first , $ last , $ delta , $ root = null , $ destRoot = null , $ levelDelta = null )
624652 {
@@ -632,19 +660,18 @@ public function shiftRangeRL(EntityManagerInterface $em, $class, $first, $last,
632660
633661 $ qb = $ em ->createQueryBuilder ();
634662 $ qb ->update ($ config ['useObjectClass ' ], 'node ' )
635- ->set ('node. ' .$ config ['left ' ], "node. {$ config ['left ' ]} {$ sign } {$ absDelta }" )
636- ->set ('node. ' .$ config ['right ' ], "node. {$ config ['right ' ]} {$ sign } {$ absDelta }" )
637- ->where ($ qb ->expr ()->gte ('node. ' .$ config ['left ' ], $ first ))
638- ->andWhere ($ qb ->expr ()->lte ('node. ' .$ config ['right ' ], $ last ))
639- ;
663+ ->set ('node. ' . $ config ['left ' ], "node. {$ config ['left ' ]} {$ sign } {$ absDelta }" )
664+ ->set ('node. ' . $ config ['right ' ], "node. {$ config ['right ' ]} {$ sign } {$ absDelta }" )
665+ ->where ($ qb ->expr ()->gte ('node. ' . $ config ['left ' ], $ first ))
666+ ->andWhere ($ qb ->expr ()->lte ('node. ' . $ config ['right ' ], $ last ));
640667 if (isset ($ config ['root ' ])) {
641- $ qb ->set ('node. ' . $ config ['root ' ], ':drid ' );
668+ $ qb ->set ('node. ' . $ config ['root ' ], ':drid ' );
642669 $ qb ->setParameter ('drid ' , $ destRoot );
643- $ qb ->andWhere ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
670+ $ qb ->andWhere ($ qb ->expr ()->eq ('node. ' . $ config ['root ' ], ':rid ' ));
644671 $ qb ->setParameter ('rid ' , $ root );
645672 }
646673 if (isset ($ config ['level ' ])) {
647- $ qb ->set ('node. ' . $ config ['level ' ], "node. {$ config ['level ' ]} {$ levelSign } {$ absLevelDelta }" );
674+ $ qb ->set ('node. ' . $ config ['level ' ], "node. {$ config ['level ' ]} {$ levelSign } {$ absLevelDelta }" );
648675 }
649676 $ qb ->getQuery ()->getSingleScalarResult ();
650677 // update in memory nodes increases performance, saves some IO
0 commit comments