/** * {@inheritDoc} */ public function apply(PropertyMetadata $propertyMetadata, array $collectedValues, MergeContext $context) { $reflectionProperty = $propertyMetadata->reflection; $mergeableObjectCollection = $context->getPropertyAccessor()->getValue($reflectionProperty, $context->getMergeTo()); foreach ($collectedValues['missing'] as $missingValue) { $mergeableObjectCollection[] = $missingValue; } $context->getPropertyAccessor()->setValue($reflectionProperty, $context->getMergeTo(), $mergeableObjectCollection); }
/** * Merges an object property. * * @param PropertyMetadata $property Metadata of the property * @param MergeContext $context The current mergingcontext */ public function mergeObject(PropertyMetadata $property, MergeContext $context) { $reflectionProperty = $property->reflection; $leftValue = $context->getPropertyAccessor()->getValue($reflectionProperty, $context->getMergeFrom()); $rightValue = $context->getPropertyAccessor()->getValue($reflectionProperty, $context->getMergeTo()); if (null === $rightValue) { $context->getPropertyAccessor()->setValue($reflectionProperty, $context->getMergeTo(), $leftValue); } else { $context->getGraphWalker()->accept($leftValue, $rightValue); } }
/** * {@inheritDoc} * * @TODO This mehtod needs to be refactored. */ public function merge(PropertyMetadata $propertyMetadata, MergeContext $context) { $innerType = $propertyMetadata->innerType; $reflectionProperty = $propertyMetadata->reflection; if (!$innerType) { throw new MergeException('You must provide an inner type.'); } $reflectionClass = new \ReflectionClass($innerType); $innerClassMetadata = $context->getGraphWalker()->getMetadataFactory()->getMetadataForClass($innerType); $objectIdentifier = $innerClassMetadata->objectIdentifier; if ($objectIdentifier === null) { throw new MergeException('You must provide at least one identifier field.'); } $sourceCollection = $reflectionProperty->getValue($context->getMergeFrom()); $targetCollection = $reflectionProperty->getValue($context->getMergeTo()); if (!$sourceCollection instanceof \Traversable && !is_array($sourceCollection)) { return; } if (!$targetCollection instanceof \Traversable && !is_array($targetCollection)) { return; } $collectedValues = array('missing' => array(), 'removed' => array()); foreach ($sourceCollection as $sourceItem) { foreach ($targetCollection as $targetItem) { if ($this->isMergeable($objectIdentifier, $reflectionClass, $sourceItem, $targetItem)) { $context->getGraphWalker()->accept($sourceItem, $targetItem); continue 2; } } array_push($collectedValues['missing'], $sourceItem); } $this->applyCollectionMergeStrategy($propertyMetadata, $collectedValues, $context); }
/** * Walks over the objectproperties which are marked as mergeable. * * @param object $mergeFrom * @param object $mergeTo * @param ClassMetadata $classMetadata * * @throws \Exception */ protected function walkProperties($mergeFrom, $mergeTo, $classMetadata) { // Preventing the object to be visited again. $this->visitedObjects[spl_object_hash($mergeFrom)] = true; // Preparing a new MergeContext. $mergeContext = new MergeContext($classMetadata, $this, $mergeFrom, $mergeTo); // Dispatching the premerge event. $this->eventDispatcher->dispatch(Events::PRE_MERGE, new MergeEvent(MergeEvent::TYPE_PRE, $mergeContext)); foreach ($classMetadata->propertyMetadata as $comparableProperty) { /** @var PropertyMetadata $comparableProperty */ if ($comparableProperty->ignoreNullValue) { $currentValue = $mergeContext->getPropertyAccessor()->getValue($comparableProperty->reflection, $mergeContext->getMergeFrom()); if (null === $currentValue) { continue; } } switch ($comparableProperty->type) { case 'string': case 'object': case 'boolean': case 'mixed': // calls a type specified merge method on the visitor. $this->visitor->{'merge' . ucfirst($comparableProperty->type)}($comparableProperty, $mergeContext); break; default: // If the type is not one of the default types, try to merge this property by a handler. try { $this->visitor->mergeByHandler($comparableProperty, $mergeContext); } catch (\Exception $e) { throw $e; } break; } } // Dispatching the postmerge event. $this->eventDispatcher->dispatch(Events::POST_MERGE, new MergeEvent(MergeEvent::TYPE_POST, $mergeContext)); }