/** * Hydrate $object with the provided $data. * * @param array $data * @param object $object * @throws \Exception * @return object */ public function hydrate(array $data, $object) { $this->metadata = $this->objectManager->getClassMetadata(get_class($object)); foreach ($data as $field => &$value) { if ($this->metadata->hasAssociation($field)) { $target = $this->metadata->getAssociationTargetClass($field); if ($this->metadata->isSingleValuedAssociation($field)) { $value = $this->toOne($value, $target); } elseif ($this->metadata->isCollectionValuedAssociation($field)) { $value = $this->toMany($value, $target); } } } return $this->hydrator->hydrate($data, $object); }
/** * Checks if the given relation should be ignored in workflows * * @param ClassMetadata $metadata * @param string $associationName * * @return bool */ protected function isIgnoredInWorkflow(ClassMetadata $metadata, $associationName) { if ($this->isWorkflowField($associationName)) { return true; } return !$metadata->isSingleValuedAssociation($associationName); }
protected function setPropertyType(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata) { /** @var \Doctrine\ODM\PHPCR\Mapping\ClassMetadata $doctrineMetadata */ $propertyName = $propertyMetadata->name; if ($doctrineMetadata->hasField($propertyName) && ($fieldType = $this->normalizeFieldType($doctrineMetadata->getTypeOfField($propertyName)))) { $field = $doctrineMetadata->getFieldMapping($propertyName); if (!empty($field['multivalue'])) { $fieldType = 'array'; } $propertyMetadata->setType($fieldType); } elseif ($doctrineMetadata->hasAssociation($propertyName)) { try { $targetEntity = $doctrineMetadata->getAssociationTargetClass($propertyName); } catch (\Exception $e) { return; } if (null === $this->tryLoadingDoctrineMetadata($targetEntity)) { return; } if (!$doctrineMetadata->isSingleValuedAssociation($propertyName)) { $targetEntity = "ArrayCollection<{$targetEntity}>"; } $propertyMetadata->setType($targetEntity); } }
/** * Hydrate $object with the provided $data. * * @param array $data * @param object $object * @throws \Exception * @return object */ public function hydrate(array $data, $object) { $this->metadata = $this->objectManager->getClassMetadata(get_class($object)); $object = $this->tryConvertArrayToObject($data, $object); foreach ($data as $field => &$value) { $value = $this->hydrateValue($field, $value); if ($value === null) { continue; } // @todo DateTime (and other types) conversion should be handled by doctrine itself in future if (in_array($this->metadata->getTypeOfField($field), array('datetime', 'time', 'date'))) { if (is_int($value)) { $dt = new DateTime(); $dt->setTimestamp($value); $value = $dt; } elseif (is_string($value)) { $value = new DateTime($value); } } if ($this->metadata->hasAssociation($field)) { $target = $this->metadata->getAssociationTargetClass($field); if ($this->metadata->isSingleValuedAssociation($field)) { $value = $this->toOne($value, $target); } elseif ($this->metadata->isCollectionValuedAssociation($field)) { $value = $this->toMany($value, $target); // Automatically merge collections using helper utility $propertyRefl = $this->metadata->getReflectionClass()->getProperty($field); $propertyRefl->setAccessible(true); $previousValue = $propertyRefl->getValue($object); $value = CollectionUtils::intersectUnion($previousValue, $value); } } } return $this->hydrator->hydrate($data, $object); }
/** * Updates a single entity association * * @param string $propertyName * @param array $propertyValue * @param object $resource */ protected function updateEntityAssociation($propertyName, array $propertyValue, $resource, ClassMetadata $entityMetadata) { if ($entityMetadata->isSingleValuedAssociation($propertyName)) { $associationTargetClass = $entityMetadata->getAssociationTargetClass($propertyName); $repository = $this->getRepositoryByTargetClass($associationTargetClass); $associationResource = $repository->findOneBy($propertyValue); if (null !== $associationResource && $this->propertyAccessor->isWritable($resource, $propertyName)) { $this->propertyAccessor->setValue($resource, $propertyName, $associationResource); } } }
/** * @param ClassMetadata $metadata * @param array $assocNames * * @return array */ private function getAssocsConfig(ClassMetadata $metadata, $assocNames) { $assocsConfigs = []; foreach ($assocNames as $assocName) { if (!$metadata->isAssociationInverseSide($assocName)) { continue; } $class = $metadata->getAssociationTargetClass($assocName); if ($metadata->isSingleValuedAssociation($assocName)) { $nullable = $metadata instanceof ClassMetadataInfo && isset($metadata->discriminatorColumn['nullable']) && $metadata->discriminatorColumn['nullable']; $assocsConfigs[$assocName] = ['field_type' => 'A2lix\\AutoFormBundle\\Form\\Type\\AutoFormType', 'data_class' => $class, 'required' => !$nullable]; continue; } $assocsConfigs[$assocName] = ['field_type' => 'Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType', 'entry_type' => 'A2lix\\AutoFormBundle\\Form\\Type\\AutoFormType', 'entry_options' => ['data_class' => $class], 'allow_add' => true, 'by_reference' => false]; } return $assocsConfigs; }
/** * Sets a persistent fields value. * * @param string $field * @param array $args * * @return void * * @throws \BadMethodCallException When no persistent field exists by that name. * @throws \InvalidArgumentException When the wrong target object type is passed to an association. */ private function set($field, $args) { $this->initializeDoctrine(); if ($this->cm->hasField($field) && !$this->cm->isIdentifier($field)) { $this->{$field} = $args[0]; } else { if ($this->cm->hasAssociation($field) && $this->cm->isSingleValuedAssociation($field)) { $targetClass = $this->cm->getAssociationTargetClass($field); if (!$args[0] instanceof $targetClass && $args[0] !== null) { throw new \InvalidArgumentException("Expected persistent object of type '" . $targetClass . "'"); } $this->{$field} = $args[0]; $this->completeOwningSide($field, $targetClass, $args[0]); } else { throw new \BadMethodCallException("no field with name '" . $field . "' exists on '" . $this->cm->getName() . "'"); } } }
protected function setPropertyType(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata) { $propertyName = $propertyMetadata->name; if ($doctrineMetadata->hasField($propertyName) && ($fieldType = $this->normalizeFieldType($doctrineMetadata->getTypeOfField($propertyName)))) { $propertyMetadata->setType($fieldType); } elseif ($doctrineMetadata->hasAssociation($propertyName)) { $targetEntity = $doctrineMetadata->getAssociationTargetClass($propertyName); if (null === ($targetMetadata = $this->tryLoadingDoctrineMetadata($targetEntity))) { return; } // For inheritance schemes, we cannot add any type as we would only add the super-type of the hierarchy. // On serialization, this would lead to only the supertype being serialized, and properties of subtypes // being ignored. if ($targetMetadata instanceof DoctrineClassMetadata && !$targetMetadata->isInheritanceTypeNone()) { return; } if (!$doctrineMetadata->isSingleValuedAssociation($propertyName)) { $targetEntity = "ArrayCollection<{$targetEntity}>"; } $propertyMetadata->setType($targetEntity); } }
/** * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $metadata * @param $model * * @return array */ protected function processAssociationNames(ClassMetadata $metadata, $model) { $data = array(); foreach ($metadata->getAssociationNames() as $assocName) { $propertyValue = $this->readProperty($model, $assocName); if (null === $propertyValue || $metadata->isAssociationInverseSide($assocName)) { continue; } if ($metadata->isSingleValuedAssociation($assocName)) { $assocValue = $this->namingStrategy->modelName($propertyValue, $this->getManager()->getClassMetadata(get_class($propertyValue))); $assocValue = $this->navigator->accept($this->getVisitor(), $assocValue, 'reference'); $data[$assocName] = $assocValue; } else { $data[$assocName] = array(); foreach ($propertyValue as $value) { $assocValue = $this->namingStrategy->modelName($value, $this->getManager()->getClassMetadata(get_class($value))); $assocValue = $this->navigator->accept($this->getVisitor(), $assocValue, 'reference'); $data[$assocName][] = $assocValue; } } } return $data; }
/** * {@inheritDoc} */ public static function validate(array $options, ClassMetadata $meta) { if (!$meta->isSingleValuedAssociation($options['parentRelationField'])) { throw new InvalidMappingException("Unable to find tree parent slug relation through field - [{$options['parentRelationField']}] in class - {$meta->name}"); } }
/** * {@inheritDoc} */ public static function validate(array $options, ClassMetadata $meta) { if (!$meta->isSingleValuedAssociation($options['relationField'])) { throw new InvalidMappingException("Unable to find tree parent slug relation through field - [{$options['relationParentRelationField']}] in class - {$meta->name}"); } // TODO Check parent relation in translatable entity is single valued // (Note: don't know if that's possible here as we need the relationField class metadada) }
/** * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata * @param string $field * @return bool */ private function isFieldSearchable(ClassMetadata $classMetadata, $field) { return $classMetadata->hasField($field) || $classMetadata->hasAssociation($field) && $classMetadata->isSingleValuedAssociation($field); }
protected function unserializeField($data, ClassMetadata $metadata, $document, $field, $mode) { if ($metadata->hasAssociation($field) && $metadata->isSingleValuedAssociation($field)) { $value = $this->unserializeSingleModel($data, $metadata, $document, $field, $mode); } elseif ($metadata->hasAssociation($field)) { $value = $this->unserializeCollection($data, $metadata, $document, $field, $mode); } else { $value = $this->unserializeSingleValue($data, $metadata, $field); } if (isset($value)) { $metadata->setFieldValue($document, $field, $value); } elseif ($mode == self::UNSERIALIZE_UPDATE) { $metadata->setFieldValue($document, $field, null); } }
/** * {@inheritdoc} */ public static function validate(array $options, ClassMetadata $meta) { // Since we cannot know, whether children of this mapped superclass // have or have not given association. if ($meta instanceof ClassMetadataInfo && $meta->isMappedSuperclass) { return; } if (!$meta->isSingleValuedAssociation($options['relationField'])) { throw new InvalidMappingException("Unable to find tree parent slug relation through field - [{$options['relationField']}] in class - {$meta->name}"); } // TODO Check parent relation in translatable entity is single valued // (Note: don't know if that's possible here as we need the relationField class metadata) }
protected function serializeField(ClassMetadata $metadata, $value, $field) { if ($metadata->hasAssociation($field) && $metadata->isSingleValuedAssociation($field)) { return $this->serializeSingleModel($metadata, $value, $field); } elseif ($metadata->hasAssociation($field)) { return $this->serializeCollection($metadata, $value, $field); } else { return $this->serializeSingleValue($metadata, $value, $field); } }
/** * Builds the association value. * * @param ClassMetadata $metadata * @param string $propertyPath * @param string $value * * @return array|object * @throws \Exception */ private function buildAssociationValue(ClassMetadata $metadata, $propertyPath, $value) { $childMetadata = $this->manager->getClassMetadata($metadata->getAssociationTargetClass($propertyPath)); // Single association if ($metadata->isSingleValuedAssociation($propertyPath)) { if (is_string($value) && '#' === substr($value, 0, 1)) { return $this->getReference(substr($value, 1)); } elseif (is_array($value)) { return $this->buildEntity($childMetadata, $value); } throw new \Exception("Unexpected value for single association '{$propertyPath}'."); // Collection association } elseif ($metadata->isCollectionValuedAssociation($propertyPath)) { if (!is_array($value)) { throw new \Exception('Expected array.'); } $builtValue = []; foreach ($value as $childData) { if (is_string($childData) && '#' === substr($childData, 0, 1)) { array_push($builtValue, $this->getReference(substr($childData, 1))); } elseif (is_array($value)) { array_push($builtValue, $this->buildEntity($childMetadata, $childData)); } else { throw new \Exception("Unexpected value for association '{$propertyPath}'."); } } return $builtValue; } throw new \Exception("Unexpected association path '{$propertyPath}'."); }
protected function writeReference(ClassMetadata $metadata, $modelName, $assocName, $reference, Writer $writer) { $setter = sprintf('set%s', ucfirst($assocName)); if ($metadata->isSingleValuedAssociation($assocName)) { $reference = sprintf("\$this->getReference('%s')", $reference); $writer->writeln(sprintf("\$%s->%s(%s);", $modelName, $setter, $reference)); } else { $class = $metadata->getName(); if ($adder = $this->findAdderMethod(new $class(), ucfirst($assocName))) { foreach ($reference as $ref) { $refString = sprintf("\$this->getReference('%s')", $ref); $writer->writeln(sprintf("\$%s->%s(%s);", $modelName, $adder, $refString)); } } else { $result = array(); foreach ($reference as $key => $ref) { $result[] = sprintf("\$this->getReference('%s')", $ref); } $writer->writeln(sprintf("\$%s->%s(array(%s));", $modelName, $setter, implode(', ', $result))); } } }