Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #422 from FabioBatSilva/DDC-1574

DDC-1574 - "new" operator
  • Loading branch information...
commit 13762f20c9f6daa0c2e4e8a113de01969c6621da 2 parents 91caff1 + dd984c7
@beberlei beberlei authored
View
19 lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php
@@ -234,6 +234,25 @@ protected function gatherRowData(array $data, array &$cache, array &$id, array &
// maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping.
continue 2;
}
+
+ if (isset($this->_rsm->newObjectMappings[$key])) {
+ $mapping = $this->_rsm->newObjectMappings[$key];
+
+ $cache[$key]['isNewObjectParameter'] = true;
+ $cache[$key]['argIndex'] = $mapping['argIndex'];
+ $cache[$key]['objIndex'] = $mapping['objIndex'];
+ $cache[$key]['class'] = new \ReflectionClass($mapping['className']);
+ }
+ }
+
+ if (isset($cache[$key]['isNewObjectParameter'])) {
+ $class = $cache[$key]['class'];
+ $argIndex = $cache[$key]['argIndex'];
+ $objIndex = $cache[$key]['objIndex'];
+ $value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform);
+
+ $rowData['newObjects'][$objIndex]['class'] = $class;
+ $rowData['newObjects'][$objIndex]['args'][$argIndex] = $value;
}
if (isset($cache[$key]['isScalar'])) {
View
253 lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
@@ -19,15 +19,12 @@
namespace Doctrine\ORM\Internal\Hydration;
-use PDO,
- Doctrine\ORM\Mapping\ClassMetadata,
- Doctrine\ORM\PersistentCollection,
- Doctrine\ORM\Query,
- Doctrine\ORM\Event\LifecycleEventArgs,
- Doctrine\ORM\Events,
- Doctrine\Common\Collections\ArrayCollection,
- Doctrine\Common\Collections\Collection,
- Doctrine\ORM\Proxy\Proxy;
+use PDO;
+use Doctrine\ORM\Mapping\ClassMetadata;
+use Doctrine\ORM\PersistentCollection;
+use Doctrine\ORM\Query;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\ORM\Proxy\Proxy;
/**
* The ObjectHydrator constructs an object graph out of an SQL result set.
@@ -35,6 +32,7 @@
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*
* @internal Highly performance-sensitive code.
*/
@@ -43,38 +41,67 @@ class ObjectHydrator extends AbstractHydrator
/* Local ClassMetadata cache to avoid going to the EntityManager all the time.
* This local cache is maintained between hydration runs and not cleared.
*/
- private $_ce = array();
+ private $ce = array();
/* The following parts are reinitialized on every hydration run. */
- private $_identifierMap;
- private $_resultPointers;
- private $_idTemplate;
- private $_resultCounter;
- private $_rootAliases = array();
- private $_initializedCollections = array();
- private $_existingCollections = array();
+ /**
+ * @var array
+ */
+ private $identifierMap;
+ /**
+ * @var array
+ */
+ private $resultPointers;
- /** @override */
+ /**
+ * @var array
+ */
+ private $idTemplate;
+
+ /**
+ * @var integer
+ */
+ private $resultCounter;
+
+ /**
+ * @var array
+ */
+ private $rootAliases = array();
+
+ /**
+ * @var array
+ */
+ private $initializedCollections = array();
+
+ /**
+ * @var array
+ */
+ private $existingCollections = array();
+
+
+ /**
+ * {@inheritdoc}
+ */
protected function prepare()
{
- $this->_identifierMap =
- $this->_resultPointers =
- $this->_idTemplate = array();
+ $this->identifierMap =
+ $this->resultPointers =
+ $this->idTemplate = array();
- $this->_resultCounter = 0;
+ $this->resultCounter = 0;
if ( ! isset($this->_hints['deferEagerLoad'])) {
$this->_hints['deferEagerLoad'] = true;
}
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
- $this->_identifierMap[$dqlAlias] = array();
- $this->_idTemplate[$dqlAlias] = '';
+ $this->identifierMap[$dqlAlias] = array();
+ $this->idTemplate[$dqlAlias] = '';
- if ( ! isset($this->_ce[$className])) {
- $this->_ce[$className] = $this->_em->getClassMetadata($className);
+ if ( ! isset($this->ce[$className])) {
+ $this->ce[$className] = $this->_em->getClassMetadata($className);
}
// Remember which associations are "fetch joined", so that we know where to inject
@@ -88,7 +115,7 @@ protected function prepare()
}
$sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
- $sourceClass = $this->_getClassMetadata($sourceClassName);
+ $sourceClass = $this->getClassMetadata($sourceClassName);
$assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
$this->_hints['fetched'][$this->_rsm->parentAliasMap[$dqlAlias]][$assoc['fieldName']] = true;
@@ -106,7 +133,7 @@ protected function prepare()
// handle fetch-joined owning side bi-directional one-to-one associations
if ($assoc['inversedBy']) {
- $class = $this->_ce[$className];
+ $class = $this->ce[$className];
$inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
if ( ! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) {
@@ -127,10 +154,10 @@ protected function cleanup()
parent::cleanup();
- $this->_identifierMap =
- $this->_initializedCollections =
- $this->_existingCollections =
- $this->_resultPointers = array();
+ $this->identifierMap =
+ $this->initializedCollections =
+ $this->existingCollections =
+ $this->resultPointers = array();
if ($eagerLoad) {
$this->_em->getUnitOfWork()->triggerEagerLoads();
@@ -150,7 +177,7 @@ protected function hydrateAllData()
}
// Take snapshots from all newly initialized collections
- foreach ($this->_initializedCollections as $coll) {
+ foreach ($this->initializedCollections as $coll) {
$coll->takeSnapshot();
}
@@ -165,7 +192,7 @@ protected function hydrateAllData()
* @param string $fieldName The name of the field on the entity that holds the collection.
* @param string $parentDqlAlias Alias of the parent fetch joining this collection.
*/
- private function _initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
+ private function initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
{
$oid = spl_object_hash($entity);
$relation = $class->associationMappings[$fieldName];
@@ -177,14 +204,14 @@ private function _initRelatedCollection($entity, $class, $fieldName, $parentDqlA
if ( ! $value instanceof PersistentCollection) {
$value = new PersistentCollection(
- $this->_em, $this->_ce[$relation['targetEntity']], $value
+ $this->_em, $this->ce[$relation['targetEntity']], $value
);
$value->setOwner($entity, $relation);
$class->reflFields[$fieldName]->setValue($entity, $value);
$this->_uow->setOriginalEntityProperty($oid, $fieldName, $value);
- $this->_initializedCollections[$oid . $fieldName] = $value;
+ $this->initializedCollections[$oid . $fieldName] = $value;
} else if (
isset($this->_hints[Query::HINT_REFRESH]) ||
isset($this->_hints['fetched'][$parentDqlAlias][$fieldName]) &&
@@ -195,10 +222,10 @@ private function _initRelatedCollection($entity, $class, $fieldName, $parentDqlA
$value->setInitialized(true);
$value->unwrap()->clear();
- $this->_initializedCollections[$oid . $fieldName] = $value;
+ $this->initializedCollections[$oid . $fieldName] = $value;
} else {
// Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
- $this->_existingCollections[$oid . $fieldName] = $value;
+ $this->existingCollections[$oid . $fieldName] = $value;
}
return $value;
@@ -211,7 +238,7 @@ private function _initRelatedCollection($entity, $class, $fieldName, $parentDqlA
* @param string $dqlAlias The DQL alias of the entity's class.
* @return object The entity.
*/
- private function _getEntity(array $data, $dqlAlias)
+ private function getEntity(array $data, $dqlAlias)
{
$className = $this->_rsm->aliasMap[$dqlAlias];
@@ -231,13 +258,13 @@ private function _getEntity(array $data, $dqlAlias)
throw HydrationException::emptyDiscriminatorValue($dqlAlias);
}
- $className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]];
+ $className = $this->ce[$className]->discriminatorMap[$data[$discrColumn]];
unset($data[$discrColumn]);
}
- if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->_rootAliases[$dqlAlias])) {
- $this->registerManaged($this->_ce[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
+ if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->rootAliases[$dqlAlias])) {
+ $this->registerManaged($this->ce[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
}
$this->_hints['fetchAlias'] = $dqlAlias;
@@ -250,10 +277,10 @@ private function _getEntity(array $data, $dqlAlias)
* @param array $data
* @return mixed
*/
- private function _getEntityFromIdentityMap($className, array $data)
+ private function getEntityFromIdentityMap($className, array $data)
{
// TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
- $class = $this->_ce[$className];
+ $class = $this->ce[$className];
/* @var $class ClassMetadata */
if ($class->isIdentifierComposite) {
@@ -281,13 +308,13 @@ private function _getEntityFromIdentityMap($className, array $data)
* @param string $className The name of the class.
* @return ClassMetadata
*/
- private function _getClassMetadata($className)
+ private function getClassMetadata($className)
{
- if ( ! isset($this->_ce[$className])) {
- $this->_ce[$className] = $this->_em->getClassMetadata($className);
+ if ( ! isset($this->ce[$className])) {
+ $this->ce[$className] = $this->_em->getClassMetadata($className);
}
- return $this->_ce[$className];
+ return $this->ce[$className];
}
/**
@@ -314,7 +341,7 @@ private function _getClassMetadata($className)
protected function hydrateRowData(array $row, array &$cache, array &$result)
{
// Initialize
- $id = $this->_idTemplate; // initialize the id-memory
+ $id = $this->idTemplate; // initialize the id-memory
$nonemptyComponents = array();
// Split the row data into chunks of class data.
$rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents);
@@ -326,7 +353,18 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
unset($rowData['scalars']);
if (empty($rowData)) {
- ++$this->_resultCounter;
+ ++$this->resultCounter;
+ }
+ }
+
+ // Extract "new" object constructor arguments. They're appended at the end.
+ if (isset($rowData['newObjects'])) {
+ $newObjects = $rowData['newObjects'];
+
+ unset($rowData['newObjects']);
+
+ if (empty($rowData)) {
+ ++$this->resultCounter;
}
}
@@ -349,21 +387,21 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
}
// Get a reference to the parent object to which the joined element belongs.
- if ($this->_rsm->isMixed && isset($this->_rootAliases[$parentAlias])) {
- $first = reset($this->_resultPointers);
+ if ($this->_rsm->isMixed && isset($this->rootAliases[$parentAlias])) {
+ $first = reset($this->resultPointers);
$parentObject = $first[key($first)];
- } else if (isset($this->_resultPointers[$parentAlias])) {
- $parentObject = $this->_resultPointers[$parentAlias];
+ } else if (isset($this->resultPointers[$parentAlias])) {
+ $parentObject = $this->resultPointers[$parentAlias];
} else {
// Parent object of relation not found, so skip it.
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)) {
@@ -371,45 +409,45 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
// PATH A: Collection-valued association
if (isset($nonemptyComponents[$dqlAlias])) {
$collKey = $oid . $relationField;
- if (isset($this->_initializedCollections[$collKey])) {
- $reflFieldValue = $this->_initializedCollections[$collKey];
- } else if ( ! isset($this->_existingCollections[$collKey])) {
- $reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
+ if (isset($this->initializedCollections[$collKey])) {
+ $reflFieldValue = $this->initializedCollections[$collKey];
+ } else if ( ! isset($this->existingCollections[$collKey])) {
+ $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])) {
+ if (isset($this->existingCollections[$collKey])) {
// Collection exists, only look for the element in the identity map.
- if ($element = $this->_getEntityFromIdentityMap($entityName, $data)) {
- $this->_resultPointers[$dqlAlias] = $element;
+ if ($element = $this->getEntityFromIdentityMap($entityName, $data)) {
+ $this->resultPointers[$dqlAlias] = $element;
} else {
- unset($this->_resultPointers[$dqlAlias]);
+ unset($this->resultPointers[$dqlAlias]);
}
} else {
- $element = $this->_getEntity($data, $dqlAlias);
+ $element = $this->getEntity($data, $dqlAlias);
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]];
$reflFieldValue->hydrateSet($indexValue, $element);
- $this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
+ $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
} else {
$reflFieldValue->hydrateAdd($element);
$reflFieldValue->last();
- $this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key();
+ $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key();
}
// Update result pointer
- $this->_resultPointers[$dqlAlias] = $element;
+ $this->resultPointers[$dqlAlias] = $element;
}
} else {
// Update result pointer
- $this->_resultPointers[$dqlAlias] = $reflFieldValue[$index];
+ $this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
}
} else if ( ! $reflFieldValue) {
- $reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
+ $reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
} else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
$reflFieldValue->setInitialized(true);
}
@@ -421,10 +459,10 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
// we only need to take action if this value is null,
// we refresh the entity or its an unitialized proxy.
if (isset($nonemptyComponents[$dqlAlias])) {
- $element = $this->_getEntity($data, $dqlAlias);
+ $element = $this->getEntity($data, $dqlAlias);
$reflField->setValue($parentObject, $element);
$this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
- $targetClass = $this->_ce[$relation['targetEntity']];
+ $targetClass = $this->ce[$relation['targetEntity']];
if ($relation['isOwningSide']) {
//TODO: Just check hints['fetched'] here?
@@ -445,7 +483,7 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
$this->_uow->setOriginalEntityProperty(spl_object_hash($element), $relation['mappedBy'], $parentObject);
}
// Update result pointer
- $this->_resultPointers[$dqlAlias] = $element;
+ $this->resultPointers[$dqlAlias] = $element;
} else {
$this->_uow->setOriginalEntityProperty($oid, $relationField, null);
$reflField->setValue($parentObject, null);
@@ -453,12 +491,12 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
// else leave $reflFieldValue null for single-valued associations
} else {
// Update result pointer
- $this->_resultPointers[$dqlAlias] = $reflFieldValue;
+ $this->resultPointers[$dqlAlias] = $reflFieldValue;
}
}
} else {
// PATH C: Its a root result element
- $this->_rootAliases[$dqlAlias] = true; // Mark as root alias
+ $this->rootAliases[$dqlAlias] = true; // Mark as root alias
$entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
// if this row has a NULL value for the root result id then make it a null result.
@@ -468,14 +506,15 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
} else {
$result[] = null;
}
- $resultKey = $this->_resultCounter;
- ++$this->_resultCounter;
+ $resultKey = $this->resultCounter;
+ ++$this->resultCounter;
continue;
}
// check for existing result from the iterations before
- if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
- $element = $this->_getEntity($rowData[$dqlAlias], $dqlAlias);
+ if ( ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
+ $element = $this->getEntity($rowData[$dqlAlias], $dqlAlias);
+
if ($this->_rsm->isMixed) {
$element = array($entityKey => $element);
}
@@ -489,8 +528,8 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
$result[$resultKey] = $element;
} else {
- $resultKey = $this->_resultCounter;
- ++$this->_resultCounter;
+ $resultKey = $this->resultCounter;
+ ++$this->resultCounter;
if (isset($this->_hints['collection'])) {
$this->_hints['collection']->hydrateAdd($element);
@@ -499,15 +538,15 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
$result[] = $element;
}
- $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
+ $this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
// Update result pointer
- $this->_resultPointers[$dqlAlias] = $element;
+ $this->resultPointers[$dqlAlias] = $element;
} else {
// Update result pointer
- $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
- $this->_resultPointers[$dqlAlias] = $result[$index];
+ $index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
+ $this->resultPointers[$dqlAlias] = $result[$index];
$resultKey = $index;
/*if ($this->_rsm->isMixed) {
$result[] = $result[$index];
@@ -523,7 +562,7 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
if (isset($this->_rsm->indexByMap['scalars'])) {
$resultKey = $row[$this->_rsm->indexByMap['scalars']];
} else {
- $resultKey = $this->_resultCounter - 1;
+ $resultKey = $this->resultCounter - 1;
}
}
@@ -531,6 +570,30 @@ protected function hydrateRowData(array $row, array &$cache, array &$result)
$result[$resultKey][$name] = $value;
}
}
+
+ // Append new object to mixed result sets
+ if (isset($newObjects)) {
+ if ( ! isset($resultKey) ) {
+ $resultKey = $this->resultCounter - 1;
+ }
+
+ $count = count($newObjects);
+
+ foreach ($newObjects as $objIndex => $newObject) {
+ $class = $newObject['class'];
+ $args = $newObject['args'];
+ $obj = $class->newInstanceArgs($args);
+
+ if ($count === 1) {
+ $result[$resultKey] = $obj;
+
+ continue;
+ }
+
+ $result[$resultKey][$objIndex] = $obj;
+ }
+ }
+
}
/**
@@ -541,11 +604,11 @@ public function onClear($eventArgs)
{
parent::onClear($eventArgs);
- $aliases = array_keys($this->_identifierMap);
- $this->_identifierMap = array();
+ $aliases = array_keys($this->identifierMap);
+ $this->identifierMap = array();
foreach ($aliases as $alias) {
- $this->_identifierMap[$alias] = array();
+ $this->identifierMap[$alias] = array();
}
}
}
View
60 lib/Doctrine/ORM/Query/AST/NewObjectExpression.php
@@ -0,0 +1,60 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the LGPL. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\ORM\Query\AST;
+
+/**
+ * NewObjectExpression ::= "NEW" IdentificationVariable "(" NewObjectArg {"," NewObjectArg}* ")"
+ *
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @link www.doctrine-project.org
+ * @since 2.3
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
+ */
+class NewObjectExpression extends Node
+{
+ /**
+ * @var string
+ */
+ public $className;
+
+ /**
+ * @var array
+ */
+ public $args;
+
+ /**
+ * @param type $className
+ * @param array $args
+ */
+ public function __construct($className, array $args)
+ {
+ $this->className = $className;
+ $this->args = $args;
+ }
+
+ /**
+ * @param \Doctrine\ORM\Query\SqlWalker $sqlWalker
+ * @return string
+ */
+ public function dispatch($sqlWalker)
+ {
+ return $sqlWalker->walkNewObject($this);
+ }
+}
View
1  lib/Doctrine/ORM/Query/Lexer.php
@@ -108,6 +108,7 @@ class Lexer extends \Doctrine\Common\Lexer
const T_WHERE = 154;
const T_WITH = 155;
const T_PARTIAL = 156;
+ const T_NEW = 157;
/**
* Creates a new query scanner object.
View
797 lib/Doctrine/ORM/Query/Parser.php
@@ -31,6 +31,7 @@
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class Parser
{
@@ -66,75 +67,96 @@ class Parser
'date_sub' => 'Doctrine\ORM\Query\AST\Functions\DateSubFunction',
);
- /**
+ /*
* Expressions that were encountered during parsing of identifiers and expressions
* and still need to be validated.
*/
- private $_deferredIdentificationVariables = array();
- private $_deferredPartialObjectExpressions = array();
- private $_deferredPathExpressions = array();
- private $_deferredResultVariables = array();
+
+ /**
+ * @var array
+ */
+ private $deferredIdentificationVariables = array();
+
+ /**
+ * @var array
+ */
+ private $deferredPartialObjectExpressions = array();
+
+ /**
+ * @var array
+ */
+ private $deferredPathExpressions = array();
+
+ /**
+ * @var array
+ */
+ private $deferredResultVariables = array();
+
+ /**
+ * @var array
+ */
+ private $deferredNewObjectExpressions = array();
/**
* The lexer.
*
* @var \Doctrine\ORM\Query\Lexer
*/
- private $_lexer;
+ private $lexer;
/**
* The parser result.
*
* @var \Doctrine\ORM\Query\ParserResult
*/
- private $_parserResult;
+ private $parserResult;
/**
* The EntityManager.
*
* @var \Doctrine\ORM\EntityManager
*/
- private $_em;
+ private $em;
/**
* The Query to parse.
*
* @var Query
*/
- private $_query;
+ private $query;
/**
* Map of declared query components in the parsed query.
*
* @var array
*/
- private $_queryComponents = array();
+ private $queryComponents = array();
/**
* Keeps the nesting level of defined ResultVariables
*
* @var integer
*/
- private $_nestingLevel = 0;
+ private $nestingLevel = 0;
/**
* Any additional custom tree walkers that modify the AST.
*
* @var array
*/
- private $_customTreeWalkers = array();
+ private $customTreeWalkers = array();
/**
* The custom last tree walker, if any, that is responsible for producing the output.
*
* @var TreeWalker
*/
- private $_customOutputWalker;
+ private $customOutputWalker;
/**
* @var array
*/
- private $_identVariableExpressions = array();
+ private $identVariableExpressions = array();
/**
* Check if a function is internally defined. Used to prevent overwriting
@@ -159,10 +181,10 @@ static public function isInternalFunction($functionName)
*/
public function __construct(Query $query)
{
- $this->_query = $query;
- $this->_em = $query->getEntityManager();
- $this->_lexer = new Lexer($query->getDql());
- $this->_parserResult = new ParserResult();
+ $this->query = $query;
+ $this->em = $query->getEntityManager();
+ $this->lexer = new Lexer($query->getDql());
+ $this->parserResult = new ParserResult();
}
/**
@@ -173,7 +195,7 @@ public function __construct(Query $query)
*/
public function setCustomOutputTreeWalker($className)
{
- $this->_customOutputWalker = $className;
+ $this->customOutputWalker = $className;
}
/**
@@ -183,7 +205,7 @@ public function setCustomOutputTreeWalker($className)
*/
public function addCustomTreeWalker($className)
{
- $this->_customTreeWalkers[] = $className;
+ $this->customTreeWalkers[] = $className;
}
/**
@@ -193,7 +215,7 @@ public function addCustomTreeWalker($className)
*/
public function getLexer()
{
- return $this->_lexer;
+ return $this->lexer;
}
/**
@@ -203,7 +225,7 @@ public function getLexer()
*/
public function getParserResult()
{
- return $this->_parserResult;
+ return $this->parserResult;
}
/**
@@ -213,7 +235,7 @@ public function getParserResult()
*/
public function getEntityManager()
{
- return $this->_em;
+ return $this->em;
}
/**
@@ -230,21 +252,25 @@ public function getAST()
// Process any deferred validations of some nodes in the AST.
// This also allows post-processing of the AST for modification purposes.
- $this->_processDeferredIdentificationVariables();
+ $this->processDeferredIdentificationVariables();
- if ($this->_deferredPartialObjectExpressions) {
- $this->_processDeferredPartialObjectExpressions();
+ if ($this->deferredPartialObjectExpressions) {
+ $this->processDeferredPartialObjectExpressions();
}
- if ($this->_deferredPathExpressions) {
- $this->_processDeferredPathExpressions($AST);
+ if ($this->deferredPathExpressions) {
+ $this->processDeferredPathExpressions($AST);
}
- if ($this->_deferredResultVariables) {
- $this->_processDeferredResultVariables();
+ if ($this->deferredResultVariables) {
+ $this->processDeferredResultVariables();
}
- $this->_processRootEntityAliasSelected();
+ if ($this->deferredNewObjectExpressions) {
+ $this->processDeferredNewObjectExpressions($AST);
+ }
+
+ $this->processRootEntityAliasSelected();
// TODO: Is there a way to remove this? It may impact the mixed hydration resultset a lot!
$this->fixIdentificationVariableOrder($AST);
@@ -264,14 +290,14 @@ public function getAST()
*/
public function match($token)
{
- $lookaheadType = $this->_lexer->lookahead['type'];
+ $lookaheadType = $this->lexer->lookahead['type'];
// short-circuit on first condition, usually types match
if ($lookaheadType !== $token && $token !== Lexer::T_IDENTIFIER && $lookaheadType <= Lexer::T_IDENTIFIER) {
- $this->syntaxError($this->_lexer->getLiteral($token));
+ $this->syntaxError($this->lexer->getLiteral($token));
}
- $this->_lexer->moveNext();
+ $this->lexer->moveNext();
}
/**
@@ -283,15 +309,15 @@ public function match($token)
public function free($deep = false, $position = 0)
{
// WARNING! Use this method with care. It resets the scanner!
- $this->_lexer->resetPosition($position);
+ $this->lexer->resetPosition($position);
// Deep = true cleans peek and also any previously defined errors
if ($deep) {
- $this->_lexer->resetPeek();
+ $this->lexer->resetPeek();
}
- $this->_lexer->token = null;
- $this->_lexer->lookahead = null;
+ $this->lexer->token = null;
+ $this->lexer->lookahead = null;
}
/**
@@ -303,19 +329,19 @@ public function parse()
{
$AST = $this->getAST();
- if (($customWalkers = $this->_query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) {
- $this->_customTreeWalkers = $customWalkers;
+ if (($customWalkers = $this->query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) {
+ $this->customTreeWalkers = $customWalkers;
}
- if (($customOutputWalker = $this->_query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER)) !== false) {
- $this->_customOutputWalker = $customOutputWalker;
+ if (($customOutputWalker = $this->query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER)) !== false) {
+ $this->customOutputWalker = $customOutputWalker;
}
// Run any custom tree walkers over the AST
- if ($this->_customTreeWalkers) {
- $treeWalkerChain = new TreeWalkerChain($this->_query, $this->_parserResult, $this->_queryComponents);
+ if ($this->customTreeWalkers) {
+ $treeWalkerChain = new TreeWalkerChain($this->query, $this->parserResult, $this->queryComponents);
- foreach ($this->_customTreeWalkers as $walker) {
+ foreach ($this->customTreeWalkers as $walker) {
$treeWalkerChain->addTreeWalker($walker);
}
@@ -334,13 +360,13 @@ public function parse()
}
}
- $outputWalkerClass = $this->_customOutputWalker ?: __NAMESPACE__ . '\SqlWalker';
- $outputWalker = new $outputWalkerClass($this->_query, $this->_parserResult, $this->_queryComponents);
+ $outputWalkerClass = $this->customOutputWalker ?: __NAMESPACE__ . '\SqlWalker';
+ $outputWalker = new $outputWalkerClass($this->query, $this->parserResult, $this->queryComponents);
// Assign an SQL executor to the parser result
- $this->_parserResult->setSqlExecutor($outputWalker->getExecutor($AST));
+ $this->parserResult->setSqlExecutor($outputWalker->getExecutor($AST));
- return $this->_parserResult;
+ return $this->parserResult;
}
/**
@@ -355,16 +381,16 @@ public function parse()
*/
private function fixIdentificationVariableOrder($AST)
{
- if (count($this->_identVariableExpressions) <= 1) {
+ if (count($this->identVariableExpressions) <= 1) {
return;
}
- foreach ($this->_queryComponents as $dqlAlias => $qComp) {
- if ( ! isset($this->_identVariableExpressions[$dqlAlias])) {
+ foreach ($this->queryComponents as $dqlAlias => $qComp) {
+ if ( ! isset($this->identVariableExpressions[$dqlAlias])) {
continue;
}
- $expr = $this->_identVariableExpressions[$dqlAlias];
+ $expr = $this->identVariableExpressions[$dqlAlias];
$key = array_search($expr, $AST->selectClause->selectExpressions);
unset($AST->selectClause->selectExpressions[$key]);
@@ -384,16 +410,16 @@ private function fixIdentificationVariableOrder($AST)
public function syntaxError($expected = '', $token = null)
{
if ($token === null) {
- $token = $this->_lexer->lookahead;
+ $token = $this->lexer->lookahead;
}
$tokenPos = (isset($token['position'])) ? $token['position'] : '-1';
$message = "line 0, col {$tokenPos}: Error: ";
$message .= ($expected !== '') ? "Expected {$expected}, got " : 'Unexpected ';
- $message .= ($this->_lexer->lookahead === null) ? 'end of string.' : "'{$token['value']}'";
+ $message .= ($this->lexer->lookahead === null) ? 'end of string.' : "'{$token['value']}'";
- throw QueryException::syntaxError($message, QueryException::dqlError($this->_query->getDQL()));
+ throw QueryException::syntaxError($message, QueryException::dqlError($this->query->getDQL()));
}
/**
@@ -407,14 +433,14 @@ public function syntaxError($expected = '', $token = null)
public function semanticalError($message = '', $token = null)
{
if ($token === null) {
- $token = $this->_lexer->lookahead;
+ $token = $this->lexer->lookahead;
}
// Minimum exposed chars ahead of token
$distance = 12;
// Find a position of a final word to display in error string
- $dql = $this->_query->getDql();
+ $dql = $this->query->getDql();
$length = strlen($dql);
$pos = $token['position'] + $distance;
$pos = strpos($dql, ' ', ($length > $pos) ? $pos : $length);
@@ -426,7 +452,7 @@ public function semanticalError($message = '', $token = null)
// Building informative message
$message = 'line 0, col ' . $tokenPos . " near '" . $tokenStr . "': Error: " . $message;
- throw QueryException::semanticalError($message, QueryException::dqlError($this->_query->getDQL()));
+ throw QueryException::semanticalError($message, QueryException::dqlError($this->query->getDQL()));
}
/**
@@ -435,9 +461,9 @@ public function semanticalError($message = '', $token = null)
* @param boolean $resetPeek Reset peek after finding the closing parenthesis
* @return array
*/
- private function _peekBeyondClosingParenthesis($resetPeek = true)
+ private function peekBeyondClosingParenthesis($resetPeek = true)
{
- $token = $this->_lexer->peek();
+ $token = $this->lexer->peek();
$numUnmatched = 1;
while ($numUnmatched > 0 && $token !== null) {
@@ -454,11 +480,11 @@ private function _peekBeyondClosingParenthesis($resetPeek = true)
// Do nothing
}
- $token = $this->_lexer->peek();
+ $token = $this->lexer->peek();
}
if ($resetPeek) {
- $this->_lexer->resetPeek();
+ $this->lexer->resetPeek();
}
return $token;
@@ -469,7 +495,7 @@ private function _peekBeyondClosingParenthesis($resetPeek = true)
*
* @return boolean TRUE if the token is a mathematical operator, FALSE otherwise.
*/
- private function _isMathOperator($token)
+ private function isMathOperator($token)
{
return in_array($token['type'], array(Lexer::T_PLUS, Lexer::T_MINUS, Lexer::T_DIVIDE, Lexer::T_MULTIPLY));
}
@@ -479,12 +505,12 @@ private function _isMathOperator($token)
*
* @return boolean TRUE if the next-next tokens start a function, FALSE otherwise.
*/
- private function _isFunction()
+ private function isFunction()
{
- $peek = $this->_lexer->peek();
- $nextpeek = $this->_lexer->peek();
+ $peek = $this->lexer->peek();
+ $nextpeek = $this->lexer->peek();
- $this->_lexer->resetPeek();
+ $this->lexer->resetPeek();
// We deny the COUNT(SELECT * FROM User u) here. COUNT won't be considered a function
return ($peek['type'] === Lexer::T_OPEN_PARENTHESIS && $nextpeek['type'] !== Lexer::T_SELECT);
@@ -495,7 +521,7 @@ private function _isFunction()
*
* @return boolean TRUE if the token type is an aggregate function, FALSE otherwise.
*/
- private function _isAggregateFunction($tokenType)
+ private function isAggregateFunction($tokenType)
{
return in_array($tokenType, array(Lexer::T_AVG, Lexer::T_MIN, Lexer::T_MAX, Lexer::T_SUM, Lexer::T_COUNT));
}
@@ -505,9 +531,9 @@ private function _isAggregateFunction($tokenType)
*
* @return boolean
*/
- private function _isNextAllAnySome()
+ private function isNextAllAnySome()
{
- return in_array($this->_lexer->lookahead['type'], array(Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME));
+ return in_array($this->lexer->lookahead['type'], array(Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME));
}
/**
@@ -516,19 +542,19 @@ private function _isNextAllAnySome()
*
* @return void
*/
- private function _processDeferredIdentificationVariables()
+ private function processDeferredIdentificationVariables()
{
- foreach ($this->_deferredIdentificationVariables as $deferredItem) {
+ foreach ($this->deferredIdentificationVariables as $deferredItem) {
$identVariable = $deferredItem['expression'];
// Check if IdentificationVariable exists in queryComponents
- if ( ! isset($this->_queryComponents[$identVariable])) {
+ if ( ! isset($this->queryComponents[$identVariable])) {
$this->semanticalError(
"'$identVariable' is not defined.", $deferredItem['token']
);
}
- $qComp = $this->_queryComponents[$identVariable];
+ $qComp = $this->queryComponents[$identVariable];
// Check if queryComponent points to an AbstractSchemaName or a ResultVariable
if ( ! isset($qComp['metadata'])) {
@@ -547,16 +573,64 @@ private function _processDeferredIdentificationVariables()
}
/**
+ * Validates that the given <tt>NewObjectExpression</tt>.
+ *
+ * @param \Doctrine\ORM\Query\AST\SelectClause $AST
+ * @return void
+ */
+ private function processDeferredNewObjectExpressions($AST)
+ {
+ foreach ($this->deferredNewObjectExpressions as $deferredItem) {
+ $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;
+
+ // 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, '\\'));
+ $fqcn = $namespace . '\\' . $className;
+
+ if (class_exists($fqcn)) {
+ $expression->className = $fqcn;
+ $className = $fqcn;
+ }
+ }
+
+ if ( ! class_exists($className)) {
+ $this->semanticalError(sprintf('Class "%s" is not defined.', $className), $token);
+ }
+
+ $class = new \ReflectionClass($className);
+
+ if ( ! $class->isInstantiable()) {
+ $this->semanticalError(sprintf('Class "%s" can not be instantiated.', $className), $token);
+ }
+
+ if ($class->getConstructor() === null) {
+ $this->semanticalError(sprintf('Class "%s" has not a valid contructor.', $className), $token);
+ }
+
+ if ($class->getConstructor()->getNumberOfRequiredParameters() > count($args)) {
+ $this->semanticalError(sprintf('Number of arguments does not match with "%s" constructor declaration.', $className), $token);
+ }
+ }
+ }
+
+ /**
* Validates that the given <tt>PartialObjectExpression</tt> is semantically correct.
* It must exist in query components list.
*
* @return void
*/
- private function _processDeferredPartialObjectExpressions()
+ private function processDeferredPartialObjectExpressions()
{
- foreach ($this->_deferredPartialObjectExpressions as $deferredItem) {
+ foreach ($this->deferredPartialObjectExpressions as $deferredItem) {
$expr = $deferredItem['expression'];
- $class = $this->_queryComponents[$expr->identificationVariable]['metadata'];
+ $class = $this->queryComponents[$expr->identificationVariable]['metadata'];
foreach ($expr->partialFieldSet as $field) {
if (isset($class->fieldMappings[$field])) {
@@ -583,19 +657,19 @@ private function _processDeferredPartialObjectExpressions()
*
* @return void
*/
- private function _processDeferredResultVariables()
+ private function processDeferredResultVariables()
{
- foreach ($this->_deferredResultVariables as $deferredItem) {
+ foreach ($this->deferredResultVariables as $deferredItem) {
$resultVariable = $deferredItem['expression'];
// Check if ResultVariable exists in queryComponents
- if ( ! isset($this->_queryComponents[$resultVariable])) {
+ if ( ! isset($this->queryComponents[$resultVariable])) {
$this->semanticalError(
"'$resultVariable' is not defined.", $deferredItem['token']
);
}
- $qComp = $this->_queryComponents[$resultVariable];
+ $qComp = $this->queryComponents[$resultVariable];
// Check if queryComponent points to an AbstractSchemaName or a ResultVariable
if ( ! isset($qComp['resultVariable'])) {
@@ -625,12 +699,12 @@ private function _processDeferredResultVariables()
* @param array $deferredItem
* @param mixed $AST
*/
- private function _processDeferredPathExpressions($AST)
+ private function processDeferredPathExpressions($AST)
{
- foreach ($this->_deferredPathExpressions as $deferredItem) {
+ foreach ($this->deferredPathExpressions as $deferredItem) {
$pathExpression = $deferredItem['expression'];
- $qComp = $this->_queryComponents[$pathExpression->identificationVariable];
+ $qComp = $this->queryComponents[$pathExpression->identificationVariable];
$class = $qComp['metadata'];
if (($field = $pathExpression->field) === null) {
@@ -691,16 +765,16 @@ private function _processDeferredPathExpressions($AST)
}
}
- private function _processRootEntityAliasSelected()
+ private function processRootEntityAliasSelected()
{
- if ( ! count($this->_identVariableExpressions)) {
+ if ( ! count($this->identVariableExpressions)) {
return;
}
$foundRootEntity = false;
- foreach ($this->_identVariableExpressions as $dqlAlias => $expr) {
- if (isset($this->_queryComponents[$dqlAlias]) && $this->_queryComponents[$dqlAlias]['parent'] === null) {
+ foreach ($this->identVariableExpressions as $dqlAlias => $expr) {
+ if (isset($this->queryComponents[$dqlAlias]) && $this->queryComponents[$dqlAlias]['parent'] === null) {
$foundRootEntity = true;
}
}
@@ -719,9 +793,9 @@ private function _processRootEntityAliasSelected()
*/
public function QueryLanguage()
{
- $this->_lexer->moveNext();
+ $this->lexer->moveNext();
- switch ($this->_lexer->lookahead['type']) {
+ switch ($this->lexer->lookahead['type']) {
case Lexer::T_SELECT:
$statement = $this->SelectStatement();
break;
@@ -740,7 +814,7 @@ public function QueryLanguage()
}
// Check for end of string
- if ($this->_lexer->lookahead !== null) {
+ if ($this->lexer->lookahead !== null) {
$this->syntaxError('end of string');
}
@@ -756,10 +830,10 @@ public function SelectStatement()
{
$selectStatement = new AST\SelectStatement($this->SelectClause(), $this->FromClause());
- $selectStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
- $selectStatement->groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null;
- $selectStatement->havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null;
- $selectStatement->orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null;
+ $selectStatement->whereClause = $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
+ $selectStatement->groupByClause = $this->lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null;
+ $selectStatement->havingClause = $this->lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null;
+ $selectStatement->orderByClause = $this->lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null;
return $selectStatement;
}
@@ -773,7 +847,7 @@ public function UpdateStatement()
{
$updateStatement = new AST\UpdateStatement($this->UpdateClause());
- $updateStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
+ $updateStatement->whereClause = $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
return $updateStatement;
}
@@ -787,7 +861,7 @@ public function DeleteStatement()
{
$deleteStatement = new AST\DeleteStatement($this->DeleteClause());
- $deleteStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
+ $deleteStatement->whereClause = $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
return $deleteStatement;
}
@@ -801,12 +875,12 @@ public function IdentificationVariable()
{
$this->match(Lexer::T_IDENTIFIER);
- $identVariable = $this->_lexer->token['value'];
+ $identVariable = $this->lexer->token['value'];
- $this->_deferredIdentificationVariables[] = array(
+ $this->deferredIdentificationVariables[] = array(
'expression' => $identVariable,
- 'nestingLevel' => $this->_nestingLevel,
- 'token' => $this->_lexer->token,
+ 'nestingLevel' => $this->nestingLevel,
+ 'token' => $this->lexer->token,
);
return $identVariable;
@@ -821,11 +895,11 @@ public function AliasIdentificationVariable()
{
$this->match(Lexer::T_IDENTIFIER);
- $aliasIdentVariable = $this->_lexer->token['value'];
- $exists = isset($this->_queryComponents[$aliasIdentVariable]);
+ $aliasIdentVariable = $this->lexer->token['value'];
+ $exists = isset($this->queryComponents[$aliasIdentVariable]);
if ($exists) {
- $this->semanticalError("'$aliasIdentVariable' is already defined.", $this->_lexer->token);
+ $this->semanticalError("'$aliasIdentVariable' is already defined.", $this->lexer->token);
}
return $aliasIdentVariable;
@@ -840,18 +914,18 @@ public function AbstractSchemaName()
{
$this->match(Lexer::T_IDENTIFIER);
- $schemaName = ltrim($this->_lexer->token['value'], '\\');
+ $schemaName = ltrim($this->lexer->token['value'], '\\');
if (strrpos($schemaName, ':') !== false) {
list($namespaceAlias, $simpleClassName) = explode(':', $schemaName);
- $schemaName = $this->_em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
+ $schemaName = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
}
$exists = class_exists($schemaName, true);
if ( ! $exists) {
- $this->semanticalError("Class '$schemaName' is not defined.", $this->_lexer->token);
+ $this->semanticalError("Class '$schemaName' is not defined.", $this->lexer->token);
}
return $schemaName;
@@ -866,11 +940,11 @@ public function AliasResultVariable()
{
$this->match(Lexer::T_IDENTIFIER);
- $resultVariable = $this->_lexer->token['value'];
- $exists = isset($this->_queryComponents[$resultVariable]);
+ $resultVariable = $this->lexer->token['value'];
+ $exists = isset($this->queryComponents[$resultVariable]);
if ($exists) {
- $this->semanticalError("'$resultVariable' is already defined.", $this->_lexer->token);
+ $this->semanticalError("'$resultVariable' is already defined.", $this->lexer->token);
}
return $resultVariable;
@@ -885,13 +959,13 @@ public function ResultVariable()
{
$this->match(Lexer::T_IDENTIFIER);
- $resultVariable = $this->_lexer->token['value'];
+ $resultVariable = $this->lexer->token['value'];
// Defer ResultVariable validation
- $this->_deferredResultVariables[] = array(
+ $this->deferredResultVariables[] = array(
'expression' => $resultVariable,
- 'nestingLevel' => $this->_nestingLevel,
- 'token' => $this->_lexer->token,
+ 'nestingLevel' => $this->nestingLevel,
+ 'token' => $this->lexer->token,
);
return $resultVariable;
@@ -906,7 +980,7 @@ public function JoinAssociationPathExpression()
{
$identVariable = $this->IdentificationVariable();
- if ( ! isset($this->_queryComponents[$identVariable])) {
+ if ( ! isset($this->queryComponents[$identVariable])) {
$this->semanticalError(
'Identification Variable ' . $identVariable .' used in join path expression but was not defined before.'
);
@@ -915,10 +989,10 @@ public function JoinAssociationPathExpression()
$this->match(Lexer::T_DOT);
$this->match(Lexer::T_IDENTIFIER);
- $field = $this->_lexer->token['value'];
+ $field = $this->lexer->token['value'];
// Validate association field
- $qComp = $this->_queryComponents[$identVariable];
+ $qComp = $this->queryComponents[$identVariable];
$class = $qComp['metadata'];
if ( ! $class->hasAssociation($field)) {
@@ -942,21 +1016,21 @@ public function PathExpression($expectedTypes)
$identVariable = $this->IdentificationVariable();
$field = null;
- if ($this->_lexer->isNextToken(Lexer::T_DOT)) {
+ if ($this->lexer->isNextToken(Lexer::T_DOT)) {
$this->match(Lexer::T_DOT);
$this->match(Lexer::T_IDENTIFIER);
- $field = $this->_lexer->token['value'];
+ $field = $this->lexer->token['value'];
}
// Creating AST node
$pathExpr = new AST\PathExpression($expectedTypes, $identVariable, $field);
// Defer PathExpression validation if requested to be defered
- $this->_deferredPathExpressions[] = array(
+ $this->deferredPathExpressions[] = array(
'expression' => $pathExpr,
- 'nestingLevel' => $this->_nestingLevel,
- 'token' => $this->_lexer->token,
+ 'nestingLevel' => $this->nestingLevel,
+ 'token' => $this->lexer->token,
);
return $pathExpr;
@@ -1029,7 +1103,7 @@ public function SelectClause()
$this->match(Lexer::T_SELECT);
// Check for DISTINCT
- if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
+ if ($this->lexer->isNextToken(Lexer::T_DISTINCT)) {
$this->match(Lexer::T_DISTINCT);
$isDistinct = true;
@@ -1039,7 +1113,7 @@ public function SelectClause()
$selectExpressions = array();
$selectExpressions[] = $this->SelectExpression();
- while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
+ while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
$this->match(Lexer::T_COMMA);
$selectExpressions[] = $this->SelectExpression();
@@ -1058,7 +1132,7 @@ public function SimpleSelectClause()
$isDistinct = false;
$this->match(Lexer::T_SELECT);
- if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
+ if ($this->lexer->isNextToken(Lexer::T_DISTINCT)) {
$this->match(Lexer::T_DISTINCT);
$isDistinct = true;
@@ -1075,16 +1149,16 @@ public function SimpleSelectClause()
public function UpdateClause()
{
$this->match(Lexer::T_UPDATE);
- $token = $this->_lexer->lookahead;
+ $token = $this->lexer->lookahead;
$abstractSchemaName = $this->AbstractSchemaName();
- if ($this->_lexer->isNextToken(Lexer::T_AS)) {
+ if ($this->lexer->isNextToken(Lexer::T_AS)) {
$this->match(Lexer::T_AS);
}
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
- $class = $this->_em->getClassMetadata($abstractSchemaName);
+ $class = $this->em->getClassMetadata($abstractSchemaName);
// Building queryComponent
$queryComponent = array(
@@ -1092,18 +1166,18 @@ public function UpdateClause()
'parent' => null,
'relation' => null,
'map' => null,
- 'nestingLevel' => $this->_nestingLevel,
+ 'nestingLevel' => $this->nestingLevel,
'token' => $token,
);
- $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
+ $this->queryComponents[$aliasIdentificationVariable] = $queryComponent;
$this->match(Lexer::T_SET);
$updateItems = array();
$updateItems[] = $this->UpdateItem();
- while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
+ while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
$this->match(Lexer::T_COMMA);
$updateItems[] = $this->UpdateItem();
@@ -1124,21 +1198,21 @@ public function DeleteClause()
{
$this->match(Lexer::T_DELETE);
- if ($this->_lexer->isNextToken(Lexer::T_FROM)) {
+ if ($this->lexer->isNextToken(Lexer::T_FROM)) {
$this->match(Lexer::T_FROM);
}
- $token = $this->_lexer->lookahead;
+ $token = $this->lexer->lookahead;
$deleteClause = new AST\DeleteClause($this->AbstractSchemaName());
- if ($this->_lexer->isNextToken(Lexer::T_AS)) {
+ if ($this->lexer->isNextToken(Lexer::T_AS)) {
$this->match(Lexer::T_AS);
}
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
$deleteClause->aliasIdentificationVariable = $aliasIdentificationVariable;
- $class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName);
+ $class = $this->em->getClassMetadata($deleteClause->abstractSchemaName);
// Building queryComponent
$queryComponent = array(
@@ -1146,11 +1220,11 @@ public function DeleteClause()
'parent' => null,
'relation' => null,
'map' => null,
- 'nestingLevel' => $this->_nestingLevel,
+ 'nestingLevel' => $this->nestingLevel,
'token' => $token,
);
- $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
+ $this->queryComponents[$aliasIdentificationVariable] = $queryComponent;
return $deleteClause;
}
@@ -1167,7 +1241,7 @@ public function FromClause()
$identificationVariableDeclarations = array();
$identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration();
- while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
+ while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
$this->match(Lexer::T_COMMA);
$identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration();
@@ -1188,7 +1262,7 @@ public function SubselectFromClause()
$identificationVariables = array();
$identificationVariables[] = $this->SubselectIdentificationVariableDeclaration();
- while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
+ while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
$this->match(Lexer::T_COMMA);
$identificationVariables[] = $this->SubselectIdentificationVariableDeclaration();
@@ -1233,7 +1307,7 @@ public function GroupByClause()
$groupByItems = array($this->GroupByItem());
- while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
+ while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
$this->match(Lexer::T_COMMA);
$groupByItems[] = $this->GroupByItem();
@@ -1255,7 +1329,7 @@ public function OrderByClause()
$orderByItems = array();
$orderByItems[] = $this->OrderByItem();
- while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
+ while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
$this->match(Lexer::T_COMMA);
$orderByItems[] = $this->OrderByItem();
@@ -1272,17 +1346,17 @@ public function OrderByClause()
public function Subselect()
{
// Increase query nesting level
- $this->_nestingLevel++;
+ $this->nestingLevel++;
$subselect = new AST\Subselect($this->SimpleSelectClause(), $this->SubselectFromClause());
- $subselect->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
- $subselect->groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null;
- $subselect->havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null;
- $subselect->orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null;
+ $subselect->whereClause = $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
+ $subselect->groupByClause = $this->lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null;
+ $subselect->havingClause = $this->lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null;
+ $subselect->orderByClause = $this->lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null;
// Decrease query nesting level
- $this->_nestingLevel--;
+ $this->nestingLevel--;
return $subselect;
}
@@ -1311,20 +1385,20 @@ public function UpdateItem()
public function GroupByItem()
{
// We need to check if we are in a IdentificationVariable or SingleValuedPathExpression
- $glimpse = $this->_lexer->glimpse();
+ $glimpse = $this->lexer->glimpse();
if ($glimpse['type'] === Lexer::T_DOT) {
return $this->SingleValuedPathExpression();
}
// Still need to decide between IdentificationVariable or ResultVariable
- $lookaheadValue = $this->_lexer->lookahead['value'];
+ $lookaheadValue = $this->lexer->lookahead['value'];
- if ( ! isset($this->_queryComponents[$lookaheadValue])) {
+ if ( ! isset($this->queryComponents[$lookaheadValue])) {
$this->semanticalError('Cannot group by undefined identification or result variable.');
}
- return (isset($this->_queryComponents[$lookaheadValue]['metadata']))
+ return (isset($this->queryComponents[$lookaheadValue]['metadata']))
? $this->IdentificationVariable()
: $this->ResultVariable();
}
@@ -1340,15 +1414,15 @@ public function GroupByItem()
public function OrderByItem()
{
- $this->_lexer->peek(); // lookahead => '.'
- $this->_lexer->peek(); // lookahead => token after '.'
- $peek = $this->_lexer->peek(); // lookahead => token after the token after the '.'
- $this->_lexer->resetPeek();
- $glimpse = $this->_lexer->glimpse();
+ $this->lexer->peek(); // lookahead => '.'
+ $this->lexer->peek(); // lookahead => token after '.'
+ $peek = $this->lexer->peek(); // lookahead => token after the token after the '.'
+ $this->lexer->resetPeek();
+ $glimpse = $this->lexer->glimpse();
switch (true) {
- case ($this->_isMathOperator($peek)):
+ case ($this->isMathOperator($peek)):
$expr = $this->SimpleArithmeticExpression();
break;
@@ -1356,7 +1430,7 @@ public function OrderByItem()
$expr = $this->SingleValuedPathExpression();
break;
- case ($this->_lexer->peek() && $this->_isMathOperator($this->_peekBeyondClosingParenthesis())):
+ case ($this->lexer->peek() && $this->isMathOperator($this->peekBeyondClosingParenthesis())):
$expr = $this->ScalarExpression();
break;
@@ -1370,12 +1444,12 @@ public function OrderByItem()
$item = new AST\OrderByItem($expr);
switch (true) {
- case ($this->_lexer->isNextToken(Lexer::T_DESC)):
+ case ($this->lexer->isNextToken(Lexer::T_DESC)):
$this->match(Lexer::T_DESC);
$type = 'DESC';
break;
- case ($this->_lexer->isNextToken(Lexer::T_ASC)):
+ case ($this->lexer->isNextToken(Lexer::T_ASC)):
$this->match(Lexer::T_ASC);
break;
@@ -1401,16 +1475,16 @@ public function OrderByItem()
*/
public function NewValue()
{
- if ($this->_lexer->isNextToken(Lexer::T_NULL)) {
+ if ($this->lexer->isNextToken(Lexer::T_NULL)) {
$this->match(Lexer::T_NULL);
return null;
}
- if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
+ if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
$this->match(Lexer::T_INPUT_PARAMETER);
- return new AST\InputParameter($this->_lexer->token['value']);
+ return new AST\InputParameter($this->lexer->token['value']);
}
return $this->SimpleArithmeticExpression();
@@ -1424,13 +1498,13 @@ public function NewValue()
public function IdentificationVariableDeclaration()
{
$rangeVariableDeclaration = $this->RangeVariableDeclaration();
- $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
+ $indexBy = $this->lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
$joins = array();
while (
- $this->_lexer->isNextToken(Lexer::T_LEFT) ||
- $this->_lexer->isNextToken(Lexer::T_INNER) ||
- $this->_lexer->isNextToken(Lexer::T_JOIN)
+ $this->lexer->isNextToken(Lexer::T_LEFT) ||
+ $this->lexer->isNextToken(Lexer::T_INNER) ||
+ $this->lexer->isNextToken(Lexer::T_JOIN)
) {
$joins[] = $this->Join();
}
@@ -1448,7 +1522,7 @@ public function IdentificationVariableDeclaration()
*/
public function SubselectIdentificationVariableDeclaration()
{
- $this->_lexer->glimpse();
+ $this->lexer->glimpse();
/* NOT YET IMPLEMENTED!
@@ -1478,20 +1552,20 @@ public function Join()
$joinType = AST\Join::JOIN_TYPE_INNER;
switch (true) {
- case ($this->_lexer->isNextToken(Lexer::T_LEFT)):
+ case ($this->lexer->isNextToken(Lexer::T_LEFT)):
$this->match(Lexer::T_LEFT);
$joinType = AST\Join::JOIN_TYPE_LEFT;
// Possible LEFT OUTER join
- if ($this->_lexer->isNextToken(Lexer::T_OUTER)) {
+ if ($this->lexer->isNextToken(Lexer::T_OUTER)) {
$this->match(Lexer::T_OUTER);
$joinType = AST\Join::JOIN_TYPE_LEFTOUTER;
}
break;
- case ($this->_lexer->isNextToken(Lexer::T_INNER)):
+ case ($this->lexer->isNextToken(Lexer::T_INNER)):
$this->match(Lexer::T_INNER);
break;
@@ -1501,7 +1575,7 @@ public function Join()
$this->match(Lexer::T_JOIN);
- $next = $this->_lexer->glimpse();
+ $next = $this->lexer->glimpse();
$joinDeclaration = ($next['type'] === Lexer::T_DOT)
? $this->JoinAssociationDeclaration()
: $this->RangeVariableDeclaration();
@@ -1510,7 +1584,7 @@ public function Join()
$join = new AST\Join($joinType, $joinDeclaration);
// Check for ad-hoc Join conditions
- if ($this->_lexer->isNextToken(Lexer::T_WITH) || $joinDeclaration instanceof AST\RangeVariableDeclaration) {
+ if ($this->lexer->isNextToken(Lexer::T_WITH) || $joinDeclaration instanceof AST\RangeVariableDeclaration) {
$this->match(Lexer::T_WITH);
$join->conditionalExpression = $this->ConditionalExpression();
@@ -1528,13 +1602,13 @@ public function RangeVariableDeclaration()
{
$abstractSchemaName = $this->AbstractSchemaName();
- if ($this->_lexer->isNextToken(Lexer::T_AS)) {
+ if ($this->lexer->isNextToken(Lexer::T_AS)) {
$this->match(Lexer::T_AS);
}
- $token = $this->_lexer->lookahead;
+ $token = $this->lexer->lookahead;
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
- $classMetadata = $this->_em->getClassMetadata($abstractSchemaName);
+ $classMetadata = $this->em->getClassMetadata($abstractSchemaName);
// Building queryComponent
$queryComponent = array(
@@ -1542,11 +1616,11 @@ public function RangeVariableDeclaration()
'parent' => null,
'relation' => null,
'map' => null,
- 'nestingLevel' => $this->_nestingLevel,
+ 'nestingLevel' => $this->nestingLevel,
'token' => $token
);
- $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
+ $this->queryComponents[$aliasIdentificationVariable] = $queryComponent;
return new AST\RangeVariableDeclaration($abstractSchemaName, $aliasIdentificationVariable);
}
@@ -1560,18 +1634,18 @@ public function JoinAssociationDeclaration()
{
$joinAssociationPathExpression = $this->JoinAssociationPathExpression();
- if ($this->_lexer->isNextToken(Lexer::T_AS)) {
+ if ($this->lexer->isNextToken(Lexer::T_AS)) {
$this->match(Lexer::T_AS);
}
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
- $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
+ $indexBy = $this->lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
$identificationVariable = $joinAssociationPathExpression->identificationVariable;
$field = $joinAssociationPathExpression->associationField;
- $class = $this->_queryComponents[$identificationVariable]['metadata'];
- $targetClass = $this->_em->getClassMetadata($class->associationMappings[$field]['targetEntity']);
+ $class = $this->queryComponents[$identificationVariable]['metadata'];
+ $targetClass = $this->em->getClassMetadata($class->associationMappings[$field]['targetEntity']);
// Building queryComponent
$joinQueryComponent = array(
@@ -1579,11 +1653,11 @@ public function JoinAssociationDeclaration()
'parent' => $joinAssociationPathExpression->identificationVariable,
'relation' => $class->getAssociationMapping($field),
'map' => null,
- 'nestingLevel' => $this->_nestingLevel,
- 'token' => $this->_lexer->lookahead
+ 'nestingLevel' => $this->nestingLevel,
+ 'token' => $this-&g