示例#1
0
 /**
  * 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 ($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;
     $targetQComp = $this->_queryComponents[$joinedDqlAlias];
     $targetClass = $targetQComp['metadata'];
     $relation = $targetQComp['relation'];
     $sourceClass = $this->_queryComponents[$joinAssocPathExpr->identificationVariable]['metadata'];
     $targetTableName = $targetClass->getQuotedTableName($this->_platform);
     $targetTableAlias = $this->getSqlTableAlias($targetClass->getTableName(), $joinedDqlAlias);
     $sourceTableAlias = $this->getSqlTableAlias($sourceClass->getTableName(), $joinAssocPathExpr->identificationVariable);
     // Ensure we got the owning side, since it has all mapping info
     if (!$relation->isOwningSide) {
         $assoc = $targetClass->associationMappings[$relation->mappedBy];
     } else {
         $assoc = $relation;
     }
     if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true) {
         if ($relation->isOneToMany() || $relation->isManyToMany()) {
             throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
         }
     }
     if ($assoc->isOneToOne()) {
         $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->isManyToMany()) {
             // Join relation table
             $joinTable = $assoc->joinTable;
             $joinTableAlias = $this->getSqlTableAlias($joinTable['name'], $joinedDqlAlias);
             $sql .= $assoc->getQuotedJoinTableName($this->_platform) . ' ' . $joinTableAlias . ' ON ';
             if ($relation->isOwningSide) {
                 foreach ($assoc->relationToSourceKeyColumns as $relationColumn => $sourceColumn) {
                     $sql .= $sourceTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$sourceColumn], $this->_platform) . ' = ' . $joinTableAlias . '.' . $relationColumn;
                 }
             } else {
                 foreach ($assoc->relationToTargetKeyColumns as $relationColumn => $targetColumn) {
                     $sql .= $sourceTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->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 ';
             if ($relation->isOwningSide) {
                 foreach ($assoc->relationToTargetKeyColumns as $relationColumn => $targetColumn) {
                     $sql .= $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform) . ' = ' . $joinTableAlias . '.' . $relationColumn;
                 }
             } else {
                 foreach ($assoc->relationToSourceKeyColumns as $relationColumn => $sourceColumn) {
                     $sql .= $targetTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$sourceColumn], $this->_platform) . ' = ' . $joinTableAlias . '.' . $relationColumn;
                 }
             }
         }
     }
     // Handle WITH clause
     if ($join->conditionalExpression !== null) {
         $sql .= ' AND (' . implode(' OR ', array_map(array($this, 'walkConditionalTerm'), $join->conditionalExpression->conditionalTerms)) . ')';
     }
     $discrSql = $this->_generateDiscriminatorColumnConditionSql($joinedDqlAlias);
     if ($discrSql) {
         $sql .= ' AND ' . $discrSql;
     }
     if ($targetClass->isInheritanceTypeJoined()) {
         $sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias);
     }
     return $sql;
 }
示例#2
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;
 }