예제 #1
0
 /**
  * Computes node positions and updates the sort field in memory and in the db
  *
  * @param SortableAdapter $ea
  * @param array           $config
  * @param ClassMetadata   $meta
  * @param object          $object
  */
 private function processUpdate(SortableAdapter $ea, array $config, $meta, $object)
 {
     $em = $ea->getObjectManager();
     $uow = $em->getUnitOfWork();
     $changed = false;
     $groupHasChanged = false;
     $changeSet = $ea->getObjectChangeSet($uow, $object);
     // Get groups
     $groups = $this->getGroups($meta, $config, $object);
     // handle old groups
     $oldGroups = $groups;
     foreach (array_keys($groups) as $group) {
         if (array_key_exists($group, $changeSet)) {
             $changed = true;
             $oldGroups[$group] = $changeSet[$group][0];
         }
     }
     if ($changed) {
         $oldHash = $this->getHash($oldGroups, $config);
         $this->maxPositions[$oldHash] = $this->getMaxPosition($ea, $meta, $config, $object, $oldGroups);
         if (array_key_exists($config['position'], $changeSet)) {
             $oldPosition = $changeSet[$config['position']][0];
         } else {
             $oldPosition = $meta->getReflectionProperty($config['position'])->getValue($object);
         }
         $this->addRelocation($oldHash, $config['useObjectClass'], $oldGroups, $oldPosition + 1, $this->maxPositions[$oldHash] + 1, -1);
         $groupHasChanged = true;
     }
     if (array_key_exists($config['position'], $changeSet)) {
         // position was manually updated
         $oldPosition = $changeSet[$config['position']][0];
         $newPosition = $changeSet[$config['position']][1];
         $changed = $changed || $oldPosition != $newPosition;
     } elseif ($changed) {
         // group has changed, so position has to be recalculated
         $oldPosition = -1;
         $newPosition = -1;
         // specific case
     }
     if ($groupHasChanged) {
         $oldPosition = -1;
     }
     if (!$changed) {
         return;
     }
     // Get hash
     $hash = $this->getHash($groups, $config);
     // Get max position
     if (!isset($this->maxPositions[$hash])) {
         $this->maxPositions[$hash] = $this->getMaxPosition($ea, $meta, $config, $object);
     }
     // Compute position if it is negative
     if ($newPosition < 0) {
         if ($oldPosition === -1) {
             $newPosition += $this->maxPositions[$hash] + 2;
             // position == -1 => append at end of list
         } else {
             $newPosition += $this->maxPositions[$hash] + 1;
             // position == -1 => append at end of list
         }
         if ($newPosition < 0) {
             $newPosition = 0;
         }
     } else {
         $newPosition = min(array($this->maxPositions[$hash], $newPosition));
     }
     // Compute relocations
     /*
     CASE 1: shift backwards
     |----0----|----1----|----2----|----3----|----4----|
     |--node1--|--node2--|--node3--|--node4--|--node5--|
     Update node4: setPosition(1)
     --> Update position + 1 where position in [1,3)
     |--node1--|--node4--|--node2--|--node3--|--node5--|
     CASE 2: shift forward
     |----0----|----1----|----2----|----3----|----4----|
     |--node1--|--node2--|--node3--|--node4--|--node5--|
     Update node2: setPosition(3)
     --> Update position - 1 where position in (1,3]
     |--node1--|--node3--|--node4--|--node2--|--node5--|
     */
     $relocation = null;
     if ($oldPosition === -1) {
         // special case when group changes
         $relocation = array($hash, $config['useObjectClass'], $groups, $newPosition, -1, +1);
     } elseif ($newPosition < $oldPosition) {
         $relocation = array($hash, $config['useObjectClass'], $groups, $newPosition, $oldPosition, +1);
     } elseif ($newPosition > $oldPosition) {
         $relocation = array($hash, $config['useObjectClass'], $groups, $oldPosition + 1, $newPosition + 1, -1);
     }
     // Apply existing relocations
     $applyDelta = 0;
     if (isset($this->relocations[$hash])) {
         foreach ($this->relocations[$hash]['deltas'] as $delta) {
             if ($delta['start'] <= $newPosition && ($delta['stop'] > $newPosition || $delta['stop'] < 0)) {
                 $applyDelta += $delta['delta'];
             }
         }
     }
     $newPosition += $applyDelta;
     if ($relocation) {
         // Add relocation
         call_user_func_array(array($this, 'addRelocation'), $relocation);
     }
     // Set new position
     $meta->getReflectionProperty($config['position'])->setValue($object, $newPosition);
     $ea->recomputeSingleObjectChangeSet($uow, $meta, $object);
 }
 /**
  * @param SortableAdapter $ea
  */
 private function processRelocations(SortableAdapter $ea)
 {
     $em = $ea->getObjectManager();
     foreach ($this->relocations as $hash => $relocation) {
         $config = $this->getConfiguration($em, $relocation['name']);
         foreach ($relocation['deltas'] as $delta) {
             if ($delta['start'] > $this->maxPositions[$hash] || $delta['delta'] == 0) {
                 continue;
             }
             $ea->updatePositions($relocation, $delta, $config);
             $meta = $em->getClassMetadata($relocation['name']);
             // now walk through the unit of work in memory objects and sync those
             $uow = $em->getUnitOfWork();
             foreach ($uow->getIdentityMap() as $className => $objects) {
                 // for inheritance mapped classes, only root is always in the identity map
                 if ($className !== $ea->getRootObjectClass($meta) || !$this->getConfiguration($em, $className)) {
                     continue;
                 }
                 foreach ($objects as $object) {
                     if ($object instanceof Proxy && !$object->__isInitialized__) {
                         continue;
                     }
                     // if the entity's position is already changed, stop now
                     if (array_key_exists($config['position'], $ea->getObjectChangeSet($uow, $object))) {
                         continue;
                     }
                     $oid = spl_object_hash($object);
                     $pos = $meta->getReflectionProperty($config['position'])->getValue($object);
                     $matches = $pos >= $delta['start'];
                     $matches = $matches && ($delta['stop'] <= 0 || $pos < $delta['stop']);
                     $value = reset($relocation['groups']);
                     while ($matches && ($group = key($relocation['groups']))) {
                         $gr = $meta->getReflectionProperty($group)->getValue($object);
                         if (null === $value) {
                             $matches = $gr === null;
                         } else {
                             $matches = $gr === $value;
                         }
                         $value = next($relocation['groups']);
                     }
                     if ($matches) {
                         $meta->getReflectionProperty($config['position'])->setValue($object, $pos + $delta['delta']);
                         $ea->setOriginalObjectProperty($uow, $oid, $config['position'], $pos + $delta['delta']);
                     }
                 }
             }
         }
     }
     // Clear relocations
     $this->relocations = array();
     $this->maxPositions = array();
 }