/** * {@inheritdoc} */ public static function create($conn, Configuration $config, EventManager $eventManager = null) { if (!$config->getMetadataDriverImpl()) { throw ORMException::missingMappingDriverImpl(); } switch (true) { case is_array($conn): if (!$eventManager) { $eventManager = new EventManager(); } if (isset($conn['prefix']) && $conn['prefix']) { $eventManager->addEventListener(Events::loadClassMetadata, new TablePrefix($conn['prefix'])); } $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager); break; case $conn instanceof Connection: if ($eventManager !== null && $conn->getEventManager() !== $eventManager) { throw ORMException::mismatchedEventManager(); } break; default: throw new \InvalidArgumentException("Invalid argument: " . $conn); } return new self($conn, $config, $conn->getEventManager()); }
/** * Returns the identifier assigned to the given entity. * * @param object $entity * @return mixed * @override */ public function generate(EntityManager $em, $entity) { $class = $em->getClassMetadata(get_class($entity)); $identifier = array(); if ($class->isIdentifierComposite) { $idFields = $class->getIdentifierFieldNames(); foreach ($idFields as $idField) { $value = $class->getReflectionProperty($idField)->getValue($entity); if (isset($value)) { if (is_object($value)) { // NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced. $identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value)); } else { $identifier[$idField] = $value; } } else { throw ORMException::entityMissingAssignedId($entity); } } } else { $idField = $class->identifier[0]; $value = $class->reflFields[$idField]->getValue($entity); if (isset($value)) { if (is_object($value)) { // NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced. $identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value)); } else { $identifier[$idField] = $value; } } else { throw ORMException::entityMissingAssignedId($entity); } } return $identifier; }
/** * Returns the identifier assigned to the given entity. * * @param object $entity * @return mixed * @override */ public function generate(EntityManager $em, $entity) { $class = $em->getClassMetadata(get_class($entity)); $identifier = array(); if ($class->isIdentifierComposite) { $idFields = $class->getIdentifierFieldNames(); foreach ($idFields as $idField) { $value = $class->getReflectionProperty($idField)->getValue($entity); if (isset($value)) { $identifier[$idField] = $value; } else { throw ORMException::entityMissingAssignedId($entity); } } } else { $idField = $class->identifier[0]; $value = $class->reflFields[$idField]->getValue($entity); if (isset($value)) { $identifier[$idField] = $value; } else { throw ORMException::entityMissingAssignedId($entity); } } return $identifier; }
/** * @param string|mixed|\ $dsn * @param array $options * * @return AdapterInterface * * @link http://docs.doctrine-project.org/en/2.0.x/reference/configuration.html * @link http://docs.doctrine-project.org/en/latest/reference/tools.html * @link https://github.com/itmcd/StormIgniter/blob/master/app/libraries/DoctrineDb.php * @link http://framework.zend.com/manual/2.2/en/user-guide/database-and-models.html * @link http://piotrdeszynski.com/zend-framework-2-and-doctrine-2-integration.html * @link http://www.jasongrimes.org/2012/01/using-doctrine-2-in-zend-framework-2/#toc-update-the-album-controller-to-use-doctrine-instead-of-zend_db * @link http://framework.zend.com/manual/2.2/en/user-guide/database-and-models.html */ public function __construct($conn, $options = array()) { $isDev = Environment::isDev(); // @see Doctrine\ORM\EntityManager#create() $config = ArrayUtils::arrayMergeRecursiveRight($options, array('cache' => $isDev ? new Cache\ArrayCache() : new Cache\ApcCache(), 'queryCache' => $isDev ? new Cache\ArrayCache() : new Cache\ApcCache(), 'modelsProxiesPath' => getcwd() . '/cache/ModelProxies')); // create Configuration object if (is_array($options)) { $config = $this->renderConfig($options); if (!$config->getMetadataDriverImpl()) { throw ORMException::missingMappingDriverImpl(); } } // test EventManager object $eventManager = empty($options['eventManager']) ? new EventManager() : $options['eventManager']; switch (true) { case $conn instanceof \PDO: $conn = array('driver' => 'pdo_' . $conn->getAttribute(\PDO::ATTR_DRIVER_NAME), 'pdo' => $conn); $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager); break; case is_string($conn): if (($pos = strpos($conn, ':')) !== false) { $driver = substr($conn, 0, $pos); // @TODO: must implement like this, but for now throws an error about not knowing the database // if ($driver !== 'oci8') { // $conn = array( // 'driver' => 'pdo_' . $driver, // 'pdo' => new \PDO($conn), // ); // } else { // $conn = $this->mapDsnToDoctrine($conn); // } // ^ by dragosc@itmcd.ro / temporary replacement untill we discover why \PDO doesn't work $dsn = new Dsn($conn); $conn = $this->mapDsnToDoctrine($dsn->parse()); if ($driver !== 'oci8') { $conn['driver'] = 'pdo_' . $conn['driver']; } // ^ END } $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager); break; case is_array($conn): $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager); break; case $conn instanceof Connection: if ($eventManager !== null && $conn->getEventManager() !== null) { throw ORMException::mismatchedEventManager(); } break; default: throw new AthemException\InvalidArgument("Invalid argument: " . json_encode($conn)); } // parent constructor // @see Doctrine\ORM\EntityManager#__construct() parent::__construct($conn, $config, $conn->getEventManager()); }
/** * Factory method to create EntityManager instances. * * @param Connection $conn * @param Configuration $config * @param EventManager $eventManager * @throws \Doctrine\ORM\ORMException * @return ModelManager */ public static function createInstance(Connection $conn, Configuration $config, EventManager $eventManager = null) { if (!$config->getMetadataDriverImpl()) { throw ORMException::missingMappingDriverImpl(); } if ($eventManager !== null && $conn->getEventManager() !== $eventManager) { throw ORMException::mismatchedEventManager(); } return new self($conn, $config, $conn->getEventManager()); }
/** * Resolves a registered namespace alias to the full namespace. * * This method looks for the alias in all registered entity managers. * * @see \Doctrine\ORM\Configuration::getEntityNamespace * @param string $alias The alias * @throws \Doctrine\ORM\ORMException * @return string The full namespace */ public function getAliasNamespace($alias) { foreach (array_keys($this->getManagers()) as $name) { try { return $this->getManager($name)->getConfiguration()->getEntityNamespace($alias); } catch (ORMException $e) { } } throw ORMException::unknownEntityNamespace($alias); }
/** * {@inheritdoc} */ public function getAliasNamespace($alias) { /** @var EntityManager $entityManager */ foreach ([$this->entityManager] as $entityManager) { try { return $entityManager->getConfiguration()->getEntityNamespace($alias); } catch (ORMException $e) { } } throw ORMException::unknownEntityNamespace($alias); }
/** * Resolves a registered namespace alias to the full namespace. * * This method looks for the alias in all registered object managers. * * @param string $alias The alias. * @return string The full namespace. * @throws ORMException */ public function getAliasNamespace($alias) { foreach (array_keys($this->getManagers()) as $name) { try { if (($em = $this->getManager($name)) instanceof EntityManager) { return $em->getConfiguration()->getEntityNamespace($alias); } } catch (ORMException $e) { // If any exception is throw when attempting to retrieve then have our custom one thrown } } throw ORMException::unknownEntityNamespace($alias); }
public static function create($conn, Configuration $config, EventManager $eventManager = null) { if (!$config->getMetadataDriverImpl()) { throw ORMException::missingMappingDriverImpl(); } if (is_array($conn)) { $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager ?: new EventManager()); } elseif ($conn instanceof Connection) { if ($eventManager !== null && $conn->getEventManager() !== $eventManager) { throw ORMException::mismatchedEventManager(); } } else { throw new \InvalidArgumentException("Invalid argument: " . $conn); } return new OroEntityManager($conn, $config, $conn->getEventManager()); }
/** * Returns the identifier assigned to the given entity. * * {@inheritDoc} * * @throws \Doctrine\ORM\ORMException */ public function generate(EntityManager $em, $entity) { $class = $em->getClassMetadata(get_class($entity)); $idFields = $class->getIdentifierFieldNames(); $identifier = array(); foreach ($idFields as $idField) { $value = $class->getFieldValue($entity, $idField); if (!isset($value)) { throw ORMException::entityMissingAssignedIdForField($entity, $idField); } if (isset($class->associationMappings[$idField])) { // NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced. $value = $em->getUnitOfWork()->getSingleIdentifierValue($value); } $identifier[$idField] = $value; } return $identifier; }
/** * Copied from Doctrine\ORM\EntityManager, cause return use new EntityManager() instead of new static() * * @param mixed $conn * @param Configuration $config * @param EventManager|null $eventManager * @return EntityManager * @throws ORMException * @throws \Doctrine\DBAL\DBALException */ public static function create($conn, Configuration $config, EventManager $eventManager = null) { if (!$config->getMetadataDriverImpl()) { throw ORMException::missingMappingDriverImpl(); } switch (true) { case is_array($conn): $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager ?: new EventManager()); break; case $conn instanceof Connection: if ($eventManager !== null && $conn->getEventManager() !== $eventManager) { throw ORMException::mismatchedEventManager(); } break; default: throw new \InvalidArgumentException("Invalid argument: " . $conn); } return new static($conn, $config, $conn->getEventManager()); }
/** * Factory method to create EntityManager instances. * * @param \Doctrine\DBAL\Connection|array $conn * @param \Doctrine\ORM\Configuration $config * @param \Doctrine\Common\EventManager $eventManager * @throws \Doctrine\ORM\ORMException * @throws InvalidArgumentException * @throws \Doctrine\ORM\ORMException * @return EntityManager */ public static function create($conn, Doctrine\ORM\Configuration $config, Doctrine\Common\EventManager $eventManager = NULL) { if (!$config->getMetadataDriverImpl()) { throw ORMException::missingMappingDriverImpl(); } switch (TRUE) { case is_array($conn): $conn = DriverManager::getConnection($conn, $config, $eventManager ?: new Doctrine\Common\EventManager()); break; case $conn instanceof Doctrine\DBAL\Connection: if ($eventManager !== NULL && $conn->getEventManager() !== $eventManager) { throw ORMException::mismatchedEventManager(); } break; default: throw new InvalidArgumentException("Invalid connection"); } return new EntityManager($conn, $config, $conn->getEventManager()); }
/** * 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); }
/** * 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; }
/** * 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); }
/** * Ensures that this Configuration instance contains settings that are * suitable for a production environment. * * @throws ORMException If a configuration setting has a value that is not * suitable for a production environment. */ public function ensureProductionSettings() { if (!$this->getQueryCacheImpl()) { throw ORMException::queryCacheNotConfigured(); } if (!$this->getMetadataCacheImpl()) { throw ORMException::metadataCacheNotConfigured(); } if ($this->getAutoGenerateProxyClasses()) { throw ORMException::proxyClassesAlwaysRegenerating(); } }
/** * @param string $alias * @return string * @throws ORMException */ public function getAliasNamespace($alias) { foreach ($this->getManagerNames() as $name) { try { return $this->getManager($name)->getConfiguration()->getEntityNamespace($alias); } catch (ORMException $e) { // throw the exception only if no manager can solve it } } throw ORMException::unknownEntityNamespace($alias); }
/** * Defines a cache driver to be used for caching result sets. * * @param Doctrine\Common\Cache\Cache $driver Cache driver * @return Doctrine\ORM\AbstractQuery */ public function setResultCacheDriver($resultCacheDriver = null) { if ($resultCacheDriver !== null && !$resultCacheDriver instanceof \Doctrine\Common\Cache\Cache) { throw ORMException::invalidResultCacheDriver(); } $this->_resultCacheDriver = $resultCacheDriver; if ($resultCacheDriver) { $this->_useResultCache = true; } return $this; }
/** * Factory method to create Connection instances. * * @param array|Connection $connection An array with the connection parameters or an existing Connection instance. * @param Configuration $config The Configuration instance to use. * @param EventManager $eventManager The EventManager instance to use. * * @return Connection * * @throws \InvalidArgumentException * @throws ORMException */ protected static function createConnection($connection, Configuration $config, EventManager $eventManager = null) { if (is_array($connection)) { return DriverManager::getConnection($connection, $config, $eventManager ?: new EventManager()); } if (!$connection instanceof Connection) { throw new \InvalidArgumentException(sprintf('Invalid $connection argument of type %s given%s.', is_object($connection) ? get_class($connection) : gettype($connection), is_object($connection) ? '' : ': "' . $connection . '"')); } if ($eventManager !== null && $connection->getEventManager() !== $eventManager) { throw ORMException::mismatchedEventManager(); } return $connection; }
/** * Adds support for magic finders. * * @return array|object The found entity/entities. * @throws BadMethodCallException If the method called is an invalid find* method * or no find* method at all and therefore an invalid * method call. */ public function __call($method, $arguments) { if (substr($method, 0, 6) == 'findBy') { $by = substr($method, 6, strlen($method)); $method = 'findBy'; } else { if (substr($method, 0, 9) == 'findOneBy') { $by = substr($method, 9, strlen($method)); $method = 'findOneBy'; } else { throw new \BadMethodCallException("Undefined method '{$method}'. The method name must start with " . "either findBy or findOneBy!"); } } if (!isset($arguments[0])) { // we dont even want to allow null at this point, because we cannot (yet) transform it into IS NULL. throw ORMException::findByRequiresParameter($method . $by); } $fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by)); if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) { return $this->{$method}(array($fieldName => $arguments[0])); } else { throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method . $by); } }
/** * Defines a cache driver to be used for caching result sets and implictly enables caching. * * @param \Doctrine\Common\Cache\Cache $driver Cache driver * @return \Doctrine\ORM\AbstractQuery */ public function setResultCacheDriver($resultCacheDriver = null) { if ($resultCacheDriver !== null && !$resultCacheDriver instanceof \Doctrine\Common\Cache\Cache) { throw ORMException::invalidResultCacheDriver(); } $this->_queryCacheProfile = $this->_queryCacheProfile ? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver) : new QueryCacheProfile(0, null, $resultCacheDriver); return $this; }
/** * Adds support for magic finders. * * @return array|object The found entity/entities. * @throws BadMethodCallException If the method called is an invalid find* method * or no find* method at all and therefore an invalid * method call. */ public function __call($method, $arguments) { switch (true) { case 0 === strpos($method, 'findBy'): $by = substr($method, 6); $method = 'findBy'; break; case 0 === strpos($method, 'findOneBy'): $by = substr($method, 9); $method = 'findOneBy'; break; default: throw new \BadMethodCallException("Undefined method '{$method}'. The method name must start with " . "either findBy or findOneBy!"); } if (empty($arguments)) { throw ORMException::findByRequiresParameter($method . $by); } $fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by)); if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) { switch (count($arguments)) { case 1: return $this->{$method}(array($fieldName => $arguments[0])); case 2: return $this->{$method}(array($fieldName => $arguments[0]), $arguments[1]); case 3: return $this->{$method}(array($fieldName => $arguments[0]), $arguments[1], $arguments[2]); case 4: return $this->{$method}(array($fieldName => $arguments[0]), $arguments[1], $arguments[2], $arguments[3]); default: // Do nothing } } throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method . $by); }
/** * 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; }
/** * Set default repository class. * * @since 2.2 * @param string $className * @throws ORMException If not is a \Doctrine\ORM\EntityRepository */ public function setDefaultRepositoryClassName($className) { $entityRepositoryClassName = 'Doctrine\\ORM\\EntityRepository'; if ($className !== $entityRepositoryClassName && !is_subclass_of($className, $entityRepositoryClassName)) { throw ORMException::invalidEntityRepository($className); } $this->_attributes['defaultRepositoryClassName'] = $className; }
/** * Computes the changes of an association. * * @param array $assoc The association mapping. * @param mixed $value The value of the association. * * @throws ORMInvalidArgumentException * @throws ORMException * * @return void */ private function computeAssociationChanges($assoc, $value) { if ($value instanceof Proxy && !$value->__isInitialized__) { return; } if ($value instanceof PersistentCollection && $value->isDirty()) { $coid = spl_object_hash($value); if ($assoc['isOwningSide']) { $this->collectionUpdates[$coid] = $value; } $this->visitedCollections[$coid] = $value; } // Look through the entities, and in any of their associations, // for transient (new) entities, recursively. ("Persistence by reachability") // Unwrap. Uninitialized collections will simply be empty. $unwrappedValue = $assoc['type'] & ClassMetadata::TO_ONE ? array($value) : $value->unwrap(); $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); foreach ($unwrappedValue as $key => $entry) { $state = $this->getEntityState($entry, self::STATE_NEW); if (!$entry instanceof $assoc['targetEntity']) { throw ORMException::unexpectedAssociationValue($assoc['sourceEntity'], $assoc['fieldName'], get_class($entry), $assoc['targetEntity']); } switch ($state) { case self::STATE_NEW: if (!$assoc['isCascadePersist']) { throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry); } $this->persistNew($targetClass, $entry); $this->computeChangeSet($targetClass, $entry); break; case self::STATE_REMOVED: // Consume the $value as array (it's either an array or an ArrayAccess) // and remove the element from Collection. if ($assoc['type'] & ClassMetadata::TO_MANY) { unset($value[$key]); } break; case self::STATE_DETACHED: // Can actually not happen right now as we assume STATE_NEW, // so the exception will be raised from the DBAL layer (constraint violation). throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry); break; default: // MANAGED associated entities are already taken into account // during changeset calculation anyway, since they are in the identity map. } } }
/** * 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 \Doctrine\DBAL\Schema\Table $table * @param \Doctrine\DBAL\Schema\Schema $schema * @return void */ private function _gatherRelationsSql($class, $table, $schema) { foreach ($class->associationMappings as $fieldName => $mapping) { if (isset($class->inheritedAssociationFields[$fieldName])) { continue; } $foreignClass = $this->_em->getClassMetadata($mapping->targetEntityName); if ($mapping->isOneToOne() && $mapping->isOwningSide) { $primaryKeyColumns = $uniqueConstraints = array(); // unnecessary for this relation-type $this->_gatherRelationJoinColumns($mapping->joinColumns, $table, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints); } else { if ($mapping->isOneToMany() && $mapping->isOwningSide) { //... create join table, one-many through join table supported later throw ORMException::notSupported(); } else { if ($mapping->isManyToMany() && $mapping->isOwningSide) { // create join table $joinTable = $mapping->joinTable; $theJoinTable = $schema->createTable($mapping->getQuotedJoinTableName($this->_platform)); $primaryKeyColumns = $uniqueConstraints = array(); // Build first FK constraint (relation table => source table) $this->_gatherRelationJoinColumns($joinTable['joinColumns'], $theJoinTable, $class, $mapping, $primaryKeyColumns, $uniqueConstraints); // Build second FK constraint (relation table => target table) $this->_gatherRelationJoinColumns($joinTable['inverseJoinColumns'], $theJoinTable, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints); foreach ($uniqueConstraints as $indexName => $unique) { $theJoinTable->addUniqueIndex($unique['columns'], is_numeric($indexName) ? null : $indexName); } $theJoinTable->setPrimaryKey($primaryKeyColumns); } } } } }
/** * 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; }
/** * Deletes an entity as part of the current unit of work. * * This method is internally called during delete() cascades as it tracks * the already visited entities to prevent infinite recursions. * * @param object $entity The entity to delete. * @param array $visited The map of the already visited entities. * @throws InvalidArgumentException If the instance is a detached entity. */ private function _doRemove($entity, array &$visited) { $oid = spl_object_hash($entity); if (isset($visited[$oid])) { return; // Prevent infinite recursion } $visited[$oid] = $entity; // mark visited $class = $this->_em->getClassMetadata(get_class($entity)); $entityState = $this->getEntityState($entity); switch ($entityState) { case self::STATE_NEW: case self::STATE_REMOVED: // nothing to do break; case self::STATE_MANAGED: if (isset($class->lifecycleCallbacks[Events::preRemove])) { $class->invokeLifecycleCallbacks(Events::preRemove, $entity); } if ($this->_evm->hasListeners(Events::preRemove)) { $this->_evm->dispatchEvent(Events::preRemove, new LifecycleEventArgs($entity, $this->_em)); } $this->scheduleForDelete($entity); break; case self::STATE_DETACHED: throw ORMException::detachedEntityCannotBeRemoved(); default: throw ORMException::invalidEntityState($entityState); } $this->_cascadeRemove($entity, $visited); }
/** * 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 \Doctrine\DBAL\Schema\Table $table * @param \Doctrine\DBAL\Schema\Schema $schema * @return void */ private function _gatherRelationsSql($class, $table, $schema) { foreach ($class->associationMappings as $fieldName => $mapping) { if (isset($mapping['inherited'])) { continue; } $foreignClass = $this->em->getClassMetadata($mapping['targetEntity']); if ($mapping['type'] & ClassMetadata::TO_ONE && $mapping['isOwningSide']) { $primaryKeyColumns = $uniqueConstraints = array(); // PK is unnecessary for this relation-type $this->_gatherRelationJoinColumns($mapping['joinColumns'], $table, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints); foreach ($uniqueConstraints as $indexName => $unique) { $table->addUniqueIndex($unique['columns'], is_numeric($indexName) ? null : $indexName); } } else { if ($mapping['type'] == ClassMetadata::ONE_TO_MANY && $mapping['isOwningSide']) { //... create join table, one-many through join table supported later throw ORMException::notSupported(); } else { if ($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 = $uniqueConstraints = array(); // Build first FK constraint (relation table => source table) $this->_gatherRelationJoinColumns($joinTable['joinColumns'], $theJoinTable, $class, $mapping, $primaryKeyColumns, $uniqueConstraints); // Build second FK constraint (relation table => target table) $this->_gatherRelationJoinColumns($joinTable['inverseJoinColumns'], $theJoinTable, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints); $theJoinTable->setPrimaryKey($primaryKeyColumns); foreach ($uniqueConstraints as $indexName => $unique) { $theJoinTable->addUniqueIndex($unique['columns'], is_numeric($indexName) ? null : $indexName); } } } } } }
/** * Sets default repository class. * * @since 2.2 * * @param string $className * * @return void * * @throws ORMException If not is a \Doctrine\Common\Persistence\ObjectRepository */ public function setDefaultRepositoryClassName($className) { $reflectionClass = new \ReflectionClass($className); if (!$reflectionClass->implementsInterface('Doctrine\\Common\\Persistence\\ObjectRepository')) { throw ORMException::invalidEntityRepository($className); } $this->_attributes['defaultRepositoryClassName'] = $className; }