diff --git a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php index f8b7607ca..5e30c825d 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -236,10 +236,12 @@ abstract class AbstractHydrator } if (isset($this->_rsm->newObjectMappings[$key])) { + $mapping = $this->_rsm->newObjectMappings[$key]; + $cache[$key]['isNewObjectParameter'] = true; - $cache[$key]['argIndex'] = $this->_rsm->newObjectMappings[$key]['argIndex']; - $cache[$key]['objIndex'] = $this->_rsm->newObjectMappings[$key]['objIndex']; - $cache[$key]['class'] = new \ReflectionClass($this->_rsm->newObjectMappings[$key]['className']); + $cache[$key]['argIndex'] = $mapping['argIndex']; + $cache[$key]['objIndex'] = $mapping['objIndex']; + $cache[$key]['class'] = new \ReflectionClass($mapping['className']); } } @@ -247,8 +249,7 @@ abstract class AbstractHydrator $class = $cache[$key]['class']; $argIndex = $cache[$key]['argIndex']; $objIndex = $cache[$key]['objIndex']; - $value = $cache[$key]['type'] - ->convertToPHPValue($value, $this->_platform); + $value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform); $rowData['newObjects'][$objIndex]['class'] = $class; $rowData['newObjects'][$objIndex]['args'][$argIndex] = $value; diff --git a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php index edce92f80..b68bf01cc 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php @@ -397,11 +397,11 @@ class ObjectHydrator extends AbstractHydrator continue; } - $parentClass = $this->ce[$this->_rsm->aliasMap[$parentAlias]]; - $oid = spl_object_hash($parentObject); - $relationField = $this->_rsm->relationMap[$dqlAlias]; - $relation = $parentClass->associationMappings[$relationField]; - $reflField = $parentClass->reflFields[$relationField]; + $parentClass = $this->ce[$this->_rsm->aliasMap[$parentAlias]]; + $oid = spl_object_hash($parentObject); + $relationField = $this->_rsm->relationMap[$dqlAlias]; + $relation = $parentClass->associationMappings[$relationField]; + $reflField = $parentClass->reflFields[$relationField]; // Check the type of the relation (many or single-valued) if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) { @@ -415,9 +415,9 @@ class ObjectHydrator extends AbstractHydrator $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias); } - $indexExists = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]); - $index = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false; - $indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false; + $indexExists = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]); + $index = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false; + $indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false; if ( ! $indexExists || ! $indexIsValid) { if (isset($this->existingCollections[$collKey])) { @@ -514,6 +514,7 @@ class ObjectHydrator extends AbstractHydrator // check for existing result from the iterations before if ( ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) { $element = $this->getEntity($rowData[$dqlAlias], $dqlAlias); + if ($this->_rsm->isMixed) { $element = array($entityKey => $element); } @@ -585,6 +586,7 @@ class ObjectHydrator extends AbstractHydrator if ($count === 1) { $result[$resultKey] = $obj; + continue; } @@ -602,7 +604,7 @@ class ObjectHydrator extends AbstractHydrator { parent::onClear($eventArgs); - $aliases = array_keys($this->identifierMap); + $aliases = array_keys($this->identifierMap); $this->identifierMap = array(); foreach ($aliases as $alias) { diff --git a/lib/Doctrine/ORM/Query/AST/NewObjectExpression.php b/lib/Doctrine/ORM/Query/AST/NewObjectExpression.php index 5ddaf0a5e..caf7a80b7 100644 --- a/lib/Doctrine/ORM/Query/AST/NewObjectExpression.php +++ b/lib/Doctrine/ORM/Query/AST/NewObjectExpression.php @@ -46,7 +46,7 @@ class NewObjectExpression extends Node public function __construct($className, array $args) { $this->className = $className; - $this->args = $args; + $this->args = $args; } /** diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index 22605a3e0..06d329b37 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -581,28 +581,18 @@ class Parser private function processDeferredNewObjectExpressions($AST) { foreach ($this->deferredNewObjectExpressions as $deferredItem) { - $expression = $deferredItem['expression']; - $token = $deferredItem['token']; - $className = $expression->className; - $args = $expression->args; + $expression = $deferredItem['expression']; + $token = $deferredItem['token']; + $className = $expression->className; + $args = $expression->args; + $fromClassName = isset($AST->fromClause->identificationVariableDeclarations[0]->rangeVariableDeclaration->abstractSchemaName) + ? $AST->fromClause->identificationVariableDeclarations[0]->rangeVariableDeclaration->abstractSchemaName + : null; - //first from item - if ( strpos($className, '\\') === false - && ! class_exists($className) - && isset($AST->fromClause - ->identificationVariableDeclarations[0] - ->rangeVariableDeclaration - ->abstractSchemaName)) { - - $fromClassName = $AST->fromClause - ->identificationVariableDeclarations[0] - ->rangeVariableDeclaration - ->abstractSchemaName; - - if (strpos($fromClassName, '\\') !== false) { - $fromClassName = substr($fromClassName, 0 , strrpos($fromClassName, '\\')); - $className = $fromClassName . '\\' . $className; - } + // If the namespace is not given then assumes the first from entity namespace + if (strpos($className, '\\') === false && ! class_exists($className) && strpos($fromClassName, '\\') !== false) { + $namespace = substr($fromClassName, 0 , strrpos($fromClassName, '\\')); + $className = $namespace . '\\' . $className; if (class_exists($className)) { $expression->className = $className; @@ -610,26 +600,21 @@ class Parser } if ( ! class_exists($className)) { - $this->semanticalError(sprintf( - 'Class "%s" is not defined.', - $expression->className - ), $token); + $this->semanticalError(sprintf('Class "%s" is not defined.', $expression->className), $token); } $class = new \ReflectionClass($className); - if($class->getConstructor() === null) { - $this->semanticalError(sprintf( - 'Class "%s" has not a valid contructor.', - $className - ), $token); + if ( ! $class->isInstantiable()) { + $this->semanticalError(sprintf('Class "%s" can not be instantiated.', $className), $token); } - if($class->getConstructor()->getNumberOfRequiredParameters() > sizeof($args)) { - $this->semanticalError(sprintf( - 'Number of arguments does not match with "%s" constructor declaration.', - $className - ), $token); + if ($class->getConstructor() === null) { + $this->semanticalError(sprintf('Class "%s" has not a valid contructor.', $className), $token); + } + + if ($class->getConstructor()->getNumberOfRequiredParameters() > sizeof($args)) { + $this->semanticalError(sprintf('Number of arguments does not match with "%s" constructor declaration.', $className), $token); } } } @@ -1719,6 +1704,7 @@ class Parser /** * NewObjectExpression ::= "NEW" IdentificationVariable "(" NewObjectArg {"," NewObjectArg}* ")" + * * @return \Doctrine\ORM\Query\AST\NewObjectExpression */ public function NewObjectExpression() @@ -1732,6 +1718,7 @@ class Parser $this->match(Lexer::T_OPEN_PARENTHESIS); $args[] = $this->NewObjectArg(); + while ($this->lexer->isNextToken(Lexer::T_COMMA)) { $this->match(Lexer::T_COMMA); @@ -2090,7 +2077,7 @@ class Parser // NewObjectExpression (New ClassName(id, name)) case ($lookaheadType === Lexer::T_NEW): - $expression = $this->NewObjectExpression(); + $expression = $this->NewObjectExpression(); break; default: diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index a24b92836..e6b962919 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -1406,15 +1406,14 @@ class SqlWalker implements TreeWalker public function walkNewObject($newObjectExpression) { $sqlSelectExpressions = array(); - $objIndex = $this->newObjectCounter ++; + $objIndex = $this->newObjectCounter++; foreach ($newObjectExpression->args as $argIndex => $e) { - $resultAlias = $this->scalarResultCounter++; $columnAlias = $this->getSQLColumnAlias('sclr'); switch (true) { - case $e instanceof AST\NewObjectExpression: + case ($e instanceof AST\NewObjectExpression): $sqlSelectExpressions[] = $e->dispatch($this); break; diff --git a/tests/Doctrine/Tests/ORM/Functional/NewOperatorTest.php b/tests/Doctrine/Tests/ORM/Functional/NewOperatorTest.php index cb340912b..6859af5e6 100644 --- a/tests/Doctrine/Tests/ORM/Functional/NewOperatorTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/NewOperatorTest.php @@ -504,6 +504,16 @@ class NewOperatorTest extends \Doctrine\Tests\OrmFunctionalTestCase $dql = "SELECT new Doctrine\Tests\ORM\Functional\ClassWithTooMuchArgs(u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u"; $this->_em->createQuery($dql)->getResult(); } + + /** + * @expectedException Doctrine\ORM\Query\QueryException + * @expectedExceptionMessage [Semantical Error] line 0, col 11 near 'Doctrine\Tests\ORM\Functional\ClassWithPrivateConstructor(u.name)': Error: Class "Doctrine\Tests\ORM\Functional\ClassWithPrivateConstructor" can not be instantiated. + */ + public function testClassCantBeInstantiatedException() + { + $dql = "SELECT new Doctrine\Tests\ORM\Functional\ClassWithPrivateConstructor(u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u"; + $this->_em->createQuery($dql)->getResult(); + } } class ClassWithTooMuchArgs @@ -513,4 +523,12 @@ class ClassWithTooMuchArgs $this->foo = $foo; $this->bor = $bar; } +} + +class ClassWithPrivateConstructor +{ + private function __construct($foo) + { + $this->foo = $foo; + } } \ No newline at end of file