Permalink
Browse files

Rebase to master

  • Loading branch information...
1 parent 0dbd742 commit 160b07d1e3107b9a8210fc73d456305b03146c39 @bakura10 bakura10 committed Dec 22, 2013
Showing with 124 additions and 26 deletions.
  1. +8 −2 lib/Doctrine/ORM/PersistentCollection.php
  2. +116 −24 lib/Doctrine/ORM/Persisters/ManyToManyPersister.php
@@ -869,8 +869,14 @@ public function matching(Criteria $criteria)
return $this->coll->matching($criteria);
}
- if ($this->association['type'] !== ClassMetadata::ONE_TO_MANY) {
- throw new \RuntimeException("Matching Criteria on PersistentCollection only works on OneToMany associations at the moment.");
+ if ($this->association['type'] !== ClassMetadata::ONE_TO_MANY
+ && $this->association['type'] !== ClassMetadata::MANY_TO_MANY) {
+ throw new \RuntimeException("Matching Criteria on PersistentCollection only works on OneToMany and ManyToMany associations at the moment.");
+ }
+
+ if ($this->association['type'] === ClassMetadata::MANY_TO_MANY) {
+ $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
+ return new ArrayCollection($persister->loadCriteria($this, $this->owner, $criteria));
}
$builder = Criteria::expr();
@@ -19,8 +19,10 @@
namespace Doctrine\ORM\Persisters;
+use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\PersistentCollection;
+use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
/**
@@ -54,7 +56,7 @@ protected function getDeleteRowSQL(PersistentCollection $coll)
}
return 'DELETE FROM ' . $tableName
- . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
+ . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
}
/**
@@ -102,7 +104,7 @@ protected function getInsertRowSQL(PersistentCollection $coll)
}
return 'INSERT INTO ' . $joinTable . ' (' . implode(', ', $columns) . ')'
- . ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
+ . ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
}
/**
@@ -178,7 +180,7 @@ protected function getDeleteSQL(PersistentCollection $coll)
}
return 'DELETE FROM ' . $joinTable
- . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
+ . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
}
/**
@@ -257,7 +259,11 @@ public function count(PersistentCollection $coll)
}
/**
- * {@inheritdoc}
+ * @param \Doctrine\ORM\PersistentCollection $coll
+ * @param int $offset
+ * @param int|null $length
+ *
+ * @return array
*/
public function slice(PersistentCollection $coll, $offset, $length = null)
{
@@ -276,7 +282,10 @@ public function containsKey(PersistentCollection $coll, $key)
}
/**
- * {@inheritdoc}
+ * @param \Doctrine\ORM\PersistentCollection $coll
+ * @param object $element
+ *
+ * @return boolean
*/
public function contains(PersistentCollection $coll, $element)
{
@@ -302,7 +311,10 @@ public function contains(PersistentCollection $coll, $element)
}
/**
- * {@inheritdoc}
+ * @param \Doctrine\ORM\PersistentCollection $coll
+ * @param object $element
+ *
+ * @return boolean
*/
public function removeElement(PersistentCollection $coll, $element)
{
@@ -485,52 +497,132 @@ public function getFilterSql($mapping)
return array('', '');
}
- $conditions = array();
+ // A join is needed if there is filtering on the target entity
+ $tableName = $this->quoteStrategy->getTableName($rootClass, $this->platform);
+ $joinSql = ' JOIN ' . $tableName . ' te' . ' ON';
+ $onConditions = $this->getOnConditionSQL($mapping);
+
+ $joinSql .= implode(' AND ', $onConditions);
+
+ return array($joinSql, $filterSql);
+ }
+
+ /**
+ * Generates the filter SQL for a given entity and table alias.
+ *
+ * @param ClassMetadata $targetEntity Metadata of the target entity.
+ * @param string $targetTableAlias The table alias of the joined/selected table.
+ *
+ * @return string The SQL query part to add to a query.
+ */
+ protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
+ {
+ $filterClauses = array();
+
+ foreach ($this->em->getFilters()->getEnabledFilters() as $filter) {
+ if ($filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) {
+ $filterClauses[] = '(' . $filterExpr . ')';
+ }
+ }
+
+ $sql = implode(' AND ', $filterClauses);
+ return $sql ? "(" . $sql . ")" : "";
+ }
+
+ /**
+ * Generate ON condition
+ *
+ * @param array $mapping
+ * @return array
+ */
+ protected function getOnConditionSQL($mapping)
+ {
$association = $mapping;
if ( ! $mapping['isOwningSide']) {
$class = $this->em->getClassMetadata($mapping['targetEntity']);
$association = $class->associationMappings[$mapping['mappedBy']];
}
- // A join is needed if there is filtering on the target entity
- $tableName = $this->quoteStrategy->getTableName($rootClass, $this->platform);
- $joinSql = ' JOIN ' . $tableName . ' te' . ' ON';
+ $targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
+
$joinColumns = $mapping['isOwningSide']
? $association['joinTable']['inverseJoinColumns']
: $association['joinTable']['joinColumns'];
+ $conditions = array();
+
foreach ($joinColumns as $joinColumn) {
$joinColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
$refColumnName = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform);
$conditions[] = ' t.' . $joinColumnName . ' = ' . 'te.' . $refColumnName;
}
- $joinSql .= implode(' AND ', $conditions);
+ return $conditions;
+ }
+
+ /**
+ * Loads Entities matching the given Criteria object.
+ *
+ * @param PersistentCollection $coll
+ * @param object $owner
+ * @param \Doctrine\Common\Collections\Criteria $criteria
+ * @return array
+ */
+ public function loadCriteria(PersistentCollection $coll, $owner, Criteria $criteria)
+ {
+ list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, $owner, true);
+
+ $parameters = $this->expandCriteriaParameters($criteria);
- return array($joinSql, $filterSql);
+ foreach ($parameters as $parameter) {
+ list($name, $value) = $parameter;
+ $whereClauses[] = sprintf("te.%s = ?", $name);
+ $params[] = $value;
+ }
+
+ $mapping = $coll->getMapping();
+ $targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
+ $tableName = $this->quoteStrategy->getTableName($targetClass, $this->platform);
+ $onConditions = $this->getOnConditionSQL($mapping);
+
+ $sql = 'SELECT * FROM ' . $tableName . ' te'
+ . ' JOIN ' . $quotedJoinTable . ' ON'
+ . implode(' AND ', $onConditions)
+ . ' WHERE ' . implode(' AND ', $whereClauses);
+
+ $stmt = $this->conn->executeQuery($sql, $params);
+ $hydrator = $this->em->newHydrator(Query::HYDRATE_ARRAY);
+
+ $rsm = new Query\ResultSetMapping();
+ $rsm->addEntityResult($mapping['targetEntity'], 'r');
+
+ return $hydrator->hydrateAll($stmt, $rsm);
}
/**
- * Generates the filter SQL for a given entity and table alias.
+ * Expands Criteria Parameters by walking the expressions and grabbing all
+ * parameters and types from it.
*
- * @param ClassMetadata $targetEntity Metadata of the target entity.
- * @param string $targetTableAlias The table alias of the joined/selected table.
+ * @param \Doctrine\Common\Collections\Criteria $criteria
*
- * @return string The SQL query part to add to a query.
+ * @return array(array(), array())
*/
- protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
+ private function expandCriteriaParameters(Criteria $criteria)
{
- $filterClauses = array();
+ $expression = $criteria->getWhereExpression();
- foreach ($this->em->getFilters()->getEnabledFilters() as $filter) {
- if ($filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) {
- $filterClauses[] = '(' . $filterExpr . ')';
- }
+ if ($expression === null) {
+ return array(array(), array());
}
- $sql = implode(' AND ', $filterClauses);
- return $sql ? "(" . $sql . ")" : "";
+ $valueVisitor = new SqlValueVisitor();
+
+ $valueVisitor->dispatch($expression);
+
+ list($values, $types) = $valueVisitor->getParamsAndTypes();
+
+ return $types;
}
}

0 comments on commit 160b07d

Please sign in to comment.