From 4d4bf6bfeebbc1eee244235f07b8ed44dfa6e280 Mon Sep 17 00:00:00 2001 From: Tom H Anderson Date: Sat, 25 Apr 2026 15:41:12 -0600 Subject: [PATCH] Override getFieldNames when extracting to limit to only configured fields --- src/Hydrator/DoctrineObjectWithComputed.php | 38 +++++++++++++++++++++ src/Hydrator/HydratorContainer.php | 6 ++++ 2 files changed, 44 insertions(+) diff --git a/src/Hydrator/DoctrineObjectWithComputed.php b/src/Hydrator/DoctrineObjectWithComputed.php index 1ebc8bb..1bca294 100644 --- a/src/Hydrator/DoctrineObjectWithComputed.php +++ b/src/Hydrator/DoctrineObjectWithComputed.php @@ -5,9 +5,11 @@ namespace ApiSkeletons\Doctrine\ORM\GraphQL\Hydrator; use Doctrine\Laminas\Hydrator\DoctrineObject; +use Generator; use Laminas\Hydrator\Filter\FilterProviderInterface; use Override; +use function array_flip; use function array_key_exists; use function array_keys; use function get_class_methods; @@ -30,6 +32,42 @@ final class DoctrineObjectWithComputed extends DoctrineObject */ private array $computedFields = []; + /** + * Flipped map of allowed field names for O(1) lookup. + * When empty, all Doctrine fields are yielded (no restriction). + * + * @var array + */ + private array $allowedFields = []; + + /** + * Restrict extraction to only the given field names. + * + * @param array $fieldNames + */ + public function setAllowedFields(array $fieldNames): void + { + $this->allowedFields = array_flip($fieldNames); + } + + /** + * Yield only the allowed subset of Doctrine field/association names. + * Falls back to all names when no restriction has been set. + * + * @return Generator + */ + #[Override] + public function getFieldNames(): iterable + { + foreach (parent::getFieldNames() as $fieldName) { + if ($this->allowedFields !== [] && ! isset($this->allowedFields[$fieldName])) { + continue; + } + + yield $fieldName; + } + } + /** * Register a computed field for extraction * diff --git a/src/Hydrator/HydratorContainer.php b/src/Hydrator/HydratorContainer.php index 74bf24e..953dff9 100644 --- a/src/Hydrator/HydratorContainer.php +++ b/src/Hydrator/HydratorContainer.php @@ -14,6 +14,8 @@ use Override; use ReflectionClass; +use function array_keys; +use function array_map; use function assert; use function class_implements; use function in_array; @@ -77,6 +79,10 @@ public function get(string $id): mixed $object->addStrategy($fieldName, $self->get($fieldMetadata['hydratorStrategy'])); } + // Restrict extraction to only GraphQL-exposed fields + /** @psalm-suppress MixedArgument */ + $object->setAllowedFields(array_map('strval', array_keys($metadata['fields']))); + // Register computed fields if (isset($metadata['computedFields'])) { /** @psalm-suppress MixedArrayAccess, MixedAssignment */