diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 02aaf79..3d11f5c 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,5 +1,11 @@ parameters: ignoreErrors: + - + message: '#^Method Patchlevel\\ODM\\Hydrator\\DocumentHydrator\:\:__construct\(\) has parameter \$documentMetadata with generic class Patchlevel\\ODM\\Metadata\\DocumentMetadata but does not specify its types\: T$#' + identifier: missingType.generics + count: 1 + path: src/Hydrator/DocumentHydrator.php + - message: '#^Parameter \#1 \$data of method Patchlevel\\ODM\\Hydrator\\MongoDBCipherKeyStore\:\:hydrate\(\) expects array\{_id\: string, subject_id\: string, key\: non\-empty\-string, method\: non\-empty\-string, created_at\: string\}, array\|object given\.$#' identifier: argument.type @@ -73,13 +79,13 @@ parameters: path: src/Repository/MongoDBRepository.php - - message: '#^Parameter \#2 \$data of method Patchlevel\\Hydrator\\HydratorWithContext\:\:hydrate\(\) expects array\, array\|object given\.$#' + message: '#^Parameter \#2 \$data of method Patchlevel\\ODM\\Hydrator\\DocumentHydrator\:\:hydrate\(\) expects array\, array\|object given\.$#' identifier: argument.type count: 2 path: src/Repository/MongoDBRepository.php - - message: '#^Parameter \#2 \$data of method Patchlevel\\Hydrator\\HydratorWithContext\:\:hydrate\(\) expects array\, array\|object\|null given\.$#' + message: '#^Parameter \#2 \$data of method Patchlevel\\ODM\\Hydrator\\DocumentHydrator\:\:hydrate\(\) expects array\, array\|object\|null given\.$#' identifier: argument.type count: 2 path: src/Repository/MongoDBRepository.php diff --git a/src/Hydrator/DocumentHydrator.php b/src/Hydrator/DocumentHydrator.php new file mode 100644 index 0000000..e59e077 --- /dev/null +++ b/src/Hydrator/DocumentHydrator.php @@ -0,0 +1,61 @@ +fieldNameOverride = $this->documentMetadata->fields[$this->documentMetadata->idProperty]->fieldNameOverride; + } + + /** + * @param class-string $class + * @param array $data + * @param array $context + * + * @return T + * + * @throws ClassNotSupported if the class is not supported or not found. + * + * @template T of object + */ + public function hydrate(string $class, array $data, array $context = []): object + { + if ($this->fieldNameOverride) { + $data[$this->fieldNameOverride] = $data[self::ID_FIELD_NAME]; + unset($data[self::ID_FIELD_NAME]); + } + + return $this->hydrator->hydrate($class, $data, $context); + } + + /** + * @param array $context + * + * @return array + */ + public function extract(object $object, array $context = []): array + { + $data = $this->hydrator->extract($object, $context); + + if ($this->fieldNameOverride) { + $data[self::ID_FIELD_NAME] = $data[$this->fieldNameOverride]; + unset($data[$this->fieldNameOverride]); + } + + return $data; + } +} diff --git a/src/Hydrator/ODMExtension.php b/src/Hydrator/ODMExtension.php deleted file mode 100644 index 5b4c391..0000000 --- a/src/Hydrator/ODMExtension.php +++ /dev/null @@ -1,16 +0,0 @@ -addMiddleware(new ODMMiddleware()); - } -} diff --git a/src/Hydrator/ODMMiddleware.php b/src/Hydrator/ODMMiddleware.php deleted file mode 100644 index b86b7d2..0000000 --- a/src/Hydrator/ODMMiddleware.php +++ /dev/null @@ -1,71 +0,0 @@ - $metadata - * @param array $data - * @param array $context - * - * @return T - * - * @template T of object - */ - public function hydrate(ClassMetadata $metadata, array $data, array $context, Stack $stack): object - { - $documentMetadata = $context[DocumentMetadata::class] ?? null; - - if (!$documentMetadata instanceof DocumentMetadata) { - return $stack->next()->hydrate($metadata, $data, $context, $stack); - } - - unset($context[DocumentMetadata::class]); - - $fieldName = $metadata->properties[$documentMetadata->idProperty]->fieldName; - - $data[$fieldName] = $data[self::ID_FIELD_NAME]; - unset($data[self::ID_FIELD_NAME]); - - return $stack->next()->hydrate($metadata, $data, $context, $stack); - } - - /** - * @param ClassMetadata $metadata - * @param T $object - * @param array $context - * - * @return array - * - * @template T of object - */ - public function extract(ClassMetadata $metadata, object $object, array $context, Stack $stack): array - { - $documentMetadata = $context[DocumentMetadata::class] ?? null; - - if (!$documentMetadata instanceof DocumentMetadata) { - return $stack->next()->extract($metadata, $object, $context, $stack); - } - - unset($context[DocumentMetadata::class]); - - $data = $stack->next()->extract($metadata, $object, $context, $stack); - - $fieldName = $metadata->properties[$documentMetadata->idProperty]->fieldName; - - $data[self::ID_FIELD_NAME] = $data[$fieldName]; - unset($data[$fieldName]); - - return $data; - } -} diff --git a/src/Metadata/AttributeDocumentMetadataFactory.php b/src/Metadata/AttributeDocumentMetadataFactory.php index fbf3f22..88092de 100644 --- a/src/Metadata/AttributeDocumentMetadataFactory.php +++ b/src/Metadata/AttributeDocumentMetadataFactory.php @@ -49,14 +49,14 @@ public function metadata(string $className): DocumentMetadata $idProperty = $this->getIdProperty($reflection); foreach ($reflection->getProperties() as $reflectionProperty) { + $field = $this->fieldResolver?->resolve($reflectionProperty); + if ($idProperty === $reflectionProperty->getName()) { - $fields[$reflectionProperty->getName()] = new FieldMapping('_id'); + $fields[$reflectionProperty->getName()] = new FieldMapping('_id', [], $field?->fieldName); continue; } - $field = $this->fieldResolver?->resolve($reflectionProperty); - if (!$field) { continue; } diff --git a/src/Metadata/FieldMapping.php b/src/Metadata/FieldMapping.php index a82d857..1f1dec7 100644 --- a/src/Metadata/FieldMapping.php +++ b/src/Metadata/FieldMapping.php @@ -10,6 +10,7 @@ public function __construct( public string $fieldName, public array $children = [], + public string|null $fieldNameOverride = null, ) { } } diff --git a/src/Repository/MongoDBRepository.php b/src/Repository/MongoDBRepository.php index 85fa436..e0db8b6 100644 --- a/src/Repository/MongoDBRepository.php +++ b/src/Repository/MongoDBRepository.php @@ -8,6 +8,7 @@ use MongoDB\Database; use MongoDB\Driver\Exception\ServerException; use Patchlevel\Hydrator\HydratorWithContext; +use Patchlevel\ODM\Hydrator\DocumentHydrator; use Patchlevel\ODM\Metadata\DocumentMetadata; use function array_map; @@ -24,12 +25,15 @@ { private Collection $collection; + private DocumentHydrator $hydrator; + /** @param DocumentMetadata $metadata */ public function __construct( private Database $database, private DocumentMetadata $metadata, - private HydratorWithContext $hydrator, + HydratorWithContext $hydrator, ) { + $this->hydrator = new DocumentHydrator($hydrator, $metadata); $this->collection = $this->database->selectCollection($this->metadata->collection); } @@ -44,10 +48,7 @@ public function insert(object ...$objects): void throw new WrongClass($this->metadata->className, $object::class); } - $data = $this->hydrator->extract( - $object, - [DocumentMetadata::class => $this->metadata], - ); + $data = $this->hydrator->extract($object); $this->collection->insertOne($data); return; @@ -58,10 +59,7 @@ public function insert(object ...$objects): void throw new WrongClass($this->metadata->className, $object::class); } - return $this->hydrator->extract( - $object, - [DocumentMetadata::class => $this->metadata], - ); + return $this->hydrator->extract($object); }, $objects)); } catch (ServerException $e) { throw new InsertionFailed($e->getMessage(), $e->getCode(), $e); @@ -82,10 +80,7 @@ public function update(object ...$objects): void throw new WrongClass($this->metadata->className, $object::class); } - $data = $this->hydrator->extract( - $object, - [DocumentMetadata::class => $this->metadata], - ); + $data = $this->hydrator->extract($object); $this->collection->updateOne(['_id' => $data['_id']], ['$set' => $data]); @@ -98,7 +93,7 @@ function (object $object): array { throw new WrongClass($this->metadata->className, $object::class); } - $data = $this->hydrator->extract($object, [DocumentMetadata::class => $this->metadata]); + $data = $this->hydrator->extract($object); return [ 'updateOne' => [ @@ -143,11 +138,7 @@ public function find(string $id): object|null return null; } - return $this->hydrator->hydrate( - $this->metadata->className, - $data, - [DocumentMetadata::class => $this->metadata], - ); + return $this->hydrator->hydrate($this->metadata->className, $data); } public function remove(string ...$id): void @@ -169,11 +160,7 @@ public function findAll(): iterable ]); foreach ($cursor as $document) { - yield $this->hydrator->hydrate( - $this->metadata->className, - $document, - [DocumentMetadata::class => $this->metadata], - ); + yield $this->hydrator->hydrate($this->metadata->className, $document); } } @@ -211,7 +198,6 @@ public function findBy( yield $this->hydrator->hydrate( $this->metadata->className, $document, - [DocumentMetadata::class => $this->metadata], ); } } @@ -239,11 +225,7 @@ public function findOneBy(array $filter = [], array|null $orderBy = null): objec return null; } - return $this->hydrator->hydrate( - $this->metadata->className, - $data, - [DocumentMetadata::class => $this->metadata], - ); + return $this->hydrator->hydrate($this->metadata->className, $data); } public function count(): int diff --git a/src/Repository/MongoDBRepositoryManager.php b/src/Repository/MongoDBRepositoryManager.php index 5babf86..d82c6b4 100644 --- a/src/Repository/MongoDBRepositoryManager.php +++ b/src/Repository/MongoDBRepositoryManager.php @@ -5,11 +5,8 @@ namespace Patchlevel\ODM\Repository; use MongoDB\Client; -use Patchlevel\Hydrator\CoreExtension; -use Patchlevel\Hydrator\Extension; use Patchlevel\Hydrator\HydratorWithContext; -use Patchlevel\Hydrator\StackHydratorBuilder; -use Patchlevel\ODM\Hydrator\ODMExtension; +use Patchlevel\Hydrator\StackHydrator; use Patchlevel\ODM\Metadata\AttributeDocumentMetadataFactory; use Patchlevel\ODM\Metadata\DocumentMetadataFactory; use Patchlevel\ODM\Metadata\StackHydratorFieldMappingResolver; @@ -51,19 +48,10 @@ public function get(string $documentClass): MongoDBRepository return $this->repositories[$documentClass]; } - /** @param list $extensions */ - public static function create(Client $client, array $extensions = []): self - { - $builder = (new StackHydratorBuilder()) - ->useExtension(new CoreExtension()) - ->useExtension(new ODMExtension()); - - foreach ($extensions as $extension) { - $builder->useExtension($extension); - } - - $hydrator = $builder->build(); - + public static function create( + Client $client, + StackHydrator $hydrator = new StackHydrator(), + ): self { $metadataFactory = new AttributeDocumentMetadataFactory( new StackHydratorFieldMappingResolver($hydrator), ); diff --git a/src/Repository/RangoRepository.php b/src/Repository/RangoRepository.php index f356ea0..c90b8ac 100644 --- a/src/Repository/RangoRepository.php +++ b/src/Repository/RangoRepository.php @@ -5,6 +5,7 @@ namespace Patchlevel\ODM\Repository; use Patchlevel\Hydrator\HydratorWithContext; +use Patchlevel\ODM\Hydrator\DocumentHydrator; use Patchlevel\ODM\Metadata\DocumentMetadata; use Patchlevel\Rango\Collection; use Patchlevel\Rango\Database; @@ -23,12 +24,15 @@ { private Collection $collection; + private DocumentHydrator $hydrator; + /** @param DocumentMetadata $metadata */ public function __construct( private Database $database, private DocumentMetadata $metadata, - private HydratorWithContext $hydrator, + HydratorWithContext $hydrator, ) { + $this->hydrator = new DocumentHydrator($hydrator, $metadata); $this->collection = $this->database->getCollection($this->metadata->collection); } @@ -43,10 +47,7 @@ public function insert(object ...$objects): void throw new WrongClass($this->metadata->className, $object::class); } - $data = $this->hydrator->extract( - $object, - [DocumentMetadata::class => $this->metadata], - ); + $data = $this->hydrator->extract($object); $this->collection->insertOne($data); @@ -60,10 +61,7 @@ function (object $object): array { throw new WrongClass($this->metadata->className, $object::class); } - return $this->hydrator->extract( - $object, - [DocumentMetadata::class => $this->metadata], - ); + return $this->hydrator->extract($object); }, $objects, ), @@ -87,10 +85,7 @@ public function update(object ...$objects): void throw new WrongClass($this->metadata->className, $object::class); } - $data = $this->hydrator->extract( - $object, - [DocumentMetadata::class => $this->metadata], - ); + $data = $this->hydrator->extract($object); $this->collection->updateOne(['_id' => $data['_id']], ['$set' => $data]); @@ -102,10 +97,7 @@ public function update(object ...$objects): void throw new WrongClass($this->metadata->className, $object::class); } - $data = $this->hydrator->extract( - $object, - [DocumentMetadata::class => $this->metadata], - ); + $data = $this->hydrator->extract($object); return [ 'updateOne' => [ @@ -146,11 +138,7 @@ public function find(string $id): object|null return null; } - return $this->hydrator->hydrate( - $this->metadata->className, - $data, - [DocumentMetadata::class => $this->metadata], - ); + return $this->hydrator->hydrate($this->metadata->className, $data); } public function remove(string ...$id): void @@ -170,11 +158,7 @@ public function findAll(): iterable $cursor = $this->collection->find(); foreach ($cursor as $document) { - yield $this->hydrator->hydrate( - $this->metadata->className, - $document, - [DocumentMetadata::class => $this->metadata], - ); + yield $this->hydrator->hydrate($this->metadata->className, $document); } } @@ -210,11 +194,7 @@ public function findBy( ); foreach ($cursor as $document) { - yield $this->hydrator->hydrate( - $this->metadata->className, - $document, - [DocumentMetadata::class => $this->metadata], - ); + yield $this->hydrator->hydrate($this->metadata->className, $document); } } @@ -238,11 +218,7 @@ public function findOneBy(array $filter = [], array|null $orderBy = null): objec return null; } - return $this->hydrator->hydrate( - $this->metadata->className, - $data, - [DocumentMetadata::class => $this->metadata], - ); + return $this->hydrator->hydrate($this->metadata->className, $data); } public function count(): int diff --git a/src/Repository/RangoRepositoryManager.php b/src/Repository/RangoRepositoryManager.php index a42c763..b3f8be2 100644 --- a/src/Repository/RangoRepositoryManager.php +++ b/src/Repository/RangoRepositoryManager.php @@ -4,11 +4,8 @@ namespace Patchlevel\ODM\Repository; -use Patchlevel\Hydrator\CoreExtension; -use Patchlevel\Hydrator\Extension; use Patchlevel\Hydrator\HydratorWithContext; -use Patchlevel\Hydrator\StackHydratorBuilder; -use Patchlevel\ODM\Hydrator\ODMExtension; +use Patchlevel\Hydrator\StackHydrator; use Patchlevel\ODM\Metadata\AttributeDocumentMetadataFactory; use Patchlevel\ODM\Metadata\DocumentMetadataFactory; use Patchlevel\ODM\Metadata\StackHydratorFieldMappingResolver; @@ -51,19 +48,10 @@ public function get(string $documentClass): RangoRepository return $this->repositories[$documentClass]; } - /** @param list $extensions */ - public static function create(Client $client, array $extensions = []): self - { - $builder = (new StackHydratorBuilder()) - ->useExtension(new CoreExtension()) - ->useExtension(new ODMExtension()); - - foreach ($extensions as $extension) { - $builder->useExtension($extension); - } - - $hydrator = $builder->build(); - + public static function create( + Client $client, + StackHydrator $hydrator = new StackHydrator(), + ): self { $metadataFactory = new AttributeDocumentMetadataFactory( new StackHydratorFieldMappingResolver($hydrator), ); diff --git a/tests/Unit/Metadata/AttributeDocumentMetadataFactoryTest.php b/tests/Unit/Metadata/AttributeDocumentMetadataFactoryTest.php index 9759493..b9976de 100644 --- a/tests/Unit/Metadata/AttributeDocumentMetadataFactoryTest.php +++ b/tests/Unit/Metadata/AttributeDocumentMetadataFactoryTest.php @@ -175,7 +175,7 @@ className: Profile::class, new Index('by_status', ['status' => 'asc'], unique: false), new Index('by_status_other', ['status' => 'desc'], unique: false), ], - fields: ['id' => new FieldMapping('_id', [])], + fields: ['id' => new FieldMapping('_id', [], '_otherId')], ); $fieldResolver = new class implements FieldMappingResolver