コード例 #1
0
 /**
  * Gets the conditional SQL fragment used in the WHERE clause when selecting
  * entities in this persister.
  *
  * Subclasses are supposed to override this method if they intend to change
  * or alter the criteria by which entities are selected.
  *
  * @param array $criteria
  * @param AssociationMapping $assoc
  * @return string
  */
 protected function _getSelectConditionSQL(array $criteria, $assoc = null)
 {
     $conditionSql = '';
     foreach ($criteria as $field => $value) {
         $conditionSql .= $conditionSql ? ' AND ' : '';
         if (isset($this->_class->columnNames[$field])) {
             if (isset($this->_class->fieldMappings[$field]['inherited'])) {
                 $conditionSql .= $this->_getSQLTableAlias($this->_class->fieldMappings[$field]['inherited']) . '.';
             } else {
                 $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
             }
             $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
         } else {
             if (isset($this->_class->associationMappings[$field])) {
                 if (!$this->_class->associationMappings[$field]['isOwningSide']) {
                     throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field);
                 }
                 if (isset($this->_class->associationMappings[$field]['inherited'])) {
                     $conditionSql .= $this->_getSQLTableAlias($this->_class->associationMappings[$field]['inherited']) . '.';
                 } else {
                     $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
                 }
                 $conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
             } else {
                 if ($assoc !== null) {
                     if ($assoc['type'] == ClassMetadata::MANY_TO_MANY) {
                         $owningAssoc = $assoc['isOwningSide'] ? $assoc : $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']];
                         $conditionSql .= $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform) . '.' . $field;
                     } else {
                         $conditionSql .= $field;
                     }
                 } else {
                     throw ORMException::unrecognizedField($field);
                 }
             }
         }
         $conditionSql .= ' = ?';
     }
     return $conditionSql;
 }
コード例 #2
0
 /**
  * Gets the conditional SQL fragment used in the WHERE clause when selecting
  * entities in this persister.
  *
  * Subclasses are supposed to override this method if they intend to change
  * or alter the criteria by which entities are selected.
  *
  * @param array $criteria
  * @param AssociationMapping $assoc
  * @return string
  */
 protected function _getSelectConditionSQL(array $criteria, $assoc = null)
 {
     $conditionSql = '';
     foreach ($criteria as $field => $value) {
         $conditionSql .= $conditionSql ? ' AND ' : '';
         if (isset($this->_class->columnNames[$field])) {
             if (isset($this->_class->fieldMappings[$field]['inherited'])) {
                 $conditionSql .= $this->_getSQLTableAlias($this->_class->fieldMappings[$field]['inherited']) . '.';
             } else {
                 $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
             }
             $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
         } else {
             if (isset($this->_class->associationMappings[$field])) {
                 if (!$this->_class->associationMappings[$field]['isOwningSide']) {
                     throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field);
                 }
                 if (isset($this->_class->associationMappings[$field]['inherited'])) {
                     $conditionSql .= $this->_getSQLTableAlias($this->_class->associationMappings[$field]['inherited']) . '.';
                 } else {
                     $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
                 }
                 $conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
             } else {
                 if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
                     // very careless developers could potentially open up this normally hidden api for userland attacks,
                     // therefore checking for spaces and function calls which are not allowed.
                     // found a join column condition, not really a "field"
                     $conditionSql .= $field;
                 } else {
                     throw ORMException::unrecognizedField($field);
                 }
             }
         }
         $conditionSql .= is_array($value) ? ' IN (?)' : ($value === null ? ' IS NULL' : ' = ?');
     }
     return $conditionSql;
 }
コード例 #3
0
 /**
  * Builds the left-hand-side of a where condition statement.
  *
  * @param string     $field
  * @param array|null $assoc
  *
  * @return string[]
  *
  * @throws \Doctrine\ORM\ORMException
  */
 private function getSelectConditionStatementColumnSQL($field, $assoc = null)
 {
     if (isset($this->class->columnNames[$field])) {
         $className = isset($this->class->fieldMappings[$field]['inherited']) ? $this->class->fieldMappings[$field]['inherited'] : $this->class->name;
         return array($this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getColumnName($field, $this->class, $this->platform));
     }
     if (isset($this->class->associationMappings[$field])) {
         $association = $this->class->associationMappings[$field];
         // Many-To-Many requires join table check for joinColumn
         $columns = array();
         $class = $this->class;
         if ($association['type'] === ClassMetadata::MANY_TO_MANY) {
             if (!$association['isOwningSide']) {
                 $association = $assoc;
             }
             $joinTableName = $this->quoteStrategy->getJoinTableName($association, $class, $this->platform);
             $joinColumns = $assoc['isOwningSide'] ? $association['joinTable']['joinColumns'] : $association['joinTable']['inverseJoinColumns'];
             foreach ($joinColumns as $joinColumn) {
                 $columns[] = $joinTableName . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
             }
         } else {
             if (!$association['isOwningSide']) {
                 throw ORMException::invalidFindByInverseAssociation($this->class->name, $field);
             }
             $className = isset($association['inherited']) ? $association['inherited'] : $this->class->name;
             foreach ($association['joinColumns'] as $joinColumn) {
                 $columns[] = $this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
             }
         }
         return $columns;
     }
     if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
         // very careless developers could potentially open up this normally hidden api for userland attacks,
         // therefore checking for spaces and function calls which are not allowed.
         // found a join column condition, not really a "field"
         return array($field);
     }
     throw ORMException::unrecognizedField($field);
 }
コード例 #4
0
    /**
     * Builds the left-hand-side of a where condition statement.
     *
     * @param string     $field
     * @param array|null $assoc
     *
     * @return string
     *
     * @throws \Doctrine\ORM\ORMException
     */
    protected function getSelectConditionStatementColumnSQL($field, $assoc = null)
    {
        if (isset($this->class->columnNames[$field])) {
            $className = (isset($this->class->fieldMappings[$field]['inherited']))
                ? $this->class->fieldMappings[$field]['inherited']
                : $this->class->name;

            return $this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getColumnName($field, $this->class, $this->platform);
        }

        if (isset($this->class->associationMappings[$field])) {

            if ( ! $this->class->associationMappings[$field]['isOwningSide']) {
                throw ORMException::invalidFindByInverseAssociation($this->class->name, $field);
            }

            $joinColumn = $this->class->associationMappings[$field]['joinColumns'][0];
            $className  = (isset($this->class->associationMappings[$field]['inherited']))
                ? $this->class->associationMappings[$field]['inherited']
                : $this->class->name;

            return $this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
        }

        if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
            // very careless developers could potentially open up this normally hidden api for userland attacks,
            // therefore checking for spaces and function calls which are not allowed.

            // found a join column condition, not really a "field"
            return $field;
        }

        throw ORMException::unrecognizedField($field);
    }
コード例 #5
0
 /**
  * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
  * @expectedExceptionMessage During the validation whether the given property is unique or not, doctrine threw an exception with the following message: "Unrecognized field: test-field". Did you misconfigure any parameters such as the field or entity name?
  */
 public function testFindOneByThrowsORMException()
 {
     $repository = $this->getMockWithoutInvokingTheOriginalConstructor(EntityRepository::class);
     $repository->expects($this->once())->method('findOneBy')->with(['test-field' => 'test'])->willReturnCallback(function () {
         throw ORMException::unrecognizedField('test-field');
     });
     $manager = $this->getMock(ObjectManager::class);
     $manager->expects($this->any())->method('getRepository')->willReturn($repository);
     $mockRegistry = $this->getMock(ManagerRegistry::class);
     $mockRegistry->expects($this->any())->method('getManagerForClass')->willReturn($manager);
     $propertyMock = new UniquePropertyValidator($mockRegistry);
     $propertyMock->initialize($this->getMock(ExecutionContextInterface::class));
     $propertyMock->validate('test', new UniqueProperty(['entity' => 'AnotherMapping:User', 'field' => 'test-field']));
 }
コード例 #6
0
 /**
  * Generate ORDER BY SQL snippet for ordered collections.
  * 
  * @param array $orderBy
  * @param string $baseTableAlias
  * @return string
  */
 protected function _getCollectionOrderBySQL(array $orderBy, $baseTableAlias)
 {
     $orderBySql = '';
     foreach ($orderBy as $fieldName => $orientation) {
         if (!isset($this->_class->fieldMappings[$fieldName])) {
             ORMException::unrecognizedField($fieldName);
         }
         $tableAlias = isset($this->_class->fieldMappings[$fieldName]['inherited']) ? $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->fieldMappings[$fieldName]['inherited'])) : $baseTableAlias;
         $columnName = $this->_class->getQuotedColumnName($fieldName, $this->_platform);
         if ($orderBySql != '') {
             $orderBySql .= ', ';
         } else {
             $orderBySql = ' ORDER BY ';
         }
         $orderBySql .= $tableAlias . '.' . $columnName . ' ' . $orientation;
     }
     return $orderBySql;
 }
コード例 #7
0
 /**
  * Gets the SELECT SQL to select one or more entities by a set of field criteria.
  *
  * @param array $criteria
  * @return string The SQL.
  * @override
  */
 protected function _getSelectEntitiesSql(array &$criteria, $assoc = null)
 {
     $tableAliases = array();
     $aliasIndex = 1;
     $idColumns = $this->_class->getIdentifierColumnNames();
     $baseTableAlias = 't0';
     $setResultColumnNames = empty($this->_resultColumnNames);
     foreach (array_merge($this->_class->subClasses, $this->_class->parentClasses) as $className) {
         $tableAliases[$className] = 't' . $aliasIndex++;
     }
     // Add regular columns
     $columnList = '';
     foreach ($this->_class->fieldMappings as $fieldName => $mapping) {
         $tableAlias = isset($mapping['inherited']) ? $tableAliases[$mapping['inherited']] : $baseTableAlias;
         if ($columnList != '') {
             $columnList .= ', ';
         }
         $columnList .= $tableAlias . '.' . $this->_class->getQuotedColumnName($fieldName, $this->_platform);
         if ($setResultColumnNames) {
             $resultColumnName = $this->_platform->getSqlResultCasing($mapping['columnName']);
             $this->_resultColumnNames[$resultColumnName] = $mapping['columnName'];
         }
     }
     // Add foreign key columns
     foreach ($this->_class->associationMappings as $assoc2) {
         if ($assoc2->isOwningSide && $assoc2->isOneToOne()) {
             foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
                 $columnList .= ', ' . $assoc2->getQuotedJoinColumnName($srcColumn, $this->_platform);
                 if ($setResultColumnNames) {
                     $resultColumnName = $this->_platform->getSqlResultCasing($srcColumn);
                     $this->_resultColumnNames[$resultColumnName] = $srcColumn;
                 }
             }
         }
     }
     // Add discriminator column
     if ($this->_class->rootEntityName == $this->_class->name) {
         $columnList .= ', ' . $baseTableAlias . '.' . $this->_class->getQuotedDiscriminatorColumnName($this->_platform);
     } else {
         $columnList .= ', ' . $tableAliases[$this->_class->rootEntityName] . '.' . $this->_class->getQuotedDiscriminatorColumnName($this->_platform);
     }
     if ($setResultColumnNames) {
         $resultColumnName = $this->_platform->getSqlResultCasing($this->_class->discriminatorColumn['name']);
         $this->_resultColumnNames[$resultColumnName] = $this->_class->discriminatorColumn['name'];
     }
     // INNER JOIN parent tables
     $joinSql = '';
     foreach ($this->_class->parentClasses as $parentClassName) {
         $parentClass = $this->_em->getClassMetadata($parentClassName);
         $tableAlias = $tableAliases[$parentClassName];
         $joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
         $first = true;
         foreach ($idColumns as $idColumn) {
             if ($first) {
                 $first = false;
             } else {
                 $joinSql .= ' AND ';
             }
             $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
         }
     }
     // OUTER JOIN sub tables
     foreach ($this->_class->subClasses as $subClassName) {
         $subClass = $this->_em->getClassMetadata($subClassName);
         $tableAlias = $tableAliases[$subClassName];
         // Add subclass columns
         foreach ($subClass->fieldMappings as $fieldName => $mapping) {
             if (isset($mapping['inherited'])) {
                 continue;
             }
             $columnList .= ', ' . $tableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform);
             if ($setResultColumnNames) {
                 $resultColumnName = $this->_platform->getSqlResultCasing($mapping['columnName']);
                 $this->_resultColumnNames[$resultColumnName] = $mapping['columnName'];
             }
         }
         // Add join columns (foreign keys)
         foreach ($subClass->associationMappings as $assoc2) {
             if ($assoc2->isOwningSide && $assoc2->isOneToOne() && !isset($subClass->inheritedAssociationFields[$assoc2->sourceFieldName])) {
                 foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
                     $columnList .= ', ' . $tableAlias . '.' . $assoc2->getQuotedJoinColumnName($srcColumn, $this->_platform);
                     if ($setResultColumnNames) {
                         $resultColumnName = $this->_platform->getSqlResultCasing($srcColumn);
                         $this->_resultColumnNames[$resultColumnName] = $srcColumn;
                     }
                 }
             }
         }
         // Add LEFT JOIN
         $joinSql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
         $first = true;
         foreach ($idColumns as $idColumn) {
             if ($first) {
                 $first = false;
             } else {
                 $joinSql .= ' AND ';
             }
             $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
         }
     }
     $conditionSql = '';
     foreach ($criteria as $field => $value) {
         if ($conditionSql != '') {
             $conditionSql .= ' AND ';
         }
         $conditionSql .= $baseTableAlias . '.';
         if (isset($this->_class->columnNames[$field])) {
             $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
         } else {
             if ($assoc !== null) {
                 $conditionSql .= $assoc->getQuotedJoinColumnName($field, $this->_platform);
             } else {
                 throw ORMException::unrecognizedField($field);
             }
         }
         $conditionSql .= ' = ?';
     }
     return 'SELECT ' . $columnList . ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias . $joinSql . ($conditionSql != '' ? ' WHERE ' . $conditionSql : '');
 }
コード例 #8
0
 /**
  * Gets the conditional SQL fragment used in the WHERE clause when selecting
  * entities in this persister.
  *
  * Subclasses are supposed to override this method if they intend to change
  * or alter the criteria by which entities are selected.
  *
  * @param array $criteria
  * @param AssociationMapping $assoc
  * @return string
  */
 protected function _getSelectConditionSQL(array $criteria, $assoc = null)
 {
     $conditionSql = '';
     foreach ($criteria as $field => $value) {
         $conditionSql .= $conditionSql ? ' AND ' : '';
         $placeholder = '?';
         if (isset($this->_class->columnNames[$field])) {
             $className = isset($this->_class->fieldMappings[$field]['inherited']) ? $this->_class->fieldMappings[$field]['inherited'] : $this->_class->name;
             $conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->getQuotedColumnName($field, $this->_platform);
             if (isset($this->_class->fieldMappings[$field]['requireSQLConversion'])) {
                 $type = Type::getType($this->_class->getTypeOfField($field));
                 $placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->_platform);
             }
         } else {
             if (isset($this->_class->associationMappings[$field])) {
                 if (!$this->_class->associationMappings[$field]['isOwningSide']) {
                     throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field);
                 }
                 $className = isset($this->_class->associationMappings[$field]['inherited']) ? $this->_class->associationMappings[$field]['inherited'] : $this->_class->name;
                 $conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
             } else {
                 if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
                     // very careless developers could potentially open up this normally hidden api for userland attacks,
                     // therefore checking for spaces and function calls which are not allowed.
                     // found a join column condition, not really a "field"
                     $conditionSql .= $field;
                 } else {
                     throw ORMException::unrecognizedField($field);
                 }
             }
         }
         //echo preg_match("/(like)/i",$value)?'ok - ':'not - ';
         $conditionSql .= is_array($value) ? ' IN (?)' : ($value === null ? ' IS NULL' : (preg_match("/(like)/i", $value) ? ' LIKE ' : ' = ') . $placeholder);
     }
     //echo $conditionSql;
     return $conditionSql;
 }
コード例 #9
0
 /**
  * Gets the conditional SQL fragment used in the WHERE clause when selecting
  * entities in this persister.
  *
  * Subclasses are supposed to override this method if they intend to change
  * or alter the criteria by which entities are selected.
  *
  * @param array $criteria
  * @param AssociationMapping $assoc
  * @return string
  */
 protected function _getSelectConditionSQL(array $criteria, $assoc = null)
 {
     $conditionSql = '';
     foreach ($criteria as $field => $value) {
         $conditionSql .= $conditionSql ? ' AND ' : '';
         if (isset($this->_class->columnNames[$field])) {
             if (isset($this->_class->fieldMappings[$field]['inherited'])) {
                 $conditionSql .= $this->_getSQLTableAlias($this->_class->fieldMappings[$field]['inherited']) . '.';
             } else {
                 $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
             }
             $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
         } else {
             if ($assoc !== null) {
                 if ($assoc->isManyToMany()) {
                     $owningAssoc = $assoc->isOwningSide ? $assoc : $this->_em->getClassMetadata($assoc->targetEntityName)->associationMappings[$assoc->mappedBy];
                     $conditionSql .= $owningAssoc->getQuotedJoinTableName($this->_platform) . '.' . $field;
                 } else {
                     $conditionSql .= $field;
                 }
             } else {
                 throw ORMException::unrecognizedField($field);
             }
         }
         $conditionSql .= ' = ?';
     }
     return $conditionSql;
 }
コード例 #10
0
 /**
  * Gets the SELECT SQL to select one or more entities by a set of field criteria.
  *
  * @param array $criteria
  * @return string The SQL.
  */
 protected function _getSelectEntitiesSql(array &$criteria, $assoc = null)
 {
     // Construct WHERE conditions
     $conditionSql = '';
     foreach ($criteria as $field => $value) {
         if ($conditionSql != '') {
             $conditionSql .= ' AND ';
         }
         if (isset($this->_class->columnNames[$field])) {
             $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
         } else {
             if (isset($this->_class->fieldNames[$field])) {
                 $conditionSql .= $this->_class->getQuotedColumnName($this->_class->fieldNames[$field], $this->_platform);
             } else {
                 if ($assoc !== null) {
                     $conditionSql .= $assoc->getQuotedJoinColumnName($field, $this->_platform);
                 } else {
                     throw ORMException::unrecognizedField($field);
                 }
             }
         }
         $conditionSql .= ' = ?';
     }
     return 'SELECT ' . $this->_getSelectColumnList() . ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ($conditionSql ? ' WHERE ' . $conditionSql : '');
 }
コード例 #11
0
 /**
  * Gets the SELECT SQL to select one or more entities by a set of field criteria.
  *
  * @param array $criteria
  * @param AssociationMapping $assoc
  * @param string $orderBy
  * @return string
  * @override
  */
 protected function _getSelectEntitiesSQL(array &$criteria, $assoc = null, $orderBy = null)
 {
     $idColumns = $this->_class->getIdentifierColumnNames();
     $baseTableAlias = $this->_getSQLTableAlias($this->_class);
     if ($this->_selectColumnListSql === null) {
         // Add regular columns
         $columnList = '';
         foreach ($this->_class->fieldMappings as $fieldName => $mapping) {
             if ($columnList != '') {
                 $columnList .= ', ';
             }
             $columnList .= $this->_getSelectColumnSQL($fieldName, isset($mapping['inherited']) ? $this->_em->getClassMetadata($mapping['inherited']) : $this->_class);
         }
         // Add foreign key columns
         foreach ($this->_class->associationMappings as $assoc) {
             if ($assoc->isOwningSide && $assoc->isOneToOne()) {
                 $tableAlias = isset($this->_class->inheritedAssociationFields[$assoc->sourceFieldName]) ? $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->inheritedAssociationFields[$assoc->sourceFieldName])) : $baseTableAlias;
                 foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
                     $columnAlias = $srcColumn . $this->_sqlAliasCounter++;
                     $columnList .= ", {$tableAlias}.{$srcColumn} AS {$columnAlias}";
                     $resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
                     if (!isset($this->_resultColumnNames[$resultColumnName])) {
                         $this->_resultColumnNames[$resultColumnName] = $srcColumn;
                     }
                 }
             }
         }
         // Add discriminator column (DO NOT ALIAS THIS COLUMN).
         $discrColumn = $this->_class->discriminatorColumn['name'];
         if ($this->_class->rootEntityName == $this->_class->name) {
             $columnList .= ", {$baseTableAlias}.{$discrColumn}";
         } else {
             $columnList .= ', ' . $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->rootEntityName)) . ".{$discrColumn}";
         }
         $resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
         $this->_resultColumnNames[$resultColumnName] = $discrColumn;
     }
     // INNER JOIN parent tables
     $joinSql = '';
     foreach ($this->_class->parentClasses as $parentClassName) {
         $parentClass = $this->_em->getClassMetadata($parentClassName);
         $tableAlias = $this->_getSQLTableAlias($parentClass);
         $joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
         $first = true;
         foreach ($idColumns as $idColumn) {
             if ($first) {
                 $first = false;
             } else {
                 $joinSql .= ' AND ';
             }
             $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
         }
     }
     // OUTER JOIN sub tables
     foreach ($this->_class->subClasses as $subClassName) {
         $subClass = $this->_em->getClassMetadata($subClassName);
         $tableAlias = $this->_getSQLTableAlias($subClass);
         if ($this->_selectColumnListSql === null) {
             // Add subclass columns
             foreach ($subClass->fieldMappings as $fieldName => $mapping) {
                 if (isset($mapping['inherited'])) {
                     continue;
                 }
                 $columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass);
             }
             // Add join columns (foreign keys)
             foreach ($subClass->associationMappings as $assoc2) {
                 if ($assoc2->isOwningSide && $assoc2->isOneToOne() && !isset($subClass->inheritedAssociationFields[$assoc2->sourceFieldName])) {
                     foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
                         $columnAlias = $srcColumn . $this->_sqlAliasCounter++;
                         $columnList .= ', ' . $tableAlias . ".{$srcColumn} AS {$columnAlias}";
                         $resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
                         if (!isset($this->_resultColumnNames[$resultColumnName])) {
                             $this->_resultColumnNames[$resultColumnName] = $srcColumn;
                         }
                     }
                 }
             }
         }
         // Add LEFT JOIN
         $joinSql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
         $first = true;
         foreach ($idColumns as $idColumn) {
             if ($first) {
                 $first = false;
             } else {
                 $joinSql .= ' AND ';
             }
             $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
         }
     }
     $conditionSql = '';
     foreach ($criteria as $field => $value) {
         if ($conditionSql != '') {
             $conditionSql .= ' AND ';
         }
         if (isset($this->_class->fieldMappings[$field]['inherited'])) {
             $conditionSql .= $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->fieldMappings[$field]['inherited'])) . '.';
         } else {
             $conditionSql .= $baseTableAlias . '.';
         }
         if (isset($this->_class->columnNames[$field])) {
             $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
         } else {
             if ($assoc !== null) {
                 $conditionSql .= $field;
             } else {
                 throw ORMException::unrecognizedField($field);
             }
         }
         $conditionSql .= ' = ?';
     }
     $orderBySql = '';
     if ($orderBy !== null) {
         $orderBySql = $this->_getCollectionOrderBySQL($orderBy, $baseTableAlias);
     }
     if ($this->_selectColumnListSql === null) {
         $this->_selectColumnListSql = $columnList;
     }
     return 'SELECT ' . $this->_selectColumnListSql . ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias . $joinSql . ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql;
 }