/** * Flush for update * * @param object $entity * @param \Doctrine\ORM\EntityManager $entityManager * @param \Doctrine\ORM\UnitOfWork $unitOfWork */ protected function onFlushForUpdates(&$entity, EntityManager &$entityManager, UnitOfWork &$unitOfWork) { $className = get_class($entity); $this->initializeAnnotationsForEntity($className); if (count(self::$storedProperties[$className]['annotations']) > 0) { foreach (self::$storedProperties[$className]['annotations'] as $propertyName => &$annotations) { /* @var $annotation Traceable */ foreach ($annotations as $annotation) { $run = $annotation->on === 'update'; if ($annotation->on === 'change') { $changeSet = $unitOfWork->getEntityChangeSet($entity); if (isset($changeSet[$annotation->field])) { $type = $this->getPropertyType($className, $annotation->field); $values = $annotation->getFieldValues($type, $entity); $run = count($values) === 0 || in_array($changeSet[$annotation->field][1], $values); } } if ($run) { list($oldValue, $value) = $this->updateEntityPropertyValue($entity, $className, $propertyName, $annotation); $entityManager->persist($entity); $unitOfWork->propertyChanged($entity, $propertyName, $oldValue, $value); $unitOfWork->scheduleExtraUpdate($entity, array($propertyName => array($oldValue, $value))); break; } } } } }
/** * @param OnFlushEventArgs $args */ public function onFlush(OnFlushEventArgs $args) { $this->initializeFromEventArgs($args); $entities = array_merge($this->uow->getScheduledEntityInsertions(), $this->uow->getScheduledEntityDeletions(), $this->uow->getScheduledEntityUpdates()); /** @var Opportunity[] $entities */ $entities = array_filter($entities, function ($entity) { return 'OroCRM\\Bundle\\SalesBundle\\Entity\\Opportunity' === ClassUtils::getClass($entity); }); foreach ($entities as $entity) { if (!$entity->getId() && $this->isValuable($entity)) { // handle creation, just add to prev lifetime value and recalculate change set $b2bCustomer = $entity->getCustomer(); $b2bCustomer->setLifetime($b2bCustomer->getLifetime() + $entity->getCloseRevenue()); $this->scheduleUpdate($b2bCustomer); $this->uow->computeChangeSet($this->em->getClassMetadata(ClassUtils::getClass($b2bCustomer)), $b2bCustomer); } elseif ($this->uow->isScheduledForDelete($entity) && $this->isValuable($entity)) { $this->scheduleUpdate($entity->getCustomer()); } elseif ($this->uow->isScheduledForUpdate($entity)) { // handle update $changeSet = $this->uow->getEntityChangeSet($entity); if ($this->isChangeSetValuable($changeSet)) { if (!empty($changeSet['customer']) && $changeSet['customer'][0] instanceof B2bCustomer && B2bCustomerRepository::VALUABLE_STATUS === $this->getOldStatus($entity, $changeSet)) { // handle change of b2b customer $this->scheduleUpdate($changeSet['customer'][0]); } if ($this->isValuable($entity, isset($changeSet['closeRevenue'])) || B2bCustomerRepository::VALUABLE_STATUS === $this->getOldStatus($entity, $changeSet) && $entity->getCustomer()) { $this->scheduleUpdate($entity->getCustomer()); } } } } }
/** * @param OnFlushEventArgs $args */ public function onFlush(OnFlushEventArgs $args) { $this->initializeFromEventArgs($args); $entities = $this->getChangedTrackedEntities(); foreach ($entities as $entity) { $className = ClassUtils::getClass($entity); if ($this->uow->isScheduledForUpdate($entity)) { $this->checkAndUpdate($entity, $this->uow->getEntityChangeSet($entity)); } else { $this->scheduleUpdate($className, $entity->getAccount(), $entity->getDataChannel()); } } }
/** * Deletes an entity if it is in relation to another entity * * Doctrine is obviously unable to entities detached from the relational entity when merging the relational entity, * so this had to be implemented. * * @param object $relationalEntity * @param string $fieldName * @param ClassMetadata $metadata * @param boolean $recomputeChangeSet */ public function deleteOnRelationalModification($relationalEntity, $fieldName, ClassMetadata $metadata, $recomputeChangeSet = true) { if ($recomputeChangeSet) { $this->unitOfWork->computeChangeSet($metadata, $relationalEntity); } $changeSet = $this->unitOfWork->getEntityChangeSet($relationalEntity); if (!isset($changeSet[$fieldName])) { return; } $orgValue = $changeSet[$fieldName][0]; if (null !== $orgValue && $this->entityManager->contains($orgValue)) { $this->entityManager->remove($orgValue); } }
/** * Computes or re-computes changes of given entity. * * @param $entity * * @author Andreas Glaser */ protected function computeChangeSet($entity) { if ($this->unitOfWork->getEntityChangeSet($entity)) { $this->unitOfWork->recomputeSingleEntityChangeSet($this->entityManager->getClassMetadata(get_class($entity)), $entity); } else { $this->unitOfWork->computeChangeSet($this->entityManager->getClassMetadata(get_class($entity)), $entity); } }
/** * Before update * * @param object $entity */ protected function preUpdate($entity) { if ($entity instanceof LocaleInterface && !$entity->isActivated()) { $changeset = $this->uow->getEntityChangeSet($entity); if (isset($changeset['activated'])) { $this->deactivatedLocales[] = $entity->getCode(); } } }
/** * Get an array describing the changes. * * @param UnitOfWork $unitOfWork * @param TermOfUse $entity * @param string $action * * @return array */ protected function getChangeSet(UnitOfWork $unitOfWork, TermOfUse $entity, $action) { switch ($action) { case 'create': return array('id' => array(null, $entity->getId()), 'weight' => array(null, $entity->getWeight()), 'keyCode' => array(null, $entity->getKeyCode()), 'langCode' => array(null, $entity->getLangCode()), 'content' => array(null, $entity->getContent()), 'created' => array(null, $entity->getCreated()), 'updated' => array(null, $entity->getUpdated())); case 'update': return $unitOfWork->getEntityChangeSet($entity); case 'delete': return array('id' => array($entity->getId(), null), 'weight' => array($entity->getWeight(), null), 'keyCode' => array($entity->getKeyCode(), null), 'langCode' => array($entity->getLangCode(), null), 'content' => array($entity->getContent(), null), 'created' => array($entity->getCreated(), null), 'updated' => array($entity->getUpdated(), null)); } }
/** * @param $emailField * @param mixed $entity * @param EmailOwnerInterface $owner * @param EntityManager $em * @param UnitOfWork $uow */ protected function processInsertionOrUpdateEntity($emailField, $entity, EmailOwnerInterface $owner, EntityManager $em, UnitOfWork $uow) { if (!empty($emailField)) { foreach ($uow->getEntityChangeSet($entity) as $field => $vals) { if ($field === $emailField) { list($oldValue, $newValue) = $vals; if ($newValue !== $oldValue) { $this->bindEmailAddress($em, $owner, $newValue, $oldValue); } } } } }
public function postUpdate(LifecycleEventArgs $eventArgs) { // onFlush was executed before, everything already initialized $entity = $eventArgs->getEntity(); $class = $this->sourceEm->getClassMetadata(get_class($entity)); if (!$this->metadataFactory->isAudited($class->name)) { return; } // get changes => should be already computed here (is a listener) $changeset = $this->uow->getEntityChangeSet($entity); foreach ($this->config->getGlobalIgnoreColumns() as $column) { if (isset($changeset[$column])) { unset($changeset[$column]); } } // if we have no changes left => don't create revision log if (count($changeset) == 0) { return; } $entityData = array_merge($this->getOriginalEntityData($entity), $this->uow->getEntityIdentifier($entity)); $this->saveRevisionEntityData($class, $entityData, 'UPD'); }
/** * @param $changeset The changeset for the entity * @param $expectedFields List of filds which should be updated/set * * @dataProvider provideLifecycle */ public function testOnFlush($changeset, $expectedFields) { $entity = $this->userBlameObject->reveal(); $this->unitOfWork->getScheduledEntityInsertions()->willReturn([$entity]); $this->unitOfWork->getScheduledEntityUpdates()->willReturn([]); $this->entityManager->getClassMetadata(get_class($entity))->willReturn($this->classMetadata); $this->unitOfWork->getEntityChangeSet($this->userBlameObject->reveal())->willReturn($changeset); foreach (['creator', 'changer'] as $field) { $prophecy = $this->classMetadata->setFieldValue($this->userBlameObject->reveal(), $field, $this->user->reveal()); if (in_array($field, $expectedFields)) { $prophecy->shouldBeCalled(); continue; } $prophecy->shouldNotBeCalled(); } if (count($expectedFields)) { $this->unitOfWork->recomputeSingleEntityChangeSet($this->classMetadata->reveal(), $this->userBlameObject->reveal())->shouldBeCalled(); } $this->subscriber->onFlush($this->onFlushEvent->reveal()); }
public function postUpdate(LifecycleEventArgs $eventArgs) { if (!$this->active) { return; } $entity = $eventArgs->getEntity(); $meta = $this->em->getClassMetadata(get_class($entity)); if (!$this->annotationReader->isRevised($meta->name, true)) { return; } $changeSet = $this->uow->getEntityChangeSet($entity); foreach ($changeSet as $field => $value) { if (!$this->annotationReader->isPropertyRevised($entity, $field)) { unset($changeSet[$field]); } } if (count($changeSet) == 0) { return; } $entityData = array_merge($this->getOriginalEntityData($entity), $this->uow->getEntityIdentifier($entity)); $this->saveRevisionEntityData($meta, $entityData, 'UPD'); }
/** * Takes an entity and works out whether it has a relation to CMF's URL Model. If so, * it updates the properties of the associated URL object. * * @param object $entity * @param \Doctrine\ORM\EntityManager $em * @param \Doctrine\ORM\UnitOfWork|null $uow * @return void */ protected function process(&$entity, &$em, &$uow) { $entity_class = get_class($entity); $entity_namespace = trim(\CMF::slug(str_replace('\\', '/', \Inflector::get_namespace($entity_class))), '/'); $metadata = $em->getClassMetadata($entity_class); // Ignore URL entities themselves if ($metadata->name == 'CMF\\Model\\URL') { return; } $url_associations = $metadata->getAssociationsByTargetClass('CMF\\Model\\URL'); if (!empty($url_associations)) { // A bit hacky, but if this is a root tree item don't bother if (property_exists($entity, 'is_root') && $entity->is_root === true) { return; } $url_field = null; foreach ($url_associations as $key => $association) { if ($association['type'] == ClassMetadataInfo::ONE_TO_ONE && $association['orphanRemoval']) { $url_field = $key; break; } } if ($url_field == null) { return; } $settings = $entity->settings(); $url_settings = isset($settings[$url_field]) ? $settings[$url_field] : array(); $url_item = $entity->get($url_field); if ($new_url = is_null($url_item)) { $url_item = new \CMF\Model\URL(); } // Don't run if this is an alias... $alias = $url_item->alias; if (!is_null($alias) && !empty($alias)) { return; } // Don't run if this is an external link... if ($url_item->isExternal()) { return; } $prefix = $this->getPrefix($entity); $slug = ''; if (isset($url_settings['keep_updated']) && !$url_settings['keep_updated']) { $slug = \CMF::slug($url_item->slug); } else { $slug = $entity->urlSlug(); } $url = $prefix . $slug; if ($url != '/') { $url = rtrim($url, '/'); } $current_url = $url_item->url; $entity_id = $entity->id; $url_id = $url_item->get('id'); // Check for duplicates, only if this is an already existing item if (!empty($entity_id) && !is_null($entity_id)) { // Set data from the entity if the prefix is null if (is_null($prefix)) { $prefix = $this->getPrefix($entity); $url = $prefix . $slug; } // Set data from the entity if the slug is null if (is_null($slug)) { $slug = $entity->urlSlug(); $url = $prefix . $slug; } // Set it to the item's ID if empty if (is_null($slug)) { $slug = $entity_id . ""; $url = $prefix . $slug; } $slug_orig = $slug; $unique = $this->checkUnique($url, $entity_id, $url_id); $counter = 2; while (!$unique) { $slug = $slug_orig . '-' . $counter; $url = $prefix . $slug; $unique = $this->checkUnique($url, $entity_id, $url_id); $counter++; } // Add it to the list of saved URLs $this->savedUrls[$url] = $entity_id; } $url_item->set('item_id', $entity->get('id')); $url_item->set('prefix', $prefix); $url_item->set('slug', $slug); $url_item->set('url', $url); $url_item->set('type', $metadata->name); $entity->set($url_field, $url_item); $em->persist($url_item); // Skip this if the url hasn't changed if (!$new_url && $current_url == $url) { return; } $url_metadata = $em->getClassMetadata('CMF\\Model\\URL'); $url_changeset = $uow->getEntityChangeSet($url_item); if (!empty($url_changeset)) { $uow->recomputeSingleEntityChangeSet($url_metadata, $url_item); } else { $uow->computeChangeSet($url_metadata, $url_item); } $uow->recomputeSingleEntityChangeSet($metadata, $entity); $associations = $metadata->getAssociationMappings(); foreach ($associations as $association_name => $association) { // Only do it if it's the inverse side, to prevent the dreaded infinite recursion if (!$association['isOwningSide']) { $items = $entity->{$association_name}; if (!empty($items)) { foreach ($items as $item) { $this->process($item, $em, $uow); } } } } } }
/** * Generates new full path and validates its uniqueness * @param PageLocalization $pageData * @return PageLocalization if changes were made */ protected function generatePath(PageLocalization $pageData, $force = false) { $page = $pageData->getMaster(); $oldPath = $pageData->getPath(); $changes = false; $oldPathEntity = $pageData->getPathEntity(); list($newPath, $active, $limited, $inSitemap) = $this->findPagePath($pageData); if (!$page->isRoot()) { if (!Path::compare($oldPath, $newPath) || $force) { $suffix = null; // Check duplicates only if path is not null if (!is_null($newPath)) { // Additional check for path length $pathString = $newPath->getPath(); if (mb_strlen($pathString) > 255) { throw new Exception\RuntimeException('Overall path length shouldn\'t be more than 255 symbols'); } $i = 2; $e = null; $pathPart = $pageData->getPathPart(); $pathValid = false; do { try { $this->checkForDuplicates($pageData, $newPath); $pathValid = true; } catch (DuplicatePagePathException $e) { if ($force) { // loop stoper if ($i > 101) { throw new Exception\RuntimeException("Couldn't find unique path for new page", null, $e); } // Will try adding unique suffix after 100 iterations if ($i > 100) { $suffix = uniqid(); } else { $suffix = $i; } $pageData->setPathPart($pathPart . '-' . $suffix); list($newPath, $active, $limited, $inSitemap) = $this->findPagePath($pageData); $i++; } } } while ($force && !$pathValid); if ($e instanceof DuplicatePagePathException && !$pathValid) { throw $e; } } // Validation passed, set the new path $pageData->setPathData($newPath, $active, $limited, $inSitemap); if (!is_null($suffix)) { $pageData->setTitle($pageData->getTitle() . " ({$suffix})"); } $changes = true; } } elseif ($page->getLeftValue() == 1) { $newPath = new Path(''); // Root page if (!$newPath->equals($oldPath)) { $changes = true; $pageData->setPathData($newPath, $active, $limited, $inSitemap); } // Another root page... } else { $newPath = null; $active = false; $pageData->setPathData($newPath, $active, $limited, $inSitemap); } if ($oldPathEntity->isActive() !== $active || $oldPathEntity->isVisibleInSitemap() != $inSitemap) { $pageData->setPathData($newPath, $active, $limited, $inSitemap); $changes = true; } if ($changes) { $pathEntity = $pageData->getPathEntity(); $pathMetaData = $this->em->getClassMetadata($pathEntity->CN()); $localizationMetaData = $this->em->getClassMetadata($pageData->CN()); if ($this->unitOfWork->getEntityState($pathEntity, UnitOfWork::STATE_NEW) === UnitOfWork::STATE_NEW) { $this->em->persist($pathEntity); // } elseif ($this->unitOfWork->getEntityState($pathEntity) === UnitOfWork::STATE_DETACHED) { // $pathEntity = $this->em->merge($pathEntity); } /* * Add the path changes to the changeset, must call different * methods depending on is the entity inside the unit of work * changeset */ if ($this->unitOfWork->getEntityChangeSet($pathEntity)) { $this->unitOfWork->recomputeSingleEntityChangeSet($pathMetaData, $pathEntity); } else { $this->unitOfWork->computeChangeSet($pathMetaData, $pathEntity); } if ($this->unitOfWork->getEntityChangeSet($pageData)) { $this->unitOfWork->recomputeSingleEntityChangeSet($localizationMetaData, $pageData); } else { $this->unitOfWork->computeChangeSet($localizationMetaData, $pageData); } return $pageData; } }
/** * @param <type> $entity * @override */ public function getEntityChangeSet($entity) { $oid = spl_object_hash($entity); return isset($this->_mockDataChangeSets[$oid]) ? $this->_mockDataChangeSets[$oid] : parent::getEntityChangeSet($entity); }
/** * Checks whether the changeset for the given source includes anything else besides the last-visited date. * * @param SourceInterface $source * @param UnitOfWork $uow * * @return bool */ protected function isSourceModified(SourceInterface $source, UnitOfWork $uow) { $changeset = $uow->getEntityChangeSet($source); $changeset = $this->filterChangeset($changeset); // see if any other keys besides datetimeLastVisited and messages is in changeset return !empty($changeset); }
public function log(LogEntity $logEntity, UnitOfWork $unitOfWork, $action) { $changeSet = $unitOfWork->getEntityChangeSet($this); $logEntity->setPage($this); if (count($changeSet) === 1 && isset($changeSet['published'])) { if ($changeSet['published'][1] === TRUE) { $logEntity->setMessage('Page has been published'); } else { $logEntity->setMessage('Page has been unpublished'); } } }
/** * @param object $entity entity * @param ObjectManager $entityManager entityManager * @param UnitOfWork $uow uow */ private function computeViolations($entity, ObjectManager $entityManager, UnitOfWork $uow) { if (!($handlers = $this->handlerManager->fetch($entity))) { return null; } $list = $this->violationManager->getViolationListNotFixed($entity); $list->setFixed(true); foreach ($handlers as $handler) { $handler->validate($entity, $list); } $uow->computeChangeSets(); foreach ($list as $violation) { $changeSet = $uow->getEntityChangeSet($violation); if (!empty($changeSet) || !$entityManager->contains($violation)) { $this->violations[spl_object_hash($violation)] = $violation; } } }
/** * @param UnitOfWork $uow * @param IncidentInterface $entity */ protected function preFlushIncident(UnitOfWork $uow, IncidentInterface $entity) { $changeSet = $uow->getEntityChangeSet($entity); if (array_key_exists('status', $changeSet) || array_key_exists('type', $changeSet)) { $this->preUpdateIncidentStatus($entity); $entity->notify(); } }
/** * @param $entity */ private function recoumputeChanges($entity) { if ($this->uow->getEntityChangeSet($entity)) { $this->uow->recomputeSingleEntityChangeSet($this->em->getClassMetadata(get_class($entity)), $entity); } }
/** * Creates data * * @param UnitOfWork $uow * @return array */ public function createEmailAddressData(UnitOfWork $uow) { return ['updates' => array_map(function ($entity) use($uow) { return ['entity' => $entity, 'changeSet' => $uow->getEntityChangeSet($entity)]; }, array_filter(array_merge($uow->getScheduledEntityInsertions(), $uow->getScheduledEntityUpdates()), $this->getEntityFilter())), 'deletions' => array_filter($uow->getScheduledEntityDeletions(), $this->getEntityFilter())]; }
/** * Get the object changeset from a UnitOfWork. * * @param \Doctrine\ORM\UnitOfWork $uow * @param object $object * @return array */ public function getObjectChangeSet(UnitOfWork $uow, $object) { return $uow->getEntityChangeSet($object); }
/** * Schedule updates for routing * * @param EntityManager $em * @param UnitOfWork $uow */ protected function updateRouting(EntityManager $em, UnitOfWork $uow) { // 302 old routes to the new 200 foreach ($uow->getScheduledEntityUpdates() as $entity) { if ($entity instanceof FieldableEntity) { $changeSet = $uow->getEntityChangeSet($entity); $oldRoute = $entity->getRoute(); // Check if we have a route. If not, create one and continue if (!$oldRoute instanceof Route) { // create the new route $oldRoute = $this->getEntityRoute($entity); $entity->setRoute($oldRoute); $this->computeChangeSet($em, $oldRoute); $this->recomputeSingleEntityChangeSet($em, $entity); } // Check if the route has been manually updated $newRoute = $this->getEntityRoute($entity); // if the route changed, update it if ($newRoute->getPath() !== $oldRoute->getPath()) { // create the new route entity $entity->setRoute($newRoute); $this->computeChangeSet($em, $newRoute); // set any old route to redirect to the new route $this->redirectRoute($oldRoute); $this->recomputeSingleEntityChangeSet($em, $oldRoute); } if (isset($changeSet['deletedOn'])) { if ($changeSet['deletedOn'] instanceof \DateTime) { // delete $this->deletedRoute($oldRoute); $this->recomputeSingleEntityChangeSet($em, $oldRoute); } else { // un-delete $newRoute = $this->getEntityRoute($entity); $entity->setRoute($newRoute); $uow->scheduleForDelete($oldRoute); $this->computeChangeSet($em, $newRoute); $this->recomputeSingleEntityChangeSet($em, $oldRoute); } } $em->persist($entity); $this->recomputeSingleEntityChangeSet($em, $entity); } } }
/** * @param array $bindings * @param $emailField * @param mixed $entity * @param EmailOwnerInterface $owner * @param UnitOfWork $uow */ protected function processInsertionOrUpdateEntity(array &$bindings, $emailField, $entity, EmailOwnerInterface $owner, UnitOfWork $uow) { $changeSet = $uow->getEntityChangeSet($entity); foreach ($changeSet as $field => $values) { if ($field === $emailField) { list($oldValue, $newValue) = $values; if ($newValue !== $oldValue) { if (!empty($newValue)) { $bindings['changes'][strtolower($newValue)] = ['email' => $newValue, 'owner' => $owner]; } if (!empty($oldValue) && !isset($bindings['changes'][strtolower($oldValue)])) { $bindings['changes'][strtolower($oldValue)] = ['email' => $oldValue, 'owner' => false]; } } } } }