Design, Programming, Projects, Technology

Sorting/Reording Symfony2 Entities Display Order.

So i had to implement a mechanism to re-order Categories and also Boards for my forum bundle, and with though there are many ways to go about it, here is how i solved the problem of reordering them. The reordering functionality is circular so last items getting pushed down end up on the top of the list, and top items getting pushed up end up on the bottom of the list.

    /**
     *
     * @access public
     * @param  Array                                               $categories
     * @param  \CCDNForum\ForumBundle\Entity\Category              $categoryShift
     * @param  int                                                 $direction
     * @return \CCDNForum\ForumBundle\Manager\BaseManagerInterface
     */
    public function reorderCategories($categories, Category $categoryShift, $direction)
    {
		$categoryCount = (count($categories) - 1);
		
		// Find category in collection to shift and use list order as array key for easier editing.
		$sorted = array();
		$shiftIndex = null;
		foreach ($categories as $categoryIndex => $category) {
			if ($categories[$categoryIndex]->getId() == $categoryShift->getId()) {
				$shiftIndex = $categoryIndex;
			}
			
			$sorted[$categoryIndex] = $category;
		}

		$incrementKeysAfterIndex = function($index, $arr) {
			$hydrated = array();
		
			foreach ($arr as $key => $el) {
				if ($key > $index) {
					$hydrated[$key + 1] = $el;
				} else {
					$hydrated[$key] = $el;
				}
			}
		
			return $hydrated;
		};
		
		$decrementKeysBeforeIndex = function($index, $arr) {
			$hydrated = array();
		
			foreach ($arr as $key => $el) {
				if ($key < $index) {
					$hydrated[$key - 1] = $el;
				} else {
					$hydrated[$key] = $el;
				}
			}
			
			return $hydrated;
		};
			
		$shifted = array();
		
		// First Category needs reordering??
		if ($shiftIndex == 0) {
			if ($direction) { // Down (move down 1)
				$shifted = $sorted;
				$shifted[$shiftIndex] = $sorted[$shiftIndex + 1];
				$shifted[$shiftIndex + 1] = $sorted[$shiftIndex];
			} else { // Up (send to bottom)
				$shifted[$categoryCount] = $sorted[0];
				unset($sorted[0]);
				$shifted = array_merge($decrementKeysBeforeIndex($categoryCount + 1, $sorted), $shifted);
			}
		} else {
			// Last category needs reordering??
			if ($shiftIndex == $categoryCount) {
				if ($direction) { // Down (send to top)
					$shifted[0] = $sorted[$categoryCount];
					unset($sorted[$categoryCount]);
					$shifted = array_merge($shifted, $incrementKeysAfterIndex(-1, $sorted));
				} else { // Up (move up 1)
					$shifted = $sorted;
					$shifted[$shiftIndex] = $sorted[$shiftIndex - 1];
					$shifted[$shiftIndex - 1] = $sorted[$shiftIndex];
				}
			} else {
				// Swap 2 categories not at beginning or end.
				$shifted = $sorted;
				if ($direction) { // Down (move down 1)
					$shifted[$shiftIndex] = $sorted[$shiftIndex + 1];
					$shifted[$shiftIndex + 1] = $sorted[$shiftIndex];
				} else { // Up (move up 1)
					$shifted[$shiftIndex] = $sorted[$shiftIndex - 1];
					$shifted[$shiftIndex - 1] = $sorted[$shiftIndex];
				}
			}
		}
		
		// Set the order from the $index arranged prior and persist.
		foreach ($shifted as $index => $category) {
			$category->setListOrderPriority($index);
			$this->persist($category);
		}
		
        $this->flush();

        return $this;
    }

What do you guys think? Know of a better approach? Let me know!