/** * {@inheritDoc} */ public function childCount($node = null, $direct = false) { $meta = $this->getClassMetadata(); if (is_object($node)) { if (!$node instanceof $meta->name) { throw new InvalidArgumentException("Node is not related to this repository"); } $wrapped = new EntityWrapper($node, $this->_em); if (!$wrapped->hasValidIdentifier()) { throw new InvalidArgumentException("Node is not managed by UnitOfWork"); } } $qb = $this->getChildrenQueryBuilder($node, $direct); // We need to remove the ORDER BY DQL part since some vendors could throw an error // in count queries $dqlParts = $qb->getDQLParts(); // We need to check first if there's an ORDER BY DQL part, because resetDQLPart doesn't // check if its internal array has an "orderby" index if (isset($dqlParts['orderBy'])) { $qb->resetDQLPart('orderBy'); } $aliases = $qb->getRootAliases(); $alias = $aliases[0]; $qb->select('COUNT(' . $alias . ')'); return (int) $qb->getQuery()->getSingleScalarResult(); }
public function testSomeFunctions() { $test = new Article(); $wrapped = new EntityWrapper($test, $this->em); $wrapped->populate(array('title' => 'test')); $this->assertEquals('test', $wrapped->getPropertyValue('title')); $this->assertFalse($wrapped->hasValidIdentifier()); }
/** * {@inheritDoc} */ public function childCount($node = null, $direct = false) { $meta = $this->getClassMetadata(); if (is_object($node)) { if (!$node instanceof $meta->name) { throw new InvalidArgumentException("Node is not related to this repository"); } $wrapped = new EntityWrapper($node, $this->_em); if (!$wrapped->hasValidIdentifier()) { throw new InvalidArgumentException("Node is not managed by UnitOfWork"); } } $qb = $this->getChildrenQueryBuilder($node, $direct); $aliases = $qb->getRootAliases(); $alias = $aliases[0]; $qb->select('COUNT(' . $alias . ')'); return (int) $qb->getQuery()->getSingleScalarResult(); }
/** * Loads all translations with all translatable * fields from the given entity * * @param object $entity Must implement Translatable * @return array list of translations in locale groups */ public function findTranslations($entity) { $result = array(); $wrapped = new EntityWrapper($entity, $this->_em); if ($wrapped->hasValidIdentifier()) { $entityId = $wrapped->getIdentifier(); $entityClass = $wrapped->getMetadata()->name; $translationMeta = $this->getClassMetadata(); // table inheritance support $qb = $this->_em->createQueryBuilder(); $qb->select('trans.content, trans.field, trans.locale')->from($translationMeta->rootEntityName, 'trans')->where('trans.foreignKey = :entityId', 'trans.objectClass = :entityClass')->orderBy('trans.locale'); $q = $qb->getQuery(); $data = $q->execute(compact('entityId', 'entityClass'), Query::HYDRATE_ARRAY); if ($data && is_array($data) && count($data)) { foreach ($data as $row) { $result[$row['locale']][$row['field']] = $row['content']; } } } return $result; }
/** * Removes given $node from the tree and reparents its descendants * * @todo: may be improved, to issue single query on reparenting * @param object $node * @throws RuntimeException - if something fails in transaction * @return void */ public function removeFromTree($node) { $meta = $this->getClassMetadata(); if (!$node instanceof $meta->name) { throw new InvalidArgumentException("Node is not related to this repository"); } $wrapped = new EntityWrapper($node, $this->_em); if (!$wrapped->hasValidIdentifier()) { throw new InvalidArgumentException("Node is not managed by UnitOfWork"); } $config = $this->listener->getConfiguration($this->_em, $meta->name); $pk = $meta->getSingleIdentifierFieldName(); $nodeId = $wrapped->getIdentifier(); $parent = $wrapped->getPropertyValue($config['parent']); $dql = "SELECT node FROM {$config['useObjectClass']} node"; $dql .= " WHERE node.{$config['parent']} = :node"; $q = $this->_em->createQuery($dql); $q->setParameters(compact('node')); $nodesToReparent = $q->getResult(); // process updates in transaction $this->_em->getConnection()->beginTransaction(); try { foreach ($nodesToReparent as $nodeToReparent) { $id = $meta->getReflectionProperty($pk)->getValue($nodeToReparent); $meta->getReflectionProperty($config['parent'])->setValue($nodeToReparent, $parent); $dql = "UPDATE {$config['useObjectClass']} node"; $dql .= " SET node.{$config['parent']} = :parent"; $dql .= " WHERE node.{$pk} = :id"; $q = $this->_em->createQuery($dql); $q->setParameters(compact('parent', 'id')); $q->getSingleScalarResult(); $this->listener->getStrategy($this->_em, $meta->name)->updateNode($this->_em, $nodeToReparent, $node); $oid = spl_object_hash($nodeToReparent); $this->_em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['parent'], $parent); } $dql = "DELETE {$config['useObjectClass']} node"; $dql .= " WHERE node.{$pk} = :nodeId"; $q = $this->_em->createQuery($dql); $q->setParameters(compact('nodeId')); $q->getSingleScalarResult(); $this->_em->getConnection()->commit(); } catch (\Exception $e) { $this->_em->close(); $this->_em->getConnection()->rollback(); throw new \Gedmo\Exception\RuntimeException('Transaction failed', null, $e); } // remove from identity map $this->_em->getUnitOfWork()->removeFromIdentityMap($node); $node = null; }
/** * Get hierarchy array of children followed by given $node * * @param object $node - from which node to start reordering the tree * @param boolean $direct - true to take only direct children * @param string $direction - sort direction : "ASC" or "DESC" * @return array $trees */ public function childrenArrayHierarchy($node = null, $direct = false, $direction = "ASC") { $meta = $this->getClassMetadata(); $config = $this->listener->getConfiguration($this->_em, $meta->name); if ($node !== null) { if ($node instanceof $meta->name) { $wrapped = new EntityWrapper($node, $this->_em); if (!$wrapped->hasValidIdentifier()) { throw new InvalidArgumentException("Node is not managed by UnitOfWork"); } } } // Gets the array of $node results. // It must be order by 'root' field $nodes = self::childrenQuery($node, $direct, 'root' , $direction)->getArrayResult(); // Trees mapped $trees = array(); $l = 0; if (count($nodes) > 0) { // Node Stack. Used to help building the hierarchy $stack = array(); foreach ($nodes as $child) { $item = $child; $item['__children'] = array(); // Number of stack items $l = count($stack); // Check if we're dealing with different levels while($l > 0 && $stack[$l - 1]['lvl'] >= $item['lvl']) { array_pop($stack); $l--; } // Stack is empty (we are inspecting the root) if ($l == 0) { // Assigning the root child $i = count($trees); $trees[$i] = $item; $stack[] = & $trees[$i]; } else { // Add child to parent $i = count($stack[$l - 1]['__children']); $stack[$l - 1]['__children'][$i] = $item; $stack[] = & $stack[$l - 1]['__children'][$i]; } } } return $trees; }
/** * Loads all translations with all translatable * fields from the given entity * * @param object $entity Must implement Translatable * * @return array list of translations in locale groups */ public function findTranslations($entity) { $result = array(); $wrapped = new EntityWrapper($entity, $this->em); if ($wrapped->hasValidIdentifier()) { if (is_object($entity)) { $entityClass = $entity instanceof Proxy ? get_parent_class($entity) : get_class($entity); } else { throw new InvalidArgumentException('Argument 1 passed to TranslationRepository::translate must be an object'); } $reflectionClass = new \ReflectionClass($entityClass); $translationClass = $this->isPersonnalTranslationRecursive($reflectionClass)->class; $qb = $this->em->createQueryBuilder(); $qb->select('trans.content, trans.field, trans.locale')->from($translationClass, 'trans')->where('trans.object = :object')->orderBy('trans.locale'); $q = $qb->getQuery(); $data = $q->execute(array('object' => $entity), Query::HYDRATE_ARRAY); if ($data && is_array($data) && count($data)) { foreach ($data as $row) { $result[$row['locale']][$row['field']] = $row['content']; } } } return $result; }
/** * Get query builder for previous siblings of the given $node * * @param object $node * @param bool $includeSelf - include the node itself * * @throws \Gedmo\Exception\InvalidArgumentException - if input is invalid * * @return \Doctrine\ORM\QueryBuilder */ public function getPrevSiblingsQueryBuilder($node, $includeSelf = false) { $meta = $this->getClassMetadata(); if (!$node instanceof $meta->name) { throw new InvalidArgumentException("Node is not related to this repository"); } $wrapped = new EntityWrapper($node, $this->getEntityManager()); if (!$wrapped->hasValidIdentifier()) { throw new InvalidArgumentException("Node is not managed by UnitOfWork"); } $config = $this->listener->getConfiguration($this->getEntityManager(), $meta->name); $parent = $wrapped->getPropertyValue($config['parent']); if (isset($config['root']) && !$parent) { throw new InvalidArgumentException("Cannot get siblings from tree root node"); } $left = $wrapped->getPropertyValue($config['left']); $qb = $this->getQueryBuilder(); $qb->select('node')->from($config['useObjectClass'], 'node')->where($includeSelf ? $qb->expr()->lte('node.' . $config['left'], $left) : $qb->expr()->lt('node.' . $config['left'], $left))->orderBy("node.{$config['left']}", 'ASC'); if ($parent) { $wrappedParent = new EntityWrapper($parent, $this->getEntityManager()); $qb->andWhere($qb->expr()->eq('node.' . $config['parent'], ':pid')); $qb->setParameter('pid', $wrappedParent->getIdentifier()); } else { $qb->andWhere($qb->expr()->isNull('node.' . $config['parent'])); } return $qb; }
/** * @see getChildrenQueryBuilder */ public function childrenWithTranslations($node = null, $locale = null, $direct = false, $sortByField = null, $direction = 'ASC', $includeNode = false, $start = null, $limit = null) { $meta = $this->getClassMetadata(); $config = $this->listener->getConfiguration($this->_em, $meta->name); $qb = $this->getQueryBuilder(); $qb->select('node', 't')->from($config['useObjectClass'], 'node')->leftJoin('node.translations', 't'); if ($node !== null) { if ($node instanceof $meta->name) { $wrapped = new EntityWrapper($node, $this->_em); if (!$wrapped->hasValidIdentifier()) { throw new InvalidArgumentException("Node is not managed by UnitOfWork"); } if ($direct) { $id = $wrapped->getIdentifier(); $qb->where($id === null ? $qb->expr()->isNull('node.' . $config['parent']) : $qb->expr()->eq('node.' . $config['parent'], is_string($id) ? $qb->expr()->literal($id) : $id)); } else { $left = $wrapped->getPropertyValue($config['left']); $right = $wrapped->getPropertyValue($config['right']); if ($left && $right) { $qb->where($qb->expr()->lt('node.' . $config['right'], $right))->andWhere($qb->expr()->gt('node.' . $config['left'], $left)); } } if (isset($config['root'])) { $rootId = $wrapped->getPropertyValue($config['root']); $qb->andWhere($rootId === null ? $qb->expr()->isNull('node.' . $config['root']) : $qb->expr()->eq('node.' . $config['root'], is_string($rootId) ? $qb->expr()->literal($rootId) : $rootId)); } if ($includeNode) { $idField = $meta->getSingleIdentifierFieldName(); $qb->where('(' . $qb->getDqlPart('where') . ') OR node.' . $idField . ' = :rootNode'); $qb->setParameter('rootNode', $node); } } else { throw new \InvalidArgumentException("Node is not related to this repository"); } } else { if ($direct) { $qb->where($qb->expr()->isNull('node.' . $config['parent'])); } } if (!$sortByField) { $qb->orderBy('node.' . $config['left'], 'ASC'); } elseif (is_array($sortByField)) { $fields = ''; foreach ($sortByField as $field) { $fields .= 'node.' . $field . ','; } $fields = rtrim($fields, ','); $qb->orderBy($fields, $direction); } else { if ($meta->hasField($sortByField) && in_array(strtolower($direction), array('asc', 'desc'))) { $qb->orderBy('node.' . $sortByField, $direction); } else { throw new InvalidArgumentException("Invalid sort options specified: field - {$sortByField}, direction - {$direction}"); } } if ($start) { $qb->setFirstResult($start); } if ($limit) { $qb->setMaxResults($limit); } return $this->setTranslatableHint($qb->getQuery(), $locale); }
/** * Retrieves the nested array or the html output * * @throws \Gedmo\Exception\InvalidArgumentException * @param object $node - from which node to start reordering the tree * @param boolean $direct - true to take only direct children * @param bool $html * @param array|null $options * @return array|string */ public function childrenHierarchy($node = null, $direct = false, $html = false, array $options = null) { $meta = $this->getClassMetadata(); $config = $this->listener->getConfiguration($this->_em, $meta->name); if ($node !== null) { if ($node instanceof $meta->name) { $wrapped = new EntityWrapper($node, $this->_em); if (!$wrapped->hasValidIdentifier()) { throw new InvalidArgumentException("Node is not managed by UnitOfWork"); } } } // Gets the array of $node results. // It must be order by 'root' field $nodes = self::childrenQuery($node, $direct, 'root', 'ASC')->getArrayResult(); return $this->buildTree($nodes, $html, $options); }
/** * Get query for previous siblings of the given $node * * @param object $node * @param bool $includeSelf - include the node itself * @throws \Gedmo\Exception\InvalidArgumentException - if input is invalid * @return Query */ public function getPrevSiblingsQuery($node, $includeSelf = false) { $meta = $this->getClassMetadata(); if (!$node instanceof $meta->name) { throw new InvalidArgumentException("Node is not related to this repository"); } $wrapped = new EntityWrapper($node, $this->_em); if (!$wrapped->hasValidIdentifier()) { throw new InvalidArgumentException("Node is not managed by UnitOfWork"); } $config = $this->listener->getConfiguration($this->_em, $meta->name); $parent = $wrapped->getPropertyValue($config['parent']); if (isset($config['root']) && !$parent) { throw new InvalidArgumentException("Cannot get siblings from tree root node"); } $left = $wrapped->getPropertyValue($config['left']); $sign = $includeSelf ? '<=' : '<'; $dql = "SELECT node FROM {$config['useObjectClass']} node"; if ($parent) { $wrappedParent = new EntityWrapper($parent, $this->_em); $parentId = $wrappedParent->getIdentifier(); $dql .= " WHERE node.{$config['parent']} = {$parentId}"; } else { $dql .= " WHERE node.{$config['parent']} IS NULL"; } $dql .= " AND node.{$config['left']} {$sign} {$left}"; $dql .= " ORDER BY node.{$config['left']} ASC"; return $this->_em->createQuery($dql); }