diff --git a/lib/Doctrine/ORM/Configuration.php b/lib/Doctrine/ORM/Configuration.php index 840ae01b4..ff7ea63da 100644 --- a/lib/Doctrine/ORM/Configuration.php +++ b/lib/Doctrine/ORM/Configuration.php @@ -25,6 +25,8 @@ use Doctrine\Common\Cache\Cache, Doctrine\Common\Annotations\AnnotationReader, Doctrine\ORM\Mapping\Driver\Driver, Doctrine\ORM\Mapping\Driver\AnnotationDriver, + Doctrine\ORM\Mapping\QuoteStrategy, + Doctrine\ORM\Mapping\DefaultQuoteStrategy, Doctrine\ORM\Mapping\NamingStrategy, Doctrine\ORM\Mapping\DefaultNamingStrategy; @@ -629,4 +631,30 @@ class Configuration extends \Doctrine\DBAL\Configuration return $this->_attributes['namingStrategy']; } + + /** + * Set quote strategy. + * + * @since 2.3 + * @param Doctrine\ORM\Mapping\QuoteStrategy $quoteStrategy + */ + public function setQuoteStrategy(QuoteStrategy $quoteStrategy) + { + $this->_attributes['quoteStrategy'] = $quoteStrategy; + } + + /** + * Get quote strategy. + * + * @since 2.3 + * @return Doctrine\ORM\Mapping\QuoteStrategy + */ + public function getQuoteStrategy() + { + if ( ! isset($this->_attributes['quoteStrategy'])) { + $this->_attributes['quoteStrategy'] = new DefaultQuoteStrategy(); + } + + return $this->_attributes['quoteStrategy']; + } } diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index 1bfa99d74..378f1cc98 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -385,12 +385,12 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface $class->validateLifecycleCallbacks($this->getReflectionService()); // verify inheritance - if (!$class->isMappedSuperclass && !$class->isInheritanceTypeNone()) { - if (!$parent) { + if ( ! $class->isMappedSuperclass && !$class->isInheritanceTypeNone()) { + if ( ! $parent) { if (count($class->discriminatorMap) == 0) { throw MappingException::missingDiscriminatorMap($class->name); } - if (!$class->discriminatorColumn) { + if ( ! $class->discriminatorColumn) { throw MappingException::missingDiscriminatorColumn($class->name); } } else if ($parent && !$class->reflClass->isAbstract() && !in_array($class->name, array_values($class->discriminatorMap))) { @@ -562,7 +562,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass) { foreach ($parentClass->namedQueries as $name => $query) { - if (!isset ($subClass->namedQueries[$name])) { + if ( ! isset ($subClass->namedQueries[$name])) { $subClass->addNamedQuery(array( 'name' => $query['name'], 'query' => $query['query'] @@ -581,7 +581,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass) { foreach ($parentClass->namedNativeQueries as $name => $query) { - if (!isset ($subClass->namedNativeQueries[$name])) { + if ( ! isset ($subClass->namedNativeQueries[$name])) { $subClass->addNamedNativeQuery(array( 'name' => $query['name'], 'query' => $query['query'], @@ -603,7 +603,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass) { foreach ($parentClass->sqlResultSetMappings as $name => $mapping) { - if (!isset ($subClass->sqlResultSetMappings[$name])) { + if ( ! isset ($subClass->sqlResultSetMappings[$name])) { $entities = array(); foreach ($mapping['entities'] as $entity) { $entities[] = array( @@ -648,44 +648,77 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface // For PostgreSQL IDENTITY (SERIAL) we need a sequence name. It defaults to // __seq in PostgreSQL for SERIAL columns. // Not pretty but necessary and the simplest solution that currently works. - $seqName = $this->targetPlatform instanceof Platforms\PostgreSQLPlatform ? - $class->getTableName() . '_' . $class->columnNames[$class->identifier[0]] . '_seq' : - null; - $class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($seqName)); + $sequenceName = null; + + if ($this->targetPlatform instanceof Platforms\PostgreSQLPlatform) { + $fieldName = $class->getSingleIdentifierFieldName(); + $columnName = $class->getSingleIdentifierColumnName(); + $quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); + $sequenceName = $class->getTableName() . '_' . $columnName . '_seq'; + $definition = array( + 'sequenceName' => $this->targetPlatform->fixSchemaElementName($sequenceName) + ); + + if ($quoted) { + $definition['quoted'] = true; + } + + $sequenceName = $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->targetPlatform); + } + + $class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($sequenceName)); break; + case ClassMetadata::GENERATOR_TYPE_SEQUENCE: // If there is no sequence definition yet, create a default definition $definition = $class->sequenceGeneratorDefinition; + if ( ! $definition) { - $sequenceName = $class->getTableName() . '_' . $class->getSingleIdentifierColumnName() . '_seq'; - $definition['sequenceName'] = $this->targetPlatform->fixSchemaElementName($sequenceName); - $definition['allocationSize'] = 1; - $definition['initialValue'] = 1; + $fieldName = $class->getSingleIdentifierFieldName(); + $columnName = $class->getSingleIdentifierColumnName(); + $quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); + $sequenceName = $class->getTableName() . '_' . $columnName . '_seq'; + $definition = array( + 'sequenceName' => $this->targetPlatform->fixSchemaElementName($sequenceName), + 'allocationSize' => 1, + 'initialValue' => 1, + ); + + if ($quoted) { + $definition['quoted'] = true; + } + $class->setSequenceGeneratorDefinition($definition); } + $sequenceGenerator = new \Doctrine\ORM\Id\SequenceGenerator( - $definition['sequenceName'], + $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->targetPlatform), $definition['allocationSize'] ); $class->setIdGenerator($sequenceGenerator); break; + case ClassMetadata::GENERATOR_TYPE_NONE: $class->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator()); break; + case ClassMetadata::GENERATOR_TYPE_UUID: $class->setIdGenerator(new \Doctrine\ORM\Id\UuidGenerator()); break; + case ClassMetadata::GENERATOR_TYPE_TABLE: throw new ORMException("TableGenerator not yet implemented."); break; + case ClassMetadata::GENERATOR_TYPE_CUSTOM: $definition = $class->customGeneratorDefinition; - if (!class_exists($definition['class'])) { + if ( ! class_exists($definition['class'])) { throw new ORMException("Can't instantiate custom generator : " . $definition['class']); } $class->setIdGenerator(new $definition['class']); break; + default: throw new ORMException("Unknown generator type: " . $class->generatorType); } diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 8434e49b2..246a2c9f2 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -1181,11 +1181,11 @@ class ClassMetadataInfo implements ClassMetadata // Complete fieldName and columnName mapping if ( ! isset($mapping['columnName'])) { $mapping['columnName'] = $this->namingStrategy->propertyToColumnName($mapping['fieldName']); - } else { - if ($mapping['columnName'][0] == '`') { - $mapping['columnName'] = trim($mapping['columnName'], '`'); - $mapping['quoted'] = true; - } + } + + if ($mapping['columnName'][0] === '`') { + $mapping['columnName'] = trim($mapping['columnName'], '`'); + $mapping['quoted'] = true; } $this->columnNames[$mapping['fieldName']] = $mapping['columnName']; @@ -1295,8 +1295,8 @@ class ClassMetadataInfo implements ClassMetadata // Mandatory and optional attributes for either side if ( ! $mapping['mappedBy']) { if (isset($mapping['joinTable']) && $mapping['joinTable']) { - if (isset($mapping['joinTable']['name']) && $mapping['joinTable']['name'][0] == '`') { - $mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`'); + if (isset($mapping['joinTable']['name']) && $mapping['joinTable']['name'][0] === '`') { + $mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`'); $mapping['joinTable']['quoted'] = true; } } @@ -1373,12 +1373,25 @@ class ClassMetadataInfo implements ClassMetadata $uniqueContraintColumns[] = $joinColumn['name']; } } + if (empty($joinColumn['name'])) { $joinColumn['name'] = $this->namingStrategy->joinColumnName($mapping['fieldName']); } + if (empty($joinColumn['referencedColumnName'])) { $joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName(); } + + if ($joinColumn['name'][0] === '`') { + $joinColumn['name'] = trim($joinColumn['name'], '`'); + $joinColumn['quoted'] = true; + } + + if ($joinColumn['referencedColumnName'][0] === '`') { + $joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`'); + $joinColumn['quoted'] = true; + } + $mapping['sourceToTargetKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName']; $mapping['joinColumnFieldNames'][$joinColumn['name']] = isset($joinColumn['fieldName']) ? $joinColumn['fieldName'] : $joinColumn['name']; @@ -1459,12 +1472,25 @@ class ClassMetadataInfo implements ClassMetadata if (empty($joinColumn['name'])) { $joinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity'], $joinColumn['referencedColumnName']); } + if (empty($joinColumn['referencedColumnName'])) { $joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName(); } + + if ($joinColumn['name'][0] === '`') { + $joinColumn['name'] = trim($joinColumn['name'], '`'); + $joinColumn['quoted'] = true; + } + + if ($joinColumn['referencedColumnName'][0] === '`') { + $joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`'); + $joinColumn['quoted'] = true; + } + if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') { $mapping['isOnDeleteCascade'] = true; } + $mapping['relationToSourceKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName']; $mapping['joinTableColumns'][] = $joinColumn['name']; } @@ -1473,12 +1499,25 @@ class ClassMetadataInfo implements ClassMetadata if (empty($inverseJoinColumn['name'])) { $inverseJoinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['targetEntity'], $inverseJoinColumn['referencedColumnName']); } + if (empty($inverseJoinColumn['referencedColumnName'])) { $inverseJoinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName(); } + + if ($inverseJoinColumn['name'][0] === '`') { + $inverseJoinColumn['name'] = trim($inverseJoinColumn['name'], '`'); + $inverseJoinColumn['quoted'] = true; + } + + if ($inverseJoinColumn['referencedColumnName'][0] === '`') { + $inverseJoinColumn['referencedColumnName'] = trim($inverseJoinColumn['referencedColumnName'], '`'); + $inverseJoinColumn['quoted'] = true; + } + if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') { $mapping['isOnDeleteCascade'] = true; } + $mapping['relationToTargetKeyColumns'][$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName']; $mapping['joinTableColumns'][] = $inverseJoinColumn['name']; } @@ -1945,12 +1984,12 @@ class ClassMetadataInfo implements ClassMetadata public function setPrimaryTable(array $table) { if (isset($table['name'])) { - if ($table['name'][0] == '`') { - $this->table['name'] = str_replace("`", "", $table['name']); - $this->table['quoted'] = true; - } else { - $this->table['name'] = $table['name']; + if ($table['name'][0] === '`') { + $table['name'] = trim($table['name'], '`'); + $this->table['quoted'] = true; } + + $this->table['name'] = $table['name']; } if (isset($table['indexes'])) { @@ -2528,9 +2567,10 @@ class ClassMetadataInfo implements ClassMetadata * The definition must have the following structure: * * array( - * 'sequenceName' => 'name', + * 'sequenceName' => 'name', * 'allocationSize' => 20, - * 'initialValue' => 1 + * 'initialValue' => 1 + * 'quoted' => 1 * ) * * @@ -2538,6 +2578,11 @@ class ClassMetadataInfo implements ClassMetadata */ public function setSequenceGeneratorDefinition(array $definition) { + if (isset($definition['name']) && $definition['name'] == '`') { + $definition['name'] = trim($definition['name'], '`'); + $definition['quoted'] = true; + } + $this->sequenceGeneratorDefinition = $definition; } @@ -2646,6 +2691,8 @@ class ClassMetadataInfo implements ClassMetadata /** * Gets the (possibly quoted) identifier column names for safe use in an SQL statement. * + * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy + * * @param AbstractPlatform $platform * @return array */ @@ -2680,8 +2727,9 @@ class ClassMetadataInfo implements ClassMetadata } /** - * Gets the (possibly quoted) column name of a mapped field for safe use - * in an SQL statement. + * Gets the (possibly quoted) column name of a mapped field for safe use in an SQL statement. + * + * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy * * @param string $field * @param AbstractPlatform $platform @@ -2695,8 +2743,9 @@ class ClassMetadataInfo implements ClassMetadata } /** - * Gets the (possibly quoted) primary table name of this class for safe use - * in an SQL statement. + * Gets the (possibly quoted) primary table name of this class for safe use in an SQL statement. + * + * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy * * @param AbstractPlatform $platform * @return string @@ -2709,6 +2758,8 @@ class ClassMetadataInfo implements ClassMetadata /** * Gets the (possibly quoted) name of the join table. * + * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy + * * @param AbstractPlatform $platform * @return string */ diff --git a/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php b/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php new file mode 100644 index 000000000..b5a6fc4f1 --- /dev/null +++ b/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php @@ -0,0 +1,140 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * A set of rules for determining the physical column, alias and table quotes + * + * @since 2.3 + * @author Fabio B. Silva + */ +class DefaultQuoteStrategy implements QuoteStrategy +{ + /** + * {@inheritdoc} + */ + public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($class->fieldMappings[$fieldName]['quoted']) + ? $platform->quoteIdentifier($class->fieldMappings[$fieldName]['columnName']) + : $class->fieldMappings[$fieldName]['columnName']; + } + + /** + * {@inheritdoc} + */ + public function getTableName(ClassMetadata $class, AbstractPlatform $platform) + { + return isset($class->table['quoted']) + ? $platform->quoteIdentifier($class->table['name']) + : $class->table['name']; + } + + /** + * {@inheritdoc} + */ + public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($definition['quoted']) + ? $platform->quoteIdentifier($definition['sequenceName']) + : $definition['sequenceName']; + } + + /** + * {@inheritdoc} + */ + public function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($joinColumn['quoted']) + ? $platform->quoteIdentifier($joinColumn['name']) + : $joinColumn['name']; + } + + /** + * {@inheritdoc} + */ + public function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($joinColumn['quoted']) + ? $platform->quoteIdentifier($joinColumn['referencedColumnName']) + : $joinColumn['referencedColumnName']; + } + + /** + * {@inheritdoc} + */ + public function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($association['joinTable']['quoted']) + ? $platform->quoteIdentifier($association['joinTable']['name']) + : $association['joinTable']['name']; + } + + /** + * {@inheritdoc} + */ + public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform) + { + $quotedColumnNames = array(); + + foreach ($class->identifier as $fieldName) { + if (isset($class->fieldMappings[$fieldName])) { + $quotedColumnNames[] = $this->getColumnName($fieldName, $class, $platform); + + continue; + } + + // Association defined as Id field + $joinColumns = $class->associationMappings[$fieldName]['joinColumns']; + $assocQuotedColumnNames = array_map( + function ($joinColumn) use ($platform) + { + return isset($joinColumn['quoted']) + ? $platform->quoteIdentifier($joinColumn['name']) + : $joinColumn['name']; + }, + $joinColumns + ); + + $quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames); + } + + return $quotedColumnNames; + } + + /** + * {@inheritdoc} + */ + public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null) + { + // Trim the column alias to the maximum identifier length of the platform. + // If the alias is to long, characters are cut off from the beginning. + // And strip non alphanumeric characters + $columnName = $columnName . $counter; + $columnName = substr($columnName, -$platform->getMaxIdentifierLength()); + $columnName = preg_replace('/[^A-Za-z0-9_]/', '', $columnName); + + return $platform->getSQLResultCasing($columnName); + } + +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Mapping/QuoteStrategy.php b/lib/Doctrine/ORM/Mapping/QuoteStrategy.php new file mode 100644 index 000000000..52e846d99 --- /dev/null +++ b/lib/Doctrine/ORM/Mapping/QuoteStrategy.php @@ -0,0 +1,112 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * A set of rules for determining the column, alias and table quotes + * + * @since 2.3 + * @author Fabio B. Silva + */ +interface QuoteStrategy +{ + /** + * Gets the (possibly quoted) column name for safe use in an SQL statement. + * + * @param string $fieldName + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) primary table name for safe use in an SQL statement. + * + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getTableName(ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) sequence name for safe use in an SQL statement. + * + * @param array $definition + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) name of the join table. + * + * @param array $association + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) join column name. + * + * @param array $joinColumn + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) join column name. + * + * @param array $joinColumn + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) identifier column names for safe use in an SQL statement. + * + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return array + */ + function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the column alias. + * + * @param string $columnName + * @param integer $counter + * @param AbstractPlatform $platform + * @param ClassMetadata $class + * @return string + */ + function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null); + +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Persisters/AbstractCollectionPersister.php b/lib/Doctrine/ORM/Persisters/AbstractCollectionPersister.php index 6f612c9fb..2728918c0 100644 --- a/lib/Doctrine/ORM/Persisters/AbstractCollectionPersister.php +++ b/lib/Doctrine/ORM/Persisters/AbstractCollectionPersister.php @@ -45,6 +45,20 @@ abstract class AbstractCollectionPersister */ protected $_uow; + /** + * The database platform. + * + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + protected $platform; + + /** + * The quote strategy. + * + * @var \Doctrine\ORM\Mapping\QuoteStrategy + */ + protected $quoteStrategy; + /** * Initializes a new instance of a class derived from AbstractCollectionPersister. * @@ -52,9 +66,11 @@ abstract class AbstractCollectionPersister */ public function __construct(EntityManager $em) { - $this->_em = $em; - $this->_uow = $em->getUnitOfWork(); - $this->_conn = $em->getConnection(); + $this->_em = $em; + $this->_uow = $em->getUnitOfWork(); + $this->_conn = $em->getConnection(); + $this->platform = $this->_conn->getDatabasePlatform(); + $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); } /** diff --git a/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php b/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php index 13d7dece5..19e77a4e7 100644 --- a/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php +++ b/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php @@ -61,7 +61,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r') { $columnName = $class->columnNames[$field]; - $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform); + $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $this->quoteStrategy->getColumnName($field, $class, $this->_platform); $columnAlias = $this->getSQLColumnAlias($columnName); $this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name); diff --git a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php index d51e2fe51..7ccc7e663 100644 --- a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -132,6 +132,15 @@ class BasicEntityPersister */ protected $_columnTypes = array(); + /** + * The map of quoted column names. + * + * @var array + * @see _prepareInsertData($entity) + * @see _prepareUpdateData($entity) + */ + protected $quotedColumns = array(); + /** * The INSERT SQL statement used for entities handled by this persister. * This SQL is only generated once per request, if at all. @@ -170,6 +179,13 @@ class BasicEntityPersister */ protected $_sqlTableAliases = array(); + /** + * The quote strategy. + * + * @var \Doctrine\ORM\Mapping\QuoteStrategy + */ + protected $quoteStrategy; + /** * Initializes a new BasicEntityPersister that uses the given EntityManager * and persists instances of the class described by the given ClassMetadata descriptor. @@ -179,10 +195,11 @@ class BasicEntityPersister */ public function __construct(EntityManager $em, ClassMetadata $class) { - $this->_em = $em; - $this->_class = $class; - $this->_conn = $em->getConnection(); - $this->_platform = $this->_conn->getDatabasePlatform(); + $this->_em = $em; + $this->_class = $class; + $this->_conn = $em->getConnection(); + $this->_platform = $this->_conn->getDatabasePlatform(); + $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); } /** @@ -281,13 +298,13 @@ class BasicEntityPersister protected function fetchVersionValue($versionedClass, $id) { $versionField = $versionedClass->versionField; - $identifier = $versionedClass->getIdentifierColumnNames(); + $identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->_platform); - $versionFieldColumnName = $versionedClass->getQuotedColumnName($versionField, $this->_platform); + $versionFieldColumnName = $this->quoteStrategy->getColumnName($versionField, $versionedClass, $this->_platform); //FIXME: Order with composite keys might not be correct $sql = 'SELECT ' . $versionFieldColumnName - . ' FROM ' . $versionedClass->getQuotedTableName($this->_platform) + . ' FROM ' . $this->quoteStrategy->getTableName($versionedClass, $this->_platform) . ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?'; $value = $this->_conn->fetchColumn($sql, array_values((array)$id)); @@ -315,7 +332,7 @@ class BasicEntityPersister if (isset($updateData[$tableName]) && $updateData[$tableName]) { $this->_updateTable( - $entity, $this->_class->getQuotedTableName($this->_platform), + $entity, $this->quoteStrategy->getTableName($this->_class, $this->_platform), $updateData[$tableName], $this->_class->isVersioned ); @@ -344,12 +361,14 @@ class BasicEntityPersister $placeholder = '?'; if (isset($this->_class->fieldNames[$columnName])) { - $column = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform); + $column = $this->quoteStrategy->getColumnName($this->_class->fieldNames[$columnName], $this->_class, $this->_platform); if (isset($this->_class->fieldMappings[$this->_class->fieldNames[$columnName]]['requireSQLConversion'])) { $type = Type::getType($this->_columnTypes[$columnName]); $placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform); } + } else if (isset($this->quotedColumns[$columnName])) { + $column = $this->quotedColumns[$columnName]; } $set[] = $column . ' = ' . $placeholder; @@ -367,7 +386,7 @@ class BasicEntityPersister $params[] = $id[$idField]; $types[] = $targetMapping->fieldMappings[$targetMapping->identifier[0]]['type']; } else { - $where[] = $this->_class->getQuotedColumnName($idField, $this->_platform); + $where[] = $this->quoteStrategy->getColumnName($idField, $this->_class, $this->_platform); $params[] = $id[$idField]; $types[] = $this->_class->fieldMappings[$idField]['type']; } @@ -376,7 +395,7 @@ class BasicEntityPersister if ($versioned) { $versionField = $this->_class->versionField; $versionFieldType = $this->_class->fieldMappings[$versionField]['type']; - $versionColumn = $this->_class->getQuotedColumnName($versionField, $this->_platform); + $versionColumn = $this->quoteStrategy->getColumnName($versionField, $this->_class, $this->_platform); if ($versionFieldType == Type::INTEGER) { $set[] = $versionColumn . ' = ' . $versionColumn . ' + 1'; @@ -412,34 +431,43 @@ class BasicEntityPersister // @Todo this only covers scenarios with no inheritance or of the same level. Is there something // like self-referential relationship between different levels of an inheritance hierachy? I hope not! $selfReferential = ($mapping['targetEntity'] == $mapping['sourceEntity']); + $otherKeys = array(); + $keys = array(); if ( ! $mapping['isOwningSide']) { - $relatedClass = $this->_em->getClassMetadata($mapping['targetEntity']); - $mapping = $relatedClass->associationMappings[$mapping['mappedBy']]; - $keys = array_keys($mapping['relationToTargetKeyColumns']); + $relatedClass = $this->_em->getClassMetadata($mapping['targetEntity']); + $mapping = $relatedClass->associationMappings[$mapping['mappedBy']]; + + foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { + $keys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $relatedClass, $this->_platform); + } if ($selfReferential) { - $otherKeys = array_keys($mapping['relationToSourceKeyColumns']); + foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { + $otherKeys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $relatedClass, $this->_platform); + } } } else { - $keys = array_keys($mapping['relationToSourceKeyColumns']); + + foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { + $keys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + } if ($selfReferential) { - $otherKeys = array_keys($mapping['relationToTargetKeyColumns']); + foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { + $otherKeys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + } } } if ( ! isset($mapping['isOnDeleteCascade'])) { - $this->_conn->delete( - $this->_class->getQuotedJoinTableName($mapping, $this->_platform), - array_combine($keys, $identifier) - ); + + $joinTableName = $this->quoteStrategy->getJoinTableName($mapping, $this->_class, $this->_platform); + + $this->_conn->delete($joinTableName, array_combine($keys, $identifier)); if ($selfReferential) { - $this->_conn->delete( - $this->_class->getQuotedJoinTableName($mapping, $this->_platform), - array_combine($otherKeys, $identifier) - ); + $this->_conn->delete($joinTableName, array_combine($otherKeys, $identifier)); } } } @@ -459,10 +487,12 @@ class BasicEntityPersister public function delete($entity) { $identifier = $this->_em->getUnitOfWork()->getEntityIdentifier($entity); + $this->deleteJoinTableRecords($identifier); - $id = array_combine($this->_class->getIdentifierColumnNames(), $identifier); - $this->_conn->delete($this->_class->getQuotedTableName($this->_platform), $id); + $id = array_combine($this->quoteStrategy->getIdentifierColumnNames($this->_class, $this->_platform), $identifier); + + $this->_conn->delete($this->quoteStrategy->getTableName($this->_class, $this->_platform), $id); } /** @@ -530,7 +560,13 @@ class BasicEntityPersister $targetClass = $this->_em->getClassMetadata($assoc['targetEntity']); $owningTable = $this->getOwningTable($field); - foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) { + foreach ($assoc['joinColumns'] as $joinColumn) { + $sourceColumn = $joinColumn['name']; + $targetColumn = $joinColumn['referencedColumnName']; + $quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + + $this->quotedColumns[$sourceColumn] = $quotedColumn; + if ($newVal === null) { $result[$owningTable][$sourceColumn] = null; } else if ($targetClass->containsForeignIdentifier) { @@ -808,7 +844,7 @@ class BasicEntityPersister $sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']); if ($assoc['isOwningSide']) { - $quotedJoinTable = $sourceClass->getQuotedJoinTableName($assoc, $this->_platform); + $quotedJoinTable = $this->quoteStrategy->getJoinTableName($assoc, $sourceClass, $this->_platform); foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) { if ($sourceClass->containsForeignIdentifier) { @@ -831,7 +867,7 @@ class BasicEntityPersister } } else { $owningAssoc = $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']]; - $quotedJoinTable = $sourceClass->getQuotedJoinTableName($owningAssoc, $this->_platform); + $quotedJoinTable = $this->quoteStrategy->getJoinTableName($owningAssoc, $sourceClass, $this->_platform); // TRICKY: since the association is inverted source and target are flipped foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) { @@ -901,7 +937,7 @@ class BasicEntityPersister } return $this->_platform->modifyLimitQuery('SELECT ' . $this->_getSelectColumnListSQL() - . $this->_platform->appendLockHint(' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' + . $this->_platform->appendLockHint(' FROM ' . $this->quoteStrategy->getTableName($this->_class, $this->_platform) . ' ' . $alias, $lockMode) . $this->_selectJoinSql . $joinSql . ($conditionSql ? ' WHERE ' . $conditionSql : '') @@ -934,7 +970,7 @@ class BasicEntityPersister $this->_getSQLTableAlias($this->_class->fieldMappings[$fieldName]['inherited']) : $baseTableAlias; - $columnName = $this->_class->getQuotedColumnName($fieldName, $this->_platform); + $columnName = $this->quoteStrategy->getColumnName($fieldName, $this->_class, $this->_platform); $orderBySql .= $orderBySql ? ', ' : ' ORDER BY '; $orderBySql .= $tableAlias . '.' . $columnName . ' ' . $orientation; @@ -1012,10 +1048,13 @@ class BasicEntityPersister if ($assoc['isOwningSide']) { $this->_selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($assoc['joinColumns']); - $this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON '; + $this->_selectJoinSql .= ' ' . $this->quoteStrategy->getTableName($eagerEntity, $this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON '; $tableAlias = $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias); - foreach ($assoc['sourceToTargetKeyColumns'] as $sourceCol => $targetCol) { + foreach ($assoc['joinColumns'] as $joinColumn) { + $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + $targetCol = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->_class, $this->_platform); + if ( ! $first) { $this->_selectJoinSql .= ' AND '; } @@ -1033,7 +1072,7 @@ class BasicEntityPersister $owningAssoc = $eagerEntity->getAssociationMapping($assoc['mappedBy']); $this->_selectJoinSql .= ' LEFT JOIN'; - $this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' + $this->_selectJoinSql .= ' ' . $this->quoteStrategy->getTableName($eagerEntity, $this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) . ' ON '; foreach ($owningAssoc['sourceToTargetKeyColumns'] as $sourceCol => $targetCol) { @@ -1066,20 +1105,22 @@ class BasicEntityPersister */ protected function _getSelectColumnAssociationSQL($field, $assoc, ClassMetadata $class, $alias = 'r') { - $columnList = ''; + $columnList = array(); if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) { - foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { - if ($columnList) $columnList .= ', '; - $resultColumnName = $this->getSQLColumnAlias($srcColumn); - $columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) ) - . '.' . $srcColumn . ' AS ' . $resultColumnName; - $this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true); + foreach ($assoc['joinColumns'] as $joinColumn) { + + $quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + $resultColumnName = $this->getSQLColumnAlias($joinColumn['name']); + $columnList[] = $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) ) + . '.' . $quotedColumn . ' AS ' . $resultColumnName; + + $this->_rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, isset($assoc['id']) && $assoc['id'] === true); } } - return $columnList; + return implode(', ', $columnList); } /** @@ -1099,7 +1140,7 @@ class BasicEntityPersister $joinClauses = $owningAssoc['relationToSourceKeyColumns']; } - $joinTableName = $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform); + $joinTableName = $this->quoteStrategy->getJoinTableName($owningAssoc, $this->_class, $this->_platform); $joinSql = ''; foreach ($joinClauses as $joinTableColumn => $sourceColumn) { @@ -1108,7 +1149,7 @@ class BasicEntityPersister if ($this->_class->containsForeignIdentifier && ! isset($this->_class->fieldNames[$sourceColumn])) { $quotedColumn = $sourceColumn; // join columns cannot be quoted } else { - $quotedColumn = $this->_class->getQuotedColumnName($this->_class->fieldNames[$sourceColumn], $this->_platform); + $quotedColumn = $this->quoteStrategy->getColumnName($this->_class->fieldNames[$sourceColumn], $this->_class, $this->_platform); } $joinSql .= $this->_getSQLTableAlias($this->_class->name) . '.' . $quotedColumn . ' = ' @@ -1131,8 +1172,8 @@ class BasicEntityPersister if (empty($columns)) { $insertSql = $this->_platform->getEmptyIdentityInsertSQL( - $this->_class->getQuotedTableName($this->_platform), - $this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform) + $this->quoteStrategy->getTableName($this->_class, $this->_platform), + $this->quoteStrategy->getColumnName($this->_class->identifier[0], $this->_class, $this->_platform) ); } else { $columns = array_unique($columns); @@ -1151,7 +1192,7 @@ class BasicEntityPersister $values[] = $placeholder; } - $insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform) + $insertSql = 'INSERT INTO ' . $this->quoteStrategy->getTableName($this->_class, $this->_platform) . ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $values) . ')'; } @@ -1180,14 +1221,13 @@ class BasicEntityPersister if (isset($this->_class->associationMappings[$name])) { $assoc = $this->_class->associationMappings[$name]; - if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) { - foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) { - $columns[] = $sourceCol; + foreach ($assoc['joinColumns'] as $joinColumn) { + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); } } } else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->_class->identifier[0] != $name) { - $columns[] = $this->_class->getQuotedColumnName($name, $this->_platform); + $columns[] = $this->quoteStrategy->getColumnName($name, $this->_class, $this->_platform); $this->_columnTypes[$name] = $this->_class->fieldMappings[$name]['type']; } } @@ -1206,7 +1246,7 @@ class BasicEntityPersister protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r') { $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) - . '.' . $class->getQuotedColumnName($field, $this->_platform); + . '.' . $this->quoteStrategy->getColumnName($field, $class, $this->_platform); $columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]); $this->_rsm->addFieldResult($alias, $columnAlias, $field); @@ -1276,7 +1316,7 @@ class BasicEntityPersister */ protected function getLockTablesSql() { - return 'FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' + return 'FROM ' . $this->quoteStrategy->getTableName($this->_class, $this->_platform) . ' ' . $this->_getSQLTableAlias($this->_class->name); } @@ -1305,7 +1345,7 @@ class BasicEntityPersister ? $this->_class->fieldMappings[$field]['inherited'] : $this->_class->name; - $conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->getQuotedColumnName($field, $this->_platform); + $conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->quoteStrategy->getColumnName($field, $this->_class, $this->_platform); if (isset($this->_class->fieldMappings[$field]['requireSQLConversion'])) { $type = Type::getType($this->_class->getTypeOfField($field)); @@ -1557,7 +1597,7 @@ class BasicEntityPersister { // if one of the join columns is nullable, return left join foreach ($joinColumns as $joinColumn) { - if (!isset($joinColumn['nullable']) || $joinColumn['nullable']) { + if ( ! isset($joinColumn['nullable']) || $joinColumn['nullable']) { return 'LEFT JOIN'; } } @@ -1573,11 +1613,7 @@ class BasicEntityPersister */ public function getSQLColumnAlias($columnName) { - // Trim the column alias to the maximum identifier length of the platform. - // If the alias is to long, characters are cut off from the beginning. - return $this->_platform->getSQLResultCasing( - substr($columnName . $this->_sqlAliasCounter++, -$this->_platform->getMaxIdentifierLength()) - ); + return $this->quoteStrategy->getColumnAlias($columnName, $this->_sqlAliasCounter++, $this->_platform); } /** diff --git a/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php index 3b8fb1e33..b41fbaede 100644 --- a/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php @@ -105,7 +105,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister $tableName = $cm->getTableName(); $this->_owningTableMap[$fieldName] = $tableName; - $this->_quotedTableMap[$tableName] = $cm->getQuotedTableName($this->_platform); + $this->_quotedTableMap[$tableName] = $this->quoteStrategy->getTableName($cm, $this->_platform); return $tableName; } @@ -225,7 +225,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister // Make sure the table with the version column is updated even if no columns on that // table were affected. if ($isVersioned && ! isset($updateData[$versionedTable])) { - $this->_updateTable($entity, $versionedClass->getQuotedTableName($this->_platform), array(), true); + $this->_updateTable($entity, $this->quoteStrategy->getTableName($versionedClass, $this->_platform), array(), true); $id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity); $this->assignDefaultVersionValue($entity, $id); @@ -247,15 +247,15 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister // delete the row from the root table. Cascades do the rest. if ($this->_platform->supportsForeignKeyConstraints()) { $this->_conn->delete( - $this->_em->getClassMetadata($this->_class->rootEntityName)->getQuotedTableName($this->_platform), $id + $this->quoteStrategy->getTableName($this->_em->getClassMetadata($this->_class->rootEntityName), $this->_platform), $id ); } else { // Delete from all tables individually, starting from this class' table up to the root table. - $this->_conn->delete($this->_class->getQuotedTableName($this->_platform), $id); + $this->_conn->delete($this->quoteStrategy->getTableName($this->_class, $this->_platform), $id); foreach ($this->_class->parentClasses as $parentClass) { $this->_conn->delete( - $this->_em->getClassMetadata($parentClass)->getQuotedTableName($this->_platform), $id + $this->quoteStrategy->getTableName($this->_em->getClassMetadata($parentClass), $this->_platform), $id ); } } @@ -321,7 +321,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister foreach ($this->_class->parentClasses as $parentClassName) { $parentClass = $this->_em->getClassMetadata($parentClassName); $tableAlias = $this->_getSQLTableAlias($parentClassName); - $joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON '; + $joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->_platform) . ' ' . $tableAlias . ' ON '; $first = true; foreach ($idColumns as $idColumn) { @@ -361,7 +361,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister } // Add LEFT JOIN - $joinSql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON '; + $joinSql .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->_platform) . ' ' . $tableAlias . ' ON '; $first = true; foreach ($idColumns as $idColumn) { @@ -400,7 +400,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister } return $this->_platform->modifyLimitQuery('SELECT ' . $this->_selectColumnListSql - . ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias + . ' FROM ' . $this->quoteStrategy->getTableName($this->_class, $this->_platform) . ' ' . $baseTableAlias . $joinSql . ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql, $limit, $offset) . $lockSql; @@ -422,7 +422,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister foreach ($this->_class->parentClasses as $parentClassName) { $parentClass = $this->_em->getClassMetadata($parentClassName); $tableAlias = $this->_getSQLTableAlias($parentClassName); - $joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON '; + $joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->_platform) . ' ' . $tableAlias . ' ON '; $first = true; foreach ($idColumns as $idColumn) { @@ -432,7 +432,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister } } - return 'FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias . $joinSql; + return 'FROM ' .$this->quoteStrategy->getTableName($this->_class, $this->_platform) . ' ' . $baseTableAlias . $joinSql; } /* Ensure this method is never called. This persister overrides _getSelectEntitiesSQL directly. */ @@ -463,7 +463,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister } } else if ($this->_class->name != $this->_class->rootEntityName || ! $this->_class->isIdGeneratorIdentity() || $this->_class->identifier[0] != $name) { - $columns[] = $this->_class->getQuotedColumnName($name, $this->_platform); + $columns[] = $this->quoteStrategy->getColumnName($name, $this->_class, $this->_platform); } } diff --git a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php index 9fc72f909..153482693 100644 --- a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php @@ -43,7 +43,7 @@ class ManyToManyPersister extends AbstractCollectionPersister $mapping = $coll->getMapping(); $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); - return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) + return 'DELETE FROM ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) . ' WHERE ' . implode(' = ? AND ', $mapping['joinTableColumns']) . ' = ?'; } @@ -76,11 +76,10 @@ class ManyToManyPersister extends AbstractCollectionPersister */ protected function _getInsertRowSQL(PersistentCollection $coll) { - $mapping = $coll->getMapping(); - $columns = $mapping['joinTableColumns']; - $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); - - $joinTable = $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()); + $mapping = $coll->getMapping(); + $columns = $mapping['joinTableColumns']; + $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); + $joinTable = $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform); return 'INSERT INTO ' . $joinTable . ' (' . implode(', ', $columns) . ')' . ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')'; @@ -148,10 +147,11 @@ class ManyToManyPersister extends AbstractCollectionPersister */ protected function _getDeleteSQL(PersistentCollection $coll) { - $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); - $mapping = $coll->getMapping(); + $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); + $mapping = $coll->getMapping(); + $joinTable = $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform); - return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) + return 'DELETE FROM ' . $joinTable . ' WHERE ' . implode(' = ? AND ', array_keys($mapping['relationToSourceKeyColumns'])) . ' = ?'; } @@ -222,7 +222,7 @@ class ManyToManyPersister extends AbstractCollectionPersister } $sql = 'SELECT COUNT(*)' - . ' FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) . ' t' + . ' FROM ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) . ' t' . $joinTargetEntitySQL . ' WHERE ' . implode(' AND ', $whereClauses); @@ -324,7 +324,7 @@ class ManyToManyPersister extends AbstractCollectionPersister $targetId = $uow->getEntityIdentifier($element); } - $quotedJoinTable = $sourceClass->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()); + $quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $sourceClass, $this->platform); $whereClauses = array(); $params = array(); @@ -385,7 +385,7 @@ class ManyToManyPersister extends AbstractCollectionPersister $joinTargetEntitySQL = ''; if ($filterSql = $this->generateFilterConditionSQL($targetClass, 'te')) { $joinTargetEntitySQL = ' JOIN ' - . $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform()) . ' te' + . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' te' . ' ON'; $joinTargetEntitySQLClauses = array(); diff --git a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php index ab586f3a3..aa0208fea 100644 --- a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php @@ -45,7 +45,7 @@ class OneToManyPersister extends AbstractCollectionPersister $mapping = $coll->getMapping(); $class = $this->_em->getClassMetadata($mapping['targetEntity']); - return 'DELETE FROM ' . $class->getQuotedTableName($this->_conn->getDatabasePlatform()) + return 'DELETE FROM ' . $this->quoteStrategy->getTableName($class, $this->platform) . ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?'; } @@ -127,7 +127,7 @@ class OneToManyPersister extends AbstractCollectionPersister } $sql = 'SELECT count(*)' - . ' FROM ' . $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform()) . ' t' + . ' FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' t' . ' WHERE ' . implode(' AND ', $whereClauses); return $this->_conn->fetchColumn($sql, $params); @@ -204,7 +204,7 @@ class OneToManyPersister extends AbstractCollectionPersister $mapping = $coll->getMapping(); $class = $this->_em->getClassMetadata($mapping['targetEntity']); - $sql = 'DELETE FROM ' . $class->getQuotedTableName($this->_conn->getDatabasePlatform()) + $sql = 'DELETE FROM ' . $this->quoteStrategy->getTableName($class, $this->platform) . ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?'; return (bool) $this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element)); diff --git a/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php index e2ed4f95d..bffff29f1 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php @@ -42,21 +42,22 @@ class SizeFunction extends FunctionNode */ public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) { - $platform = $sqlWalker->getConnection()->getDatabasePlatform(); - $dqlAlias = $this->collectionPathExpression->identificationVariable; - $assocField = $this->collectionPathExpression->field; + $platform = $sqlWalker->getEntityManager()->getConnection()->getDatabasePlatform(); + $quoteStrategy = $sqlWalker->getEntityManager()->getConfiguration()->getQuoteStrategy(); + $dqlAlias = $this->collectionPathExpression->identificationVariable; + $assocField = $this->collectionPathExpression->field; - $qComp = $sqlWalker->getQueryComponent($dqlAlias); - $class = $qComp['metadata']; - $assoc = $class->associationMappings[$assocField]; - $sql = 'SELECT COUNT(*) FROM '; + $qComp = $sqlWalker->getQueryComponent($dqlAlias); + $class = $qComp['metadata']; + $assoc = $class->associationMappings[$assocField]; + $sql = 'SELECT COUNT(*) FROM '; if ($assoc['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY) { - $targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']); - $targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->getTableName()); - $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); + $targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']); + $targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->getTableName()); + $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); - $sql .= $targetClass->getQuotedTableName($platform) . ' ' . $targetTableAlias . ' WHERE '; + $sql .= $quoteStrategy->getTableName($targetClass, $platform) . ' ' . $targetTableAlias . ' WHERE '; $owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']]; @@ -67,7 +68,7 @@ class SizeFunction extends FunctionNode $sql .= $targetTableAlias . '.' . $sourceColumn . ' = ' - . $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$targetColumn], $platform); + . $sourceTableAlias . '.' . $quoteStrategy->getColumnName($class->fieldNames[$targetColumn], $class, $platform); } } else { // many-to-many $targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']); @@ -80,7 +81,7 @@ class SizeFunction extends FunctionNode $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); // join to target table - $sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $platform) . ' ' . $joinTableAlias . ' WHERE '; + $sql .= $quoteStrategy->getJoinTableName($owningAssoc, $targetClass, $platform) . ' ' . $joinTableAlias . ' WHERE '; $joinColumns = $assoc['isOwningSide'] ? $joinTable['joinColumns'] @@ -91,8 +92,8 @@ class SizeFunction extends FunctionNode foreach ($joinColumns as $joinColumn) { if ($first) $first = false; else $sql .= ' AND '; - $sourceColumnName = $class->getQuotedColumnName( - $class->fieldNames[$joinColumn['referencedColumnName']], $platform + $sourceColumnName = $quoteStrategy->getColumnName( + $class->fieldNames[$joinColumn['referencedColumnName']], $class, $platform ); $sql .= $joinTableAlias . '.' . $joinColumn['name'] diff --git a/lib/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php b/lib/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php index 02cc8a54b..d40b37edc 100644 --- a/lib/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php +++ b/lib/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php @@ -47,17 +47,18 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor */ public function __construct(AST\Node $AST, $sqlWalker) { - $em = $sqlWalker->getEntityManager(); - $conn = $em->getConnection(); - $platform = $conn->getDatabasePlatform(); + $em = $sqlWalker->getEntityManager(); + $conn = $em->getConnection(); + $platform = $conn->getDatabasePlatform(); + $quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); - $primaryClass = $em->getClassMetadata($AST->deleteClause->abstractSchemaName); - $primaryDqlAlias = $AST->deleteClause->aliasIdentificationVariable; - $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); + $primaryClass = $em->getClassMetadata($AST->deleteClause->abstractSchemaName); + $primaryDqlAlias = $AST->deleteClause->aliasIdentificationVariable; + $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); - $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); - $idColumnNames = $rootClass->getIdentifierColumnNames(); - $idColumnList = implode(', ', $idColumnNames); + $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); + $idColumnNames = $rootClass->getIdentifierColumnNames(); + $idColumnList = implode(', ', $idColumnNames); // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $primaryDqlAlias); @@ -80,7 +81,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor // 3. Create and store DELETE statements $classNames = array_merge($primaryClass->parentClasses, array($primaryClass->name), $primaryClass->subClasses); foreach (array_reverse($classNames) as $className) { - $tableName = $em->getClassMetadata($className)->getQuotedTableName($platform); + $tableName = $quoteStrategy->getTableName($em->getClassMetadata($className), $platform); $this->_sqlStatements[] = 'DELETE FROM ' . $tableName . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')'; } diff --git a/lib/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php b/lib/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php index 575e6dfb8..7dc3fed82 100644 --- a/lib/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php +++ b/lib/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php @@ -50,20 +50,20 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor */ public function __construct(AST\Node $AST, $sqlWalker) { - $em = $sqlWalker->getEntityManager(); - $conn = $em->getConnection(); - $platform = $conn->getDatabasePlatform(); + $em = $sqlWalker->getEntityManager(); + $conn = $em->getConnection(); + $platform = $conn->getDatabasePlatform(); + $quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); - $updateClause = $AST->updateClause; + $updateClause = $AST->updateClause; + $primaryClass = $sqlWalker->getEntityManager()->getClassMetadata($updateClause->abstractSchemaName); + $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); - $primaryClass = $sqlWalker->getEntityManager()->getClassMetadata($updateClause->abstractSchemaName); - $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); + $updateItems = $updateClause->updateItems; - $updateItems = $updateClause->updateItems; - - $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); - $idColumnNames = $rootClass->getIdentifierColumnNames(); - $idColumnList = implode(', ', $idColumnNames); + $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); + $idColumnNames = $rootClass->getIdentifierColumnNames(); + $idColumnList = implode(', ', $idColumnNames); // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $updateClause->aliasIdentificationVariable); @@ -86,7 +86,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor foreach (array_reverse($classNames) as $className) { $affected = false; $class = $em->getClassMetadata($className); - $updateSql = 'UPDATE ' . $class->getQuotedTableName($platform) . ' SET '; + $updateSql = 'UPDATE ' . $quoteStrategy->getTableName($class, $platform) . ' SET '; foreach ($updateItems as $updateItem) { $field = $updateItem->pathExpression->field; diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 2d034ddcd..13c2b5df0 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -47,82 +47,131 @@ class SqlWalker implements TreeWalker /** * @var ResultSetMapping */ - private $_rsm; + private $rsm; - /** Counters for generating unique column aliases, table aliases and parameter indexes. */ - private $_aliasCounter = 0; - private $_tableAliasCounter = 0; - private $_scalarResultCounter = 1; - private $_sqlParamIndex = 0; + /** + * Counters for generating unique column aliases. + * + * @var integer + */ + private $aliasCounter = 0; + + /** + * Counters for generating unique table aliases. + * + * @var integer + */ + private $tableAliasCounter = 0; + + /** + * Counters for generating unique scalar result. + * + * @var integer + */ + private $scalarResultCounter = 1; + + /** + * Counters for generating unique parameter indexes. + * + * @var integer + */ + private $sqlParamIndex = 0; /** * @var ParserResult */ - private $_parserResult; + private $parserResult; /** * @var EntityManager */ - private $_em; + private $em; /** * @var \Doctrine\DBAL\Connection */ - private $_conn; + private $conn; /** * @var AbstractQuery */ - private $_query; + private $query; - private $_tableAliasMap = array(); + /** + * @var array + */ + private $tableAliasMap = array(); - /** Map from result variable names to their SQL column alias names. */ - private $_scalarResultAliasMap = array(); + /** + * Map from result variable names to their SQL column alias names. + * + * @var array + */ + private $scalarResultAliasMap = array(); /** * Map from DQL-Alias + Field-Name to SQL Column Alias * * @var array */ - private $_scalarFields = array(); + private $scalarFields = array(); - /** Map of all components/classes that appear in the DQL query. */ - private $_queryComponents; + /** + * Map of all components/classes that appear in the DQL query. + * + * @var array + */ + private $queryComponents; - /** A list of classes that appear in non-scalar SelectExpressions. */ - private $_selectedClasses = array(); + /** + * A list of classes that appear in non-scalar SelectExpressions. + * + * @var array + */ + private $selectedClasses = array(); /** * The DQL alias of the root class of the currently traversed query. + * + * @var array */ - private $_rootAliases = array(); + private $rootAliases = array(); /** * Flag that indicates whether to generate SQL table aliases in the SQL. * These should only be generated for SELECT queries, not for UPDATE/DELETE. + * + * @var boolean */ - private $_useSqlTableAliases = true; + private $useSqlTableAliases = true; /** * The database platform abstraction. * * @var AbstractPlatform */ - private $_platform; + private $platform; + + /** + * The quote strategy. + * + * @var \Doctrine\ORM\Mapping\QuoteStrategy + */ + private $quoteStrategy; /** * {@inheritDoc} */ public function __construct($query, $parserResult, array $queryComponents) { - $this->_query = $query; - $this->_parserResult = $parserResult; - $this->_queryComponents = $queryComponents; - $this->_rsm = $parserResult->getResultSetMapping(); - $this->_em = $query->getEntityManager(); - $this->_conn = $this->_em->getConnection(); - $this->_platform = $this->_conn->getDatabasePlatform(); + $this->query = $query; + $this->parserResult = $parserResult; + $this->queryComponents = $queryComponents; + $this->rsm = $parserResult->getResultSetMapping(); + $this->em = $query->getEntityManager(); + $this->conn = $this->em->getConnection(); + $this->platform = $this->conn->getDatabasePlatform(); + $this->quoteStrategy = $this->em->getConfiguration()->getQuoteStrategy(); } /** @@ -132,7 +181,7 @@ class SqlWalker implements TreeWalker */ public function getQuery() { - return $this->_query; + return $this->query; } /** @@ -142,7 +191,7 @@ class SqlWalker implements TreeWalker */ public function getConnection() { - return $this->_conn; + return $this->conn; } /** @@ -152,7 +201,7 @@ class SqlWalker implements TreeWalker */ public function getEntityManager() { - return $this->_em; + return $this->em; } /** @@ -163,7 +212,7 @@ class SqlWalker implements TreeWalker */ public function getQueryComponent($dqlAlias) { - return $this->_queryComponents[$dqlAlias]; + return $this->queryComponents[$dqlAlias]; } /** @@ -175,14 +224,14 @@ class SqlWalker implements TreeWalker { switch (true) { case ($AST instanceof AST\DeleteStatement): - $primaryClass = $this->_em->getClassMetadata($AST->deleteClause->abstractSchemaName); + $primaryClass = $this->em->getClassMetadata($AST->deleteClause->abstractSchemaName); return ($primaryClass->isInheritanceTypeJoined()) ? new Exec\MultiTableDeleteExecutor($AST, $this) : new Exec\SingleTableDeleteUpdateExecutor($AST, $this); case ($AST instanceof AST\UpdateStatement): - $primaryClass = $this->_em->getClassMetadata($AST->updateClause->abstractSchemaName); + $primaryClass = $this->em->getClassMetadata($AST->updateClause->abstractSchemaName); return ($primaryClass->isInheritanceTypeJoined()) ? new Exec\MultiTableUpdateExecutor($AST, $this) @@ -204,11 +253,11 @@ class SqlWalker implements TreeWalker { $tableName .= ($dqlAlias) ? '@[' . $dqlAlias . ']' : ''; - if ( ! isset($this->_tableAliasMap[$tableName])) { - $this->_tableAliasMap[$tableName] = strtolower(substr($tableName, 0, 1)) . $this->_tableAliasCounter++ . '_'; + if ( ! isset($this->tableAliasMap[$tableName])) { + $this->tableAliasMap[$tableName] = strtolower(substr($tableName, 0, 1)) . $this->tableAliasCounter++ . '_'; } - return $this->_tableAliasMap[$tableName]; + return $this->tableAliasMap[$tableName]; } /** @@ -224,7 +273,7 @@ class SqlWalker implements TreeWalker { $tableName .= ($dqlAlias) ? '@[' . $dqlAlias . ']' : ''; - $this->_tableAliasMap[$tableName] = $alias; + $this->tableAliasMap[$tableName] = $alias; return $alias; } @@ -237,11 +286,7 @@ class SqlWalker implements TreeWalker */ public function getSQLColumnAlias($columnName) { - // Trim the column alias to the maximum identifier length of the platform. - // If the alias is to long, characters are cut off from the beginning. - return $this->_platform->getSQLResultCasing( - substr($columnName . $this->_aliasCounter++, -$this->_platform->getMaxIdentifierLength()) - ); + return $this->quoteStrategy->getColumnAlias($columnName, $this->aliasCounter++, $this->platform); } /** @@ -260,16 +305,16 @@ class SqlWalker implements TreeWalker // INNER JOIN parent class tables foreach ($class->parentClasses as $parentClassName) { - $parentClass = $this->_em->getClassMetadata($parentClassName); + $parentClass = $this->em->getClassMetadata($parentClassName); $tableAlias = $this->getSQLTableAlias($parentClass->getTableName(), $dqlAlias); // If this is a joined association we must use left joins to preserve the correct result. - $sql .= isset($this->_queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER '; - $sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON '; + $sql .= isset($this->queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER '; + $sql .= 'JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON '; $sqlParts = array(); - foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) { + foreach ($this->quoteStrategy->getIdentifierColumnNames($class, $this->platform) as $columnName) { $sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; } @@ -282,20 +327,20 @@ class SqlWalker implements TreeWalker } // Ignore subclassing inclusion if partial objects is disallowed - if ($this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) { + if ($this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) { return $sql; } // LEFT JOIN child class tables foreach ($class->subClasses as $subClassName) { - $subClass = $this->_em->getClassMetadata($subClassName); + $subClass = $this->em->getClassMetadata($subClassName); $tableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); - $sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON '; + $sql .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->platform) . ' ' . $tableAlias . ' ON '; $sqlParts = array(); - foreach ($subClass->getQuotedIdentifierColumnNames($this->_platform) as $columnName) { + foreach ($this->quoteStrategy->getIdentifierColumnNames($subClass, $this->platform) as $columnName) { $sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; } @@ -309,16 +354,16 @@ class SqlWalker implements TreeWalker { $sqlParts = array(); - foreach ($this->_selectedClasses as $selectedClass) { + foreach ($this->selectedClasses as $selectedClass) { $dqlAlias = $selectedClass['dqlAlias']; - $qComp = $this->_queryComponents[$dqlAlias]; + $qComp = $this->queryComponents[$dqlAlias]; if ( ! isset($qComp['relation']['orderBy'])) continue; foreach ($qComp['relation']['orderBy'] as $fieldName => $orientation) { - $columnName = $qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform); + $columnName = $this->quoteStrategy->getColumnName($fieldName, $qComp['metadata'], $this->platform); $tableName = ($qComp['metadata']->isInheritanceTypeJoined()) - ? $this->_em->getUnitOfWork()->getEntityPersister($qComp['metadata']->name)->getOwningTable($fieldName) + ? $this->em->getUnitOfWork()->getEntityPersister($qComp['metadata']->name)->getOwningTable($fieldName) : $qComp['metadata']->getTableName(); $sqlParts[] = $this->getSQLTableAlias($tableName, $dqlAlias) . '.' . $columnName . ' ' . $orientation; @@ -339,11 +384,11 @@ class SqlWalker implements TreeWalker $sqlParts = array(); foreach ($dqlAliases as $dqlAlias) { - $class = $this->_queryComponents[$dqlAlias]['metadata']; + $class = $this->queryComponents[$dqlAlias]['metadata']; if ( ! $class->isInheritanceTypeSingleTable()) continue; - $conn = $this->_em->getConnection(); + $conn = $this->em->getConnection(); $values = array(); if ($class->discriminatorValue !== null) { // discrimnators can be 0 @@ -351,10 +396,10 @@ class SqlWalker implements TreeWalker } foreach ($class->subClasses as $subclassName) { - $values[] = $conn->quote($this->_em->getClassMetadata($subclassName)->discriminatorValue); + $values[] = $conn->quote($this->em->getClassMetadata($subclassName)->discriminatorValue); } - $sqlParts[] = (($this->_useSqlTableAliases) ? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.' : '') + $sqlParts[] = (($this->useSqlTableAliases) ? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.' : '') . $class->discriminatorColumn['name'] . ' IN (' . implode(', ', $values) . ')'; } @@ -373,7 +418,7 @@ class SqlWalker implements TreeWalker */ private function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) { - if (!$this->_em->hasFilters()) { + if (!$this->em->hasFilters()) { return ''; } @@ -390,7 +435,7 @@ class SqlWalker implements TreeWalker case ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE: // With STI the table will only be queried once, make sure that the filters // are added to the root entity - $targetEntity = $this->_em->getClassMetadata($targetEntity->rootEntityName); + $targetEntity = $this->em->getClassMetadata($targetEntity->rootEntityName); break; default: //@todo: throw exception? @@ -399,7 +444,7 @@ class SqlWalker implements TreeWalker } $filterClauses = array(); - foreach ($this->_em->getFilters()->getEnabledFilters() as $filter) { + foreach ($this->em->getFilters()->getEnabledFilters() as $filter) { if ('' !== $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) { $filterClauses[] = '(' . $filterExpr . ')'; } @@ -426,22 +471,22 @@ class SqlWalker implements TreeWalker $sql .= ' ORDER BY ' . $orderBySql; } - $sql = $this->_platform->modifyLimitQuery( - $sql, $this->_query->getMaxResults(), $this->_query->getFirstResult() + $sql = $this->platform->modifyLimitQuery( + $sql, $this->query->getMaxResults(), $this->query->getFirstResult() ); - if (($lockMode = $this->_query->getHint(Query::HINT_LOCK_MODE)) !== false) { + if (($lockMode = $this->query->getHint(Query::HINT_LOCK_MODE)) !== false) { switch ($lockMode) { case LockMode::PESSIMISTIC_READ: - $sql .= ' ' . $this->_platform->getReadLockSQL(); + $sql .= ' ' . $this->platform->getReadLockSQL(); break; case LockMode::PESSIMISTIC_WRITE: - $sql .= ' ' . $this->_platform->getWriteLockSQL(); + $sql .= ' ' . $this->platform->getWriteLockSQL(); break; case LockMode::OPTIMISTIC: - foreach ($this->_selectedClasses as $selectedClass) { + foreach ($this->selectedClasses as $selectedClass) { if ( ! $selectedClass['class']->isVersioned) { throw \Doctrine\ORM\OptimisticLockException::lockFailed($selectedClass['class']->name); } @@ -466,7 +511,7 @@ class SqlWalker implements TreeWalker */ public function walkUpdateStatement(AST\UpdateStatement $AST) { - $this->_useSqlTableAliases = false; + $this->useSqlTableAliases = false; return $this->walkUpdateClause($AST->updateClause) . $this->walkWhereClause($AST->whereClause); @@ -480,7 +525,7 @@ class SqlWalker implements TreeWalker */ public function walkDeleteStatement(AST\DeleteStatement $AST) { - $this->_useSqlTableAliases = false; + $this->useSqlTableAliases = false; return $this->walkDeleteClause($AST->deleteClause) . $this->walkWhereClause($AST->whereClause); @@ -495,11 +540,11 @@ class SqlWalker implements TreeWalker */ public function walkEntityIdentificationVariable($identVariable) { - $class = $this->_queryComponents[$identVariable]['metadata']; + $class = $this->queryComponents[$identVariable]['metadata']; $tableAlias = $this->getSQLTableAlias($class->getTableName(), $identVariable); $sqlParts = array(); - foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) { + foreach ($this->quoteStrategy->getIdentifierColumnNames($class, $this->platform) as $columnName) { $sqlParts[] = $tableAlias . '.' . $columnName; } @@ -515,13 +560,13 @@ class SqlWalker implements TreeWalker */ public function walkIdentificationVariable($identificationVariable, $fieldName = null) { - $class = $this->_queryComponents[$identificationVariable]['metadata']; + $class = $this->queryComponents[$identificationVariable]['metadata']; if ( $fieldName !== null && $class->isInheritanceTypeJoined() && isset($class->fieldMappings[$fieldName]['inherited']) ) { - $class = $this->_em->getClassMetadata($class->fieldMappings[$fieldName]['inherited']); + $class = $this->em->getClassMetadata($class->fieldMappings[$fieldName]['inherited']); } return $this->getSQLTableAlias($class->getTableName(), $identificationVariable); @@ -541,13 +586,13 @@ class SqlWalker implements TreeWalker case AST\PathExpression::TYPE_STATE_FIELD: $fieldName = $pathExpr->field; $dqlAlias = $pathExpr->identificationVariable; - $class = $this->_queryComponents[$dqlAlias]['metadata']; + $class = $this->queryComponents[$dqlAlias]['metadata']; - if ($this->_useSqlTableAliases) { + if ($this->useSqlTableAliases) { $sql .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.'; } - $sql .= $class->getQuotedColumnName($fieldName, $this->_platform); + $sql .= $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); break; case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION: @@ -555,10 +600,10 @@ class SqlWalker implements TreeWalker // Just use the foreign key, i.e. u.group_id $fieldName = $pathExpr->field; $dqlAlias = $pathExpr->identificationVariable; - $class = $this->_queryComponents[$dqlAlias]['metadata']; + $class = $this->queryComponents[$dqlAlias]['metadata']; if (isset($class->associationMappings[$fieldName]['inherited'])) { - $class = $this->_em->getClassMetadata($class->associationMappings[$fieldName]['inherited']); + $class = $this->em->getClassMetadata($class->associationMappings[$fieldName]['inherited']); } $assoc = $class->associationMappings[$fieldName]; @@ -572,7 +617,7 @@ class SqlWalker implements TreeWalker throw QueryException::associationPathCompositeKeyNotSupported(); } - if ($this->_useSqlTableAliases) { + if ($this->useSqlTableAliases) { $sql .= $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.'; } @@ -597,44 +642,44 @@ class SqlWalker implements TreeWalker $sql = 'SELECT ' . (($selectClause->isDistinct) ? 'DISTINCT ' : ''); $sqlSelectExpressions = array_filter(array_map(array($this, 'walkSelectExpression'), $selectClause->selectExpressions)); - if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true && $selectClause->isDistinct) { - $this->_query->setHint(self::HINT_DISTINCT, true); + if ($this->query->getHint(Query::HINT_INTERNAL_ITERATION) == true && $selectClause->isDistinct) { + $this->query->setHint(self::HINT_DISTINCT, true); } - $addMetaColumns = ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) && - $this->_query->getHydrationMode() == Query::HYDRATE_OBJECT + $addMetaColumns = ! $this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) && + $this->query->getHydrationMode() == Query::HYDRATE_OBJECT || - $this->_query->getHydrationMode() != Query::HYDRATE_OBJECT && - $this->_query->getHint(Query::HINT_INCLUDE_META_COLUMNS); + $this->query->getHydrationMode() != Query::HYDRATE_OBJECT && + $this->query->getHint(Query::HINT_INCLUDE_META_COLUMNS); - foreach ($this->_selectedClasses as $selectedClass) { + foreach ($this->selectedClasses as $selectedClass) { $class = $selectedClass['class']; $dqlAlias = $selectedClass['dqlAlias']; $resultAlias = $selectedClass['resultAlias']; // Register as entity or joined entity result - if ($this->_queryComponents[$dqlAlias]['relation'] === null) { - $this->_rsm->addEntityResult($class->name, $dqlAlias, $resultAlias); + if ($this->queryComponents[$dqlAlias]['relation'] === null) { + $this->rsm->addEntityResult($class->name, $dqlAlias, $resultAlias); } else { - $this->_rsm->addJoinedEntityResult( + $this->rsm->addJoinedEntityResult( $class->name, $dqlAlias, - $this->_queryComponents[$dqlAlias]['parent'], - $this->_queryComponents[$dqlAlias]['relation']['fieldName'] + $this->queryComponents[$dqlAlias]['parent'], + $this->queryComponents[$dqlAlias]['relation']['fieldName'] ); } if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) { // Add discriminator columns to SQL - $rootClass = $this->_em->getClassMetadata($class->rootEntityName); + $rootClass = $this->em->getClassMetadata($class->rootEntityName); $tblAlias = $this->getSQLTableAlias($rootClass->getTableName(), $dqlAlias); $discrColumn = $rootClass->discriminatorColumn; $columnAlias = $this->getSQLColumnAlias($discrColumn['name']); $sqlSelectExpressions[] = $tblAlias . '.' . $discrColumn['name'] . ' AS ' . $columnAlias; - $this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias); - $this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']); + $this->rsm->setDiscriminatorColumn($dqlAlias, $columnAlias); + $this->rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']); } // Add foreign key columns to SQL, if necessary @@ -650,7 +695,7 @@ class SqlWalker implements TreeWalker continue; } - $owningClass = (isset($assoc['inherited'])) ? $this->_em->getClassMetadata($assoc['inherited']) : $class; + $owningClass = (isset($assoc['inherited'])) ? $this->em->getClassMetadata($assoc['inherited']) : $class; $sqlTableAlias = $this->getSQLTableAlias($owningClass->getTableName(), $dqlAlias); foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { @@ -658,7 +703,7 @@ class SqlWalker implements TreeWalker $sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias; - $this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true)); + $this->rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true)); } } @@ -669,7 +714,7 @@ class SqlWalker implements TreeWalker // Add foreign key columns of subclasses foreach ($class->subClasses as $subClassName) { - $subClass = $this->_em->getClassMetadata($subClassName); + $subClass = $this->em->getClassMetadata($subClassName); $sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); foreach ($subClass->associationMappings as $assoc) { @@ -683,7 +728,7 @@ class SqlWalker implements TreeWalker $sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias; - $this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn); + $this->rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn); } } } @@ -715,17 +760,17 @@ class SqlWalker implements TreeWalker $alias = $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->identificationVariable; $field = $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->field; - if (isset($this->_scalarFields[$alias][$field])) { - $this->_rsm->addIndexByScalar($this->_scalarFields[$alias][$field]); + if (isset($this->scalarFields[$alias][$field])) { + $this->rsm->addIndexByScalar($this->scalarFields[$alias][$field]); } else { - $this->_rsm->addIndexBy( + $this->rsm->addIndexBy( $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->identificationVariable, $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->field ); } } - $sqlParts[] = $this->_platform->appendLockHint($sql, $this->_query->getHint(Query::HINT_LOCK_MODE)); + $sqlParts[] = $this->platform->appendLockHint($sql, $this->query->getHint(Query::HINT_LOCK_MODE)); } return ' FROM ' . implode(', ', $sqlParts); @@ -738,12 +783,12 @@ class SqlWalker implements TreeWalker */ public function walkRangeVariableDeclaration($rangeVariableDeclaration) { - $class = $this->_em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName); + $class = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName); $dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable; - $this->_rootAliases[] = $dqlAlias; + $this->rootAliases[] = $dqlAlias; - $sql = $class->getQuotedTableName($this->_platform) . ' ' + $sql = $class->getQuotedTableName($this->platform) . ' ' . $this->getSQLTableAlias($class->getTableName(), $dqlAlias); if ($class->isInheritanceTypeJoined()) { @@ -766,10 +811,10 @@ class SqlWalker implements TreeWalker $joinedDqlAlias = $joinAssociationDeclaration->aliasIdentificationVariable; $indexBy = $joinAssociationDeclaration->indexBy; - $relation = $this->_queryComponents[$joinedDqlAlias]['relation']; - $targetClass = $this->_em->getClassMetadata($relation['targetEntity']); - $sourceClass = $this->_em->getClassMetadata($relation['sourceEntity']); - $targetTableName = $targetClass->getQuotedTableName($this->_platform); + $relation = $this->queryComponents[$joinedDqlAlias]['relation']; + $targetClass = $this->em->getClassMetadata($relation['targetEntity']); + $sourceClass = $this->em->getClassMetadata($relation['sourceEntity']); + $targetTableName = $targetClass->getQuotedTableName($this->platform); $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias); $sourceTableAlias = $this->getSQLTableAlias($sourceClass->getTableName(), $associationPathExpression->identificationVariable); @@ -777,7 +822,7 @@ class SqlWalker implements TreeWalker // Ensure we got the owning side, since it has all mapping info $assoc = ( ! $relation['isOwningSide']) ? $targetClass->associationMappings[$relation['mappedBy']] : $relation; - if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true && (!$this->_query->getHint(self::HINT_DISTINCT) || isset($this->_selectedClasses[$joinedDqlAlias]))) { + if ($this->query->getHint(Query::HINT_INTERNAL_ITERATION) == true && (!$this->query->getHint(self::HINT_DISTINCT) || isset($this->selectedClasses[$joinedDqlAlias]))) { if ($relation['type'] == ClassMetadata::ONE_TO_MANY || $relation['type'] == ClassMetadata::MANY_TO_MANY) { throw QueryException::iterateWithFetchJoinNotAllowed($assoc); } @@ -790,22 +835,17 @@ class SqlWalker implements TreeWalker case ($assoc['type'] & ClassMetadata::TO_ONE): $conditions = array(); - foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) { - if ($relation['isOwningSide']) { - $quotedTargetColumn = ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$targetColumn])) - ? $targetColumn // Join columns cannot be quoted. - : $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform); + foreach ($assoc['joinColumns'] as $joinColumn) { + $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); + $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); - $conditions[] = $sourceTableAlias . '.' . $sourceColumn . ' = ' . $targetTableAlias . '.' . $quotedTargetColumn; + if ($relation['isOwningSide']) { + $conditions[] = $sourceTableAlias . '.' . $quotedSourceColumn . ' = ' . $targetTableAlias . '.' . $quotedTargetColumn; continue; } - $quotedTargetColumn = ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$targetColumn])) - ? $targetColumn // Join columns cannot be quoted. - : $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform); - - $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn; + $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $quotedSourceColumn; } // Apply remaining inheritance restrictions @@ -829,19 +869,18 @@ class SqlWalker implements TreeWalker // Join relation table $joinTable = $assoc['joinTable']; $joinTableAlias = $this->getSQLTableAlias($joinTable['name'], $joinedDqlAlias); - $joinTableName = $sourceClass->getQuotedJoinTableName($assoc, $this->_platform); + $joinTableName = $sourceClass->getQuotedJoinTableName($assoc, $this->platform); $conditions = array(); $relationColumns = ($relation['isOwningSide']) - ? $assoc['relationToSourceKeyColumns'] - : $assoc['relationToTargetKeyColumns']; + ? $assoc['joinTable']['joinColumns'] + : $assoc['joinTable']['inverseJoinColumns']; - foreach ($relationColumns as $relationColumn => $sourceColumn) { - $quotedTargetColumn = ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$sourceColumn])) - ? $sourceColumn // Join columns cannot be quoted. - : $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$sourceColumn], $this->_platform); + foreach ($relationColumns as $joinColumn) { + $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); + $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); - $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn; + $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $quotedSourceColumn; } $sql .= $joinTableName . ' ' . $joinTableAlias . ' ON ' . implode(' AND ', $conditions); @@ -851,15 +890,14 @@ class SqlWalker implements TreeWalker $conditions = array(); $relationColumns = ($relation['isOwningSide']) - ? $assoc['relationToTargetKeyColumns'] - : $assoc['relationToSourceKeyColumns']; + ? $assoc['joinTable']['inverseJoinColumns'] + : $assoc['joinTable']['joinColumns']; - foreach ($relationColumns as $relationColumn => $targetColumn) { - $quotedTargetColumn = ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$targetColumn])) - ? $targetColumn // Join columns cannot be quoted. - : $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform); + foreach ($relationColumns as $joinColumn) { + $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); + $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); - $conditions[] = $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn; + $conditions[] = $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $quotedSourceColumn; } // Apply remaining inheritance restrictions @@ -888,12 +926,12 @@ class SqlWalker implements TreeWalker // Apply the indexes if ($indexBy) { // For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently. - $this->_rsm->addIndexBy( + $this->rsm->addIndexBy( $indexBy->simpleStateFieldPathExpression->identificationVariable, $indexBy->simpleStateFieldPathExpression->field ); } else if (isset($relation['indexBy'])) { - $this->_rsm->addIndexBy($joinedDqlAlias, $relation['indexBy']); + $this->rsm->addIndexBy($joinedDqlAlias, $relation['indexBy']); } return $sql; @@ -937,7 +975,7 @@ class SqlWalker implements TreeWalker $expr = $orderByItem->expression; $sql = ($expr instanceof AST\Node) ? $expr->dispatch($this) - : $this->walkResultVariable($this->_queryComponents[$expr]['token']['value']); + : $this->walkResultVariable($this->queryComponents[$expr]['token']['value']); return $sql . ' ' . strtoupper($orderByItem->type); } @@ -1044,11 +1082,11 @@ class SqlWalker implements TreeWalker public function walkNullIfExpression($nullIfExpression) { $firstExpression = is_string($nullIfExpression->firstExpression) - ? $this->_conn->quote($nullIfExpression->firstExpression) + ? $this->conn->quote($nullIfExpression->firstExpression) : $this->walkSimpleArithmeticExpression($nullIfExpression->firstExpression); $secondExpression = is_string($nullIfExpression->secondExpression) - ? $this->_conn->quote($nullIfExpression->secondExpression) + ? $this->conn->quote($nullIfExpression->secondExpression) : $this->walkSimpleArithmeticExpression($nullIfExpression->secondExpression); return 'NULLIF(' . $firstExpression . ', ' . $secondExpression . ')'; @@ -1114,16 +1152,16 @@ class SqlWalker implements TreeWalker $fieldName = $expr->field; $dqlAlias = $expr->identificationVariable; - $qComp = $this->_queryComponents[$dqlAlias]; + $qComp = $this->queryComponents[$dqlAlias]; $class = $qComp['metadata']; $resultAlias = $selectExpression->fieldIdentificationVariable ?: $fieldName; $tableName = ($class->isInheritanceTypeJoined()) - ? $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName) + ? $this->em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName) : $class->getTableName(); $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); - $columnName = $class->getQuotedColumnName($fieldName, $this->_platform); + $columnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); $columnAlias = $this->getSQLColumnAlias($class->fieldMappings[$fieldName]['columnName']); $col = $sqlTableAlias . '.' . $columnName; @@ -1132,16 +1170,16 @@ class SqlWalker implements TreeWalker if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { $type = Type::getType($fieldType); - $col = $type->convertToPHPValueSQL($col, $this->_conn->getDatabasePlatform()); + $col = $type->convertToPHPValueSQL($col, $this->conn->getDatabasePlatform()); } $sql .= $col . ' AS ' . $columnAlias; - $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; + $this->scalarResultAliasMap[$resultAlias] = $columnAlias; if ( ! $hidden) { - $this->_rsm->addScalarResult($columnAlias, $resultAlias, $fieldType); - $this->_scalarFields[$dqlAlias][$fieldName] = $columnAlias; + $this->rsm->addScalarResult($columnAlias, $resultAlias, $fieldType); + $this->scalarFields[$dqlAlias][$fieldName] = $columnAlias; } break; @@ -1157,29 +1195,29 @@ class SqlWalker implements TreeWalker case ($expr instanceof AST\GeneralCaseExpression): case ($expr instanceof AST\SimpleCaseExpression): $columnAlias = $this->getSQLColumnAlias('sclr'); - $resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++; + $resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; $sql .= $expr->dispatch($this) . ' AS ' . $columnAlias; - $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; + $this->scalarResultAliasMap[$resultAlias] = $columnAlias; if ( ! $hidden) { // We cannot resolve field type here; assume 'string'. - $this->_rsm->addScalarResult($columnAlias, $resultAlias, 'string'); + $this->rsm->addScalarResult($columnAlias, $resultAlias, 'string'); } break; case ($expr instanceof AST\Subselect): $columnAlias = $this->getSQLColumnAlias('sclr'); - $resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++; + $resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; $sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias; - $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; + $this->scalarResultAliasMap[$resultAlias] = $columnAlias; if ( ! $hidden) { // We cannot resolve field type here; assume 'string'. - $this->_rsm->addScalarResult($columnAlias, $resultAlias, 'string'); + $this->rsm->addScalarResult($columnAlias, $resultAlias, 'string'); } break; @@ -1193,12 +1231,12 @@ class SqlWalker implements TreeWalker $partialFieldSet = array(); } - $queryComp = $this->_queryComponents[$dqlAlias]; + $queryComp = $this->queryComponents[$dqlAlias]; $class = $queryComp['metadata']; $resultAlias = $selectExpression->fieldIdentificationVariable ?: null; - if ( ! isset($this->_selectedClasses[$dqlAlias])) { - $this->_selectedClasses[$dqlAlias] = array( + if ( ! isset($this->selectedClasses[$dqlAlias])) { + $this->selectedClasses[$dqlAlias] = array( 'class' => $class, 'dqlAlias' => $dqlAlias, 'resultAlias' => $resultAlias @@ -1214,34 +1252,34 @@ class SqlWalker implements TreeWalker } $tableName = (isset($mapping['inherited'])) - ? $this->_em->getClassMetadata($mapping['inherited'])->getTableName() + ? $this->em->getClassMetadata($mapping['inherited'])->getTableName() : $class->getTableName(); $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); $columnAlias = $this->getSQLColumnAlias($mapping['columnName']); - $quotedColumnName = $class->getQuotedColumnName($fieldName, $this->_platform); + $quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); $col = $sqlTableAlias . '.' . $quotedColumnName; if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($fieldName)); - $col = $type->convertToPHPValueSQL($col, $this->_platform); + $col = $type->convertToPHPValueSQL($col, $this->platform); } $sqlParts[] = $col . ' AS '. $columnAlias; - $this->_scalarResultAliasMap[$resultAlias][] = $columnAlias; + $this->scalarResultAliasMap[$resultAlias][] = $columnAlias; - $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name); + $this->rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name); } // Add any additional fields of subclasses (excluding inherited fields) // 1) on Single Table Inheritance: always, since its marginal overhead // 2) on Class Table Inheritance only if partial objects are disallowed, // since it requires outer joining subtables. - if ($class->isInheritanceTypeSingleTable() || ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) { + if ($class->isInheritanceTypeSingleTable() || ! $this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) { foreach ($class->subClasses as $subClassName) { - $subClass = $this->_em->getClassMetadata($subClassName); + $subClass = $this->em->getClassMetadata($subClassName); $sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); foreach ($subClass->fieldMappings as $fieldName => $mapping) { @@ -1250,20 +1288,20 @@ class SqlWalker implements TreeWalker } $columnAlias = $this->getSQLColumnAlias($mapping['columnName']); - $quotedColumnName = $subClass->getQuotedColumnName($fieldName, $this->_platform); + $quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $subClass, $this->platform); $col = $sqlTableAlias . '.' . $quotedColumnName; if (isset($subClass->fieldMappings[$fieldName]['requireSQLConversion'])) { $type = Type::getType($subClass->getTypeOfField($fieldName)); - $col = $type->convertToPHPValueSQL($col, $this->_platform); + $col = $type->convertToPHPValueSQL($col, $this->platform); } $sqlParts[] = $col . ' AS ' . $columnAlias; - $this->_scalarResultAliasMap[$resultAlias][] = $columnAlias; + $this->scalarResultAliasMap[$resultAlias][] = $columnAlias; - $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName); + $this->rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName); } } } @@ -1293,11 +1331,11 @@ class SqlWalker implements TreeWalker */ public function walkSubselect($subselect) { - $useAliasesBefore = $this->_useSqlTableAliases; - $rootAliasesBefore = $this->_rootAliases; + $useAliasesBefore = $this->useSqlTableAliases; + $rootAliasesBefore = $this->rootAliases; - $this->_rootAliases = array(); // reset the rootAliases for the subselect - $this->_useSqlTableAliases = true; + $this->rootAliases = array(); // reset the rootAliases for the subselect + $this->useSqlTableAliases = true; $sql = $this->walkSimpleSelectClause($subselect->simpleSelectClause); $sql .= $this->walkSubselectFromClause($subselect->subselectFromClause); @@ -1307,8 +1345,8 @@ class SqlWalker implements TreeWalker $sql .= $subselect->havingClause ? $this->walkHavingClause($subselect->havingClause) : ''; $sql .= $subselect->orderByClause ? $this->walkOrderByClause($subselect->orderByClause) : ''; - $this->_rootAliases = $rootAliasesBefore; // put the main aliases back - $this->_useSqlTableAliases = $useAliasesBefore; + $this->rootAliases = $rootAliasesBefore; // put the main aliases back + $this->useSqlTableAliases = $useAliasesBefore; return $sql; } @@ -1331,7 +1369,7 @@ class SqlWalker implements TreeWalker $sql .= $this->walkJoin($join); } - $sqlParts[] = $this->_platform->appendLockHint($sql, $this->_query->getHint(Query::HINT_LOCK_MODE)); + $sqlParts[] = $this->platform->appendLockHint($sql, $this->query->getHint(Query::HINT_LOCK_MODE)); } return ' FROM ' . implode(', ', $sqlParts); @@ -1366,16 +1404,16 @@ class SqlWalker implements TreeWalker break; case ($expr instanceof AST\AggregateExpression): - $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++; + $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; $sql .= $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias; break; case ($expr instanceof AST\Subselect): - $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++; + $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; - $columnAlias = 'sclr' . $this->_aliasCounter++; - $this->_scalarResultAliasMap[$alias] = $columnAlias; + $columnAlias = 'sclr' . $this->aliasCounter++; + $this->scalarResultAliasMap[$alias] = $columnAlias; $sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias; break; @@ -1390,10 +1428,10 @@ class SqlWalker implements TreeWalker case ($expr instanceof AST\CoalesceExpression): case ($expr instanceof AST\GeneralCaseExpression): case ($expr instanceof AST\SimpleCaseExpression): - $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++; + $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; $columnAlias = $this->getSQLColumnAlias('sclr'); - $this->_scalarResultAliasMap[$alias] = $columnAlias; + $this->scalarResultAliasMap[$alias] = $columnAlias; $sql .= $expr->dispatch($this) . ' AS ' . $columnAlias; break; @@ -1449,21 +1487,21 @@ class SqlWalker implements TreeWalker } // ResultVariable - if (isset($this->_queryComponents[$groupByItem]['resultVariable'])) { + if (isset($this->queryComponents[$groupByItem]['resultVariable'])) { return $this->walkResultVariable($groupByItem); } // IdentificationVariable $sqlParts = array(); - foreach ($this->_queryComponents[$groupByItem]['metadata']->fieldNames as $field) { + foreach ($this->queryComponents[$groupByItem]['metadata']->fieldNames as $field) { $item = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $field); $item->type = AST\PathExpression::TYPE_STATE_FIELD; $sqlParts[] = $this->walkPathExpression($item); } - foreach ($this->_queryComponents[$groupByItem]['metadata']->associationMappings as $mapping) { + foreach ($this->queryComponents[$groupByItem]['metadata']->associationMappings as $mapping) { if ($mapping['isOwningSide'] && $mapping['type'] & ClassMetadataInfo::TO_ONE) { $item = new AST\PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $groupByItem, $mapping['fieldName']); $item->type = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; @@ -1483,12 +1521,12 @@ class SqlWalker implements TreeWalker */ public function walkDeleteClause(AST\DeleteClause $deleteClause) { - $class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName); + $class = $this->em->getClassMetadata($deleteClause->abstractSchemaName); $tableName = $class->getTableName(); - $sql = 'DELETE FROM ' . $class->getQuotedTableName($this->_platform); + $sql = 'DELETE FROM ' . $this->quoteStrategy->getTableName($class, $this->platform); $this->setSQLTableAlias($tableName, $tableName, $deleteClause->aliasIdentificationVariable); - $this->_rootAliases[] = $deleteClause->aliasIdentificationVariable; + $this->rootAliases[] = $deleteClause->aliasIdentificationVariable; return $sql; } @@ -1501,12 +1539,12 @@ class SqlWalker implements TreeWalker */ public function walkUpdateClause($updateClause) { - $class = $this->_em->getClassMetadata($updateClause->abstractSchemaName); + $class = $this->em->getClassMetadata($updateClause->abstractSchemaName); $tableName = $class->getTableName(); - $sql = 'UPDATE ' . $class->getQuotedTableName($this->_platform); + $sql = 'UPDATE ' . $this->quoteStrategy->getTableName($class, $this->platform); $this->setSQLTableAlias($tableName, $tableName, $updateClause->aliasIdentificationVariable); - $this->_rootAliases[] = $updateClause->aliasIdentificationVariable; + $this->rootAliases[] = $updateClause->aliasIdentificationVariable; $sql .= ' SET ' . implode(', ', array_map(array($this, 'walkUpdateItem'), $updateClause->updateItems)); @@ -1521,8 +1559,8 @@ class SqlWalker implements TreeWalker */ public function walkUpdateItem($updateItem) { - $useTableAliasesBefore = $this->_useSqlTableAliases; - $this->_useSqlTableAliases = false; + $useTableAliasesBefore = $this->useSqlTableAliases; + $this->useSqlTableAliases = false; $sql = $this->walkPathExpression($updateItem->pathExpression) . ' = '; $newValue = $updateItem->newValue; @@ -1537,11 +1575,11 @@ class SqlWalker implements TreeWalker break; default: - $sql .= $this->_conn->quote($newValue); + $sql .= $this->conn->quote($newValue); break; } - $this->_useSqlTableAliases = $useTableAliasesBefore; + $this->useSqlTableAliases = $useTableAliasesBefore; return $sql; } @@ -1556,12 +1594,12 @@ class SqlWalker implements TreeWalker public function walkWhereClause($whereClause) { $condSql = null !== $whereClause ? $this->walkConditionalExpression($whereClause->conditionalExpression) : ''; - $discrSql = $this->_generateDiscriminatorColumnConditionSql($this->_rootAliases); + $discrSql = $this->_generateDiscriminatorColumnConditionSql($this->rootAliases); - if ($this->_em->hasFilters()) { + if ($this->em->hasFilters()) { $filterClauses = array(); - foreach ($this->_rootAliases as $dqlAlias) { - $class = $this->_queryComponents[$dqlAlias]['metadata']; + foreach ($this->rootAliases as $dqlAlias) { + $class = $this->queryComponents[$dqlAlias]['metadata']; $tableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias); if ($filterExpr = $this->generateFilterConditionSQL($class, $tableAlias)) { @@ -1689,7 +1727,7 @@ class SqlWalker implements TreeWalker $fieldName = $collPathExpr->field; $dqlAlias = $collPathExpr->identificationVariable; - $class = $this->_queryComponents[$dqlAlias]['metadata']; + $class = $this->queryComponents[$dqlAlias]['metadata']; switch (true) { // InputParameter @@ -1710,24 +1748,24 @@ class SqlWalker implements TreeWalker $assoc = $class->associationMappings[$fieldName]; if ($assoc['type'] == ClassMetadata::ONE_TO_MANY) { - $targetClass = $this->_em->getClassMetadata($assoc['targetEntity']); + $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName()); $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); - $sql .= $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' WHERE '; + $sql .= $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' ' . $targetTableAlias . ' WHERE '; $owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']]; $sqlParts = array(); foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) { - $targetColumn = $class->getQuotedColumnName($class->fieldNames[$targetColumn], $this->_platform); + $targetColumn = $this->quoteStrategy->getColumnName($class->fieldNames[$targetColumn], $class, $this->platform); $sqlParts[] = $sourceTableAlias . '.' . $targetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn; } - foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) { + foreach ($this->quoteStrategy->getIdentifierColumnNames($targetClass, $this->platform) as $targetColumnName) { if (isset($dqlParamKey)) { - $this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++); + $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); } $sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql; @@ -1735,7 +1773,7 @@ class SqlWalker implements TreeWalker $sql .= implode(' AND ', $sqlParts); } else { // many-to-many - $targetClass = $this->_em->getClassMetadata($assoc['targetEntity']); + $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); $owningAssoc = $assoc['isOwningSide'] ? $assoc : $targetClass->associationMappings[$assoc['mappedBy']]; $joinTable = $owningAssoc['joinTable']; @@ -1746,18 +1784,15 @@ class SqlWalker implements TreeWalker $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); // join to target table - $sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $this->_platform) . ' ' . $joinTableAlias - . ' INNER JOIN ' . $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' ON '; + $sql .= $this->quoteStrategy->getJoinTableName($owningAssoc, $targetClass, $this->platform) . ' ' . $joinTableAlias + . ' INNER JOIN ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' ' . $targetTableAlias . ' ON '; // join conditions $joinColumns = $assoc['isOwningSide'] ? $joinTable['inverseJoinColumns'] : $joinTable['joinColumns']; $joinSqlParts = array(); foreach ($joinColumns as $joinColumn) { - $targetColumn = $targetClass->getQuotedColumnName( - $targetClass->fieldNames[$joinColumn['referencedColumnName']], - $this->_platform - ); + $targetColumn = $this->quoteStrategy->getColumnName($targetClass->fieldNames[$joinColumn['referencedColumnName']], $targetClass, $this->platform); $joinSqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $targetTableAlias . '.' . $targetColumn; } @@ -1769,17 +1804,14 @@ class SqlWalker implements TreeWalker $sqlParts = array(); foreach ($joinColumns as $joinColumn) { - $targetColumn = $class->getQuotedColumnName( - $class->fieldNames[$joinColumn['referencedColumnName']], - $this->_platform - ); + $targetColumn = $this->quoteStrategy->getColumnName($class->fieldNames[$joinColumn['referencedColumnName']], $class, $this->platform); $sqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $sourceTableAlias . '.' . $targetColumn; } - foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) { + foreach ($this->quoteStrategy->getIdentifierColumnNames($targetClass, $this->platform) as $targetColumnName) { if (isset($dqlParamKey)) { - $this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++); + $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); } $sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql; @@ -1818,7 +1850,7 @@ class SqlWalker implements TreeWalker if ($innerExpr instanceof AST\InputParameter) { $dqlParamKey = $innerExpr->name; - $this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++); + $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); $sql .= ' ?'; } else { $sql .= $this->walkPathExpression($innerExpr); @@ -1859,13 +1891,13 @@ class SqlWalker implements TreeWalker $sql = ''; $dqlAlias = $instanceOfExpr->identificationVariable; - $discrClass = $class = $this->_queryComponents[$dqlAlias]['metadata']; - + $discrClass = $class = $this->queryComponents[$dqlAlias]['metadata']; + if ($class->discriminatorColumn) { - $discrClass = $this->_em->getClassMetadata($class->rootEntityName); + $discrClass = $this->em->getClassMetadata($class->rootEntityName); } - if ($this->_useSqlTableAliases) { + if ($this->useSqlTableAliases) { $sql .= $this->getSQLTableAlias($discrClass->getTableName(), $dqlAlias) . '.'; } @@ -1877,8 +1909,8 @@ class SqlWalker implements TreeWalker if ($parameter instanceof AST\InputParameter) { // We need to modify the parameter value to be its correspondent mapped value $dqlParamKey = $parameter->name; - $dqlParam = $this->_query->getParameter($dqlParamKey); - $paramValue = $this->_query->processParameterValue($dqlParam->getValue()); + $dqlParam = $this->query->getParameter($dqlParamKey); + $paramValue = $this->query->processParameterValue($dqlParam->getValue()); if ( ! ($paramValue instanceof \Doctrine\ORM\Mapping\ClassMetadata)) { throw QueryException::invalidParameterType('ClassMetadata', get_class($paramValue)); @@ -1887,11 +1919,11 @@ class SqlWalker implements TreeWalker $entityClassName = $paramValue->name; } else { // Get name from ClassMetadata to resolve aliases. - $entityClassName = $this->_em->getClassMetadata($parameter)->name; + $entityClassName = $this->em->getClassMetadata($parameter)->name; } if ($entityClassName == $class->name) { - $sqlParameterList[] = $this->_conn->quote($class->discriminatorValue); + $sqlParameterList[] = $this->conn->quote($class->discriminatorValue); } else { $discrMap = array_flip($class->discriminatorMap); @@ -1899,7 +1931,7 @@ class SqlWalker implements TreeWalker throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName); } - $sqlParameterList[] = $this->_conn->quote($discrMap[$entityClassName]); + $sqlParameterList[] = $this->conn->quote($discrMap[$entityClassName]); } } @@ -1931,11 +1963,11 @@ class SqlWalker implements TreeWalker { switch ($literal->type) { case AST\Literal::STRING: - return $this->_conn->quote($literal->value); + return $this->conn->quote($literal->value); case AST\Literal::BOOLEAN: $bool = strtolower($literal->value) == 'true' ? true : false; - $boolVal = $this->_conn->getDatabasePlatform()->convertBooleans($bool); + $boolVal = $this->conn->getDatabasePlatform()->convertBooleans($bool); return $boolVal; @@ -1979,7 +2011,7 @@ class SqlWalker implements TreeWalker if ($likeExpr->stringPattern instanceof AST\InputParameter) { $inputParam = $likeExpr->stringPattern; $dqlParamKey = $inputParam->name; - $this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++); + $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); $sql .= '?'; } elseif ($likeExpr->stringPattern instanceof AST\Functions\FunctionNode ) { $sql .= $this->walkFunction($likeExpr->stringPattern); @@ -2021,13 +2053,13 @@ class SqlWalker implements TreeWalker $sql .= ($leftExpr instanceof AST\Node) ? $leftExpr->dispatch($this) - : (is_numeric($leftExpr) ? $leftExpr : $this->_conn->quote($leftExpr)); + : (is_numeric($leftExpr) ? $leftExpr : $this->conn->quote($leftExpr)); $sql .= ' ' . $compExpr->operator . ' '; $sql .= ($rightExpr instanceof AST\Node) ? $rightExpr->dispatch($this) - : (is_numeric($rightExpr) ? $rightExpr : $this->_conn->quote($rightExpr)); + : (is_numeric($rightExpr) ? $rightExpr : $this->conn->quote($rightExpr)); return $sql; } @@ -2040,7 +2072,7 @@ class SqlWalker implements TreeWalker */ public function walkInputParameter($inputParam) { - $this->_parserResult->addParameterMapping($inputParam->name, $this->_sqlParamIndex++); + $this->parserResult->addParameterMapping($inputParam->name, $this->sqlParamIndex++); return '?'; } @@ -2082,8 +2114,8 @@ class SqlWalker implements TreeWalker public function walkArithmeticTerm($term) { if (is_string($term)) { - return (isset($this->_queryComponents[$term])) - ? $this->walkResultVariable($this->_queryComponents[$term]['token']['value']) + return (isset($this->queryComponents[$term])) + ? $this->walkResultVariable($this->queryComponents[$term]['token']['value']) : $term; } @@ -2147,7 +2179,7 @@ class SqlWalker implements TreeWalker public function walkStringPrimary($stringPrimary) { return (is_string($stringPrimary)) - ? $this->_conn->quote($stringPrimary) + ? $this->conn->quote($stringPrimary) : $stringPrimary->dispatch($this); } @@ -2159,7 +2191,7 @@ class SqlWalker implements TreeWalker */ public function walkResultVariable($resultVariable) { - $resultAlias = $this->_scalarResultAliasMap[$resultVariable]; + $resultAlias = $this->scalarResultAliasMap[$resultVariable]; if (is_array($resultAlias)) { return implode(', ', $resultAlias); diff --git a/lib/Doctrine/ORM/Tools/SchemaTool.php b/lib/Doctrine/ORM/Tools/SchemaTool.php index 3955b8c3d..23a361e97 100644 --- a/lib/Doctrine/ORM/Tools/SchemaTool.php +++ b/lib/Doctrine/ORM/Tools/SchemaTool.php @@ -36,7 +36,6 @@ use Doctrine\ORM\ORMException, * * @link www.doctrine-project.org * @since 2.0 - * @version $Revision$ * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel @@ -47,12 +46,19 @@ class SchemaTool /** * @var \Doctrine\ORM\EntityManager */ - private $_em; + private $em; /** * @var \Doctrine\DBAL\Platforms\AbstractPlatform */ - private $_platform; + private $platform; + + /** + * The quote strategy. + * + * @var \Doctrine\ORM\Mapping\QuoteStrategy + */ + private $quoteStrategy; /** * Initializes a new SchemaTool instance that uses the connection of the @@ -62,8 +68,9 @@ class SchemaTool */ public function __construct(EntityManager $em) { - $this->_em = $em; - $this->_platform = $em->getConnection()->getDatabasePlatform(); + $this->em = $em; + $this->platform = $em->getConnection()->getDatabasePlatform(); + $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); } /** @@ -76,7 +83,7 @@ class SchemaTool public function createSchema(array $classes) { $createSchemaSql = $this->getCreateSchemaSql($classes); - $conn = $this->_em->getConnection(); + $conn = $this->em->getConnection(); foreach ($createSchemaSql as $sql) { try { @@ -97,7 +104,7 @@ class SchemaTool public function getCreateSchemaSql(array $classes) { $schema = $this->getSchemaFromMetadata($classes); - return $schema->toSql($this->_platform); + return $schema->toSql($this->platform); } /** @@ -124,23 +131,22 @@ class SchemaTool */ public function getSchemaFromMetadata(array $classes) { - $processedClasses = array(); // Reminder for processed classes, used for hierarchies + // Reminder for processed classes, used for hierarchies + $processedClasses = array(); + $eventManager = $this->em->getEventManager(); + $schemaManager = $this->em->getConnection()->getSchemaManager(); + $metadataSchemaConfig = $schemaManager->createSchemaConfig(); - $sm = $this->_em->getConnection()->getSchemaManager(); - $metadataSchemaConfig = $sm->createSchemaConfig(); $metadataSchemaConfig->setExplicitForeignKeyIndexes(false); $schema = new Schema(array(), array(), $metadataSchemaConfig); - $evm = $this->_em->getEventManager(); - foreach ($classes as $class) { if ($this->processingNotRequired($class, $processedClasses)) { continue; } - $table = $schema->createTable($class->getQuotedTableName($this->_platform)); - - $columns = array(); // table columns + $table = $schema->createTable($this->quoteStrategy->getTableName($class, $this->platform)); + $columns = array(); // table columns if ($class->isInheritanceTypeSingleTable()) { $columns = $this->_gatherColumns($class, $table); @@ -156,7 +162,7 @@ class SchemaTool } foreach ($class->subClasses as $subClassName) { - $subClass = $this->_em->getClassMetadata($subClassName); + $subClass = $this->em->getClassMetadata($subClassName); $this->_gatherColumns($subClass, $table); $this->_gatherRelationsSql($subClass, $table, $schema); $processedClasses[$subClassName] = true; @@ -166,7 +172,7 @@ class SchemaTool $pkColumns = array(); foreach ($class->fieldMappings as $fieldName => $mapping) { if ( ! isset($mapping['inherited'])) { - $columnName = $class->getQuotedColumnName($mapping['fieldName'], $this->_platform); + $columnName = $this->quoteStrategy->getColumnName($mapping['fieldName'], $class, $this->platform); $this->_gatherColumn($class, $mapping, $table); if ($class->isIdentifier($fieldName)) { @@ -185,7 +191,7 @@ class SchemaTool /* @var \Doctrine\ORM\Mapping\ClassMetadata $class */ $idMapping = $class->fieldMappings[$class->identifier[0]]; $this->_gatherColumn($class, $idMapping, $table); - $columnName = $class->getQuotedColumnName($class->identifier[0], $this->_platform); + $columnName = $this->quoteStrategy->getColumnName($class->identifier[0], $class, $this->platform); // TODO: This seems rather hackish, can we optimize it? $table->getColumn($columnName)->setAutoincrement(false); @@ -193,7 +199,7 @@ class SchemaTool // Add a FK constraint on the ID column $table->addUnnamedForeignKeyConstraint( - $this->_em->getClassMetadata($class->rootEntityName)->getQuotedTableName($this->_platform), + $this->quoteStrategy->getTableName($this->em->getClassMetadata($class->rootEntityName), $this->platform), array($columnName), array($columnName), array('onDelete' => 'CASCADE') ); } @@ -210,16 +216,17 @@ class SchemaTool $pkColumns = array(); foreach ($class->identifier as $identifierField) { if (isset($class->fieldMappings[$identifierField])) { - $pkColumns[] = $class->getQuotedColumnName($identifierField, $this->_platform); + $pkColumns[] = $this->quoteStrategy->getColumnName($identifierField, $class, $this->platform); } else if (isset($class->associationMappings[$identifierField])) { /* @var $assoc \Doctrine\ORM\Mapping\OneToOne */ $assoc = $class->associationMappings[$identifierField]; foreach ($assoc['joinColumns'] as $joinColumn) { - $pkColumns[] = $joinColumn['name']; + $pkColumns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); } } } - if (!$table->hasIndex('primary')) { + + if ( ! $table->hasIndex('primary')) { $table->setPrimaryKey($pkColumns); } @@ -244,28 +251,28 @@ class SchemaTool $processedClasses[$class->name] = true; if ($class->isIdGeneratorSequence() && $class->name == $class->rootEntityName) { - $seqDef = $class->sequenceGeneratorDefinition; - - if (!$schema->hasSequence($seqDef['sequenceName'])) { + $seqDef = $class->sequenceGeneratorDefinition; + $quotedName = $this->quoteStrategy->getSequenceName($seqDef, $class, $this->platform); + if ( ! $schema->hasSequence($quotedName)) { $schema->createSequence( - $seqDef['sequenceName'], + $quotedName, $seqDef['allocationSize'], $seqDef['initialValue'] ); } } - if ($evm->hasListeners(ToolEvents::postGenerateSchemaTable)) { - $evm->dispatchEvent(ToolEvents::postGenerateSchemaTable, new GenerateSchemaTableEventArgs($class, $schema, $table)); + if ($eventManager->hasListeners(ToolEvents::postGenerateSchemaTable)) { + $eventManager->dispatchEvent(ToolEvents::postGenerateSchemaTable, new GenerateSchemaTableEventArgs($class, $schema, $table)); } } - if ( ! $this->_platform->supportsSchemas() && ! $this->_platform->canEmulateSchemas() ) { + if ( ! $this->platform->supportsSchemas() && ! $this->platform->canEmulateSchemas() ) { $schema->visit(new RemoveNamespacedAssets()); } - if ($evm->hasListeners(ToolEvents::postGenerateSchema)) { - $evm->dispatchEvent(ToolEvents::postGenerateSchema, new GenerateSchemaEventArgs($this->_em, $schema)); + if ($eventManager->hasListeners(ToolEvents::postGenerateSchema)) { + $eventManager->dispatchEvent(ToolEvents::postGenerateSchema, new GenerateSchemaEventArgs($this->em, $schema)); } return $schema; @@ -283,7 +290,7 @@ class SchemaTool { $discrColumn = $class->discriminatorColumn; - if (!isset($discrColumn['type']) || (strtolower($discrColumn['type']) == 'string' && $discrColumn['length'] === null)) { + if ( ! isset($discrColumn['type']) || (strtolower($discrColumn['type']) == 'string' && $discrColumn['length'] === null)) { $discrColumn['type'] = 'string'; $discrColumn['length'] = 255; } @@ -321,7 +328,7 @@ class SchemaTool $column = $this->_gatherColumn($class, $mapping, $table); if ($class->isIdentifier($mapping['fieldName'])) { - $pkColumns[] = $class->getQuotedColumnName($mapping['fieldName'], $this->_platform); + $pkColumns[] = $this->quoteStrategy->getColumnName($mapping['fieldName'], $class, $this->platform); } } @@ -344,7 +351,7 @@ class SchemaTool */ private function _gatherColumn($class, array $mapping, $table) { - $columnName = $class->getQuotedColumnName($mapping['fieldName'], $this->_platform); + $columnName = $this->quoteStrategy->getColumnName($mapping['fieldName'], $class, $this->platform); $columnType = $mapping['type']; $options = array(); @@ -417,7 +424,7 @@ class SchemaTool continue; } - $foreignClass = $this->_em->getClassMetadata($mapping['targetEntity']); + $foreignClass = $this->em->getClassMetadata($mapping['targetEntity']); if ($mapping['type'] & ClassMetadata::TO_ONE && $mapping['isOwningSide']) { $primaryKeyColumns = $uniqueConstraints = array(); // PK is unnecessary for this relation-type @@ -434,7 +441,7 @@ class SchemaTool // create join table $joinTable = $mapping['joinTable']; - $theJoinTable = $schema->createTable($foreignClass->getQuotedJoinTableName($mapping, $this->_platform)); + $theJoinTable = $schema->createTable($this->quoteStrategy->getJoinTableName($mapping, $foreignClass, $this->platform)); $primaryKeyColumns = $uniqueConstraints = array(); @@ -477,7 +484,7 @@ class SchemaTool foreach ($class->getIdentifierFieldNames() as $fieldName) { if ($class->hasAssociation($fieldName) && $class->getSingleAssociationJoinColumnName($fieldName) == $referencedColumnName) { return $this->getDefiningClass( - $this->_em->getClassMetadata($class->associationMappings[$fieldName]['targetEntity']), + $this->em->getClassMetadata($class->associationMappings[$fieldName]['targetEntity']), $class->getSingleAssociationReferencedJoinColumnName($fieldName) ); } @@ -499,27 +506,30 @@ class SchemaTool */ private function _gatherRelationJoinColumns($joinColumns, $theJoinTable, $class, $mapping, &$primaryKeyColumns, &$uniqueConstraints) { - $localColumns = array(); - $foreignColumns = array(); - $fkOptions = array(); - $foreignTableName = $class->getQuotedTableName($this->_platform); + $localColumns = array(); + $foreignColumns = array(); + $fkOptions = array(); + $foreignTableName = $this->quoteStrategy->getTableName($class, $this->platform); foreach ($joinColumns as $joinColumn) { - $columnName = $joinColumn['name']; + list($definingClass, $referencedFieldName) = $this->getDefiningClass($class, $joinColumn['referencedColumnName']); - if (!$definingClass) { + if ( ! $definingClass) { throw new \Doctrine\ORM\ORMException( "Column name `".$joinColumn['referencedColumnName']."` referenced for relation from ". $mapping['sourceEntity'] . " towards ". $mapping['targetEntity'] . " does not exist." ); } - $primaryKeyColumns[] = $columnName; - $localColumns[] = $columnName; - $foreignColumns[] = $joinColumn['referencedColumnName']; + $quotedColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + $quotedRefColumnName = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $class, $this->platform); - if ( ! $theJoinTable->hasColumn($joinColumn['name'])) { + $primaryKeyColumns[] = $quotedColumnName; + $localColumns[] = $quotedColumnName; + $foreignColumns[] = $quotedRefColumnName; + + if ( ! $theJoinTable->hasColumn($quotedColumnName)) { // Only add the column to the table if it does not exist already. // It might exist already if the foreign key is mapped into a regular // property as well. @@ -543,11 +553,11 @@ class SchemaTool $columnOptions['precision'] = $fieldMapping['precision']; } - $theJoinTable->addColumn($columnName, $fieldMapping['type'], $columnOptions); + $theJoinTable->addColumn($quotedColumnName, $fieldMapping['type'], $columnOptions); } if (isset($joinColumn['unique']) && $joinColumn['unique'] == true) { - $uniqueConstraints[] = array('columns' => array($columnName)); + $uniqueConstraints[] = array('columns' => array($quotedColumnName)); } if (isset($joinColumn['onDelete'])) { @@ -572,7 +582,7 @@ class SchemaTool public function dropSchema(array $classes) { $dropSchemaSql = $this->getDropSchemaSQL($classes); - $conn = $this->_em->getConnection(); + $conn = $this->em->getConnection(); foreach ($dropSchemaSql as $sql) { try { @@ -591,7 +601,7 @@ class SchemaTool public function dropDatabase() { $dropSchemaSql = $this->getDropDatabaseSQL(); - $conn = $this->_em->getConnection(); + $conn = $this->em->getConnection(); foreach ($dropSchemaSql as $sql) { $conn->executeQuery($sql); @@ -605,10 +615,10 @@ class SchemaTool */ public function getDropDatabaseSQL() { - $sm = $this->_em->getConnection()->getSchemaManager(); + $sm = $this->em->getConnection()->getSchemaManager(); $schema = $sm->createSchema(); - $visitor = new \Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector($this->_platform); + $visitor = new \Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector($this->platform); /* @var $schema \Doctrine\DBAL\Schema\Schema */ $schema->visit($visitor); return $visitor->getQueries(); @@ -622,13 +632,13 @@ class SchemaTool */ public function getDropSchemaSQL(array $classes) { - $visitor = new \Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector($this->_platform); + $visitor = new \Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector($this->platform); $schema = $this->getSchemaFromMetadata($classes); - $sm = $this->_em->getConnection()->getSchemaManager(); + $sm = $this->em->getConnection()->getSchemaManager(); $fullSchema = $sm->createSchema(); foreach ($fullSchema->getTables() as $table) { - if (!$schema->hasTable($table->getName())) { + if ( ! $schema->hasTable($table->getName())) { foreach ($table->getForeignKeys() as $foreignKey) { /* @var $foreignKey \Doctrine\DBAL\Schema\ForeignKeyConstraint */ if ($schema->hasTable($foreignKey->getForeignTableName())) { @@ -643,7 +653,7 @@ class SchemaTool } } - if ($this->_platform->supportsSequences()) { + if ($this->platform->supportsSequences()) { foreach ($schema->getSequences() as $sequence) { $visitor->acceptSequence($sequence); } @@ -676,7 +686,7 @@ class SchemaTool public function updateSchema(array $classes, $saveMode=false) { $updateSchemaSql = $this->getUpdateSchemaSql($classes, $saveMode); - $conn = $this->_em->getConnection(); + $conn = $this->em->getConnection(); foreach ($updateSchemaSql as $sql) { $conn->executeQuery($sql); @@ -695,7 +705,7 @@ class SchemaTool */ public function getUpdateSchemaSql(array $classes, $saveMode=false) { - $sm = $this->_em->getConnection()->getSchemaManager(); + $sm = $this->em->getConnection()->getSchemaManager(); $fromSchema = $sm->createSchema(); $toSchema = $this->getSchemaFromMetadata($classes); @@ -704,9 +714,9 @@ class SchemaTool $schemaDiff = $comparator->compare($fromSchema, $toSchema); if ($saveMode) { - return $schemaDiff->toSaveSql($this->_platform); + return $schemaDiff->toSaveSql($this->platform); } else { - return $schemaDiff->toSql($this->_platform); + return $schemaDiff->toSql($this->platform); } } } diff --git a/tests/Doctrine/Tests/Models/Quote/Address.php b/tests/Doctrine/Tests/Models/Quote/Address.php new file mode 100644 index 000000000..58e303f13 --- /dev/null +++ b/tests/Doctrine/Tests/Models/Quote/Address.php @@ -0,0 +1,54 @@ +user !== $user) { + $this->user = $user; + $user->setAddress($this); + } + } + + + public function getId() + { + return $this->id; + } + + public function getZip() + { + return $this->zip; + } + + public function getUser() + { + return $this->user; + } + +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/Quote/Group.php b/tests/Doctrine/Tests/Models/Quote/Group.php new file mode 100644 index 000000000..c653b6974 --- /dev/null +++ b/tests/Doctrine/Tests/Models/Quote/Group.php @@ -0,0 +1,42 @@ +name = $name; + $this->parent = $parent; + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/Quote/Phone.php b/tests/Doctrine/Tests/Models/Quote/Phone.php new file mode 100644 index 000000000..3d4475372 --- /dev/null +++ b/tests/Doctrine/Tests/Models/Quote/Phone.php @@ -0,0 +1,24 @@ +value = $value; + } + +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/Quote/User.php b/tests/Doctrine/Tests/Models/Quote/User.php new file mode 100644 index 000000000..72715d783 --- /dev/null +++ b/tests/Doctrine/Tests/Models/Quote/User.php @@ -0,0 +1,83 @@ +phones = new ArrayCollection; + $this->groups = new ArrayCollection; + } + + + public function getPhones() + { + return $this->phones; + } + + public function getAddress() + { + return $this->address; + } + + public function getGroups() + { + return $this->groups; + } + + public function setAddress(Address $address) { + if ($this->address !== $address) { + $this->address = $address; + $address->setUser($this); + } + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1151Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1151Test.php index 51a2d4555..fe975f69d 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1151Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1151Test.php @@ -25,8 +25,8 @@ class DDC1151Test extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals("CREATE INDEX IDX_88A3259AC5AD08A ON ddc1151user_ddc1151group (ddc1151user_id)", $sql[2]); $this->assertEquals("CREATE INDEX IDX_88A32597357E0B1 ON ddc1151user_ddc1151group (ddc1151group_id)", $sql[3]); $this->assertEquals("CREATE TABLE \"Group\" (id INT NOT NULL, PRIMARY KEY(id))", $sql[4]); - $this->assertEquals("CREATE SEQUENCE User_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[5]); - $this->assertEquals("CREATE SEQUENCE Group_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[6]); + $this->assertEquals("CREATE SEQUENCE \"User_id_seq\" INCREMENT BY 1 MINVALUE 1 START 1", $sql[5]); + $this->assertEquals("CREATE SEQUENCE \"Group_id_seq\" INCREMENT BY 1 MINVALUE 1 START 1", $sql[6]); $this->assertEquals("ALTER TABLE ddc1151user_ddc1151group ADD CONSTRAINT FK_88A3259AC5AD08A FOREIGN KEY (ddc1151user_id) REFERENCES \"User\" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[7]); $this->assertEquals("ALTER TABLE ddc1151user_ddc1151group ADD CONSTRAINT FK_88A32597357E0B1 FOREIGN KEY (ddc1151group_id) REFERENCES \"Group\" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[8]); } diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1360Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1360Test.php index f95f77eb4..38f5837e5 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1360Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1360Test.php @@ -21,7 +21,7 @@ class DDC1360Test extends OrmFunctionalTestCase $this->assertEquals(array( 'CREATE TABLE "user"."user" (id INT NOT NULL, PRIMARY KEY(id))', - 'CREATE SEQUENCE "user".user_id_seq INCREMENT BY 1 MINVALUE 1 START 1', + 'CREATE SEQUENCE "user"."user_id_seq" INCREMENT BY 1 MINVALUE 1 START 1', ), $sql); } } diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC142Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC142Test.php new file mode 100644 index 000000000..6965c6e3b --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC142Test.php @@ -0,0 +1,89 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\User'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Group'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Phone'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Address'), + )); + } catch(\Exception $e) { + } + } + + public function testCreateRetreaveUpdateDelete() + { + + $user = new User; + $user->name = 'FabioBatSilva'; + $this->_em->persist($user); + + $address = new Address; + $address->zip = '12345'; + $this->_em->persist($address); + + $this->_em->flush(); + + $addressRef = $this->_em->getReference('Doctrine\Tests\Models\Quote\Address', $address->getId()); + + $user->setAddress($addressRef); + + $this->_em->flush(); + $this->_em->clear(); + + $id = $user->id; + $this->assertNotNull($id); + + + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $id); + $address = $user->getAddress(); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Address', $user->getAddress()); + + $this->assertEquals('FabioBatSilva', $user->name); + $this->assertEquals('12345', $address->zip); + + + $user->name = 'FabioBatSilva1'; + $user->address = null; + + $this->_em->persist($user); + $this->_em->remove($address); + $this->_em->flush(); + $this->_em->clear(); + + + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $id); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertNull($user->getAddress()); + + $this->assertEquals('FabioBatSilva1', $user->name); + + + $this->_em->remove($user); + $this->_em->flush(); + $this->_em->clear(); + + $this->assertNull($this->_em->find('Doctrine\Tests\Models\Quote\User', $id)); + } + +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1719Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1719Test.php new file mode 100644 index 000000000..93b3458e6 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1719Test.php @@ -0,0 +1,88 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(self::CLASS_NAME), + )); + } catch(\Exception $e) { + } + } + + public function testCreateRetreaveUpdateDelete() + { + $e1 = new SimpleEntity('Bar 1'); + $e2 = new SimpleEntity('Foo 1'); + + // Create + $this->_em->persist($e1); + $this->_em->persist($e2); + $this->_em->flush(); + $this->_em->clear(); + + $e1Id = $e1->id; + $e2Id = $e2->id; + + // Retreave + $e1 = $this->_em->find(self::CLASS_NAME, $e1Id); + $e2 = $this->_em->find(self::CLASS_NAME, $e2Id); + + $this->assertInstanceOf(self::CLASS_NAME, $e1); + $this->assertInstanceOf(self::CLASS_NAME, $e2); + + $this->assertEquals($e1Id, $e1->id); + $this->assertEquals($e2Id, $e2->id); + + $this->assertEquals('Bar 1', $e1->value); + $this->assertEquals('Foo 1', $e2->value); + + $e1->value = 'Bar 2'; + $e2->value = 'Foo 2'; + + // Update + $this->_em->persist($e1); + $this->_em->persist($e2); + $this->_em->flush(); + + $this->assertEquals('Bar 2', $e1->value); + $this->assertEquals('Foo 2', $e2->value); + + $this->assertInstanceOf(self::CLASS_NAME, $e1); + $this->assertInstanceOf(self::CLASS_NAME, $e2); + + $this->assertEquals($e1Id, $e1->id); + $this->assertEquals($e2Id, $e2->id); + + $this->assertEquals('Bar 2', $e1->value); + $this->assertEquals('Foo 2', $e2->value); + + // Delete + $this->_em->remove($e1); + $this->_em->remove($e2); + $this->_em->flush(); + + + $e1 = $this->_em->find(self::CLASS_NAME, $e1Id); + $e2 = $this->_em->find(self::CLASS_NAME, $e2Id); + + $this->assertNull($e1); + $this->assertNull($e2); + } + +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1843Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1843Test.php new file mode 100644 index 000000000..15cfd5903 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1843Test.php @@ -0,0 +1,136 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\User'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Group'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Phone'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Address'), + )); + } catch(\Exception $e) { + } + } + + public function testCreateRetreaveUpdateDelete() + { + + $e1 = new Group('Parent Bar 1'); + $e2 = new Group('Parent Foo 2'); + + $this->_em->persist($e1); + $this->_em->persist($e2); + $this->_em->flush(); + + $e3 = new Group('Bar 3', $e1); + $e4 = new Group('Foo 4', $e2); + + // Create + $this->_em->persist($e3); + $this->_em->persist($e4); + $this->_em->flush(); + $this->_em->clear(); + + $e1Id = $e1->id; + $e2Id = $e2->id; + $e3Id = $e3->id; + $e4Id = $e4->id; + + // Retreave + $e1 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e1Id); + $e2 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e2Id); + $e3 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e3Id); + $e4 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e4Id); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e1); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e2); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e3); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e4); + + $this->assertEquals($e1Id, $e1->id); + $this->assertEquals($e2Id, $e2->id); + $this->assertEquals($e3Id, $e3->id); + $this->assertEquals($e4Id, $e4->id); + + + $this->assertEquals('Parent Bar 1', $e1->name); + $this->assertEquals('Parent Foo 2', $e2->name); + $this->assertEquals('Bar 3', $e3->name); + $this->assertEquals('Foo 4', $e4->name); + + $e1->name = 'Parent Bar 11'; + $e2->name = 'Parent Foo 22'; + $e3->name = 'Bar 33'; + $e4->name = 'Foo 44'; + + // Update + $this->_em->persist($e1); + $this->_em->persist($e2); + $this->_em->persist($e3); + $this->_em->persist($e4); + $this->_em->flush(); + + $this->assertEquals('Parent Bar 11', $e1->name); + $this->assertEquals('Parent Foo 22', $e2->name); + $this->assertEquals('Bar 33', $e3->name); + $this->assertEquals('Foo 44', $e4->name); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e1); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e2); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e3); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e4); + + $this->assertEquals($e1Id, $e1->id); + $this->assertEquals($e2Id, $e2->id); + $this->assertEquals($e3Id, $e3->id); + $this->assertEquals($e4Id, $e4->id); + + $this->assertEquals('Parent Bar 11', $e1->name); + $this->assertEquals('Parent Foo 22', $e2->name); + $this->assertEquals('Bar 33', $e3->name); + $this->assertEquals('Foo 44', $e4->name); + + // Delete + $this->_em->remove($e4); + $this->_em->remove($e3); + $this->_em->remove($e2); + $this->_em->remove($e1); + + $this->_em->flush(); + $this->_em->clear(); + + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e1); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e2); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e3); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e4); + + // Retreave + $e1 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e1Id); + $e2 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e2Id); + $e3 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e3Id); + $e4 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e4Id); + + $this->assertNull($e1); + $this->assertNull($e2); + $this->assertNull($e3); + $this->assertNull($e4); + } + +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php index 2a2f46ce3..f1654dcfd 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php @@ -243,6 +243,86 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase $cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO); return $cm1; } + + /** + * @group DDC-1845 + */ + public function testQuoteMetadata() + { + $cmf = new ClassMetadataFactory(); + $driver = $this->createAnnotationDriver(array(__DIR__ . '/../../Models/Quote/')); + $em = $this->_createEntityManager($driver); + $cmf->setEntityManager($em); + + + $userMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\Quote\User'); + $phoneMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\Quote\Phone'); + $groupMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\Quote\Group'); + $addressMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\Quote\Address'); + + + // Phone Class Metadata + $this->assertTrue($phoneMetadata->fieldMappings['number']['quoted']); + $this->assertEquals('phone-number', $phoneMetadata->fieldMappings['number']['columnName']); + + $user = $phoneMetadata->associationMappings['user']; + $this->assertTrue($user['joinColumns'][0]['quoted']); + $this->assertEquals('user-id', $user['joinColumns'][0]['name']); + $this->assertEquals('user-id', $user['joinColumns'][0]['referencedColumnName']); + + + + // User Group Metadata + $this->assertTrue($groupMetadata->fieldMappings['id']['quoted']); + $this->assertTrue($groupMetadata->fieldMappings['name']['quoted']); + + $this->assertEquals('user-id', $userMetadata->fieldMappings['id']['columnName']); + $this->assertEquals('user-name', $userMetadata->fieldMappings['name']['columnName']); + + $user = $groupMetadata->associationMappings['parent']; + $this->assertTrue($user['joinColumns'][0]['quoted']); + $this->assertEquals('parent-id', $user['joinColumns'][0]['name']); + $this->assertEquals('group-id', $user['joinColumns'][0]['referencedColumnName']); + + + // Address Class Metadata + $this->assertTrue($addressMetadata->fieldMappings['id']['quoted']); + $this->assertTrue($addressMetadata->fieldMappings['zip']['quoted']); + + $this->assertEquals('address-id', $addressMetadata->fieldMappings['id']['columnName']); + $this->assertEquals('address-zip', $addressMetadata->fieldMappings['zip']['columnName']); + + $user = $addressMetadata->associationMappings['user']; + $this->assertTrue($user['joinColumns'][0]['quoted']); + $this->assertEquals('user-id', $user['joinColumns'][0]['name']); + $this->assertEquals('user-id', $user['joinColumns'][0]['referencedColumnName']); + + + + // User Class Metadata + $this->assertTrue($userMetadata->fieldMappings['id']['quoted']); + $this->assertTrue($userMetadata->fieldMappings['name']['quoted']); + + $this->assertEquals('user-id', $userMetadata->fieldMappings['id']['columnName']); + $this->assertEquals('user-name', $userMetadata->fieldMappings['name']['columnName']); + + + $address = $userMetadata->associationMappings['address']; + $this->assertTrue($address['joinColumns'][0]['quoted']); + $this->assertEquals('address-id', $address['joinColumns'][0]['name']); + $this->assertEquals('address-id', $address['joinColumns'][0]['referencedColumnName']); + + $groups = $userMetadata->associationMappings['groups']; + $this->assertTrue($groups['joinTable']['quoted']); + $this->assertTrue($groups['joinTable']['joinColumns'][0]['quoted']); + $this->assertEquals('quote-users-groups', $groups['joinTable']['name']); + $this->assertEquals('user-id', $groups['joinTable']['joinColumns'][0]['name']); + $this->assertEquals('user-id', $groups['joinTable']['joinColumns'][0]['referencedColumnName']); + + $this->assertTrue($groups['joinTable']['inverseJoinColumns'][0]['quoted']); + $this->assertEquals('group-id', $groups['joinTable']['inverseJoinColumns'][0]['name']); + $this->assertEquals('group-id', $groups['joinTable']['inverseJoinColumns'][0]['referencedColumnName']); + } } /* Test subject class with overriden factory method for mocking purposes */ diff --git a/tests/Doctrine/Tests/ORM/Mapping/QuoteStrategyTest.php b/tests/Doctrine/Tests/ORM/Mapping/QuoteStrategyTest.php new file mode 100644 index 000000000..23f02b451 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/QuoteStrategyTest.php @@ -0,0 +1,197 @@ +_getTestEntityManager(); + $this->platform = $em->getConnection()->getDatabasePlatform(); + $this->strategy = new DefaultQuoteStrategy(); + } + + /** + * @param string $className + * @return \Doctrine\ORM\Mapping\ClassMetadata + */ + private function createClassMetadata($className) + { + $cm = new ClassMetadata($className); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + return $cm; + } + + public function testConfiguration() + { + $em = $this->_getTestEntityManager(); + $config = $em->getConfiguration(); + + $this->assertInstanceOf('Doctrine\ORM\Mapping\QuoteStrategy', $config->getQuoteStrategy()); + $this->assertInstanceOf('Doctrine\ORM\Mapping\DefaultQuoteStrategy', $config->getQuoteStrategy()); + + $config->setQuoteStrategy(new MyQuoteStrategy()); + + $this->assertInstanceOf('Doctrine\ORM\Mapping\QuoteStrategy', $config->getQuoteStrategy()); + $this->assertInstanceOf('Doctrine\Tests\ORM\Mapping\MyQuoteStrategy', $config->getQuoteStrategy()); + } + + public function testGetColumnName() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->mapField(array('fieldName' => 'name', 'columnName' => '`name`')); + $cm->mapField(array('fieldName' => 'id', 'columnName' => 'id')); + + $this->assertEquals('id' ,$this->strategy->getColumnName('id', $cm, $this->platform)); + $this->assertEquals('"name"' ,$this->strategy->getColumnName('name', $cm, $this->platform)); + } + + public function testGetTableName() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->setPrimaryTable(array('name'=>'`cms_user`')); + $this->assertEquals('"cms_user"' ,$this->strategy->getTableName($cm, $this->platform)); + + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->setPrimaryTable(array('name'=>'cms_user')); + $this->assertEquals('cms_user' ,$this->strategy->getTableName($cm, $this->platform)); + } + + public function testJoinTableName() + { + $cm1 = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + $cm2 = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + + $cm1->mapManyToMany(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser', + 'inversedBy' => 'users', + 'joinTable' => array( + 'name' => '`cmsaddress_cmsuser`' + ) + )); + + $cm2->mapManyToMany(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser', + 'inversedBy' => 'users', + 'joinTable' => array( + 'name' => 'cmsaddress_cmsuser' + ) + ) + ); + + $this->assertEquals('"cmsaddress_cmsuser"', $this->strategy->getJoinTableName($cm1->associationMappings['user'], $cm1, $this->platform)); + $this->assertEquals('cmsaddress_cmsuser', $this->strategy->getJoinTableName($cm2->associationMappings['user'], $cm2, $this->platform)); + + } + + public function testIdentifierColumnNames() + { + $cm1 = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + $cm2 = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + + $cm1->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'columnName' => '`id`', + )); + + $cm2->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'columnName' => 'id', + )); + + $this->assertEquals(array('"id"'), $this->strategy->getIdentifierColumnNames($cm1, $this->platform)); + $this->assertEquals(array('id'), $this->strategy->getIdentifierColumnNames($cm2, $this->platform)); + } + + + public function testColumnAlias() + { + $i = 0; + $this->assertEquals('columnName0', $this->strategy->getColumnAlias('columnName', $i++, $this->platform)); + $this->assertEquals('column_name1', $this->strategy->getColumnAlias('column_name', $i++, $this->platform)); + $this->assertEquals('COLUMN_NAME2', $this->strategy->getColumnAlias('COLUMN_NAME', $i++, $this->platform)); + $this->assertEquals('COLUMNNAME3', $this->strategy->getColumnAlias('COLUMN-NAME-', $i++, $this->platform)); + } + + public function testQuoteIdentifierJoinColumns() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + + $cm->mapOneToOne(array( + 'id' => true, + 'fieldName' => 'article', + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'joinColumns' => array(array( + 'name' => '`article`' + )), + )); + + $this->assertEquals(array('"article"'), $this->strategy->getIdentifierColumnNames($cm, $this->platform)); + } + + public function testJoinColumnName() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + + $cm->mapOneToOne(array( + 'id' => true, + 'fieldName' => 'article', + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'joinColumns' => array(array( + 'name' => '`article`' + )), + )); + + $joinColumn = $cm->associationMappings['article']['joinColumns'][0]; + $this->assertEquals('"article"',$this->strategy->getJoinColumnName($joinColumn, $cm, $this->platform)); + } + + public function testReferencedJoinColumnName() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + + $cm->mapOneToOne(array( + 'id' => true, + 'fieldName' => 'article', + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'joinColumns' => array(array( + 'name' => '`article`' + )), + )); + + $joinColumn = $cm->associationMappings['article']['joinColumns'][0]; + $this->assertEquals('"id"',$this->strategy->getReferencedJoinColumnName($joinColumn, $cm, $this->platform)); + } +} + +class MyQuoteStrategy extends \Doctrine\ORM\Mapping\DefaultQuoteStrategy +{ + +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php index f31fb2b2f..fa1d7530a 100644 --- a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php +++ b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php @@ -76,4 +76,16 @@ class BasicEntityPersisterTypeValueSqlTest extends \Doctrine\Tests\OrmTestCase $this->assertEquals('t0.customInteger = ABS(?) AND t0.child_id = ?', $sql); } + + /** + * @group DDC-1719 + */ + public function testStripNonAlphanumericCharactersFromSelectColumnListSQL() + { + $persister = new BasicEntityPersister($this->_em, $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\SimpleEntity')); + $method = new \ReflectionMethod($persister, '_getSelectColumnListSQL'); + $method->setAccessible(true); + + $this->assertEquals('t0."simple-entity-id" AS simpleentityid1, t0."simple-entity-value" AS simpleentityvalue2', $method->invoke($persister)); + } } diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 09fc39b9d..fa5b06d82 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -1641,8 +1641,63 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ); } -} + /** + * @group DDC-1719 + */ + public function testStripNonAlphanumericCharactersFromAlias() + { + $this->assertSqlGeneration( + 'SELECT e FROM Doctrine\Tests\Models\Quote\SimpleEntity e', + 'SELECT d0_."simple-entity-id" AS simpleentityid0, d0_."simple-entity-value" AS simpleentityvalue1 FROM "ddc-1719-simple-entity" d0_' + ); + $this->assertSqlGeneration( + 'SELECT e.value FROM Doctrine\Tests\Models\Quote\SimpleEntity e ORDER BY e.value', + 'SELECT d0_."simple-entity-value" AS simpleentityvalue0 FROM "ddc-1719-simple-entity" d0_ ORDER BY d0_."simple-entity-value" ASC' + ); + + $this->assertSqlGeneration( + 'SELECT TRIM(e.value) FROM Doctrine\Tests\Models\Quote\SimpleEntity e ORDER BY e.value', + 'SELECT TRIM(d0_."simple-entity-value") AS sclr0 FROM "ddc-1719-simple-entity" d0_ ORDER BY d0_."simple-entity-value" ASC' + ); + } + + /** + * @group DDC-1845 + */ + public function testQuotedWalkJoinVariableDeclaration() + { + $this->assertSqlGeneration( + 'SELECT u, a FROM Doctrine\Tests\Models\Quote\User u JOIN u.address a', + 'SELECT q0_."user-id" AS userid0, q0_."user-name" AS username1, q1_."address-id" AS addressid2, q1_."address-zip" AS addresszip3 FROM "quote-user" q0_ INNER JOIN "quote-address" q1_ ON q0_."address-id" = q1_."address-id"' + ); + + $this->assertSqlGeneration( + 'SELECT u, p FROM Doctrine\Tests\Models\Quote\User u JOIN u.phones p', + 'SELECT q0_."user-id" AS userid0, q0_."user-name" AS username1, q1_."phone-number" AS phonenumber2 FROM "quote-user" q0_ INNER JOIN "quote-phone" q1_ ON q0_."user-id" = q1_."user-id"' + ); + + $this->assertSqlGeneration( + 'SELECT u, g FROM Doctrine\Tests\Models\Quote\User u JOIN u.groups g', + 'SELECT q0_."user-id" AS userid0, q0_."user-name" AS username1, q1_."group-id" AS groupid2, q1_."group-name" AS groupname3 FROM "quote-user" q0_ INNER JOIN "quote-users-groups" q2_ ON q0_."user-id" = q2_."user-id" INNER JOIN "quote-group" q1_ ON q1_."group-id" = q2_."group-id"' + ); + + $this->assertSqlGeneration( + 'SELECT a, u FROM Doctrine\Tests\Models\Quote\Address a JOIN a.user u', + 'SELECT q0_."address-id" AS addressid0, q0_."address-zip" AS addresszip1, q1_."user-id" AS userid2, q1_."user-name" AS username3 FROM "quote-address" q0_ INNER JOIN "quote-user" q1_ ON q0_."user-id" = q1_."user-id"' + ); + + $this->assertSqlGeneration( + 'SELECT g, u FROM Doctrine\Tests\Models\Quote\Group g JOIN g.users u', + 'SELECT q0_."group-id" AS groupid0, q0_."group-name" AS groupname1, q1_."user-id" AS userid2, q1_."user-name" AS username3 FROM "quote-group" q0_ INNER JOIN "quote-users-groups" q2_ ON q0_."group-id" = q2_."group-id" INNER JOIN "quote-user" q1_ ON q1_."user-id" = q2_."user-id"' + ); + + $this->assertSqlGeneration( + 'SELECT g, p FROM Doctrine\Tests\Models\Quote\Group g JOIN g.parent p', + 'SELECT q0_."group-id" AS groupid0, q0_."group-name" AS groupname1, q1_."group-id" AS groupid2, q1_."group-name" AS groupname3 FROM "quote-group" q0_ INNER JOIN "quote-group" q1_ ON q0_."parent-id" = q1_."group-id"' + ); + } +} class MyAbsFunction extends \Doctrine\ORM\Query\AST\Functions\FunctionNode {