private function extractWithMetadata($entity, Entity $metadata) : array { if ($entity instanceof ProxyInterface) { $entity = $entity->__getRealEntity(); } Assertion::isInstanceOf($entity, $metadata->getClassName()); $data = []; $reflectionClass = new ReflectionClass($entity); foreach ($metadata->getFields() as $fieldMetadata) { if ($fieldMetadata->isReadOnly()) { continue; } $fieldName = $fieldMetadata->getFieldName(); try { $type = $fieldMetadata->getType(); $value = $this->getProperty($reflectionClass, $entity, $fieldMetadata->getPropertyName()); if (!$fieldMetadata->isRepeatable()) { $data[$fieldName] = $type->toFileMakerValue($value); continue; } Assertion::isArray($value); $index = 0; foreach ($value as $individualValue) { $data[sprintf('%s(%d)', $fieldName, ++$index)] = $type->toFileMakerValue($individualValue); } } catch (Exception $e) { throw ExtractionException::fromInvalidField($metadata, $fieldMetadata, $e); } } foreach ($metadata->getEmbeddables() as $embeddableMetadata) { $prefix = $embeddableMetadata->getFieldNamePrefix(); $embeddableData = $this->extractWithMetadata($this->getProperty($reflectionClass, $entity, $embeddableMetadata->getPropertyName()), $embeddableMetadata->getMetadata()); foreach ($embeddableData as $key => $value) { $data[$prefix . $key] = $value; } } $toOne = array_filter($metadata->getManyToOne(), function (ManyToOne $manyToOneMetadata) { return !$manyToOneMetadata->isReadOnly(); }) + array_filter($metadata->getOneToOne(), function (OneToOne $oneToOneMetadata) { return $oneToOneMetadata->isOwningSide() && !$oneToOneMetadata->isReadOnly(); }); foreach ($toOne as $relationMetadata) { $relation = $this->getProperty($reflectionClass, $entity, $relationMetadata->getPropertyName()); if (null === $relation) { $data[$relationMetadata->getFieldName()] = null; continue; } if ($relation instanceof ProxyInterface) { Assertion::isInstanceOf($relation->__getRealEntity(), $relationMetadata->getTargetEntity()); $relationId = $relation->__getRelationId(); } else { Assertion::isInstanceOf($relation, $relationMetadata->getTargetEntity()); $relationId = $this->getProperty(new ReflectionClass($relation), $relation, $relationMetadata->getTargetPropertyName()); } $data[$relationMetadata->getFieldName()] = $relationId; } return $data; }
public function testGenericGetters() { $fields = [new Field('', '', $this->prophesize(TypeInterface::class)->reveal(), false, false)]; $embeddables = [new Embeddable('', '', new Entity('', '', [], [], [], [], []))]; $oneToMany = [new OneToMany('', '', '', '')]; $manyToOne = [new ManyToOne('', '', '', '', '', '', '', false)]; $oneToOne = [new OneToOne('', '', '', '', '', false, false)]; $metadata = new Entity('layout', 'className', $fields, $embeddables, $oneToMany, $manyToOne, $oneToOne); $this->assertSame('layout', $metadata->getLayout()); $this->assertSame('className', $metadata->getClassName()); $this->assertSame($fields, $metadata->getFields()); $this->assertSame($embeddables, $metadata->getEmbeddables()); $this->assertSame($oneToMany, $metadata->getOneToMany()); $this->assertSame($manyToOne, $metadata->getManyToOne()); $this->assertSame($oneToOne, $metadata->getOneToOne()); }
private function hydrateWithMetadata(array $data, $entity, Entity $metadata) { Assertion::isInstanceOf($entity, $metadata->getClassName()); $reflectionClass = new ReflectionClass($entity); foreach ($metadata->getFields() as $fieldMetadata) { try { $type = $fieldMetadata->getType(); $value = $data[$fieldMetadata->getFieldName()]; if ($fieldMetadata->isRepeatable()) { Assertion::isArray($value); $value = array_map(function ($value) use($type) { return $type->fromFileMakerValue($value); }, $value); } else { $value = $type->fromFileMakerValue($value); } $this->setProperty($reflectionClass, $entity, $fieldMetadata->getPropertyName(), $value); } catch (Exception $e) { throw HydrationException::fromInvalidField($metadata, $fieldMetadata, $e); } } foreach ($metadata->getEmbeddables() as $embeddableMetadata) { $prefix = $embeddableMetadata->getFieldNamePrefix(); if ('' === $prefix) { $embeddableData = $data; } else { $prefixLength = strlen($prefix); foreach ($data as $key => $value) { if (0 !== strpos($key, $prefix)) { continue; } $embeddableData[substr($key, $prefixLength)] = $value; } } $reflectionProperty = $reflectionClass->getProperty($embeddableMetadata->getPropertyName()); $reflectionProperty->setAccessible(true); $embeddable = $reflectionProperty->getValue($entity); if (null === $embeddable) { $embeddable = (new ReflectionClass($embeddableMetadata->getMetadata()->getClassName()))->newInstanceWithoutConstructor(); } $reflectionProperty->setValue($entity, $this->hydrateWithMetadata($embeddableData, $embeddable, $embeddableMetadata->getMetadata())); } foreach ($metadata->getOneToMany() as $relationMetadata) { $repository = $this->repositoryBuilder->buildRepository($relationMetadata->getTargetEntity()); if ($relationMetadata->hasEagerHydration()) { $items = []; foreach ($data[$relationMetadata->getTargetTable()] as $record) { $items[] = $repository->createEntity($record); } $collection = new ItemCollection($items, count($items)); } else { $collection = new LazyLoadedCollection($repository, $relationMetadata->getTargetFieldName(), $data[$relationMetadata->getTargetTable()]); } $this->setProperty($reflectionClass, $entity, $relationMetadata->getPropertyName(), $collection); } $toOne = $metadata->getManyToOne() + $metadata->getOneToOne(); foreach ($toOne as $relationMetadata) { if (empty($data[$relationMetadata->getTargetTable()])) { $this->setProperty($reflectionClass, $entity, $relationMetadata->getPropertyName(), null); continue; } $repository = $this->repositoryBuilder->buildRepository($relationMetadata->getTargetEntity()); if ($relationMetadata->hasEagerHydration()) { $this->setProperty($reflectionClass, $entity, $relationMetadata->getPropertyName(), $repository->createEntity($data[$relationMetadata->getTargetTable()][0])); continue; } Assertion::true($metadata->hasInterfaceName(), sprintf('Entity "%s" has no interface name definied', $metadata->getClassName())); $fieldName = $relationMetadata->getTargetFieldName(); $fieldValue = (string) $data[$relationMetadata->getTargetTable()][0][$fieldName]; $proxy = $this->proxyBuilder->createProxy($relationMetadata->getTargetInterfaceName(), function () use($repository, $fieldName, $fieldValue) { return $repository->findOneBy([$fieldName => $repository->quoteString($fieldValue)]); }, $fieldValue); $this->setProperty($reflectionClass, $entity, $relationMetadata->getPropertyName(), $proxy); } if ($metadata->hasRecordId()) { $recordIdMetadata = $metadata->getRecordId(); $this->setProperty($reflectionClass, $entity, $recordIdMetadata->getPropertyName(), $data['record-id']); } return $entity; }