om = $om; $this->meta = $meta; $this->listener = $listener; $this->repo = $repo; } public function getClassMetadata() { return $this->meta; } /** * {@inheritDoc} */ public function childrenHierarchy($node = null, $direct = false, array $options = array(), $includeNode = false) { $meta = $this->getClassMetadata(); if ($node !== null) { if ($node instanceof $meta->name) { $wrapperClass = $this->om instanceof \Doctrine\ORM\EntityManager ? '\Gedmo\Tool\Wrapper\EntityWrapper' : '\Gedmo\Tool\Wrapper\MongoDocumentWrapper'; $wrapped = new $wrapperClass($node, $this->om); if (!$wrapped->hasValidIdentifier()) { throw new InvalidArgumentException("Node is not managed by UnitOfWork"); } } } else { $includeNode = true; } // Gets the array of $node results. It must be ordered by depth $nodes = $this->repo->getNodesHierarchy($node, $direct, $options, $includeNode); return $this->repo->buildTree($nodes, $options); } /** * {@inheritDoc} */ public function buildTree(array $nodes, array $options = array()) { $meta = $this->getClassMetadata(); $nestedTree = $this->repo->buildTreeArray($nodes); $default = array( 'decorate' => false, 'rootOpen' => '', 'childOpen' => '
  • ', 'childClose' => '
  • ', 'nodeDecorator' => function ($node) use ($meta) { // override and change it, guessing which field to use if ($meta->hasField('title')) { $field = 'title'; } elseif ($meta->hasField('name')) { $field = 'name'; } else { throw new InvalidArgumentException("Cannot find any representation field"); } return $node[$field]; } ); $options = array_merge($default, $options); // If you don't want any html output it will return the nested array if (!$options['decorate']) { return $nestedTree; } if (!count($nestedTree)) { return ''; } $childrenIndex = $this->childrenIndex; $build = function($tree) use (&$build, &$options, $childrenIndex) { $output = is_string($options['rootOpen']) ? $options['rootOpen'] : $options['rootOpen']($tree); foreach ($tree as $node) { $output .= is_string($options['childOpen']) ? $options['childOpen'] : $options['childOpen']($node); $output .= $options['nodeDecorator']($node); if (count($node[$childrenIndex]) > 0) { $output .= $build($node[$childrenIndex]); } $output .= is_string($options['childClose']) ? $options['childClose'] : $options['childClose']($node); } return $output . (is_string($options['rootClose']) ? $options['rootClose'] : $options['rootClose']($tree)); }; return $build($nestedTree); } /** * {@inheritDoc} */ public function buildTreeArray(array $nodes) { $meta = $this->getClassMetadata(); $config = $this->listener->getConfiguration($this->om, $meta->name); $nestedTree = array(); $l = 0; if (count($nodes) > 0) { // Node Stack. Used to help building the hierarchy $stack = array(); foreach ($nodes as $child) { $item = $child; $item[$this->childrenIndex] = array(); // Number of stack items $l = count($stack); // Check if we're dealing with different levels while($l > 0 && $stack[$l - 1][$config['level']] >= $item[$config['level']]) { array_pop($stack); $l--; } // Stack is empty (we are inspecting the root) if ($l == 0) { // Assigning the root child $i = count($nestedTree); $nestedTree[$i] = $item; $stack[] = &$nestedTree[$i]; } else { // Add child to parent $i = count($stack[$l - 1][$this->childrenIndex]); $stack[$l - 1][$this->childrenIndex][$i] = $item; $stack[] = &$stack[$l - 1][$this->childrenIndex][$i]; } } } return $nestedTree; } /** * {@inheritDoc} */ public function setChildrenIndex($childrenIndex) { $this->childrenIndex = $childrenIndex; } /** * {@inheritDoc} */ public function getChildrenIndex() { return $this->childrenIndex; } }