diff --git a/lib/Doctrine/ORM/AbstractQuery.php b/lib/Doctrine/ORM/AbstractQuery.php index 787770a34..26eee1fb8 100644 --- a/lib/Doctrine/ORM/AbstractQuery.php +++ b/lib/Doctrine/ORM/AbstractQuery.php @@ -195,10 +195,13 @@ abstract class AbstractQuery */ public function setParameter($key, $value, $type = null) { - if ($type !== null) { - $this->_paramTypes[$key] = $type; + if ($type === null) { + $type = Query\ParameterTypeInferer::inferType($value); } + + $this->_paramTypes[$key] = $type; $this->_params[$key] = $value; + return $this; } @@ -558,10 +561,6 @@ abstract class AbstractQuery $this->setParameters($params); } - if (isset($this->_params[0])) { - throw QueryException::invalidParameterPosition(0); - } - // Check result cache if ($this->_useResultCache && $cacheDriver = $this->getResultCacheDriver()) { list($key, $hash) = $this->getResultCacheId(); @@ -572,8 +571,8 @@ abstract class AbstractQuery $stmt = $this->_doExecute(); $result = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll( - $stmt, $this->_resultSetMapping, $this->_hints - ); + $stmt, $this->_resultSetMapping, $this->_hints + ); $cacheDriver->save($hash, array($key => $result), $this->_resultCacheTTL); diff --git a/lib/Doctrine/ORM/Configuration.php b/lib/Doctrine/ORM/Configuration.php index 0bc206d27..999d0c84c 100644 --- a/lib/Doctrine/ORM/Configuration.php +++ b/lib/Doctrine/ORM/Configuration.php @@ -163,6 +163,16 @@ class Configuration extends \Doctrine\DBAL\Configuration { $this->_attributes['entityNamespaces'] = $entityNamespaces; } + + /** + * Retrieves the list of registered entity namespace aliases. + * + * @return array + */ + public function getEntityNamespaces() + { + return $this->_attributes['entityNamespaces']; + } /** * Gets the cache driver implementation that is used for the mapping metadata. diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index f556257f9..b52029421 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -909,9 +909,13 @@ class ClassMetadataInfo implements ClassMetadata $mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']); } - //TODO: if orphanRemoval, cascade=remove is implicit! $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false; + + // if orphanRemoval, cascade=remove is implicit + if ($mapping['orphanRemoval']) { + $mapping['isCascadeRemove'] = true; + } if (isset($mapping['id']) && $mapping['id'] === true && !$mapping['isOwningSide']) { throw MappingException::illegalInverseIdentifierAssocation($this->name, $mapping['fieldName']); @@ -936,10 +940,14 @@ class ClassMetadataInfo implements ClassMetadata throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']); } - //TODO: if orphanRemoval, cascade=remove is implicit! $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false; + // if orphanRemoval, cascade=remove is implicit + if ($mapping['orphanRemoval']) { + $mapping['isCascadeRemove'] = true; + } + if (isset($mapping['orderBy'])) { if ( ! is_array($mapping['orderBy'])) { throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy'])); diff --git a/lib/Doctrine/ORM/Proxy/ProxyFactory.php b/lib/Doctrine/ORM/Proxy/ProxyFactory.php index 956b06503..23186d7aa 100644 --- a/lib/Doctrine/ORM/Proxy/ProxyFactory.php +++ b/lib/Doctrine/ORM/Proxy/ProxyFactory.php @@ -209,7 +209,7 @@ class ProxyFactory $methods .= $parameterString . ')'; $methods .= PHP_EOL . ' {' . PHP_EOL; - $methods .= ' $this->_load();' . PHP_EOL; + $methods .= ' $this->__load();' . PHP_EOL; $methods .= ' return parent::' . $method->getName() . '(' . $argumentString . ');'; $methods .= PHP_EOL . ' }' . PHP_EOL; } @@ -269,7 +269,7 @@ class extends \ implements \Doctrine\ORM\Proxy\Proxy $this->_entityPersister = $entityPersister; $this->_identifier = $identifier; } - private function _load() + private function __load() { if (!$this->__isInitialized__ && $this->_entityPersister) { $this->__isInitialized__ = true; diff --git a/lib/Doctrine/ORM/Query/Expr/Andx.php b/lib/Doctrine/ORM/Query/Expr/Andx.php index 9f7d8a580..c26055c2a 100644 --- a/lib/Doctrine/ORM/Query/Expr/Andx.php +++ b/lib/Doctrine/ORM/Query/Expr/Andx.php @@ -32,9 +32,9 @@ namespace Doctrine\ORM\Query\Expr; * @author Jonathan Wage * @author Roman Borschel */ -class Andx extends Base +class Andx extends Composite { - protected $_separator = ') AND ('; + protected $_separator = ' AND '; protected $_allowedClasses = array( 'Doctrine\ORM\Query\Expr\Comparison', 'Doctrine\ORM\Query\Expr\Func', diff --git a/lib/Doctrine/ORM/Query/Expr/Base.php b/lib/Doctrine/ORM/Query/Expr/Base.php index 904b69bbe..93bca7507 100644 --- a/lib/Doctrine/ORM/Query/Expr/Base.php +++ b/lib/Doctrine/ORM/Query/Expr/Base.php @@ -39,7 +39,7 @@ abstract class Base protected $_postSeparator = ')'; protected $_allowedClasses = array(); - private $_parts = array(); + protected $_parts = array(); public function __construct($args = array()) { diff --git a/lib/Doctrine/ORM/Query/Expr/Composite.php b/lib/Doctrine/ORM/Query/Expr/Composite.php new file mode 100644 index 000000000..97c15e64b --- /dev/null +++ b/lib/Doctrine/ORM/Query/Expr/Composite.php @@ -0,0 +1,53 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for building DQL and parts + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Composite extends Base +{ + public function __toString() + { + if ($this->count() === 1) { + return (string) $this->_parts[0]; + } + + $components = array(); + + foreach ($this->_parts as $part) { + $components[] = (is_object($part) && $part instanceof self && $part->count() > 1) + ? $this->_preSeparator . ((string) $part) . $this->_postSeparator + : ((string) $part); + } + + return implode($this->_separator, $components); + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/Expr/Join.php b/lib/Doctrine/ORM/Query/Expr/Join.php index a1a3955c6..54ad6ead7 100644 --- a/lib/Doctrine/ORM/Query/Expr/Join.php +++ b/lib/Doctrine/ORM/Query/Expr/Join.php @@ -45,20 +45,23 @@ class Join private $_alias; private $_conditionType; private $_condition; + private $_indexBy; - public function __construct($joinType, $join, $alias = null, $conditionType = null, $condition = null) + public function __construct($joinType, $join, $alias = null, $conditionType = null, $condition = null, $indexBy = null) { - $this->_joinType = $joinType; - $this->_join = $join; - $this->_alias = $alias; + $this->_joinType = $joinType; + $this->_join = $join; + $this->_alias = $alias; $this->_conditionType = $conditionType; - $this->_condition = $condition; + $this->_condition = $condition; + $this->_indexBy = $indexBy; } public function __toString() { return strtoupper($this->_joinType) . ' JOIN ' . $this->_join . ($this->_alias ? ' ' . $this->_alias : '') - . ($this->_condition ? ' ' . strtoupper($this->_conditionType) . ' ' . $this->_condition : ''); + . ($this->_condition ? ' ' . strtoupper($this->_conditionType) . ' ' . $this->_condition : '') + . ($this->_indexBy ? ' INDEX BY ' . $this->_indexBy : ''); } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/Expr/Orx.php b/lib/Doctrine/ORM/Query/Expr/Orx.php index fe695f40d..7eb66535c 100644 --- a/lib/Doctrine/ORM/Query/Expr/Orx.php +++ b/lib/Doctrine/ORM/Query/Expr/Orx.php @@ -32,9 +32,9 @@ namespace Doctrine\ORM\Query\Expr; * @author Jonathan Wage * @author Roman Borschel */ -class Orx extends Base +class Orx extends Composite { - protected $_separator = ') OR ('; + protected $_separator = ' OR '; protected $_allowedClasses = array( 'Doctrine\ORM\Query\Expr\Andx', 'Doctrine\ORM\Query\Expr\Comparison', diff --git a/lib/Doctrine/ORM/Query/Lexer.php b/lib/Doctrine/ORM/Query/Lexer.php index 82355faec..70c8b7db6 100644 --- a/lib/Doctrine/ORM/Query/Lexer.php +++ b/lib/Doctrine/ORM/Query/Lexer.php @@ -126,7 +126,7 @@ class Lexer extends \Doctrine\Common\Lexer '[a-z_\\\][a-z0-9_\:\\\]*[a-z0-9_]{1}', '(?:[0-9]+(?:[\.][0-9]+)*)(?:e[+-]?[0-9]+)?', "'(?:[^']|'')*'", - '\?[1-9][0-9]*|:[a-z]{1}[a-z0-9_]{0,}' + '\?[0-9]*|:[a-z]{1}[a-z0-9_]{0,}' ); } diff --git a/lib/Doctrine/ORM/Query/ParameterTypeInferer.php b/lib/Doctrine/ORM/Query/ParameterTypeInferer.php new file mode 100644 index 000000000..d0e3e24b5 --- /dev/null +++ b/lib/Doctrine/ORM/Query/ParameterTypeInferer.php @@ -0,0 +1,72 @@ +. + */ + +namespace Doctrine\ORM\Query; + +use Doctrine\DBAL\Connection, + Doctrine\DBAL\Types\Type; + +/** + * Provides an enclosed support for parameter infering. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ParameterTypeInferer +{ + /** + * Infer type of a given value, returning a compatible constant: + * - Type (Doctrine\DBAL\Types\Type::*) + * - Connection (Doctrine\DBAL\Connection::PARAM_*) + * + * @param mixed $value Parameter value + * + * @return mixed Parameter type constant + */ + public static function inferType($value) + { + switch (true) { + case is_integer($value): + return Type::INTEGER; + + case ($value instanceof \DateTime): + return Type::DATETIME; + + case is_array($value): + $key = key($value); + + if (is_integer($value[$key])) { + return Connection::PARAM_INT_ARRAY; + } + + return Connection::PARAM_STR_ARRAY; + + default: + // Do nothing + break; + } + + return \PDO::PARAM_STR; + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index a14987eaa..0b5cfbef0 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -44,7 +44,7 @@ class SqlWalker implements TreeWalker private $_aliasCounter = 0; private $_tableAliasCounter = 0; private $_scalarResultCounter = 1; - private $_sqlParamIndex = 1; + private $_sqlParamIndex = 0; /** * @var ParserResult diff --git a/lib/Doctrine/ORM/QueryBuilder.php b/lib/Doctrine/ORM/QueryBuilder.php index 436522b69..fce4731c5 100644 --- a/lib/Doctrine/ORM/QueryBuilder.php +++ b/lib/Doctrine/ORM/QueryBuilder.php @@ -227,15 +227,28 @@ class QueryBuilder * ->select('u') * ->from('User', 'u'); * - * echo $qb->getRootAlias(); // u + * $qb->getRootAliases(); // array('u') * * * @return string $rootAlias - * @todo Rename/Refactor: getRootAliases(), there can be multiple roots! */ - public function getRootAlias() + public function getRootAliases() { - return $this->_dqlParts['from'][0]->getAlias(); + $aliases = array(); + + foreach ($this->_dqlParts['from'] as &$fromClause) { + if (is_string($fromClause)) { + $spacePos = strrpos($fromClause, ' '); + $from = substr($fromClause, 0, $spacePos); + $alias = substr($fromClause, $spacePos + 1); + + $fromClause = new Query\Expr\From($from, $alias); + } + + $aliases[] = $fromClause->getAlias(); + } + + return $aliases; } /** @@ -256,10 +269,13 @@ class QueryBuilder */ public function setParameter($key, $value, $type = null) { - if ($type !== null) { - $this->_paramTypes[$key] = $type; + if ($type === null) { + $type = Query\ParameterTypeInferer::inferType($value); } + + $this->_paramTypes[$key] = $type; $this->_params[$key] = $value; + return $this; } @@ -282,8 +298,13 @@ class QueryBuilder */ public function setParameters(array $params, array $types = array()) { - $this->_paramTypes = $types; - $this->_params = $params; + foreach ($params as $key => $value) { + if (isset($types[$key])) { + $this->setParameter($key, $value, $types[$key]); + } else { + $this->setParameter($key, $value); + } + } return $this; } @@ -370,7 +391,13 @@ class QueryBuilder $isMultiple = is_array($this->_dqlParts[$dqlPartName]); if ($append && $isMultiple) { - $this->_dqlParts[$dqlPartName][] = $dqlPart; + if (is_array($dqlPart)) { + $key = key($dqlPart); + + $this->_dqlParts[$dqlPartName][$key][] = $dqlPart[$key]; + } else { + $this->_dqlParts[$dqlPartName][] = $dqlPart; + } } else { $this->_dqlParts[$dqlPartName] = ($isMultiple) ? array($dqlPart) : $dqlPart; } @@ -523,11 +550,12 @@ class QueryBuilder * @param string $alias The alias of the join * @param string $conditionType The condition type constant. Either ON or WITH. * @param string $condition The condition for the join + * @param string $indexBy The index for the join * @return QueryBuilder This QueryBuilder instance. */ - public function join($join, $alias, $conditionType = null, $condition = null) + public function join($join, $alias, $conditionType = null, $condition = null, $indexBy = null) { - return $this->innerJoin($join, $alias, $conditionType, $condition); + return $this->innerJoin($join, $alias, $conditionType, $condition, $indexBy); } /** @@ -547,12 +575,15 @@ class QueryBuilder * @param string $alias The alias of the join * @param string $conditionType The condition type constant. Either ON or WITH. * @param string $condition The condition for the join + * @param string $indexBy The index for the join * @return QueryBuilder This QueryBuilder instance. */ - public function innerJoin($join, $alias, $conditionType = null, $condition = null) + public function innerJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null) { - return $this->add('join', new Expr\Join( - Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition + $rootAlias = substr($join, 0, strpos($join, '.')); + + return $this->add('join', array( + $rootAlias => new Expr\Join(Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy) ), true); } @@ -574,12 +605,15 @@ class QueryBuilder * @param string $alias The alias of the join * @param string $conditionType The condition type constant. Either ON or WITH. * @param string $condition The condition for the join + * @param string $indexBy The index for the join * @return QueryBuilder This QueryBuilder instance. */ - public function leftJoin($join, $alias, $conditionType = null, $condition = null) + public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null) { - return $this->add('join', new Expr\Join( - Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition + $rootAlias = substr($join, 0, strpos($join, '.')); + + return $this->add('join', array( + $rootAlias => new Expr\Join(Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy) ), true); } @@ -629,7 +663,7 @@ class QueryBuilder */ public function where($predicates) { - if ( ! (func_num_args() == 1 && ($predicates instanceof Expr\Andx || $predicates instanceof Expr\Orx))) { + if ( ! (func_num_args() == 1 && $predicates instanceof Expr\Composite)) { $predicates = new Expr\Andx(func_get_args()); } @@ -865,14 +899,36 @@ class QueryBuilder private function _getDQLForSelect() { - return 'SELECT' - . $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', ')) - . $this->_getReducedDQLQueryPart('from', array('pre' => ' FROM ', 'separator' => ', ')) - . $this->_getReducedDQLQueryPart('join', array('pre' => ' ', 'separator' => ' ')) + $dql = 'SELECT' . $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', ')); + + $fromParts = $this->getDQLPart('from'); + $joinParts = $this->getDQLPart('join'); + $fromClauses = array(); + + // Loop through all FROM clauses + if ( ! empty($fromParts)) { + $dql .= ' FROM '; + + foreach ($fromParts as $from) { + $fromClause = (string) $from; + + if (isset($joinParts[$from->getAlias()])) { + foreach ($joinParts[$from->getAlias()] as $join) { + $fromClause .= ' ' . ((string) $join); + } + } + + $fromClauses[] = $fromClause; + } + } + + $dql .= implode(', ', $fromClauses) . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE ')) . $this->_getReducedDQLQueryPart('groupBy', array('pre' => ' GROUP BY ', 'separator' => ', ')) . $this->_getReducedDQLQueryPart('having', array('pre' => ' HAVING ')) . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', ')); + + return $dql; } private function _getReducedDQLQueryPart($queryPartName, $options = array()) diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php index 835835d28..d0b881806 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php @@ -65,7 +65,7 @@ EOT protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas) { - $output->write('ATTENTION: This operation should not be executed in a production enviroment.' . PHP_EOL . PHP_EOL); + $output->write('ATTENTION: This operation should not be executed in a production environment.' . PHP_EOL . PHP_EOL); if ($input->getOption('dump-sql') === true) { $sqls = $schemaTool->getCreateSchemaSql($metadatas); diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php index f6f16cb79..57243f2f0 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php @@ -92,7 +92,7 @@ EOT } $output->write('Database schema dropped successfully!' . PHP_EOL); } else { - $output->write('ATTENTION: This operation should not be executed in a production enviroment.' . PHP_EOL . PHP_EOL); + $output->write('ATTENTION: This operation should not be executed in a production environment.' . PHP_EOL . PHP_EOL); if ($isFullDatabaseDrop) { $sqls = $schemaTool->getDropDatabaseSQL(); diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php index ed12358cd..195f5efef 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php @@ -86,7 +86,7 @@ EOT $schemaTool->updateSchema($metadatas, $saveMode); $output->write('Database schema updated successfully!' . PHP_EOL); } else { - $output->write('ATTENTION: This operation should not be executed in a production enviroment.' . PHP_EOL); + $output->write('ATTENTION: This operation should not be executed in a production environment.' . PHP_EOL); $output->write('Use the incremental update to detect changes during development and use' . PHP_EOL); $output->write('this SQL DDL to manually update your database in production.' . PHP_EOL . PHP_EOL); diff --git a/lib/Doctrine/ORM/Tools/EntityGenerator.php b/lib/Doctrine/ORM/Tools/EntityGenerator.php index 9eb1f4d2a..80998b82a 100644 --- a/lib/Doctrine/ORM/Tools/EntityGenerator.php +++ b/lib/Doctrine/ORM/Tools/EntityGenerator.php @@ -183,7 +183,7 @@ public function () } if ($this->_backupExisting && file_exists($path)) { - $backupPath = dirname($path) . DIRECTORY_SEPARATOR . "~" . basename($path); + $backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~"; if (!copy($path, $backupPath)) { throw new \RuntimeException("Attempt to backup overwritten entitiy file but copy operation failed."); } diff --git a/lib/vendor/Symfony/Component/Console b/lib/vendor/Symfony/Component/Console index 76280e55c..4200b4bc9 160000 --- a/lib/vendor/Symfony/Component/Console +++ b/lib/vendor/Symfony/Component/Console @@ -1 +1 @@ -Subproject commit 76280e55c7058afcbce623eae571cf1bf7c22b84 +Subproject commit 4200b4bc95ae3c1b03d943cd875277e35a17898a diff --git a/lib/vendor/Symfony/Component/Yaml b/lib/vendor/Symfony/Component/Yaml index 0603a77ab..3d864452c 160000 --- a/lib/vendor/Symfony/Component/Yaml +++ b/lib/vendor/Symfony/Component/Yaml @@ -1 +1 @@ -Subproject commit 0603a77abada52469a7b889124dae57618441613 +Subproject commit 3d864452ca73ae5409f1434b65f0c7204a50e061 diff --git a/lib/vendor/doctrine-common b/lib/vendor/doctrine-common index 076a03f8f..ba63ae0f0 160000 --- a/lib/vendor/doctrine-common +++ b/lib/vendor/doctrine-common @@ -1 +1 @@ -Subproject commit 076a03f8f40b6e08f0ae2f4ee2678474e64b6f59 +Subproject commit ba63ae0f0b6b62a2a8617f01386698730ff2b713 diff --git a/tests/Doctrine/Tests/ORM/Functional/QueryTest.php b/tests/Doctrine/Tests/ORM/Functional/QueryTest.php index 02b4d267e..d8937289a 100644 --- a/tests/Doctrine/Tests/ORM/Functional/QueryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/QueryTest.php @@ -2,6 +2,7 @@ namespace Doctrine\Tests\ORM\Functional; +use Doctrine\DBAL\Connection; use Doctrine\Tests\Models\CMS\CmsUser, Doctrine\Tests\Models\CMS\CmsArticle; use Doctrine\ORM\Mapping\ClassMetadata; @@ -95,6 +96,23 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals('Symfony 2', $users[0]->articles[1]->topic); } + public function testUsingZeroBasedQueryParameterShouldWork() + { + $user = new CmsUser; + $user->name = 'Jonathan'; + $user->username = 'jwage'; + $user->status = 'developer'; + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ?0'); + $q->setParameter(0, 'jwage'); + $user = $q->getSingleResult(); + + $this->assertNotNull($user); + } + public function testUsingUnknownQueryParameterShouldThrowException() { $this->setExpectedException( @@ -438,4 +456,49 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase $query = $this->_em->createQuery("select u.username from Doctrine\Tests\Models\CMS\CmsUser u where u.username = 'gblanco'"); $this->assertNull($query->getOneOrNullResult(Query::HYDRATE_SCALAR)); } + + public function testDqlWithAutoInferOfParameters() + { + $user = new CmsUser; + $user->name = 'Benjamin'; + $user->username = 'beberlei'; + $user->status = 'developer'; + $this->_em->persist($user); + + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'developer'; + $this->_em->persist($user); + + $user = new CmsUser; + $user->name = 'Jonathan'; + $user->username = 'jwage'; + $user->status = 'developer'; + $this->_em->persist($user); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username IN (?0)"); + $query->setParameter(0, array('beberlei', 'jwage')); + + $users = $query->execute(); + + $this->assertEquals(2, count($users)); + } + + public function testQueryBuilderWithStringWhereClauseContainingOrAndConditionalPrimary() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->innerJoin('u.articles', 'a') + ->where('(u.id = 0) OR (u.id IS NULL)'); + + $query = $qb->getQuery(); + $users = $query->execute(); + + $this->assertEquals(0, count($users)); + } } \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC192Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC192Test.php index 07c8d1317..2238c0319 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC192Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC192Test.php @@ -44,17 +44,12 @@ class DDC192Phonenumber */ protected $phone; - /** - * @Id @Column(name="userId", type="integer") - */ - protected $userId; - /** * @Id * @ManyToOne(targetEntity="DDC192User") * @JoinColumn(name="userId", referencedColumnName="id") */ - protected $User; // Id on this docblock is ignored! + protected $User; public function setPhone($value) { $this->phone = $value; } @@ -64,7 +59,6 @@ class DDC192Phonenumber public function setUser(User $user) { $this->User = $user; - $this->userId = $user->getId(); // TODO: Remove once ManyToOne supports Id annotation } public function getUser() { return $this->User; } diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php index 5c6af8a42..82cb67223 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php @@ -77,21 +77,23 @@ class DDC719Group extends Entity { * adds group as new child * * @param Group $child - * @todo check against endless recursion - * @todo check if the group is already member of the group */ public function addGroup(Group $child) { - $this->children->add($child); + if ( ! $this->children->contains($child)) { + $this->children->add($child); + $child->addGroup($this); + } } /** * adds channel as new child * * @param Channel $child - * @todo check if the channel is already member of the group */ public function addChannel(Channel $child) { - $this->channels->add($child); + if ( ! $this->channels->contains($child)) { + $this->channels->add($child); + } } /** diff --git a/tests/Doctrine/Tests/ORM/Query/ExprTest.php b/tests/Doctrine/Tests/ORM/Query/ExprTest.php index 786eb1f0c..ccc033b2e 100644 --- a/tests/Doctrine/Tests/ORM/Query/ExprTest.php +++ b/tests/Doctrine/Tests/ORM/Query/ExprTest.php @@ -111,20 +111,20 @@ class ExprTest extends \Doctrine\Tests\OrmTestCase public function testAndExpr() { - $this->assertEquals('(1 = 1) AND (2 = 2)', (string) $this->_expr->andx((string) $this->_expr->eq(1, 1), (string) $this->_expr->eq(2, 2))); + $this->assertEquals('1 = 1 AND 2 = 2', (string) $this->_expr->andx((string) $this->_expr->eq(1, 1), (string) $this->_expr->eq(2, 2))); } public function testIntelligentParenthesisPreventionAndExpr() { $this->assertEquals( - '(1 = 1) AND (2 = 2)', + '1 = 1 AND 2 = 2', (string) $this->_expr->andx($this->_expr->orx($this->_expr->andx($this->_expr->eq(1, 1))), (string) $this->_expr->eq(2, 2)) ); } public function testOrExpr() { - $this->assertEquals('(1 = 1) OR (2 = 2)', (string) $this->_expr->orx((string) $this->_expr->eq(1, 1), (string) $this->_expr->eq(2, 2))); + $this->assertEquals('1 = 1 OR 2 = 2', (string) $this->_expr->orx((string) $this->_expr->eq(1, 1), (string) $this->_expr->eq(2, 2))); } public function testAbsExpr() @@ -296,7 +296,7 @@ class ExprTest extends \Doctrine\Tests\OrmTestCase $orExpr->add($andExpr); $orExpr->add($this->_expr->eq(1, 1)); - $this->assertEquals('((1 = 1) AND (1 < 5)) OR (1 = 1)', (string) $orExpr); + $this->assertEquals('(1 = 1 AND 1 < 5) OR 1 = 1', (string) $orExpr); } public function testOrxExpr() @@ -305,7 +305,7 @@ class ExprTest extends \Doctrine\Tests\OrmTestCase $orExpr->add($this->_expr->eq(1, 1)); $orExpr->add($this->_expr->lt(1, 5)); - $this->assertEquals('(1 = 1) OR (1 < 5)', (string) $orExpr); + $this->assertEquals('1 = 1 OR 1 < 5', (string) $orExpr); } public function testOrderByCountExpr() diff --git a/tests/Doctrine/Tests/ORM/Query/QueryTest.php b/tests/Doctrine/Tests/ORM/Query/QueryTest.php index c5f36f387..b1d2bee23 100644 --- a/tests/Doctrine/Tests/ORM/Query/QueryTest.php +++ b/tests/Doctrine/Tests/ORM/Query/QueryTest.php @@ -13,15 +13,6 @@ class QueryTest extends \Doctrine\Tests\OrmTestCase $this->_em = $this->_getTestEntityManager(); } - /** - * @expectedException Doctrine\ORM\Query\QueryException - */ - public function testParameterIndexZeroThrowsException() - { - $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1"); - $query->execute(array(42)); // same as array(0 => 42), 0 is invalid parameter position - } - public function testGetParameters() { $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1"); diff --git a/tests/Doctrine/Tests/ORM/QueryBuilderTest.php b/tests/Doctrine/Tests/ORM/QueryBuilderTest.php index f18516fc4..119a40dcd 100644 --- a/tests/Doctrine/Tests/ORM/QueryBuilderTest.php +++ b/tests/Doctrine/Tests/ORM/QueryBuilderTest.php @@ -144,6 +144,50 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase $this->assertValidQueryBuilder($qb, 'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a'); } + public function testLeftJoinWithIndexBy() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'a') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->leftJoin('u.articles', 'a', null, null, 'a.name'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a INDEX BY a.name'); + } + + public function testMultipleFrom() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'g') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->from('Doctrine\Tests\Models\CMS\CmsGroup', 'g'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, g FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsGroup g'); + } + + public function testMultipleFromWithJoin() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'g') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->from('Doctrine\Tests\Models\CMS\CmsGroup', 'g') + ->innerJoin('u.articles', 'a', 'ON', 'u.id = a.author_id'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, g FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a ON u.id = a.author_id, Doctrine\Tests\Models\CMS\CmsGroup g'); + } + + public function testMultipleFromWithMultipleJoin() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'g') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->from('Doctrine\Tests\Models\CMS\CmsArticle', 'a') + ->innerJoin('u.groups', 'g') + ->leftJoin('u.address', 'ad') + ->innerJoin('a.comments', 'c'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, g FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.groups g LEFT JOIN u.address ad, Doctrine\Tests\Models\CMS\CmsArticle a INNER JOIN a.comments c'); + } + public function testWhere() { $qb = $this->_em->createQueryBuilder() @@ -162,7 +206,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->where('u.id = :uid') ->andWhere('u.id = :uid2'); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) AND (u.id = :uid2)'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id = :uid2'); } public function testOrWhere() @@ -173,7 +217,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->where('u.id = :uid') ->orWhere('u.id = :uid2'); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) OR (u.id = :uid2)'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid OR u.id = :uid2'); } public function testComplexAndWhereOrWhereNesting() @@ -187,7 +231,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->orWhere('u.name = :name1', 'u.name = :name2') ->andWhere('u.name <> :noname'); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((((u.id = :uid) OR (u.id = :uid2)) AND (u.id = :uid3)) OR (u.name = :name1) OR (u.name = :name2)) AND (u.name <> :noname)'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (((u.id = :uid OR u.id = :uid2) AND u.id = :uid3) OR u.name = :name1 OR u.name = :name2) AND u.name <> :noname'); } public function testAndWhereIn() @@ -198,7 +242,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->where('u.id = :uid') ->andWhere($qb->expr()->in('u.id', array(1, 2, 3))); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) AND (u.id IN(1, 2, 3))'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id IN(1, 2, 3)'); } public function testOrWhereIn() @@ -209,7 +253,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->where('u.id = :uid') ->orWhere($qb->expr()->in('u.id', array(1, 2, 3))); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) OR (u.id IN(1, 2, 3))'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid OR u.id IN(1, 2, 3)'); } public function testAndWhereNotIn() @@ -220,7 +264,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->where('u.id = :uid') ->andWhere($qb->expr()->notIn('u.id', array(1, 2, 3))); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) AND (u.id NOT IN(1, 2, 3))'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id NOT IN(1, 2, 3)'); } public function testOrWhereNotIn() @@ -231,7 +275,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->where('u.id = :uid') ->orWhere($qb->expr()->notIn('u.id', array(1, 2, 3))); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) OR (u.id NOT IN(1, 2, 3))'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid OR u.id NOT IN(1, 2, 3)'); } public function testGroupBy() @@ -265,7 +309,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->having('COUNT(u.id) > 1') ->andHaving('COUNT(u.id) < 1'); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id HAVING (COUNT(u.id) > 1) AND (COUNT(u.id) < 1)'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id HAVING COUNT(u.id) > 1 AND COUNT(u.id) < 1'); } public function testOrHaving() @@ -278,7 +322,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->andHaving('COUNT(u.id) < 1') ->orHaving('COUNT(u.id) > 1'); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id HAVING ((COUNT(u.id) > 1) AND (COUNT(u.id) < 1)) OR (COUNT(u.id) > 1)'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id HAVING (COUNT(u.id) > 1 AND COUNT(u.id) < 1) OR COUNT(u.id) > 1'); } public function testOrderBy() @@ -375,7 +419,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') ->where('u.id = :uid', 'u.id = :uid2'); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) AND (u.id = :uid2)'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id = :uid2'); } public function testMultipleAndWhere() @@ -385,7 +429,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') ->andWhere('u.id = :uid', 'u.id = :uid2'); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) AND (u.id = :uid2)'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id = :uid2'); } public function testMultipleOrWhere() @@ -395,7 +439,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') ->orWhere('u.id = :uid', $qb->expr()->eq('u.id', ':uid2')); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid) OR (u.id = :uid2)'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid OR u.id = :uid2'); } public function testComplexWhere() @@ -409,7 +453,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') ->where($orExpr); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid3) OR (u.id IN(1))'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid3 OR u.id IN(1)'); } public function testWhereInWithStringLiterals() @@ -453,7 +497,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') ->where($orExpr); - $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid3) OR (NOT(u.id IN(1)))'); + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid3 OR NOT(u.id IN(1))'); } public function testSomeAllAny() @@ -490,7 +534,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase $q2 = $qb->getQuery(); - $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.name = :name) AND (u.id = :id)', $q2->getDql()); + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = :name AND u.id = :id', $q2->getDql()); $this->assertTrue($q1 !== $q2); // two different, independent queries $this->assertEquals(2, count($q2->getParameters())); $this->assertEquals(1, count($q1->getParameters())); // $q1 unaffected diff --git a/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php b/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php index 5a9c5d7eb..d7cd56132 100644 --- a/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php @@ -122,7 +122,7 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase $this->_generator->writeEntityClass($metadata, $this->_tmpDir); - $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/~EntityGeneratorBook.php"); + $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~"); $book = $this->newInstance($metadata); $reflClass = new \ReflectionClass($metadata->name);