Esempio n. 1
0
 /**
  * @group DDC-117
  */
 public function testIndexByMetadataColumn()
 {
     $this->_rsm->addEntityResult('Doctrine\\Tests\\Models\\Legacy\\LegacyUser', 'u');
     $this->_rsm->addJoinedEntityResult('Doctrine\\Tests\\Models\\Legacy', 'lu', 'u', '_references');
     $this->_rsm->addMetaResult('lu', '_source', '_source', true);
     $this->_rsm->addMetaResult('lu', '_target', '_target', true);
     $this->_rsm->addIndexBy('lu', '_source');
     $this->assertTrue($this->_rsm->hasIndexBy('lu'));
 }
Esempio n. 2
0
 /**
  * Walks down a FromClause AST node, thereby generating the appropriate SQL.
  *
  * @return string The SQL.
  */
 public function walkFromClause($fromClause)
 {
     $sql = ' FROM ';
     $identificationVarDecls = $fromClause->identificationVariableDeclarations;
     $firstIdentificationVarDecl = $identificationVarDecls[0];
     $rangeDecl = $firstIdentificationVarDecl->rangeVariableDeclaration;
     $dqlAlias = $rangeDecl->aliasIdentificationVariable;
     $this->_currentRootAlias = $dqlAlias;
     $class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName);
     $sql .= $class->getQuotedTableName($this->_platform) . ' ' . $this->getSqlTableAlias($class->table['name'], $dqlAlias);
     if ($class->isInheritanceTypeJoined()) {
         $sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
     }
     foreach ($firstIdentificationVarDecl->joinVariableDeclarations as $joinVarDecl) {
         $sql .= $this->walkJoinVariableDeclaration($joinVarDecl);
     }
     if ($firstIdentificationVarDecl->indexBy) {
         $this->_rsm->addIndexBy($firstIdentificationVarDecl->indexBy->simpleStateFieldPathExpression->identificationVariable, $firstIdentificationVarDecl->indexBy->simpleStateFieldPathExpression->parts[0]);
     }
     return $this->_platform->appendLockHint($sql, $this->_query->getHint(Query::HINT_LOCK_MODE));
 }
Esempio n. 3
0
 /**
  * Walks down a JoinAssociationDeclaration AST node, thereby generating the appropriate SQL.
  *
  * @param AST\JoinAssociationDeclaration $joinAssociationDeclaration
  * @param int $joinType
  *
  * @return string
  *
  * @throws QueryException
  */
 public function walkJoinAssociationDeclaration($joinAssociationDeclaration, $joinType = AST\Join::JOIN_TYPE_INNER)
 {
     $sql = '';
     $associationPathExpression = $joinAssociationDeclaration->joinAssociationPathExpression;
     $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);
     $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias);
     $sourceTableAlias = $this->getSQLTableAlias($sourceClass->getTableName(), $associationPathExpression->identificationVariable);
     // 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 ($relation['type'] == ClassMetadata::ONE_TO_MANY || $relation['type'] == ClassMetadata::MANY_TO_MANY) {
             throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
         }
     }
     // This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot
     // be the owning side and previously we ensured that $assoc is always the owning side of the associations.
     // The owning side is necessary at this point because only it contains the JoinColumn information.
     switch (true) {
         case $assoc['type'] & ClassMetadata::TO_ONE:
             $conditions = array();
             foreach ($assoc['joinColumns'] as $joinColumn) {
                 $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
                 $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform);
                 if ($relation['isOwningSide']) {
                     $conditions[] = $sourceTableAlias . '.' . $quotedSourceColumn . ' = ' . $targetTableAlias . '.' . $quotedTargetColumn;
                     continue;
                 }
                 $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $quotedSourceColumn;
             }
             // Apply remaining inheritance restrictions
             $discrSql = $this->_generateDiscriminatorColumnConditionSQL(array($joinedDqlAlias));
             if ($discrSql) {
                 $conditions[] = $discrSql;
             }
             // Apply the filters
             $filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias);
             if ($filterExpr) {
                 $conditions[] = $filterExpr;
             }
             $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions);
             break;
         case $assoc['type'] == ClassMetadata::MANY_TO_MANY:
             // Join relation table
             $joinTable = $assoc['joinTable'];
             $joinTableAlias = $this->getSQLTableAlias($joinTable['name'], $joinedDqlAlias);
             $joinTableName = $sourceClass->getQuotedJoinTableName($assoc, $this->platform);
             $conditions = array();
             $relationColumns = $relation['isOwningSide'] ? $assoc['joinTable']['joinColumns'] : $assoc['joinTable']['inverseJoinColumns'];
             foreach ($relationColumns as $joinColumn) {
                 $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
                 $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform);
                 $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $quotedSourceColumn;
             }
             $sql .= $joinTableName . ' ' . $joinTableAlias . ' ON ' . implode(' AND ', $conditions);
             // Join target table
             $sql .= $joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER ? ' LEFT JOIN ' : ' INNER JOIN ';
             $conditions = array();
             $relationColumns = $relation['isOwningSide'] ? $assoc['joinTable']['inverseJoinColumns'] : $assoc['joinTable']['joinColumns'];
             foreach ($relationColumns as $joinColumn) {
                 $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
                 $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform);
                 $conditions[] = $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $quotedSourceColumn;
             }
             // Apply remaining inheritance restrictions
             $discrSql = $this->_generateDiscriminatorColumnConditionSQL(array($joinedDqlAlias));
             if ($discrSql) {
                 $conditions[] = $discrSql;
             }
             // Apply the filters
             $filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias);
             if ($filterExpr) {
                 $conditions[] = $filterExpr;
             }
             $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions);
             break;
     }
     // FIXME: these should either be nested or all forced to be left joins (DDC-XXX)
     if ($targetClass->isInheritanceTypeJoined()) {
         $sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias);
     }
     // 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($indexBy->simpleStateFieldPathExpression->identificationVariable, $indexBy->simpleStateFieldPathExpression->field);
     } else {
         if (isset($relation['indexBy'])) {
             $this->rsm->addIndexBy($joinedDqlAlias, $relation['indexBy']);
         }
     }
     return $sql;
 }
 /**
  * Walks down a JoinVariableDeclaration AST node and creates the corresponding SQL.
  *
  * @param JoinVariableDeclaration $joinVarDecl
  * @return string The SQL.
  */
 public function walkJoinVariableDeclaration($joinVarDecl)
 {
     $join = $joinVarDecl->join;
     $joinType = $join->joinType;
     if ($joinVarDecl->indexBy) {
         // For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently.
         $this->_rsm->addIndexBy($joinVarDecl->indexBy->simpleStateFieldPathExpression->identificationVariable, $joinVarDecl->indexBy->simpleStateFieldPathExpression->field);
     }
     if ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) {
         $sql = ' LEFT JOIN ';
     } else {
         $sql = ' INNER JOIN ';
     }
     $joinAssocPathExpr = $join->joinAssociationPathExpression;
     $joinedDqlAlias = $join->aliasIdentificationVariable;
     $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->table['name'], $joinedDqlAlias);
     $sourceTableAlias = $this->getSqlTableAlias($sourceClass->table['name'], $joinAssocPathExpr->identificationVariable);
     // 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) {
         if ($relation['type'] == ClassMetadata::ONE_TO_MANY || $relation['type'] == ClassMetadata::MANY_TO_MANY) {
             throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
         }
     }
     if ($assoc['type'] & ClassMetadata::TO_ONE) {
         $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
         $first = true;
         foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) {
             if (!$first) {
                 $sql .= ' AND ';
             } else {
                 $first = false;
             }
             if ($relation['isOwningSide']) {
                 $quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
                 $sql .= $sourceTableAlias . '.' . $sourceColumn . ' = ' . $targetTableAlias . '.' . $quotedTargetColumn;
             } else {
                 $quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
                 $sql .= $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn;
             }
         }
     } else {
         if ($assoc['type'] == ClassMetadata::MANY_TO_MANY) {
             // Join relation table
             $joinTable = $assoc['joinTable'];
             $joinTableAlias = $this->getSqlTableAlias($joinTable['name'], $joinedDqlAlias);
             $sql .= $sourceClass->getQuotedJoinTableName($assoc, $this->_platform) . ' ' . $joinTableAlias . ' ON ';
             $first = true;
             if ($relation['isOwningSide']) {
                 foreach ($assoc['relationToSourceKeyColumns'] as $relationColumn => $sourceColumn) {
                     if (!$first) {
                         $sql .= ' AND ';
                     } else {
                         $first = false;
                     }
                     $sql .= $sourceTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$sourceColumn], $this->_platform) . ' = ' . $joinTableAlias . '.' . $relationColumn;
                 }
             } else {
                 foreach ($assoc['relationToTargetKeyColumns'] as $relationColumn => $targetColumn) {
                     if (!$first) {
                         $sql .= ' AND ';
                     } else {
                         $first = false;
                     }
                     $sql .= $sourceTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform) . ' = ' . $joinTableAlias . '.' . $relationColumn;
                 }
             }
             // Join target table
             $sql .= $joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER ? ' LEFT JOIN ' : ' INNER JOIN ';
             $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
             $first = true;
             if ($relation['isOwningSide']) {
                 foreach ($assoc['relationToTargetKeyColumns'] as $relationColumn => $targetColumn) {
                     if (!$first) {
                         $sql .= ' AND ';
                     } else {
                         $first = false;
                     }
                     $sql .= $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform) . ' = ' . $joinTableAlias . '.' . $relationColumn;
                 }
             } else {
                 foreach ($assoc['relationToSourceKeyColumns'] as $relationColumn => $sourceColumn) {
                     if (!$first) {
                         $sql .= ' AND ';
                     } else {
                         $first = false;
                     }
                     $sql .= $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$sourceColumn], $this->_platform) . ' = ' . $joinTableAlias . '.' . $relationColumn;
                 }
             }
         }
     }
     // Handle WITH clause
     if (($condExpr = $join->conditionalExpression) !== null) {
         // Phase 2 AST optimization: Skip processment of ConditionalExpression
         // if only one ConditionalTerm is defined
         $sql .= ' AND (' . $this->walkConditionalExpression($condExpr) . ')';
     }
     $discrSql = $this->_generateDiscriminatorColumnConditionSQL(array($joinedDqlAlias));
     if ($discrSql) {
         $sql .= ' AND ' . $discrSql;
     }
     // FIXME: these should either be nested or all forced to be left joins (DDC-XXX)
     if ($targetClass->isInheritanceTypeJoined()) {
         $sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias);
     }
     return $sql;
 }
 /**
  * Gets the SQL fragment with the list of columns to select when querying for
  * an entity in this persister.
  *
  * Subclasses should override this method to alter or change the select column
  * list SQL fragment. Note that in the implementation of BasicEntityPersister
  * the resulting SQL fragment is generated only once and cached in {@link selectColumnListSql}.
  * Subclasses may or may not do the same.
  *
  * @return string The SQL fragment.
  */
 protected function getSelectColumnsSQL()
 {
     if ($this->selectColumnListSql !== null) {
         return $this->selectColumnListSql;
     }
     $columnList = array();
     $this->rsm = new Query\ResultSetMapping();
     $this->rsm->addEntityResult($this->class->name, 'r');
     // r for root
     // Add regular columns to select list
     foreach ($this->class->fieldNames as $field) {
         $columnList[] = $this->getSelectColumnSQL($field, $this->class);
     }
     $this->selectJoinSql = '';
     $eagerAliasCounter = 0;
     foreach ($this->class->associationMappings as $assocField => $assoc) {
         $assocColumnSQL = $this->getSelectColumnAssociationSQL($assocField, $assoc, $this->class);
         if ($assocColumnSQL) {
             $columnList[] = $assocColumnSQL;
         }
         $isAssocToOneInverseSide = $assoc['type'] & ClassMetadata::TO_ONE && !$assoc['isOwningSide'];
         $isAssocFromOneEager = $assoc['type'] !== ClassMetadata::MANY_TO_MANY && $assoc['fetch'] === ClassMetadata::FETCH_EAGER;
         if (!($isAssocFromOneEager || $isAssocToOneInverseSide)) {
             continue;
         }
         $eagerEntity = $this->em->getClassMetadata($assoc['targetEntity']);
         if ($eagerEntity->inheritanceType != ClassMetadata::INHERITANCE_TYPE_NONE) {
             continue;
             // now this is why you shouldn't use inheritance
         }
         $assocAlias = 'e' . $eagerAliasCounter++;
         $this->rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField);
         foreach ($eagerEntity->fieldNames as $field) {
             $columnList[] = $this->getSelectColumnSQL($field, $eagerEntity, $assocAlias);
         }
         foreach ($eagerEntity->associationMappings as $eagerAssocField => $eagerAssoc) {
             $eagerAssocColumnSQL = $this->getSelectColumnAssociationSQL($eagerAssocField, $eagerAssoc, $eagerEntity, $assocAlias);
             if ($eagerAssocColumnSQL) {
                 $columnList[] = $eagerAssocColumnSQL;
             }
         }
         $association = $assoc;
         $joinCondition = array();
         if (isset($assoc['indexBy'])) {
             $this->rsm->addIndexBy($assocAlias, $assoc['indexBy']);
         }
         if (!$assoc['isOwningSide']) {
             $eagerEntity = $this->em->getClassMetadata($assoc['targetEntity']);
             $association = $eagerEntity->getAssociationMapping($assoc['mappedBy']);
         }
         $joinTableAlias = $this->getSQLTableAlias($eagerEntity->name, $assocAlias);
         $joinTableName = $this->quoteStrategy->getTableName($eagerEntity, $this->platform);
         if ($assoc['isOwningSide']) {
             $tableAlias = $this->getSQLTableAlias($association['targetEntity'], $assocAlias);
             $this->selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($association['joinColumns']);
             foreach ($association['joinColumns'] as $joinColumn) {
                 $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
                 $targetCol = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform);
                 $joinCondition[] = $this->getSQLTableAlias($association['sourceEntity']) . '.' . $sourceCol . ' = ' . $tableAlias . '.' . $targetCol;
             }
             // Add filter SQL
             if ($filterSql = $this->generateFilterConditionSQL($eagerEntity, $tableAlias)) {
                 $joinCondition[] = $filterSql;
             }
         } else {
             $this->selectJoinSql .= ' LEFT JOIN';
             foreach ($association['joinColumns'] as $joinColumn) {
                 $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
                 $targetCol = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform);
                 $joinCondition[] = $this->getSQLTableAlias($association['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = ' . $this->getSQLTableAlias($association['targetEntity']) . '.' . $targetCol;
             }
         }
         $this->selectJoinSql .= ' ' . $joinTableName . ' ' . $joinTableAlias . ' ON ';
         $this->selectJoinSql .= implode(' AND ', $joinCondition);
     }
     $this->selectColumnListSql = implode(', ', $columnList);
     return $this->selectColumnListSql;
 }
Esempio n. 6
0
 /**
  * select u.id, u.status, upper(u.name) nameUpper from User u index by u.id
  * join u.phonenumbers p indexby p.phonenumber
  * =
  * select u.id, u.status, upper(u.name) as p__0 from USERS u
  * INNER JOIN PHONENUMBERS p ON u.id = p.user_id
  */
 public function testNewHydrationMixedQueryFetchJoinCustomIndex()
 {
     $rsm = new ResultSetMapping();
     $rsm->addEntityResult('Doctrine\\Tests\\Models\\CMS\\CmsUser', 'u');
     $rsm->addJoinedEntityResult('Doctrine\\Tests\\Models\\CMS\\CmsPhonenumber', 'p', 'u', $this->_em->getClassMetadata('Doctrine\\Tests\\Models\\CMS\\CmsUser')->getAssociationMapping('phonenumbers'));
     $rsm->addFieldResult('u', 'u__id', 'id');
     $rsm->addFieldResult('u', 'u__status', 'status');
     $rsm->addScalarResult('sclr0', 'nameUpper');
     $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
     $rsm->addIndexBy('u', 'id');
     $rsm->addIndexBy('p', 'phonenumber');
     // Faked result set
     $resultSet = array(array('u__id' => '1', 'u__status' => 'developer', 'sclr0' => 'ROMANB', 'p__phonenumber' => '42'), array('u__id' => '1', 'u__status' => 'developer', 'sclr0' => 'ROMANB', 'p__phonenumber' => '43'), array('u__id' => '2', 'u__status' => 'developer', 'sclr0' => 'JWAGE', 'p__phonenumber' => '91'));
     $stmt = new HydratorMockStatement($resultSet);
     $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
     $result = $hydrator->hydrateAll($stmt, $rsm);
     $this->assertEquals(2, count($result));
     $this->assertTrue(is_array($result));
     $this->assertTrue(is_array($result[0]));
     $this->assertTrue(is_array($result[1]));
     // test the scalar values
     $this->assertEquals('ROMANB', $result[0]['nameUpper']);
     $this->assertEquals('JWAGE', $result[1]['nameUpper']);
     // first user => 2 phonenumbers. notice the custom indexing by user id
     $this->assertEquals(2, count($result[0]['1']['phonenumbers']));
     // second user => 1 phonenumber. notice the custom indexing by user id
     $this->assertEquals(1, count($result[1]['2']['phonenumbers']));
     // test the custom indexing of the phonenumbers
     $this->assertTrue(isset($result[0]['1']['phonenumbers']['42']));
     $this->assertTrue(isset($result[0]['1']['phonenumbers']['43']));
     $this->assertTrue(isset($result[1]['2']['phonenumbers']['91']));
 }
Esempio n. 7
0
 /**
  * SELECT PARTIAL u.{id, status}, UPPER(u.name) AS nameUpper
  *   FROM Doctrine\Tests\Models\CMS\CmsUser u
  *        INDEX BY u.id
  *
  * @group DDC-1385
  * @dataProvider provideDataForUserEntityResult
  */
 public function testIndexByAndMixedResult($userEntityKey)
 {
     $rsm = new ResultSetMapping();
     $rsm->addEntityResult('Doctrine\\Tests\\Models\\CMS\\CmsUser', 'u', $userEntityKey ?: null);
     $rsm->addFieldResult('u', 'u__id', 'id');
     $rsm->addFieldResult('u', 'u__status', 'status');
     $rsm->addScalarResult('sclr0', 'nameUpper');
     $rsm->addIndexBy('u', 'id');
     // Faked result set
     $resultSet = array(array('u__id' => '1', 'u__status' => 'developer', 'sclr0' => 'ROMANB'), array('u__id' => '2', 'u__status' => 'developer', 'sclr0' => 'JWAGE'));
     $stmt = new HydratorMockStatement($resultSet);
     $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
     $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
     $this->assertEquals(2, count($result));
     $this->assertTrue(isset($result[1]));
     $this->assertEquals(1, $result[1][$userEntityKey]->id);
     $this->assertTrue(isset($result[2]));
     $this->assertEquals(2, $result[2][$userEntityKey]->id);
 }
 /**
  * select u.id, u.status, upper(u.name) nameUpper from User u index by u.id
  * join u.phonenumbers p indexby p.phonenumber
  * =
  * select u.id, u.status, upper(u.name) as p__0 from USERS u
  * INNER JOIN PHONENUMBERS p ON u.id = p.user_id
  */
 public function testMixedQueryFetchJoinCustomIndex()
 {
     $rsm = new ResultSetMapping();
     $rsm->addEntityResult('Doctrine\\Tests\\Models\\CMS\\CmsUser', 'u');
     $rsm->addJoinedEntityResult('Doctrine\\Tests\\Models\\CMS\\CmsPhonenumber', 'p', 'u', 'phonenumbers');
     $rsm->addFieldResult('u', 'u__id', 'id');
     $rsm->addFieldResult('u', 'u__status', 'status');
     $rsm->addScalarResult('sclr0', 'nameUpper');
     $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
     $rsm->addIndexBy('u', 'id');
     $rsm->addIndexBy('p', 'phonenumber');
     // Faked result set
     $resultSet = array(array('u__id' => '1', 'u__status' => 'developer', 'sclr0' => 'ROMANB', 'p__phonenumber' => '42'), array('u__id' => '1', 'u__status' => 'developer', 'sclr0' => 'ROMANB', 'p__phonenumber' => '43'), array('u__id' => '2', 'u__status' => 'developer', 'sclr0' => 'JWAGE', 'p__phonenumber' => '91'));
     $stmt = new HydratorMockStatement($resultSet);
     $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
     $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
     $this->assertEquals(2, count($result));
     $this->assertTrue(is_array($result));
     $this->assertTrue(is_array($result[0]));
     $this->assertTrue(is_array($result[1]));
     // test the scalar values
     $this->assertEquals('ROMANB', $result[0]['nameUpper']);
     $this->assertEquals('JWAGE', $result[1]['nameUpper']);
     $this->assertTrue($result[0]['1'] instanceof \Doctrine\Tests\Models\CMS\CmsUser);
     $this->assertTrue($result[1]['2'] instanceof \Doctrine\Tests\Models\CMS\CmsUser);
     $this->assertTrue($result[0]['1']->phonenumbers instanceof \Doctrine\ORM\PersistentCollection);
     // first user => 2 phonenumbers. notice the custom indexing by user id
     $this->assertEquals(2, count($result[0]['1']->phonenumbers));
     // second user => 1 phonenumber. notice the custom indexing by user id
     $this->assertEquals(1, count($result[1]['2']->phonenumbers));
     // test the custom indexing of the phonenumbers
     $this->assertTrue(isset($result[0]['1']->phonenumbers['42']));
     $this->assertTrue(isset($result[0]['1']->phonenumbers['43']));
     $this->assertTrue(isset($result[1]['2']->phonenumbers['91']));
 }