示例#1
0
 /**
  * Gathers the SQL for properly setting up the relations of the given class.
  * This includes the SQL for foreign key constraints and join tables.
  *
  * @param ClassMetadata $class
  * @param Table         $table
  * @param Schema        $schema
  * @param array         $addedFks
  * @param array         $blacklistedFks
  *
  * @return void
  *
  * @throws \Doctrine\ORM\ORMException
  */
 private function gatherRelationsSql($class, $table, $schema, &$addedFks, &$blacklistedFks)
 {
     foreach ($class->associationMappings as $mapping) {
         if (isset($mapping['inherited'])) {
             continue;
         }
         $foreignClass = $this->em->getClassMetadata($mapping['targetEntity']);
         if ($mapping['type'] & ClassMetadata::TO_ONE && $mapping['isOwningSide']) {
             $primaryKeyColumns = array();
             // PK is unnecessary for this relation-type
             $this->gatherRelationJoinColumns($mapping['joinColumns'], $table, $foreignClass, $mapping, $primaryKeyColumns, $addedFks, $blacklistedFks);
         } elseif ($mapping['type'] == ClassMetadata::ONE_TO_MANY && $mapping['isOwningSide']) {
             //... create join table, one-many through join table supported later
             throw ORMException::notSupported();
         } elseif ($mapping['type'] == ClassMetadata::MANY_TO_MANY && $mapping['isOwningSide']) {
             // create join table
             $joinTable = $mapping['joinTable'];
             $theJoinTable = $schema->createTable($this->quoteStrategy->getJoinTableName($mapping, $foreignClass, $this->platform));
             $primaryKeyColumns = array();
             // Build first FK constraint (relation table => source table)
             $this->gatherRelationJoinColumns($joinTable['joinColumns'], $theJoinTable, $class, $mapping, $primaryKeyColumns, $addedFks, $blacklistedFks);
             // Build second FK constraint (relation table => target table)
             $this->gatherRelationJoinColumns($joinTable['inverseJoinColumns'], $theJoinTable, $foreignClass, $mapping, $primaryKeyColumns, $addedFks, $blacklistedFks);
             $theJoinTable->setPrimaryKey($primaryKeyColumns);
         }
     }
 }
示例#2
0
 /**
  * {@inheritdoc}
  */
 public function walkCollectionMemberExpression($collMemberExpr)
 {
     $sql = $collMemberExpr->not ? 'NOT ' : '';
     $sql .= 'EXISTS (SELECT 1 FROM ';
     $entityExpr = $collMemberExpr->entityExpression;
     $collPathExpr = $collMemberExpr->collectionValuedPathExpression;
     $fieldName = $collPathExpr->field;
     $dqlAlias = $collPathExpr->identificationVariable;
     $class = $this->queryComponents[$dqlAlias]['metadata'];
     switch (true) {
         // InputParameter
         case $entityExpr instanceof AST\InputParameter:
             $dqlParamKey = $entityExpr->name;
             $entitySql = '?';
             break;
             // SingleValuedAssociationPathExpression | IdentificationVariable
         // SingleValuedAssociationPathExpression | IdentificationVariable
         case $entityExpr instanceof AST\PathExpression:
             $entitySql = $this->walkPathExpression($entityExpr);
             break;
         default:
             throw new \BadMethodCallException("Not implemented");
     }
     $assoc = $class->associationMappings[$fieldName];
     if ($assoc['type'] == ClassMetadata::ONE_TO_MANY) {
         $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
         $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName());
         $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
         $sql .= $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' ' . $targetTableAlias . ' WHERE ';
         $owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']];
         $sqlParts = array();
         foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) {
             $targetColumn = $this->quoteStrategy->getColumnName($class->fieldNames[$targetColumn], $class, $this->platform);
             $sqlParts[] = $sourceTableAlias . '.' . $targetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn;
         }
         foreach ($this->quoteStrategy->getIdentifierColumnNames($targetClass, $this->platform) as $targetColumnName) {
             if (isset($dqlParamKey)) {
                 $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++);
             }
             $sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql;
         }
         $sql .= implode(' AND ', $sqlParts);
     } else {
         // many-to-many
         $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
         $owningAssoc = $assoc['isOwningSide'] ? $assoc : $targetClass->associationMappings[$assoc['mappedBy']];
         $joinTable = $owningAssoc['joinTable'];
         // SQL table aliases
         $joinTableAlias = $this->getSQLTableAlias($joinTable['name']);
         $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName());
         $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
         // join to target table
         $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 = $this->quoteStrategy->getColumnName($targetClass->fieldNames[$joinColumn['referencedColumnName']], $targetClass, $this->platform);
             $joinSqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $targetTableAlias . '.' . $targetColumn;
         }
         $sql .= implode(' AND ', $joinSqlParts);
         $sql .= ' WHERE ';
         $joinColumns = $assoc['isOwningSide'] ? $joinTable['joinColumns'] : $joinTable['inverseJoinColumns'];
         $sqlParts = array();
         foreach ($joinColumns as $joinColumn) {
             $targetColumn = $this->quoteStrategy->getColumnName($class->fieldNames[$joinColumn['referencedColumnName']], $class, $this->platform);
             $sqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $sourceTableAlias . '.' . $targetColumn;
         }
         foreach ($this->quoteStrategy->getIdentifierColumnNames($targetClass, $this->platform) as $targetColumnName) {
             if (isset($dqlParamKey)) {
                 $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++);
             }
             $sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql;
         }
         $sql .= implode(' AND ', $sqlParts);
     }
     return $sql . ')';
 }
示例#3
0
    /**
     * Gets the SQL join fragment used when selecting entities from a
     * many-to-many association.
     *
     * @param array $manyToMany
     *
     * @return string
     */
    protected function getSelectManyToManyJoinSQL(array $manyToMany)
    {
        $conditions         = array();
        $association        = $manyToMany;
        $sourceTableAlias   = $this->getSQLTableAlias($this->class->name);

        if ( ! $manyToMany['isOwningSide']) {
            $targetEntity   = $this->em->getClassMetadata($manyToMany['targetEntity']);
            $association    = $targetEntity->associationMappings[$manyToMany['mappedBy']];
        }

        $joinTableName  = $this->quoteStrategy->getJoinTableName($association, $this->class, $this->platform);
        $joinColumns    = ($manyToMany['isOwningSide'])
            ? $association['joinTable']['inverseJoinColumns']
            : $association['joinTable']['joinColumns'];

        foreach ($joinColumns as $joinColumn) {
            $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
            $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform);
            $conditions[]       = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableName . '.' . $quotedSourceColumn;
        }

        return ' INNER JOIN ' . $joinTableName . ' ON ' . implode(' AND ', $conditions);
    }
 /**
  * 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);
 }
 /**
  * @param array    $assoc
  * @param object   $sourceEntity
  * @param int|null $offset
  * @param int|null $limit
  *
  * @return \Doctrine\DBAL\Driver\Statement
  *
  * @throws \Doctrine\ORM\Mapping\MappingException
  */
 private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null)
 {
     $this->switchPersisterContext($offset, $limit);
     $sourceClass = $this->em->getClassMetadata($assoc['sourceEntity']);
     $class = $sourceClass;
     $association = $assoc;
     $criteria = array();
     $parameters = array();
     if (!$assoc['isOwningSide']) {
         $class = $this->em->getClassMetadata($assoc['targetEntity']);
         $association = $class->associationMappings[$assoc['mappedBy']];
     }
     $joinColumns = $assoc['isOwningSide'] ? $association['joinTable']['joinColumns'] : $association['joinTable']['inverseJoinColumns'];
     $quotedJoinTable = $this->quoteStrategy->getJoinTableName($association, $class, $this->platform);
     foreach ($joinColumns as $joinColumn) {
         $sourceKeyColumn = $joinColumn['referencedColumnName'];
         $quotedKeyColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
         switch (true) {
             case $sourceClass->containsForeignIdentifier:
                 $field = $sourceClass->getFieldForColumn($sourceKeyColumn);
                 $value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
                 if (isset($sourceClass->associationMappings[$field])) {
                     $value = $this->em->getUnitOfWork()->getEntityIdentifier($value);
                     $value = $value[$this->em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
                 }
                 break;
             case isset($sourceClass->fieldNames[$sourceKeyColumn]):
                 $field = $sourceClass->fieldNames[$sourceKeyColumn];
                 $value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
                 break;
             default:
                 throw MappingException::joinColumnMustPointToMappedField($sourceClass->name, $sourceKeyColumn);
         }
         $criteria[$quotedJoinTable . '.' . $quotedKeyColumn] = $value;
         $parameters[] = array('value' => $value, 'field' => $field, 'class' => $sourceClass);
     }
     $sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset);
     list($params, $types) = $this->expandToManyParameters($parameters);
     return $this->conn->executeQuery($sql, $params, $types);
 }