protected function getClassAndId($object) { $wrapped = AbstractWrapper::wrap($object, $this->getEntityManager()); $id = $wrapped->getIdentifier(); $class = $wrapped->getRootObjectName(); return array('id' => $id, 'class' => $class); }
/** * {@inheritDoc} */ public function getSimilarSlugs($object, $meta, array $config, $slug) { $em = $this->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $em); $qb = $em->createQueryBuilder(); $qb->select('rec.' . $config['slug'])->from($config['useObjectClass'], 'rec')->where($qb->expr()->like('rec.' . $config['slug'], ':slug')); $qb->setParameter('slug', $slug . '%'); // use the unique_base to restrict the uniqueness check if ($config['unique'] && isset($config['unique_base'])) { if (($ubase = $wrapped->getPropertyValue($config['unique_base'])) && !array_key_exists($config['unique_base'], $wrapped->getMetadata()->getAssociationMappings())) { $qb->andWhere('rec.' . $config['unique_base'] . ' = :unique_base'); $qb->setParameter(':unique_base', $ubase); } elseif (array_key_exists($config['unique_base'], $wrapped->getMetadata()->getAssociationMappings())) { $associationMappings = $wrapped->getMetadata()->getAssociationMappings(); $qb->join($associationMappings[$config['unique_base']]['targetEntity'], 'unique_' . $config['unique_base']); } else { $qb->andWhere($qb->expr()->isNull('rec.' . $config['unique_base'])); } } // include identifiers foreach ((array) $wrapped->getIdentifier(false) as $id => $value) { if (!$meta->isIdentifier($config['slug'])) { $qb->andWhere($qb->expr()->neq('rec.' . $id, ':' . $id)); $qb->setParameter($id, $value); } } $q = $qb->getQuery(); $q->setHydrationMode(Query::HYDRATE_ARRAY); return $q->execute(); }
public function getLogsByObject($object, $searchChild = true, $searchOnlyChild = false) { $wrapped = AbstractWrapper::wrap($object, $this->getEntityManager()); $id = $wrapped->getIdentifier(); $class = $wrapped->getRootObjectName(); return $this->getLogsByClassId($class, $id, $searchChild, $searchOnlyChild); }
/** * {@inheritdoc} */ public function removeNode($om, $meta, $config, $node) { $uow = $om->getUnitOfWork(); $wrapped = AbstractWrapper::wrap($node, $om); // Remove node's children $results = $om->createQueryBuilder()->find($meta->name)->field($config['path'])->equals(new \MongoRegex('/^' . preg_quote($wrapped->getPropertyValue($config['path'])) . '.?+/'))->getQuery()->execute(); foreach ($results as $node) { $uow->scheduleForDelete($node); } }
/** * {@inheritdoc} */ public function removeNode($om, $meta, $config, $node) { $uow = $om->getUnitOfWork(); $wrapped = AbstractWrapper::wrap($node, $om); $path = addcslashes($wrapped->getPropertyValue($config['path']), '%'); // Remove node's children $qb = $om->createQueryBuilder(); $qb->select('e')->from($config['useObjectClass'], 'e')->where($qb->expr()->like('e.' . $config['path'], $qb->expr()->literal($path . '%'))); $results = $qb->getQuery()->execute(); foreach ($results as $node) { $uow->scheduleForDelete($node); } }
/** * This query can cause some data integrity failures since it does not * execute atomically * * {@inheritDoc} */ public function replaceInverseRelative($object, array $config, $target, $replacement) { $dm = $this->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $dm); $meta = $dm->getClassMetadata($config['useObjectClass']); $q = $dm->createQueryBuilder($config['useObjectClass'])->field($config['mappedBy'] . '.' . $meta->identifier)->equals($wrapped->getIdentifier())->getQuery(); $q->setHydrate(false); $result = $q->execute(); if ($result instanceof Cursor) { $result = $result->toArray(); foreach ($result as $targetObject) { $slug = preg_replace("@^{$replacement}@smi", $target, $targetObject[$config['slug']]); $dm->createQueryBuilder()->update($config['useObjectClass'])->field($config['slug'])->set($slug)->field($meta->identifier)->equals($targetObject['_id'])->getQuery()->execute(); } } }
/** * {@inheritDoc} */ public function getSimilarSlugs($object, $meta, array $config, $slug) { $em = $this->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $em); $qb = $em->createQueryBuilder(); $qb->select('rec.' . $config['slug'])->from($config['useObjectClass'], 'rec')->where($qb->expr()->like('rec.' . $config['slug'], $qb->expr()->literal($slug . '%'))); // include identifiers foreach ((array) $wrapped->getIdentifier(false) as $id => $value) { if (!$meta->isIdentifier($config['slug'])) { $qb->andWhere($qb->expr()->neq('rec.' . $id, ':' . $id)); $qb->setParameter($id, $value); } } $q = $qb->getQuery(); $q->setHydrationMode(Query::HYDRATE_ARRAY); return $q->execute(); }
/** * {@inheritDoc} */ public function getSimilarSlugs($object, $meta, array $config, $slug) { $dm = $this->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $dm); $qb = $dm->createQueryBuilder($config['useObjectClass']); if (($identifier = $wrapped->getIdentifier()) && !$meta->isIdentifier($config['slug'])) { $qb->field($meta->identifier)->notEqual($identifier); } $qb->field($config['slug'])->equals(new \MongoRegex('/^' . preg_quote($slug, '/') . '/')); $q = $qb->getQuery(); $q->setHydrate(false); $result = $q->execute(); if ($result instanceof Cursor) { $result = $result->toArray(); } return $result; }
/** * prepare object for display * * * @access public * @param array $objectsArray * @param mixed $sampleObject object used to get expected properties when $objectsArray is array of arrays not array of objects ,default is null * @param int $depthLevel ,default is 0 * @param int $maxDepthLevel depth level including first object level ,default is 3 * @return array objects prepared for display */ public function prepareForDisplay($objectsArray, $sampleObject = null, $depthLevel = 0, $maxDepthLevel = 3) { $depthLevel++; foreach ($objectsArray as &$object) { $notObject = false; // support array of arrays instead of array of objects if (is_array($object)) { $object = (object) $object; $notObject = true; } $objectProperties = $this->prepareForStatusDisplay($object); if (($notObject === false || $notObject === true && !is_null($sampleObject)) && $depthLevel == 1) { if (is_null($sampleObject)) { $sampleObjectForWrapper = $object; } else { $sampleObjectForWrapper = $sampleObject; } $wrapped = AbstractWrapper::wrap($sampleObjectForWrapper, $this->query->entityManager); $meta = $wrapped->getMetadata(); } foreach ($objectProperties as $objectPropertyName => $objectPropertyValue) { if (is_string($objectPropertyValue) && strlen($objectPropertyValue) <= 5) { $textObjectPropertyName = $objectPropertyName . "Text"; if (array_key_exists($objectPropertyValue, $this->languages)) { $object->{$textObjectPropertyName} = $this->languages[$objectPropertyValue]; } elseif (strlen($objectPropertyValue) == 2 && array_key_exists($objectPropertyValue, $this->countries)) { $object->{$textObjectPropertyName} = $this->countries[$objectPropertyValue]; } } elseif ($objectPropertyValue instanceof \DateTime) { $formattedString = $objectPropertyValue->format("D, d M Y"); if ($formattedString == Time::UNIX_DATE_STRING) { $formattedString = $objectPropertyValue->format("H:i"); } $object->{$objectPropertyName} = $formattedString; } elseif (is_object($objectPropertyValue) && $depthLevel != $maxDepthLevel) { $objectsPropertyValue = $this->prepareForDisplay(array($objectPropertyValue), $sampleObject, $depthLevel, $maxDepthLevel); $object->{$objectPropertyName} = reset($objectsPropertyValue); } elseif (is_array($objectPropertyValue) && array_key_exists("id", $objectPropertyValue) && isset($meta) && $meta->isSingleValuedAssociation($objectPropertyName)) { $object->{$objectPropertyName} = $this->query->find($meta->getAssociationMapping($objectPropertyName)["targetEntity"], $objectPropertyValue["id"]); } } } return $objectsArray; }
/** * {@inheritDoc} */ public function onSlugCompletion(SluggableAdapter $ea, array &$config, $object, &$slug) { $this->om = $ea->getObjectManager(); $isInsert = $this->om->getUnitOfWork()->isScheduledForInsert($object); if (!$isInsert) { $options = $config['handlers'][get_called_class()]; $wrapped = AbstractWrapper::wrap($object, $this->om); $oldSlug = $wrapped->getPropertyValue($config['slug']); $mappedByConfig = $this->sluggable->getConfiguration($this->om, $options['relationClass']); if ($mappedByConfig) { $meta = $this->om->getClassMetadata($options['relationClass']); if (!$meta->isSingleValuedAssociation($options['mappedBy'])) { throw new InvalidMappingException("Unable to find " . $wrapped->getMetadata()->name . " relation - [{$options['mappedBy']}] in class - {$meta->name}"); } if (!isset($mappedByConfig['slugs'][$options['inverseSlugField']])) { throw new InvalidMappingException("Unable to find slug field - [{$options['inverseSlugField']}] in class - {$meta->name}"); } $mappedByConfig['slug'] = $mappedByConfig['slugs'][$options['inverseSlugField']]['slug']; $mappedByConfig['mappedBy'] = $options['mappedBy']; $ea->replaceInverseRelative($object, $mappedByConfig, $slug, $oldSlug); $uow = $this->om->getUnitOfWork(); // update in memory objects foreach ($uow->getIdentityMap() as $className => $objects) { // for inheritance mapped classes, only root is always in the identity map if ($className !== $mappedByConfig['useObjectClass']) { continue; } foreach ($objects as $object) { if (property_exists($object, '__isInitialized__') && !$object->__isInitialized__) { continue; } $oid = spl_object_hash($object); $objectSlug = $meta->getReflectionProperty($mappedByConfig['slug'])->getValue($object); if (preg_match("@^{$oldSlug}@smi", $objectSlug)) { $objectSlug = str_replace($oldSlug, $slug, $objectSlug); $meta->getReflectionProperty($mappedByConfig['slug'])->setValue($object, $objectSlug); $ea->setOriginalObjectProperty($uow, $oid, $mappedByConfig['slug'], $objectSlug); } } } } } }
/** * {@inheritDoc} */ public function getSimilarSlugs($object, $meta, array $config, $slug) { $em = $this->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $em); $qb = $em->createQueryBuilder(); $qb->select('rec.' . $config['slug'])->from($config['useObjectClass'], 'rec')->where($qb->expr()->like('rec.' . $config['slug'], ':slug')); $qb->setParameter('slug', $slug . '%'); // use the unique_base to restrict the uniqueness check if ($config['unique'] && isset($config['unique_base'])) { $ubase = $wrapped->getPropertyValue($config['unique_base']); if (array_key_exists($config['unique_base'], $wrapped->getMetadata()->getAssociationMappings())) { $mapping = $wrapped->getMetadata()->getAssociationMapping($config['unique_base']); } else { $mapping = false; } if ($ubase && !$mapping) { $qb->andWhere('rec.' . $config['unique_base'] . ' = :unique_base'); $qb->setParameter(':unique_base', $ubase); } elseif ($ubase && $mapping && in_array($mapping['type'], array(ClassMetadataInfo::ONE_TO_ONE, ClassMetadataInfo::MANY_TO_ONE))) { $mappedAlias = 'mapped_' . $config['unique_base']; $wrappedUbase = AbstractWrapper::wrap($ubase, $em); $qb->innerJoin('rec.' . $config['unique_base'], $mappedAlias); foreach (array_keys($mapping['targetToSourceKeyColumns']) as $i => $mappedKey) { $mappedProp = $wrappedUbase->getMetadata()->fieldNames[$mappedKey]; $qb->andWhere($qb->expr()->eq($mappedAlias . '.' . $mappedProp, ':assoc' . $i)); $qb->setParameter(':assoc' . $i, $wrappedUbase->getPropertyValue($mappedProp)); } } else { $qb->andWhere($qb->expr()->isNull('rec.' . $config['unique_base'])); } } // include identifiers foreach ((array) $wrapped->getIdentifier(false) as $id => $value) { if (!$meta->isIdentifier($config['slug'])) { $qb->andWhere($qb->expr()->neq('rec.' . $id, ':' . $id)); $qb->setParameter($id, $value); } } $q = $qb->getQuery(); $q->setHydrationMode(Query::HYDRATE_ARRAY); return $q->execute(); }
/** * {@inheritDoc} */ public function onSlugCompletion(SluggableAdapter $ea, array &$config, $object, &$slug) { if (!$this->isInsert) { $options = $config['handlers'][get_called_class()]; $wrapped = AbstractWrapper::wrap($object, $this->om); $meta = $wrapped->getMetadata(); $target = $wrapped->getPropertyValue($config['slug']); $config['pathSeparator'] = $this->usedPathSeparator; $ea->replaceRelative($object, $config, $target . $config['pathSeparator'], $slug); $uow = $this->om->getUnitOfWork(); // update in memory objects foreach ($uow->getIdentityMap() as $className => $objects) { // for inheritance mapped classes, only root is always in the identity map if ($className !== $wrapped->getRootObjectName()) { continue; } foreach ($objects as $object) { if (property_exists($object, '__isInitialized__') && !$object->__isInitialized__) { continue; } $oid = spl_object_hash($object); $objectSlug = $meta->getReflectionProperty($config['slug'])->getValue($object); if (preg_match("@^{$target}{$config['pathSeparator']}@smi", $objectSlug)) { $objectSlug = str_replace($target, $slug, $objectSlug); $meta->getReflectionProperty($config['slug'])->setValue($object, $objectSlug); $ea->setOriginalObjectProperty($uow, $oid, $config['slug'], $objectSlug); } } } } }
/** * {@inheritDoc} */ public function setTranslationValue($object, $field, $value) { $em = $this->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $em); $meta = $wrapped->getMetadata(); $type = Type::getType($meta->getTypeOfField($field)); $value = $type->convertToPHPValue($value, $em->getConnection()->getDatabasePlatform()); $wrapped->setPropertyValue($field, $value); }
/** * Update the $node with a diferent $parent * destination * * @param EntityManager $em * @param object $node - target node * @param object $parent - destination node * @param string $position * @throws Gedmo\Exception\UnexpectedValueException * @return void */ public function updateNode(EntityManager $em, $node, $parent, $position = 'FirstChild') { // die (1); $wrapped = AbstractWrapper::wrap($node, $em); $meta = $wrapped->getMetadata(); $config = $this->listener->getConfiguration($em, $meta->name); $rootId = isset($config['root']) ? $wrapped->getPropertyValue($config['root']) : null; $identifierField = $meta->getSingleIdentifierFieldName(); $nodeId = $wrapped->getIdentifier(); $left = $wrapped->getPropertyValue($config['left']); $right = $wrapped->getPropertyValue($config['right']); $isNewNode = empty($left) && empty($right); if ($isNewNode) { $left = 1; $right = 2; } // var_dump($node); // var_dump($isNewNode); $oid = spl_object_hash($node); if (isset($this->nodePositions[$oid])) { $position = $this->nodePositions[$oid]; } // print "\n".$position." ".$node->getTitle()."(".$oid.")"; $level = 0; $treeSize = $right - $left + 1; $newRootId = null; if ($parent) { $wrappedParent = AbstractWrapper::wrap($parent, $em); $parentRootId = isset($config['root']) ? $wrappedParent->getPropertyValue($config['root']) : null; $parentLeft = $wrappedParent->getPropertyValue($config['left']); $parentRight = $wrappedParent->getPropertyValue($config['right']); if (!$isNewNode && $rootId === $parentRootId && $parentLeft >= $left && $parentRight <= $right) { throw new UnexpectedValueException("Cannot set child as parent to node: {$nodeId}"); } if (isset($config['level'])) { $level = $wrappedParent->getPropertyValue($config['level']); } switch ($position) { case self::PREV_SIBLING: $newParent = $wrappedParent->getPropertyValue($config['parent']); if (is_null($newParent) && (isset($config['root']) || $isNewNode)) { throw new UnexpectedValueException("Cannot persist sibling for a root node, tree operation is not possible"); } $wrapped->setPropertyValue($config['parent'], $newParent); $em->getUnitOfWork()->recomputeSingleEntityChangeSet($meta, $node); $start = $parentLeft; break; case self::NEXT_SIBLING: $newParent = $wrappedParent->getPropertyValue($config['parent']); if (is_null($newParent) && (isset($config['root']) || $isNewNode)) { throw new UnexpectedValueException("Cannot persist sibling for a root node, tree operation is not possible"); } $wrapped->setPropertyValue($config['parent'], $newParent); $em->getUnitOfWork()->recomputeSingleEntityChangeSet($meta, $node); $start = $parentRight + 1; break; case self::LAST_CHILD: $start = $parentRight; $level++; break; case self::FIRST_CHILD: default: $start = $parentLeft + 1; $level++; break; } $this->shiftRL($em, $config['useObjectClass'], $start, $treeSize, $parentRootId); if (!$isNewNode && $rootId === $parentRootId && $left >= $start) { $left += $treeSize; $wrapped->setPropertyValue($config['left'], $left); } if (!$isNewNode && $rootId === $parentRootId && $right >= $start) { $right += $treeSize; $wrapped->setPropertyValue($config['right'], $right); } $newRootId = $parentRootId; } elseif (!isset($config['root'])) { $start = isset($this->treeEdges[$meta->name]) ? $this->treeEdges[$meta->name] : $this->max($em, $config['useObjectClass']); $this->treeEdges[$meta->name] = $start + 2; $start++; } else { $start = 1; $newRootId = $nodeId; } // die ('Update Node'); $diff = $start - $left; if (!$isNewNode) { $levelDiff = isset($config['level']) ? $level - $wrapped->getPropertyValue($config['level']) : null; $this->shiftRangeRL($em, $config['useObjectClass'], $left, $right, $diff, $rootId, $newRootId, $levelDiff); $this->shiftRL($em, $config['useObjectClass'], $left, -$treeSize, $rootId); } else { $qb = $em->createQueryBuilder(); $qb->update($config['useObjectClass'], 'node'); if (isset($config['root'])) { $qb->set('node.' . $config['root'], $newRootId); $wrapped->setPropertyValue($config['root'], $newRootId); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['root'], $newRootId); } if (isset($config['level'])) { $qb->set('node.' . $config['level'], $level); $wrapped->setPropertyValue($config['level'], $level); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['level'], $level); } if (isset($newParent)) { $wrappedNewParent = AbstractWrapper::wrap($newParent, $em); $newParentId = $wrappedNewParent->getIdentifier(); $qb->set('node.' . $config['parent'], $newParentId); $wrapped->setPropertyValue($config['parent'], $newParent); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['parent'], $newParent); } if (isset($wrappedParent)) { $this->setPathData($qb, $wrapped, isset($newParent) ? $newParent : $wrappedParent); } $qb->set('node.' . $config['left'], $left + $diff); $qb->set('node.' . $config['right'], $right + $diff); $qb->where("node.{$identifierField} = {$nodeId}"); //var_dump ($qb->getDQL()); //exit(); $qb->getQuery()->getSingleScalarResult(); $wrapped->setPropertyValue($config['left'], $left + $diff); $wrapped->setPropertyValue($config['right'], $right + $diff); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['left'], $left + $diff); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['right'], $right + $diff); } }
function updateChildrenPath($em, $node) { $wrapped = AbstractWrapper::wrap($node, $em); $meta = $wrapped->getMetadata(); $config = $this->listener->getConfiguration($em, $meta->name); foreach ($em->getRepository($config['useObjectClass'])->children($node, false, $config['left']) as $child) { $this->updateNodePath($em, $child, $child->getParent()); } }
/** * Create a new Log instance * * @param string $action * @param object $object * @param LoggableAdapter $ea * @return \Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry|null */ protected function createLogEntry($action, $object, LoggableAdapter $ea) { $om = $ea->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $om); $meta = $wrapped->getMetadata(); if ($config = $this->getConfiguration($om, $meta->name)) { $logEntryClass = $this->getLogEntryClass($ea, $meta->name); $logEntryMeta = $om->getClassMetadata($logEntryClass); /** @var \Gedmo\Loggable\Entity\LogEntry $logEntry */ $logEntry = $logEntryMeta->newInstance(); $logEntry->setAction($action); $logEntry->setUsername($this->username); $logEntry->setObjectClass($meta->name); $logEntry->setLoggedAt(); // check for the availability of the primary key $uow = $om->getUnitOfWork(); if ($action === self::ACTION_CREATE && $ea->isPostInsertGenerator($meta)) { $this->pendingLogEntryInserts[spl_object_hash($object)] = $logEntry; } else { $logEntry->setObjectId($wrapped->getIdentifier()); } $newValues = array(); if ($action !== self::ACTION_REMOVE && isset($config['versioned'])) { foreach ($ea->getObjectChangeSet($uow, $object) as $field => $changes) { if (!in_array($field, $config['versioned'])) { continue; } $value = $changes[1]; if ($meta->isSingleValuedAssociation($field) && $value) { $oid = spl_object_hash($value); $wrappedAssoc = AbstractWrapper::wrap($value, $om); $value = $wrappedAssoc->getIdentifier(false); if (!is_array($value) && !$value) { $this->pendingRelatedObjects[$oid][] = array('log' => $logEntry, 'field' => $field); } } $newValues[$field] = $value; } $logEntry->setData($newValues); } if ($action === self::ACTION_UPDATE && 0 === count($newValues)) { return null; } $version = 1; if ($action !== self::ACTION_CREATE) { $version = $ea->getNewVersion($logEntryMeta, $object); if (empty($version)) { // was versioned later $version = 1; } } $logEntry->setVersion($version); $this->prePersistLogEntry($logEntry, $object); $om->persist($logEntry); $uow->computeChangeSet($logEntryMeta, $logEntry); return $logEntry; } return null; }
/** * Transliterates the slug and prefixes the slug * by relative one * * @param string $text * @param string $separator * @param object $object * * @return string */ public function transliterate($text, $separator, $object) { $result = call_user_func_array($this->originalTransliterator, array($text, $separator, $object)); $wrapped = AbstractWrapper::wrap($object, $this->om); $relation = $wrapped->getPropertyValue($this->usedOptions['relationField']); if ($relation) { $wrappedRelation = AbstractWrapper::wrap($relation, $this->om); $slug = $wrappedRelation->getPropertyValue($this->usedOptions['relationSlugField']); if (isset($this->usedOptions['urilize']) && $this->usedOptions['urilize']) { $slug = call_user_func_array($this->originalTransliterator, array($slug, $separator, $object)); } $result = $slug . $this->usedOptions['separator'] . $result; } $this->sluggable->setTransliterator($this->originalTransliterator); return $result; }
/** * @param LoggableAdapter $ea * @param Log $logEntry * @param $object * @param $message * @return LogParent */ protected function addLogParent(LoggableAdapter $ea, Log $logEntry, $object, $message, $childObject, $fieldName) { $om = $ea->getObjectManager(); $parentLogEntry = new LogParent(); $parentLogEntry->setAction($message); $parentLogEntry->setUsername($this->username); $parentLogEntry->setSourceUsername($this->sourceUsername); $wrappedParent = AbstractWrapper::wrap($object, $om); $parentLogEntry->setObjectClass($wrappedParent->getMetadata()->name); $parentLogEntry->setObjectId($wrappedParent->getIdentifier()); $parentLogEntry->setFieldName($fieldName); $logEntry->addParent($parentLogEntry); $this->pendingParents[spl_object_hash($object)][] = array('log' => $parentLogEntry, 'field' => 'objectId'); $this->pendingParents[spl_object_hash($childObject)][] = array('log' => $parentLogEntry, 'field' => 'childId'); return $parentLogEntry; }
/** * Process an object's unchanged data * * @access protected * @param array $unchangedData * @param object $object * * @return array unchanged data */ protected function processObjectUnchangedData($unchangedData, $object) { $objectManager = $this->eventAdapter->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $objectManager); $meta = $wrapped->getMetadata(); $unchangedValues = array(); foreach ($unchangedData as $field => $value) { if ($meta->isSingleValuedAssociation($field) && $value) { $wrappedAssoc = AbstractWrapper::wrap($value, $objectManager); $value = $wrappedAssoc->getIdentifier(false); } $unchangedValues[$field] = $value; } return $unchangedValues; }
/** * {@inheritDoc} */ public function setTranslationValue($object, $field, $value) { $dm = $this->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $dm); $meta = $wrapped->getMetadata(); $mapping = $meta->getFieldMapping($field); $type = $this->getType($mapping['type']); $value = $type->convertToPHPValue($value); $wrapped->setPropertyValue($field, $value); }
protected function resetVersionedData($ea, $object) { $om = $ea->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $om); $objectMeta = $wrapped->getMetadata(); $meta = $wrapped->getMetadata(); $config = $this->getConfiguration($om, $meta->name); /** @var UnitOfWork $uow */ $uow = $om->getUnitOfWork(); foreach ($ea->getObjectChangeSet($uow, $object) as $field => $changes) { if (empty($config['versioned']) || !in_array($field, $config['versioned'])) { continue; } $value = $changes[0]; // $this->mapValue($om, $objectMeta, $field, $value); $wrapped->setPropertyValue($field, $value); } // $uow->computeChangeSet($objectMeta, $object); }
/** * Update the $node with a diferent $parent * destination * * @param EntityManager $em * @param object $node - target node * @param object $parent - destination node * @param string $position * * @throws \Gedmo\Exception\UnexpectedValueException */ public function updateNode(EntityManager $em, $node, $parent, $position = 'FirstChild') { $wrapped = AbstractWrapper::wrap($node, $em); /** @var ClassMetadata $meta */ $meta = $wrapped->getMetadata(); $config = $this->listener->getConfiguration($em, $meta->name); $root = isset($config['root']) ? $wrapped->getPropertyValue($config['root']) : null; $identifierField = $meta->getSingleIdentifierFieldName(); $nodeId = $wrapped->getIdentifier(); $left = $wrapped->getPropertyValue($config['left']); $right = $wrapped->getPropertyValue($config['right']); $isNewNode = empty($left) && empty($right); if ($isNewNode) { $left = 1; $right = 2; } $oid = spl_object_hash($node); if (isset($this->nodePositions[$oid])) { $position = $this->nodePositions[$oid]; } $level = 0; $treeSize = $right - $left + 1; $newRoot = null; if ($parent) { $wrappedParent = AbstractWrapper::wrap($parent, $em); $parentRoot = isset($config['root']) ? $wrappedParent->getPropertyValue($config['root']) : null; $parentOid = spl_object_hash($parent); $parentLeft = $wrappedParent->getPropertyValue($config['left']); $parentRight = $wrappedParent->getPropertyValue($config['right']); if (empty($parentLeft) && empty($parentRight)) { // parent node is a new node, but wasn't processed yet (due to Doctrine commit order calculator redordering) // We delay processing of node to the moment parent node will be processed if (!isset($this->delayedNodes[$parentOid])) { $this->delayedNodes[$parentOid] = array(); } $this->delayedNodes[$parentOid][] = array('node' => $node, 'position' => $position); return; } if (!$isNewNode && $root === $parentRoot && $parentLeft >= $left && $parentRight <= $right) { throw new UnexpectedValueException("Cannot set child as parent to node: {$nodeId}"); } if (isset($config['level'])) { $level = $wrappedParent->getPropertyValue($config['level']); } switch ($position) { case self::PREV_SIBLING: if (property_exists($node, 'sibling')) { $wrappedSibling = AbstractWrapper::wrap($node->sibling, $em); $start = $wrappedSibling->getPropertyValue($config['left']); $level++; } else { $newParent = $wrappedParent->getPropertyValue($config['parent']); if (is_null($newParent) && (isset($config['root']) || $isNewNode)) { throw new UnexpectedValueException("Cannot persist sibling for a root node, tree operation is not possible"); } $wrapped->setPropertyValue($config['parent'], $newParent); $em->getUnitOfWork()->recomputeSingleEntityChangeSet($meta, $node); $start = $parentLeft; } break; case self::NEXT_SIBLING: if (property_exists($node, 'sibling')) { $wrappedSibling = AbstractWrapper::wrap($node->sibling, $em); $start = $wrappedSibling->getPropertyValue($config['right']) + 1; $level++; } else { $newParent = $wrappedParent->getPropertyValue($config['parent']); if (is_null($newParent) && (isset($config['root']) || $isNewNode)) { throw new UnexpectedValueException("Cannot persist sibling for a root node, tree operation is not possible"); } $wrapped->setPropertyValue($config['parent'], $newParent); $em->getUnitOfWork()->recomputeSingleEntityChangeSet($meta, $node); $start = $parentRight + 1; } break; case self::LAST_CHILD: $start = $parentRight; $level++; break; case self::FIRST_CHILD: default: $start = $parentLeft + 1; $level++; break; } $this->shiftRL($em, $config['useObjectClass'], $start, $treeSize, $parentRoot); if (!$isNewNode && $root === $parentRoot && $left >= $start) { $left += $treeSize; $wrapped->setPropertyValue($config['left'], $left); } if (!$isNewNode && $root === $parentRoot && $right >= $start) { $right += $treeSize; $wrapped->setPropertyValue($config['right'], $right); } $newRoot = $parentRoot; } elseif (!isset($config['root'])) { $start = isset($this->treeEdges[$meta->name]) ? $this->treeEdges[$meta->name] : $this->max($em, $config['useObjectClass']); $this->treeEdges[$meta->name] = $start + 2; $start++; } else { $start = 1; if ($meta->isSingleValuedAssociation($config['root'])) { $newRoot = $node; } else { $newRoot = $wrapped->getIdentifier(); } } $diff = $start - $left; if (!$isNewNode) { $levelDiff = isset($config['level']) ? $level - $wrapped->getPropertyValue($config['level']) : null; $this->shiftRangeRL($em, $config['useObjectClass'], $left, $right, $diff, $root, $newRoot, $levelDiff); $this->shiftRL($em, $config['useObjectClass'], $left, -$treeSize, $root); } else { $qb = $em->createQueryBuilder(); $qb->update($config['useObjectClass'], 'node'); if (isset($config['root'])) { $qb->set('node.' . $config['root'], ':rid'); $qb->setParameter('rid', $newRoot); $wrapped->setPropertyValue($config['root'], $newRoot); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['root'], $newRoot); } if (isset($config['level'])) { $qb->set('node.' . $config['level'], $level); $wrapped->setPropertyValue($config['level'], $level); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['level'], $level); } if (isset($newParent)) { $wrappedNewParent = AbstractWrapper::wrap($newParent, $em); $newParentId = $wrappedNewParent->getIdentifier(); $qb->set('node.' . $config['parent'], ':pid'); $qb->setParameter('pid', $newParentId); $wrapped->setPropertyValue($config['parent'], $newParent); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['parent'], $newParent); } $qb->set('node.' . $config['left'], $left + $diff); $qb->set('node.' . $config['right'], $right + $diff); // node id cannot be null $qb->where($qb->expr()->eq('node.' . $identifierField, ':id')); $qb->setParameter('id', $nodeId); $qb->getQuery()->getSingleScalarResult(); $wrapped->setPropertyValue($config['left'], $left + $diff); $wrapped->setPropertyValue($config['right'], $right + $diff); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['left'], $left + $diff); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['right'], $right + $diff); } if (isset($this->delayedNodes[$oid])) { foreach ($this->delayedNodes[$oid] as $nodeData) { $this->updateNode($em, $nodeData['node'], $node, $nodeData['position']); } } }
/** * Update node and closures * * @param EntityManager $em * @param object $node * @param object $oldParent */ public function updateNode(EntityManager $em, $node, $oldParent) { $wrapped = AbstractWrapper::wrap($node, $em); $meta = $wrapped->getMetadata(); $config = $this->listener->getConfiguration($em, $meta->name); $closureMeta = $em->getClassMetadata($config['closure']); $nodeId = $wrapped->getIdentifier(); $parent = $wrapped->getPropertyValue($config['parent']); $table = $closureMeta->getTableName(); $conn = $em->getConnection(); // ensure integrity if ($parent) { $dql = "SELECT COUNT(c) FROM {$closureMeta->name} c"; $dql .= " WHERE c.ancestor = :node"; $dql .= " AND c.descendant = :parent"; $q = $em->createQuery($dql); $q->setParameters(compact('node', 'parent')); if ($q->getSingleScalarResult()) { throw new \Gedmo\Exception\UnexpectedValueException("Cannot set child as parent to node: {$nodeId}"); } } if ($oldParent) { $subQuery = "SELECT c2.id FROM {$table} c1"; $subQuery .= " JOIN {$table} c2 ON c1.descendant = c2.descendant"; $subQuery .= " WHERE c1.ancestor = :nodeId AND c2.depth > c1.depth"; $ids = $conn->fetchAll($subQuery, compact('nodeId')); if ($ids) { $ids = array_map(function ($el) { return $el['id']; }, $ids); } // using subquery directly, sqlite acts unfriendly $query = "DELETE FROM {$table} WHERE id IN (" . implode(', ', $ids) . ")"; if (!$conn->executeQuery($query)) { throw new RuntimeException('Failed to remove old closures'); } } if ($parent) { $wrappedParent = AbstractWrapper::wrap($parent, $em); $parentId = $wrappedParent->getIdentifier(); $query = "SELECT c1.ancestor, c2.descendant, (c1.depth + c2.depth + 1) AS depth"; $query .= " FROM {$table} c1, {$table} c2"; $query .= " WHERE c1.descendant = :parentId"; $query .= " AND c2.ancestor = :nodeId"; $closures = $conn->fetchAll($query, compact('nodeId', 'parentId')); foreach ($closures as $closure) { if (!$conn->insert($table, $closure)) { throw new RuntimeException('Failed to insert new Closure record'); } } } if (isset($config['level'])) { $this->pendingNodesLevelProcess[$nodeId] = $node; } }
/** * Create a new Log instance * * @param string $action * @param object $object * @param LoggableAdapter $ea * * @return \Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry|null */ protected function createLogEntry($action, $object, LoggableAdapter $ea) { $om = $ea->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $om); $meta = $wrapped->getMetadata(); // Filter embedded documents if (isset($meta->isEmbeddedDocument) && $meta->isEmbeddedDocument) { return; } // TODO replace with more generic interface if ($object instanceof BlockInterface && $object->isPublish()) { return; } if ($config = $this->getConfiguration($om, $meta->name)) { $logEntryClass = $this->getLogEntryClass($ea, $meta->name); $logEntryMeta = $om->getClassMetadata($logEntryClass); /** @var \Gedmo\Loggable\Entity\LogEntry $logEntry */ $logEntry = $logEntryMeta->newInstance(); $logEntry->setAction($action); $logEntry->setUsername($this->username); $logEntry->setObjectClass($meta->name); $logEntry->setLoggedAt(); // check for the availability of the primary key /** @var UnitOfWork $uow */ $uow = $om->getUnitOfWork(); if ($action === self::ACTION_CREATE && $ea->isPostInsertGenerator($meta)) { $this->pendingLogEntryInserts[spl_object_hash($object)] = $logEntry; } else { $logEntry->setObjectId($wrapped->getIdentifier()); } $newValues = array(); if (isset($config['versioned'])) { //$action !== self::ACTION_REMOVE && $newValues = $this->getObjectChangeSetData($ea, $object, $logEntry); $logEntry->setData($newValues); if (isset($this->changeSets[spl_object_hash($object)])) { // Recalculate changeset data from scratch because we are overwriting // and we are at risk to store only the latest change if we are flushing // the object multiple times in the same request. This happens for example // when we are sorting objects. $prevValues = $this->changeSets[spl_object_hash($object)]; $newValues = array_merge($prevValues, $newValues); } else { $this->changeSets[spl_object_hash($object)] = $newValues; } } if ($action === self::ACTION_UPDATE && 0 === count($newValues)) { return null; } $version = 1; if ($action !== self::ACTION_CREATE) { $version = $ea->getNewVersion($logEntryMeta, $object); if (empty($version)) { // was versioned later $version = 1; } } $logEntry->setVersion($version); $this->prePersistLogEntry($logEntry, $object); // TODO replace with more generic code if ($object instanceof BlockInterface) { // Check if this rootVersion has an Entry already, if so, update that instead $existingLogEntry = $om->getRepository($logEntryClass)->findOneBy(['rootVersion' => $this->rootVersion, 'objectId' => $object->getId()]); if ($existingLogEntry) { unset($this->pendingLogEntryInserts[spl_object_hash($object)]); $logEntry = $existingLogEntry; $logEntry->setUsername($this->username); $logEntry->setObjectClass($meta->name); $logEntry->setLoggedAt(); $logEntry->setData($newValues); } if ($action !== self::ACTION_CREATE) { $uow->clearEntityChangeSet(spl_object_hash($object)); // $uow->detach($object); } // Reset version number to that of owner Document, so we keep a tree // of blocks together on a single version # $logEntry->setRootVersion($this->rootVersion); $logEntry->setRootId($object instanceof BlockOwnerInterface ? $object->getId() : $object->getOwner()->getId()); // $uow->computeChangeSet($logEntryMeta, $logEntry); } $om->persist($logEntry); $uow->computeChangeSet($logEntryMeta, $logEntry); return $logEntry; } return null; }
/** * Creates the translation for object being flushed * * @param TranslatableAdapter $ea * @param object $object * @param boolean $isInsert * * @throws \UnexpectedValueException - if locale is not valid, or * primary key is composite, missing or invalid */ private function handleTranslatableObjectUpdate(TranslatableAdapter $ea, $object, $isInsert) { $om = $ea->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $om); $meta = $wrapped->getMetadata(); $config = $this->getConfiguration($om, $meta->name); // no need cache, metadata is loaded only once in MetadataFactoryClass $translationClass = $this->getTranslationClass($ea, $config['useObjectClass']); $translationMetadata = $om->getClassMetadata($translationClass); // check for the availability of the primary key $objectId = $wrapped->getIdentifier(); // load the currently used locale $locale = $this->getTranslatableLocale($object, $meta); $uow = $om->getUnitOfWork(); $oid = spl_object_hash($object); $changeSet = $ea->getObjectChangeSet($uow, $object); $translatableFields = $config['fields']; foreach ($translatableFields as $field) { $wasPersistedSeparetely = false; $skip = isset($this->translatedInLocale[$oid]) && $locale === $this->translatedInLocale[$oid]; $skip = $skip && !isset($changeSet[$field]) && !$this->getTranslationInDefaultLocale($oid, $field); if ($skip) { continue; // locale is same and nothing changed } $translation = null; foreach ($ea->getScheduledObjectInsertions($uow) as $trans) { if ($locale !== $this->defaultLocale && get_class($trans) === $translationClass && $trans->getLocale() === $this->defaultLocale && $trans->getField() === $field && $this->belongsToObject($ea, $trans, $object)) { $this->setTranslationInDefaultLocale($oid, $field, $trans); break; } } // lookup persisted translations foreach ($ea->getScheduledObjectInsertions($uow) as $trans) { if (get_class($trans) !== $translationClass || $trans->getLocale() !== $locale || $trans->getField() !== $field) { continue; } if ($ea->usesPersonalTranslation($translationClass)) { $wasPersistedSeparetely = $trans->getObject() === $object; } else { $wasPersistedSeparetely = $trans->getObjectClass() === $config['useObjectClass'] && $trans->getForeignKey() === $objectId; } if ($wasPersistedSeparetely) { $translation = $trans; break; } } // check if translation already is created if (!$isInsert && !$translation) { $translation = $ea->findTranslation($wrapped, $locale, $field, $translationClass, $config['useObjectClass']); } // create new translation if translation not already created and locale is different from default locale, otherwise, we have the date in the original record $persistNewTranslation = !$translation && ($locale !== $this->defaultLocale || $this->persistDefaultLocaleTranslation); if ($persistNewTranslation) { $translation = $translationMetadata->newInstance(); $translation->setLocale($locale); $translation->setField($field); if ($ea->usesPersonalTranslation($translationClass)) { $translation->setObject($object); } else { $translation->setObjectClass($config['useObjectClass']); $translation->setForeignKey($objectId); } } if ($translation) { // set the translated field, take value using reflection $content = $ea->getTranslationValue($object, $field); $translation->setContent($content); // check if need to update in database $transWrapper = AbstractWrapper::wrap($translation, $om); if ((is_null($content) && !$isInsert || is_bool($content) || is_int($content) || is_string($content) && strlen($content) > 0 || !empty($content)) && ($isInsert || !$transWrapper->getIdentifier() || isset($changeSet[$field]))) { if ($isInsert && !$objectId && !$ea->usesPersonalTranslation($translationClass)) { // if we do not have the primary key yet available // keep this translation in memory to insert it later with foreign key $this->pendingTranslationInserts[spl_object_hash($object)][] = $translation; } else { // persist and compute change set for translation if ($wasPersistedSeparetely) { $ea->recomputeSingleObjectChangeset($uow, $translationMetadata, $translation); } else { $om->persist($translation); $uow->computeChangeSet($translationMetadata, $translation); } } } } if ($isInsert && $this->getTranslationInDefaultLocale($oid, $field) !== null) { // We can't rely on object field value which is created in non-default locale. // If we provide translation for default locale as well, the latter is considered to be trusted // and object content should be overridden. $wrapped->setPropertyValue($field, $this->getTranslationInDefaultLocale($oid, $field)->getContent()); $ea->recomputeSingleObjectChangeset($uow, $meta, $object); $this->removeTranslationInDefaultLocale($oid, $field); } } $this->translatedInLocale[$oid] = $locale; // check if we have default translation and need to reset the translation if (!$isInsert && strlen($this->defaultLocale)) { $this->validateLocale($this->defaultLocale); $modifiedChangeSet = $changeSet; foreach ($changeSet as $field => $changes) { if (in_array($field, $translatableFields)) { if ($locale !== $this->defaultLocale) { $ea->setOriginalObjectProperty($uow, $oid, $field, $changes[0]); unset($modifiedChangeSet[$field]); } } } $ea->recomputeSingleObjectChangeset($uow, $meta, $object); // cleanup current changeset only if working in a another locale different than de default one, otherwise the changeset will always be reverted if ($locale !== $this->defaultLocale) { $ea->clearObjectChangeSet($uow, $oid); // recompute changeset only if there are changes other than reverted translations if ($modifiedChangeSet || $this->hasTranslationsInDefaultLocale($oid)) { foreach ($modifiedChangeSet as $field => $changes) { $ea->setOriginalObjectProperty($uow, $oid, $field, $changes[0]); } foreach ($translatableFields as $field) { if ($this->getTranslationInDefaultLocale($oid, $field) !== null) { $wrapped->setPropertyValue($field, $this->getTranslationInDefaultLocale($oid, $field)->getContent()); $this->removeTranslationInDefaultLocale($oid, $field); } } $ea->recomputeSingleObjectChangeset($uow, $meta, $object); } } } }
/** * Create a new Log instance * * @param string $action * @param object $object * @param LoggableAdapter $ea * * @return \Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry|null */ protected function createLogEntry($action, $object, LoggableAdapter $ea) { $om = $ea->getObjectManager(); $wrapped = AbstractWrapper::wrap($object, $om); $meta = $wrapped->getMetadata(); // Filter embedded documents $ident = $meta->getIdentifier(); if (empty($ident) || empty($ident[0])) { return; } if ($config = $this->getConfiguration($om, $meta->name)) { $logEntryClass = $this->getLogEntryClass($ea, $meta->name); $logEntryMeta = $om->getClassMetadata($logEntryClass); /** @var \Gedmo\Loggable\Entity\LogEntry $logEntry */ $logEntry = $logEntryMeta->newInstance(); $logEntry->setAction($action); $logEntry->setUsername($this->username); $logEntry->setObjectClass($meta->name); $logEntry->setLoggedAt(); // check for the availability of the primary key $uow = $om->getUnitOfWork(); if ($action === self::ACTION_CREATE && $ea->isPostInsertGenerator($meta)) { $this->pendingLogEntryInserts[spl_object_hash($object)] = $logEntry; } else { $logEntry->setObjectId($wrapped->getIdentifier()); } $newValues = array(); if ($action !== self::ACTION_REMOVE && isset($config['versioned'])) { $newValues = $this->getObjectChangeSetData($ea, $object, $logEntry); $logEntry->setData($newValues); } if ($action === self::ACTION_UPDATE && 0 === count($newValues)) { return null; } $version = 1; if ($action !== self::ACTION_CREATE) { $version = $ea->getNewVersion($logEntryMeta, $object); if (empty($version)) { // was versioned later $version = 1; } } $logEntry->setVersion($version); $this->prePersistLogEntry($logEntry, $object); $om->persist($logEntry); $uow->computeChangeSet($logEntryMeta, $logEntry); return $logEntry; } return null; }