/** * Get the subscribed event systems * * @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata. * @param string $eventName The entity lifecycle event. * * @return integer Bitmask of subscribed event systems. */ public function getSubscribedSystems(ClassMetadata $metadata, $eventName) { $invoke = self::INVOKE_NONE; if (isset($metadata->lifecycleCallbacks[$eventName])) { $invoke |= self::INVOKE_CALLBACKS; } if (isset($metadata->entityListeners[$eventName])) { $invoke |= self::INVOKE_LISTENERS; } if ($this->eventManager->hasListeners($eventName)) { $invoke |= self::INVOKE_MANAGER; } return $invoke; }
/** * Dispatches postHydrate event for specified entity or enqueues it for later dispatching * * @param object $entity */ public function dispatchPostHydrate($entity) { $className = get_class($entity); if (!$this->eventManager->hasListeners(Events::postHydrate)) { return; } if (isset($this->hints[Query::HINT_INTERNAL_ITERATION])) { $this->eventManager->dispatchEvent(Events::postHydrate, new LifecycleEventArgs($entity, $this->entityManager)); } else { if (!isset($this->entities[$className])) { $this->entities[$className] = array(); } $this->entities[$className][] = $entity; } }
/** * Creates a new database. * * @param string $name The database name * * @return Database * * @throws Exception If the database could not be created. */ public function createDatabase($name) { if (preg_match('@[^a-z0-9\\_\\$\\(\\)+\\-]@', $name)) { throw new InvalidDatabasenameException(sprintf('The database name %s is invalid. The database name must match the following pattern (a-z0-9_$()+-)', $name)); } if ($this->eventManager->hasListeners(Events::PRE_CREATE_DATABASE)) { // @codeCoverageIgnoreStart $this->eventManager->dispatchEvent(Events::PRE_CREATE_DATABASE, new EventArgs($this, $name)); // @codeCoverageIgnoreEnd } $response = $this->client->request('PUT', sprintf('/%s', $name)); if (412 === $response->getStatusCode()) { throw new Exception(sprintf('The database "%s" already exist', $name)); } $json = (string) $response->getBody(); $value = JSONEncoder::decode($json); if (isset($value['error'])) { throw new Exception(sprintf('[%s] Failed to create database "%s". (%s)', $value['error'], $name, $value['reason'])); } $database = $this->wrapDatabase($name); if ($this->eventManager->hasListeners(Events::POST_CREATE_DATABASE)) { // @codeCoverageIgnoreStart $this->eventManager->dispatchEvent(Events::POST_CREATE_DATABASE, new EventArgs($database)); // @codeCoverageIgnoreEnd } return $database; }
/** * Construct an entity object * * @param ClassMetadata $class * @param object $document */ public function hydrateEntity(ClassMetadata $class, $document) { // TODO: add support for different result set types from different clients // perhaps by wrapping documents in a layer of abstraction $data = $document->getData(); $fields = array_merge($document->hasFields() ? $document->getFields() : array(), array('_version' => $document->getVersion())); foreach ($fields as $name => $value) { if (isset($class->parameters[$name])) { $data[$name] = $value; } else { foreach ($class->parameters as $param => $mapping) { if ($mapping->name == $name) { $data[$param] = $value; break; } } } } $data[$class->getIdentifier()] = $document->getId(); if (method_exists($document, 'getScore')) { $data['score'] = $document->getScore(); } $entity = $this->sm->getSerializer()->deserialize($class->className, json_encode($data)); if ($this->evm->hasListeners(Events::postLoad)) { $this->evm->dispatchEvent(Events::postLoad, new Event\LifecycleEventArgs($entity, $this->sm)); } return $entity; }
/** * Executes the queued restorations. */ private function executeRestores() { $deletedFieldName = $this->configuration->getDeletedFieldName(); $persisters = array(); foreach ($this->restoreBy as $className => $criterias) { $persister = $this->getDocumentPersister($className); $persisters[$className] = $persister; foreach ($criterias as $criteria) { $persister->addRestoreBy($criteria); } } $documentRestores = array(); foreach ($this->documentRestores as $document) { $className = get_class($document); $documentRestores[$className][] = $document; $persister = $this->getDocumentPersister($className); $persisters[$className] = $persister; $persister->addRestore($document); } foreach ($persisters as $className => $persister) { $persister->executeRestores(); $class = $this->dm->getClassMetadata($className); if (isset($documentRestores[$className])) { $documents = $documentRestores[$className]; foreach ($documents as $document) { $class->setFieldValue($document, $deletedFieldName, null); if ($this->eventManager->hasListeners(Events::postRestore)) { $this->eventManager->dispatchEvent(Events::postRestore, new Event\LifecycleEventArgs($document, $this)); } } } } }
/** * {@inheritDoc} */ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) { /* @var $class \Doctrine\OXM\Mapping\ClassMetadata */ /* @var $parent \Doctrine\OXM\Mapping\ClassMetadata */ if ($parent) { $class->setIdGeneratorType($parent->generatorType); $this->addInheritedFields($class, $parent); $class->setXmlNamespaces($parent->xmlNamespaces); $class->setIdentifier($parent->identifier); $class->setLifecycleCallbacks($parent->lifecycleCallbacks); $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); $class->parent = $parent->getName(); } // Invoke driver try { $this->driver->loadMetadataForClass($class->getName(), $class); } catch (ReflectionException $e) { throw MappingException::reflectionFailure($class->getName(), $e); } $xmlNamespace = empty($class->xmlNamespaces) ? '' : $class->xmlNamespaces[0]['url']; foreach ($class->xmlNamespaces as $namespaceData) { if (empty($namespaceData['prefix'])) { $xmlNamespace = $namespaceData['url']; } } $xmlName = $class->getXmlName(); // Ignore duplicate binding issues -- at least for now /* if ( $this->isEntity($class) && array_key_exists($xmlName, $this->xmlToClassMap) && array_key_exists($xmlNamespace, $this->xmlToClassMap[$xmlName])) { if ($this->xmlToClassMap[$xmlName][$xmlNamespace] == $class->getName() || $this->xmlToClassMap[$xmlName][$xmlNamespace] == '\\' . $class->getName()) { // Ignore } else { throw MappingException::duplicateXmlNameBinding($class->getName(), $class->getXmlName()); } } */ // The previous test should be sufficent for us to just assume that the namespace/alternative is fine if (!empty($parent)) { $this->alternativeClassMap[$parent->getName()][$xmlNamespace] = $class->getName(); } if (!$class->isMappedSuperclass) { $this->xmlToClassMap[$xmlName][$xmlNamespace] = $class->getName(); } if ($parent && !$parent->isMappedSuperclass) { if ($parent->generatorType) { $class->setIdGeneratorType($parent->generatorType); } if ($parent->idGenerator) { $class->setIdGenerator($parent->idGenerator); } } else { $this->completeIdGeneratorMapping($class); } $class->setParentClasses($nonSuperclassParents); // Todo - ensure that root elements have an ID mapped if ($this->evm->hasListeners(Events::loadClassMetadata)) { $eventArgs = new LoadClassMetadataEventArgs($class, $this); $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); } }
/** * Hydrate array of MongoDB document data into the given document object. * * @param object $document The document object to hydrate the data into. * @param array $data The array of document data. * @return array $values The array of hydrated values. */ public function hydrate($document, $data) { $metadata = $this->dm->getClassMetadata(get_class($document)); // Invoke preLoad lifecycle events and listeners if (isset($metadata->lifecycleCallbacks[Events::preLoad])) { $args = array(&$data); $metadata->invokeLifecycleCallbacks(Events::preLoad, $document, $args); } if ($this->evm->hasListeners(Events::preLoad)) { $this->evm->dispatchEvent(Events::preLoad, new PreLoadEventArgs($document, $this->dm, $data)); } // Use the alsoLoadMethods on the document object to transform the data before hydration if (isset($metadata->alsoLoadMethods)) { foreach ($metadata->alsoLoadMethods as $fieldName => $method) { if (isset($data[$fieldName])) { $document->{$method}($data[$fieldName]); } } } if ($this->hydratorFactory !== null) { $data = $this->hydratorFactory->getHydratorFor($metadata->name)->hydrate($document, $data); } else { $data = $this->doGenericHydration($metadata, $document, $data); } // Invoke the postLoad lifecycle callbacks and listeners if (isset($metadata->lifecycleCallbacks[Events::postLoad])) { $metadata->invokeLifecycleCallbacks(Events::postLoad, $document); } if ($this->evm->hasListeners(Events::postLoad)) { $this->evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($document, $this->dm)); } return $data; }
/** * Get the subscribed event systems * * @param ClassMetadata $metadata * @param string $eventName The entity lifecycle event. * * @return integer Bitmask of subscribed event systems. */ public function getSubscribedSystems(ClassMetadata $metadata, $eventName) { $invoke = self::INVOKE_NONE; if ($metadata && isset($metadata->lifecycleCallbacks[$eventName])) { $invoke |= self::INVOKE_CALLBACKS; } /* * Not implemented for phpcr-odm at the moment. * if (isset($metadata->documentListeners[$eventName])) { $invoke |= self::INVOKE_LISTENERS; } */ if ($this->eventManager->hasListeners($eventName)) { $invoke |= self::INVOKE_MANAGER; } return $invoke; }
/** * Actually load the metadata from the underlying metadata * * @param ClassMetadataInterface|ClassMetadata $class * @param ClassMetadataInterface|ClassMetadata $parent * @param bool $rootEntityFound * @param array $nonSuperclassParents */ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) { //Manipulates $classMetadata; $this->driver->loadMetadataForClass($class->getName(), $class); if ($this->evm->hasListeners(Events::loadClassMetadata)) { $eventArgs = new LoadClassMetadataEventArgs($class, $this->sm); $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); } }
public function save(array &$a, array $options = array()) { if ($this->eventManager->hasListeners(Events::preSave)) { $this->eventManager->dispatchEvent(Events::preSave, new EventArgs($this, $a)); } $result = $this->doSave($a, $options); if ($this->eventManager->hasListeners(Events::postSave)) { $this->eventManager->dispatchEvent(Events::postSave, new EventArgs($this, $result)); } return $result; }
/** * {@inheritdoc} */ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) { if ($this->getDriver()) { $this->getDriver()->loadMetadataForClass($class->getName(), $class); } if ($this->evm->hasListeners(Event::loadClassMetadata)) { $eventArgs = new Event\LoadClassMetadataEventArgs($class, $this->objectAdapterManager); $this->evm->dispatchEvent(Event::loadClassMetadata, $eventArgs); } $this->validateRuntimeMetadata($class, $parent); }
/** @proxy */ public function selectCollection($name) { if ($this->eventManager->hasListeners(Events::preSelectCollection)) { $this->eventManager->dispatchEvent(Events::preSelectCollection, new EventArgs($this, $name)); } $collection = $this->doSelectCollection($name); if ($this->eventManager->hasListeners(Events::postSelectCollection)) { $this->eventManager->dispatchEvent(Events::postSelectCollection, new EventArgs($this, $collection)); } return $collection; }
/** * @param ObjectManager $om * * @return MetadataFactory */ protected function getMetadataFactory(ObjectManager $om, EventManager $evm) { if ($this->metadataFactory === null) { $driverFactory = DriverFactory::instance(); if ($evm->hasListeners(Events::REGISTER_DRIVER_METADATA)) { $eventArgs = new RegisterDriverMetadataEventArgs($driverFactory, $om); $evm->dispatchEvent(Events::REGISTER_DRIVER_METADATA, $eventArgs); } $this->metadataFactory = new MetadataFactory($driverFactory->driversFromManager($om)); } return $this->metadataFactory; }
/** @proxy */ public function selectDatabase($name) { if ($this->eventManager->hasListeners(Events::preSelectDatabase)) { $this->eventManager->dispatchEvent(Events::preSelectDatabase, new EventArgs($this, $name)); } $this->initialize(); $database = $this->wrapDatabase($name); if ($this->eventManager->hasListeners(Events::postSelectDatabase)) { $this->eventManager->dispatchEvent(Events::postSelectDatabase, new EventArgs($this, $database)); } return $database; }
/** * @param TableDiff $diff * @param array $columnSql */ protected function onSchemaAlterTable(TableDiff $diff, &$sql) { if (null === $this->_eventManager) { return false; } if (!$this->_eventManager->hasListeners(Events::onSchemaAlterTable)) { return false; } $eventArgs = new SchemaAlterTableEventArgs($diff, $this); $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs); $sql = array_merge($sql, $eventArgs->getSql()); return $eventArgs->isDefaultPrevented(); }
/** * Wrapper method for RiakCollection::update(). * * This method will dispatch preUpdate and postUpdate events. * * @see http://php.net/manual/en/mongocollection.update.php * @param array $query * @param array $newObj * @param array $options * @return array|boolean */ public function update($query, array $newObj, array $options = array()) { if (is_scalar($query)) { trigger_error('Scalar $query argument for update() is deprecated', E_USER_DEPRECATED); $query = array('_id' => $query); } if ($this->eventManager->hasListeners(Events::preUpdate)) { $this->eventManager->dispatchEvent(Events::preUpdate, new UpdateEventArgs($this, $query, $newObj, $options)); } $result = $this->doUpdate($query, $newObj, $options); if ($this->eventManager->hasListeners(Events::postUpdate)) { $this->eventManager->dispatchEvent(Events::postUpdate, new EventArgs($this, $result)); } return $result; }
/** * {@inheritdoc} */ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) { if ($parent) { $this->addInheritedDocumentOptions($class, $parent); $this->addInheritedFields($class, $parent); } if ($this->getDriver()) { $this->getDriver()->loadMetadataForClass($class->getName(), $class); } if ($this->evm->hasListeners(Event::loadClassMetadata)) { $eventArgs = new LoadClassMetadataEventArgs($class, $this->dm); $this->evm->dispatchEvent(Event::loadClassMetadata, $eventArgs); } $this->validateRuntimeMetadata($class, $parent); $class->setParentClasses($this->getParentClasses($class->name)); }
/** * Establishes the connection with the database. * * @return boolean TRUE if the connection was successfully established, FALSE if * the connection is already open. */ public function connect() { if ($this->_isConnected) { return false; } $driverOptions = isset($this->_params['driverOptions']) ? $this->_params['driverOptions'] : array(); $user = isset($this->_params['user']) ? $this->_params['user'] : null; $password = isset($this->_params['password']) ? $this->_params['password'] : null; $this->_conn = $this->_driver->connect($this->_params, $user, $password, $driverOptions); $this->_isConnected = true; if ($this->_eventManager->hasListeners(Events::postConnect)) { $eventArgs = new Event\ConnectionEventArgs($this); $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } return true; }
/** * Hydrate array of MongoDB document data into the given document object. * * @param object $document The document object to hydrate the data into. * @param array $data The array of document data. * @param array $hints Any hints to account for during reconstitution/lookup of the document. * @return array $values The array of hydrated values. */ public function hydrate($document, $data, array $hints = array()) { $metadata = $this->dm->getClassMetadata(get_class($document)); // Invoke preLoad lifecycle events and listeners if (!empty($metadata->lifecycleCallbacks[Events::preLoad])) { $args = array(&$data); $metadata->invokeLifecycleCallbacks(Events::preLoad, $document, $args); } if ($this->evm->hasListeners(Events::preLoad)) { $this->evm->dispatchEvent(Events::preLoad, new PreLoadEventArgs($document, $this->dm, $data)); } // alsoLoadMethods may transform the document before hydration if (!empty($metadata->alsoLoadMethods)) { foreach ($metadata->alsoLoadMethods as $method => $fieldNames) { foreach ($fieldNames as $fieldName) { // Invoke the method only once for the first field we find if (array_key_exists($fieldName, $data)) { $document->{$method}($data[$fieldName]); continue 2; } } } } $data = $this->getHydratorFor($metadata->name)->hydrate($document, $data, $hints); if ($document instanceof Proxy) { $document->__isInitialized__ = true; $document->__setInitializer(null); $document->__setCloner(null); // lazy properties may be left uninitialized $properties = $document->__getLazyProperties(); foreach ($properties as $propertyName => $property) { if (!isset($document->{$propertyName})) { $document->{$propertyName} = $properties[$propertyName]; } } } // Invoke the postLoad lifecycle callbacks and listeners if (!empty($metadata->lifecycleCallbacks[Events::postLoad])) { $metadata->invokeLifecycleCallbacks(Events::postLoad, $document); } if ($this->evm->hasListeners(Events::postLoad)) { $this->evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($document, $this->dm)); } return $data; }
/** * Clears the UnitOfWork. * * @param string|null $class if given, only documents of this type will be detached. * * @throws \Exception if $class is not null (not implemented) */ public function clear($class = null) { if ($class === null) { $this->identityMap = $this->documentIdentifiers = $this->originalDocumentData = $this->documentChangeSets = $this->documentStates = $this->scheduledForDirtyCheck = $this->documentInsertions = $this->documentUpdates = $this->documentDeletions = $this->collectionUpdates = $this->collectionDeletions = $this->orphanRemovals = []; } else { $visited = []; foreach ($this->identityMap as $className => $documents) { if ($className === $class) { foreach ($documents as $document) { $this->doDetach($document, $visited); } } } } if ($this->evm->hasListeners(Events::onClear)) { $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->dm, $class)); } }
/** * Will remove all scheduled stuff. This method can only be calles once. */ public function clear() { if ($this->hasCleared()) { return; } $this->hasCleared = true; // trigger clear on all managers of the referenced objects $managedObjects = $this->getScheduledReferencesByManager(); foreach ($managedObjects as $value) { $value['manager']->clear(); } // clear all object stores $this->objects = $this->objectState = $this->referencedObjects = $this->referencedObjectState = $this->removeReferences = $this->insertReferences = $this->updateReferences = array(); $this->hasCleared = false; $this->hasFlushed = false; if ($this->eventManager->hasListeners(Event::onClear)) { $this->eventManager->dispatchEvent(Event::onClear, new ManagerEventArgs($this->objectAdapterManager)); } }
/** * Actually loads PHPCR-ODM metadata from the underlying metadata. * * @param ClassMetadata $class * @param ClassMetadata|null $parent * @param bool $rootEntityFound * @param array $nonSuperclassParents All parent class names * that are not marked as mapped superclasses. */ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) { if ($parent) { $this->addInheritedDocumentOptions($class, $parent); $this->addInheritedFields($class, $parent); } if ($this->getDriver()) { $this->getDriver()->loadMetadataForClass($class->getName(), $class); } // once we loaded the metadata of this class, we might have to merge in the mixins of the parent. if ($parent && $class->getInheritMixins()) { $class->setMixins(array_merge($parent->getMixins(), $class->getMixins())); } if ($this->evm->hasListeners(Event::loadClassMetadata)) { $eventArgs = new LoadClassMetadataEventArgs($class, $this->dm); $this->evm->dispatchEvent(Event::loadClassMetadata, $eventArgs); } $this->validateRuntimeMetadata($class, $parent); $class->setParentClasses($this->getParentClasses($class->name)); }
/** * Wrapper method for MongoCollection::update(). * * This method will dispatch preUpdate and postUpdate events. * * @see http://php.net/manual/en/mongocollection.update.php * @param array $query * @param array $newObj * @param array $options * @return array|boolean */ public function update($query, array $newObj, array $options = []) { if (is_scalar($query)) { trigger_error('Scalar $query argument for update() is deprecated', E_USER_DEPRECATED); $query = ['_id' => $query]; } if ($this->eventManager->hasListeners(Events::preUpdate)) { $updateEventArgs = new UpdateEventArgs($this, $query, $newObj, $options); $this->eventManager->dispatchEvent(Events::preUpdate, $updateEventArgs); $query = $updateEventArgs->getQuery(); $newObj = $updateEventArgs->getNewObj(); $options = $updateEventArgs->getOptions(); } $result = $this->doUpdate($query, $newObj, $options); if ($this->eventManager->hasListeners(Events::postUpdate)) { $eventArgs = new MutableEventArgs($this, $result); $this->eventManager->dispatchEvent(Events::postUpdate, $eventArgs); $result = $eventArgs->getData(); } return $result; }
/** * {@inheritDoc} */ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) { /* @var $class ClassMetadata */ /* @var $parent ClassMetadata */ if ($parent) { $class->setInheritanceType($parent->inheritanceType); $class->setDiscriminatorColumn($parent->discriminatorColumn); $class->setIdGeneratorType($parent->generatorType); $this->addInheritedFields($class, $parent); $this->addInheritedRelations($class, $parent); $this->addInheritedEmbeddedClasses($class, $parent); $class->setIdentifier($parent->identifier); $class->setVersioned($parent->isVersioned); $class->setVersionField($parent->versionField); $class->setDiscriminatorMap($parent->discriminatorMap); $class->setLifecycleCallbacks($parent->lifecycleCallbacks); $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); if (!empty($parent->customGeneratorDefinition)) { $class->setCustomGeneratorDefinition($parent->customGeneratorDefinition); } if ($parent->isMappedSuperclass) { $class->setCustomRepositoryClass($parent->customRepositoryClassName); } } // Invoke driver try { $this->driver->loadMetadataForClass($class->getName(), $class); } catch (ReflectionException $e) { throw MappingException::reflectionFailure($class->getName(), $e); } // If this class has a parent the id generator strategy is inherited. // However this is only true if the hierarchy of parents contains the root entity, // if it consists of mapped superclasses these don't necessarily include the id field. if ($parent && $rootEntityFound) { if ($parent->isIdGeneratorSequence()) { $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition); } else { if ($parent->isIdGeneratorTable()) { $class->tableGeneratorDefinition = $parent->tableGeneratorDefinition; } } if ($parent->generatorType) { $class->setIdGeneratorType($parent->generatorType); } if ($parent->idGenerator) { $class->setIdGenerator($parent->idGenerator); } } else { $this->completeIdGeneratorMapping($class); } if (!$class->isMappedSuperclass) { foreach ($class->embeddedClasses as $property => $embeddableClass) { if (isset($embeddableClass['inherited'])) { continue; } if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) { throw MappingException::infiniteEmbeddableNesting($class->name, $property); } $this->embeddablesActiveNesting[$class->name] = true; $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); if ($embeddableMetadata->isEmbeddedClass) { $this->addNestedEmbeddedClasses($embeddableMetadata, $class, $property); } $class->inlineEmbeddable($property, $embeddableMetadata); unset($this->embeddablesActiveNesting[$class->name]); } } if ($parent && $parent->isInheritanceTypeSingleTable()) { $class->setPrimaryTable($parent->table); } if ($parent && $parent->cache) { $class->cache = $parent->cache; } if ($parent && $parent->containsForeignIdentifier) { $class->containsForeignIdentifier = true; } if ($parent && !empty($parent->namedQueries)) { $this->addInheritedNamedQueries($class, $parent); } if ($parent && !empty($parent->namedNativeQueries)) { $this->addInheritedNamedNativeQueries($class, $parent); } if ($parent && !empty($parent->sqlResultSetMappings)) { $this->addInheritedSqlResultSetMappings($class, $parent); } if ($parent && !empty($parent->entityListeners) && empty($class->entityListeners)) { $class->entityListeners = $parent->entityListeners; } $class->setParentClasses($nonSuperclassParents); if ($class->isRootEntity() && !$class->isInheritanceTypeNone() && !$class->discriminatorMap) { $this->addDefaultDiscriminatorMap($class); } if ($this->evm->hasListeners(Events::loadClassMetadata)) { $eventArgs = new LoadClassMetadataEventArgs($class, $this->em); $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); } $this->validateRuntimeMetadata($class, $parent); }
/** * To invoke a global invent without using the ListenersInvoker. * * @param $eventName * @param EventArgs $event */ public function invokeGlobalEvent($eventName, EventArgs $event) { if ($this->eventManager->hasListeners($eventName)) { $this->eventManager->dispatchEvent($eventName, $event); } }
/** * Loads the metadata of the class in question and all it's ancestors whose metadata * is still not loaded. * * @param string $name The name of the class for which the metadata should get loaded. * @param array $tables The metadata collection to which the loaded metadata is added. */ protected function loadMetadata($name) { if (!$this->initialized) { $this->initialize(); } $loaded = array(); $parentClasses = $this->getParentClasses($name); $parentClasses[] = $name; // Move down the hierarchy of parent classes, starting from the topmost class $parent = null; $visited = array(); foreach ($parentClasses as $className) { if (isset($this->loadedMetadata[$className])) { $parent = $this->loadedMetadata[$className]; if ($parent->isMappedSuperclass) { array_unshift($visited, $className); } continue; } $class = $this->newClassMetadataInstance($className); if ($parent) { $class->setIdGeneratorType($parent->generatorType); $this->addInheritedFields($class, $parent); $class->setXmlNamespaces($parent->xmlNamespaces); $class->setIdentifier($parent->identifier); $class->setLifecycleCallbacks($parent->lifecycleCallbacks); $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); } // Invoke driver try { $this->driver->loadMetadataForClass($className, $class); } catch (ReflectionException $e) { throw MappingException::reflectionFailure($className, $e); } if (!$class->isMappedSuperclass && in_array($class->getXmlName(), array_keys($this->xmlToClassMap))) { throw MappingException::duplicateXmlNameBinding($className, $class->getXmlName()); } if ($parent && !$parent->isMappedSuperclass) { if ($parent->generatorType) { $class->setIdGeneratorType($parent->generatorType); } if ($parent->idGenerator) { $class->setIdGenerator($parent->idGenerator); } } else { $this->completeIdGeneratorMapping($class); } $class->setParentClasses($visited); // Todo - ensure that root elements have an ID mapped if ($this->evm->hasListeners(Events::loadClassMetadata)) { $eventArgs = new \Doctrine\OXM\Event\LoadClassMetadataEventArgs($class, $this); $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); } $this->loadedMetadata[$className] = $class; $this->completeMappingTypeValidation($className, $class); if (!$class->isMappedSuperclass) { $this->xmlToClassMap[$class->getXmlName()] = $className; } $parent = $class; if ($class->isMappedSuperclass) { array_unshift($visited, $className); } $loaded[] = $className; } return $loaded; }
/** * Cascades the preLoad event to embedded documents. * * @param ClassMetadata $class * @param object $document * @param array $data */ private function cascadePreLoad(ClassMetadata $class, $document, $data) { foreach ($class->fieldMappings as $mapping) { if (isset($mapping['embedded'])) { $value = $class->reflFields[$mapping['fieldName']]->getValue($document); if ($value === null) { continue; } if ($mapping['type'] === 'one') { $value = array($value); } foreach ($value as $entry) { $entryClass = $this->dm->getClassMetadata(get_class($entry)); if (isset($entryClass->lifecycleCallbacks[Events::preLoad])) { $args = array(&$data); $entryClass->invokeLifecycleCallbacks(Events::preLoad, $entry, $args); } if ($this->evm->hasListeners(Events::preLoad)) { $this->evm->dispatchEvent(Events::preLoad, new PreLoadEventArgs($entry, $this->dm, $data[$mapping['name']])); } $this->cascadePreLoad($entryClass, $entry, $data[$mapping['name']]); } } } }
private function dispatchPostFlushEvent() { if ($this->evm->hasListeners(Events::postFlush)) { $this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em)); } }
/** * INTERNAL: * Creates an entity. Used for reconstitution of persistent entities. * * @ignore * @param string $className The name of the entity class. * @param array $data The data for the entity. * @param array $hints Any hints to account for during reconstitution/lookup of the entity. * * @return object The managed entity instance. * @internal Highly performance-sensitive method. * * @todo Rename: getOrCreateEntity */ public function createEntity($className, array $data, &$hints = array()) { $class = $this->em->getClassMetadata($className); //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]); if ($class->isIdentifierComposite) { $id = array(); foreach ($class->identifier as $fieldName) { $id[$fieldName] = isset($class->associationMappings[$fieldName]) ? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']] : $data[$fieldName]; } $idHash = implode(' ', $id); } else { $idHash = isset($class->associationMappings[$class->identifier[0]]) ? $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']] : $data[$class->identifier[0]]; $id = array($class->identifier[0] => $idHash); } if (isset($this->identityMap[$class->rootEntityName][$idHash])) { $entity = $this->identityMap[$class->rootEntityName][$idHash]; $oid = spl_object_hash($entity); if ($entity instanceof Proxy && !$entity->__isInitialized__) { $entity->__isInitialized__ = true; $overrideLocalValues = true; if ($entity instanceof NotifyPropertyChanged) { $entity->addPropertyChangedListener($this); } } else { $overrideLocalValues = isset($hints[Query::HINT_REFRESH]); // If only a specific entity is set to refresh, check that it's the one if (isset($hints[Query::HINT_REFRESH_ENTITY])) { $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity; // inject ObjectManager into just loaded proxies. if ($overrideLocalValues && $entity instanceof ObjectManagerAware) { $entity->injectObjectManager($this->em, $class); } } } if ($overrideLocalValues) { $this->originalEntityData[$oid] = $data; } } else { $entity = $this->newInstance($class); $oid = spl_object_hash($entity); $this->entityIdentifiers[$oid] = $id; $this->entityStates[$oid] = self::STATE_MANAGED; $this->originalEntityData[$oid] = $data; $this->identityMap[$class->rootEntityName][$idHash] = $entity; if ($entity instanceof NotifyPropertyChanged) { $entity->addPropertyChangedListener($this); } $overrideLocalValues = true; } if (!$overrideLocalValues) { return $entity; } foreach ($data as $field => $value) { if (isset($class->fieldMappings[$field])) { $class->reflFields[$field]->setValue($entity, $value); } } // Loading the entity right here, if its in the eager loading map get rid of it there. unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]); if (isset($this->eagerLoadingEntities[$class->rootEntityName]) && !$this->eagerLoadingEntities[$class->rootEntityName]) { unset($this->eagerLoadingEntities[$class->rootEntityName]); } // Properly initialize any unfetched associations, if partial objects are not allowed. if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) { return $entity; } foreach ($class->associationMappings as $field => $assoc) { // Check if the association is not among the fetch-joined associations already. if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) { continue; } $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); switch (true) { case $assoc['type'] & ClassMetadata::TO_ONE: if (!$assoc['isOwningSide']) { // Inverse side of x-to-one can never be lazy $class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity)); continue 2; } $associatedId = array(); // TODO: Is this even computed right in all cases of composite keys? foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) { $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null; if ($joinColumnValue !== null) { if ($targetClass->containsForeignIdentifier) { $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue; } else { $associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue; } } } if (!$associatedId) { // Foreign key is NULL $class->reflFields[$field]->setValue($entity, null); $this->originalEntityData[$oid][$field] = null; continue; } if (!isset($hints['fetchMode'][$class->name][$field])) { $hints['fetchMode'][$class->name][$field] = $assoc['fetch']; } // Foreign key is set // Check identity map first // FIXME: Can break easily with composite keys if join column values are in // wrong order. The correct order is the one in ClassMetadata#identifier. $relatedIdHash = implode(' ', $associatedId); switch (true) { case isset($this->identityMap[$targetClass->rootEntityName][$relatedIdHash]): $newValue = $this->identityMap[$targetClass->rootEntityName][$relatedIdHash]; // If this is an uninitialized proxy, we are deferring eager loads, // this association is marked as eager fetch, and its an uninitialized proxy (wtf!) // then we can append this entity for eager loading! if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER && isset($hints['deferEagerLoad']) && !$targetClass->isIdentifierComposite && $newValue instanceof Proxy && $newValue->__isInitialized__ === false) { $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId); } break; case $targetClass->subClasses: // If it might be a subtype, it can not be lazy. There isn't even // a way to solve this with deferred eager loading, which means putting // an entity with subclasses at a *-to-one location is really bad! (performance-wise) $newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId); break; default: switch (true) { // We are negating the condition here. Other cases will assume it is valid! case $hints['fetchMode'][$class->name][$field] !== ClassMetadata::FETCH_EAGER: $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId); break; // Deferred eager load only works for single identifier classes // Deferred eager load only works for single identifier classes case isset($hints['deferEagerLoad']) && !$targetClass->isIdentifierComposite: // TODO: Is there a faster approach? $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId); $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId); break; default: // TODO: This is very imperformant, ignore it? $newValue = $this->em->find($assoc['targetEntity'], $associatedId); break; } // PERF: Inlined & optimized code from UnitOfWork#registerManaged() $newValueOid = spl_object_hash($newValue); $this->entityIdentifiers[$newValueOid] = $associatedId; $this->identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue; $this->entityStates[$newValueOid] = self::STATE_MANAGED; // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also! break; } $this->originalEntityData[$oid][$field] = $newValue; $class->reflFields[$field]->setValue($entity, $newValue); if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) { $inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']]; $targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($newValue, $entity); } break; default: // Inject collection $pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection()); $pColl->setOwner($entity, $assoc); $pColl->setInitialized(false); $reflField = $class->reflFields[$field]; $reflField->setValue($entity, $pColl); if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) { $this->loadCollection($pColl); $pColl->takeSnapshot(); } $this->originalEntityData[$oid][$field] = $pColl; break; } } if ($overrideLocalValues) { if (isset($class->lifecycleCallbacks[Events::postLoad])) { $class->invokeLifecycleCallbacks(Events::postLoad, $entity); } if ($this->evm->hasListeners(Events::postLoad)) { $this->evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->em)); } } return $entity; }
/** * Establishes the connection with the database. * * @return boolean TRUE if the connection was successfully established, FALSE if * the connection is already open. */ public function connect() { if ($this->_isConnected) { return false; } $driverOptions = isset($this->_params['driverOptions']) ? $this->_params['driverOptions'] : array(); $user = isset($this->_params['user']) ? $this->_params['user'] : null; $password = isset($this->_params['password']) ? $this->_params['password'] : null; $this->_conn = $this->_driver->connect($this->_params, $user, $password, $driverOptions); $this->_isConnected = true; if (null === $this->platform) { $this->detectDatabasePlatform(); } if (false === $this->autoCommit) { $this->beginTransaction(); } if ($this->_eventManager->hasListeners(Events::postConnect)) { $eventArgs = new Event\ConnectionEventArgs($this); $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } return true; }