From 933a6b07c4ae30842ce5d58cbf24b6b10eb30fda Mon Sep 17 00:00:00 2001 From: Tom H Anderson Date: Wed, 27 Jun 2018 17:34:50 -0600 Subject: [PATCH 1/7] Added graphiql to docs --- docs/graphiql.rst | 20 ++++++++++++++++++++ docs/index.rst | 1 + 2 files changed, 21 insertions(+) create mode 100644 docs/graphiql.rst diff --git a/docs/graphiql.rst b/docs/graphiql.rst new file mode 100644 index 0000000..488c092 --- /dev/null +++ b/docs/graphiql.rst @@ -0,0 +1,20 @@ +GraphiQL and Documentation +========================== + +Support for GraphiQL was added in v1.0.5 along with support for introspection queries. + +The documentation for each field is created with a DocumentationProvider. Included +with zf-doctrine-graphql is an ApigilityDocumentationProvider. If you have need for +another form of documentation provider please create an issue on github. The more +included providers the merrier. + + + +.. role:: raw-html(raw) + :format: html + +.. note:: + Authored by `API Skeletons `_. All rights reserved. + + +:raw-html:`` diff --git a/docs/index.rst b/docs/index.rst index 4a4507a..abb09b0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,6 +16,7 @@ schema, if you wish, allowing deep GraphQL queries on your data with a single en queries configuration events + graphiql internals From f30a0809ae8e4765bf0b255118a5a3071e20e12b Mon Sep 17 00:00:00 2001 From: Tom H Anderson Date: Wed, 27 Jun 2018 18:51:21 -0600 Subject: [PATCH 2/7] Added GraphiQL support with documentation for all filters --- docs/queries.rst | 2 +- src/ConfigProvider.php | 5 ++ src/Criteria/FilterTypeAbstractFactory.php | 42 ++++++++------ .../ApigilityDocumentationProvider.php | 56 +++++++++++++++++++ .../ApigilityDocumentationProviderFactory.php | 19 +++++++ .../DocumentationProviderInterface.php | 9 +++ src/Filter/FilterTypeAbstractFactory.php | 38 ++++++++----- src/Type/DateTimeType.php | 8 +++ src/Type/EntityTypeAbstractFactory.php | 5 +- 9 files changed, 151 insertions(+), 33 deletions(-) create mode 100644 src/Documentation/ApigilityDocumentationProvider.php create mode 100644 src/Documentation/ApigilityDocumentationProviderFactory.php create mode 100644 src/Documentation/DocumentationProviderInterface.php diff --git a/docs/queries.rst b/docs/queries.rst index eb50b51..250ed98 100644 --- a/docs/queries.rst +++ b/docs/queries.rst @@ -40,7 +40,7 @@ Provided Filters:: fieldName_lte - Less Than or Equal To fieldName_in - Filter for values in an array fieldName_notin - Filter for values not in an array - fieldName_between - Fiilter between `from` and `to` values. Good substitute for DateTime Equals. + fieldName_between - Filter between `from` and `to` values. Good substitute for DateTime Equals. fieldName_contains - Strings only. Similar to a Like query as `like '%value%'` fieldName_startswith - Strings only. A like query from the beginning of the value `like 'value%'` fieldName_endswith - Strings only. A like query from the end of the value `like '%value'` diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index ec63dbd..19b3d71 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -31,6 +31,8 @@ public function getDependencyConfig() return [ 'aliases' => [ 'ZF\Doctrine\GraphQL\Hydrator\HydratorExtractTool' => Hydrator\HydratorExtractToolDefault::class, + 'ZF\Doctrine\GraphQL\Documentation\DocumentationProvider' + => Documentation\ApigilityDocumentationProvider::class, ], 'factories' => [ Hydrator\HydratorExtractToolDefault::class => Hydrator\HydratorExtractToolDefaultFactory::class, @@ -52,6 +54,9 @@ public function getDependencyConfig() Resolve\Loader::class => Resolve\LoaderFactory::class, Type\Loader::class => Type\LoaderFactory::class, Type\TypeManager::class => Type\TypeManagerFactory::class, + + Documentation\ApigilityDocumentationProvider::class => + Documentation\ApigilityDocumentationProviderFactory::class, ], ]; } diff --git a/src/Criteria/FilterTypeAbstractFactory.php b/src/Criteria/FilterTypeAbstractFactory.php index 2a8cfe6..2ab0ba7 100644 --- a/src/Criteria/FilterTypeAbstractFactory.php +++ b/src/Criteria/FilterTypeAbstractFactory.php @@ -93,7 +93,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_sort'] = [ 'name' => $fieldName . '_sort', 'type' => Type::string(), - 'description' => 'building...', + 'description' => 'Sort the result either ASC or DESC', ]; } @@ -102,13 +102,13 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName] = [ 'name' => $fieldName, 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Equals; same as name: value. DateTime not supported.', ]; $fields[$fieldName . '_eq'] = [ 'name' => $fieldName . '_eq', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Equals; same as name: value. DateTime not supported.', ]; } @@ -116,7 +116,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_neq'] = [ 'name' => $fieldName . '_neq', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Not Equals', ]; } @@ -124,7 +124,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_lt'] = [ 'name' => $fieldName . '_lt', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Less Than', ]; } @@ -132,7 +132,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_lte'] = [ 'name' => $fieldName . '_lte', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Less Than or Equal To', ]; } @@ -140,7 +140,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_gt'] = [ 'name' => $fieldName . '_gt', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Greater Than', ]; } @@ -148,7 +148,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_gte'] = [ 'name' => $fieldName . '_gte', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Greater Than or Equal To', ]; } @@ -156,13 +156,17 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_isnull'] = [ 'name' => $fieldName . '_isnull', 'type' => Type::boolean(), - 'description' => 'building...', + 'description' => 'Takes a boolean. If TRUE return results where the field is null. ' + . 'If FALSE returns results where the field is not null. ' + . 'NOTE: acts as "isEmpty" for collection filters. A value of false will ' + . 'be handled as though it were null.', ]; } if ($filterManager->has('lte') && $filterManager->has('gte')) { $fields[$fieldName . '_between'] = [ 'name' => $fieldName . '_between', + 'description' => 'Filter between `from` and `to` values. Good substitute for DateTime Equals.', 'type' => new FilterTypeNS\Between(['fields' => [ 'from' => [ 'name' => 'from', @@ -181,7 +185,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_in'] = [ 'name' => $fieldName . '_in', 'type' => Type::listOf($graphQLType), - 'description' => 'building...', + 'description' => 'Filter for values in an array', ]; } @@ -189,7 +193,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_notin'] = [ 'name' => $fieldName . '_notin', 'type' => Type::listOf($graphQLType), - 'description' => 'building...', + 'description' => 'Filter for values not in an array', ]; } @@ -198,7 +202,8 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_startswith'] = [ 'name' => $fieldName . '_startswith', 'type' => $graphQLType, - 'description' => 'building...', + 'documentation' => 'Strings only. ' + . 'A like query from the beginning of the value `like \'value%\'`', ]; } @@ -206,7 +211,8 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_endswith'] = [ 'name' => $fieldName . '_endswith', 'type' => $graphQLType, - 'description' => 'building...', + 'documentation' => 'Strings only. ' + . 'A like query from the end of the value `like \'%value\'`', ]; } @@ -214,7 +220,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_contains'] = [ 'name' => $fieldName . '_contains', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Strings only. Similar to a Like query as `like \'%value%\'`', ]; } } @@ -223,7 +229,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_memberof'] = [ 'name' => $fieldName . '_memberof', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Matches a value in an array field.', ]; } } @@ -231,21 +237,23 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_distinct'] = [ 'name' => $fieldName . '_distinct', 'type' => Type::boolean(), - 'description' => 'building...', + 'description' => 'Return a unique list of fieldName. Only one distinct fieldName allowed per filter.', ]; } $fields['_skip'] = [ 'name' => '_skip', 'type' => Type::int(), + 'documentation' => 'Skip forward x records from beginning of data set.', ]; $fields['_limit'] = [ 'name' => '_limit', 'type' => Type::int(), + 'documentation' => 'Limit the number of results to x.', ]; $instance = new FilterType([ - 'name' => str_replace('\\', '_', $requestedName) . 'CriteriaFilter', + 'name' => str_replace('\\', '_', $requestedName) . '__CriteriaFilter', 'fields' => function () use ($fields) { return $fields; }, diff --git a/src/Documentation/ApigilityDocumentationProvider.php b/src/Documentation/ApigilityDocumentationProvider.php new file mode 100644 index 0000000..0e70948 --- /dev/null +++ b/src/Documentation/ApigilityDocumentationProvider.php @@ -0,0 +1,56 @@ +config = $config; + } + + public function getEntity($entityName) { + // Documentation for entities is stored in the documentation.php config file. + // Fetching all those files is outside the scope of work for this class for now. + return 'Doctrine Entity ' . $entityName; + } + + /** + * Populate the field documentation based on teh input filter + * for the first matching entity found in zf-rest configuration + */ + public function getField($entityName, $fieldName) + { + $inputFilter = null; + $description = null; + + if (! isset($this->config['zf-rest'])) { + return null; + } + + foreach ($this->config['zf-rest'] as $controllerName => $restConfig) + { + if ($restConfig['entity_class'] == $entityName) { + $inputFilter = $this->config['zf-content-validation'][$controllerName]['input_filter'] ?? null; + break; + } + } + + if ($inputFilter + && isset($this->config['input_filter_specs']) + && isset($this->config['input_filter_specs'][$inputFilter])) + { + foreach ($this->config['input_filter_specs'][$inputFilter] as $fieldConfig) { + if ($fieldConfig['name'] == $fieldName) { + $description = $fieldConfig['description'] ?? null; + break; + } + } + } + + return $description; + } +} diff --git a/src/Documentation/ApigilityDocumentationProviderFactory.php b/src/Documentation/ApigilityDocumentationProviderFactory.php new file mode 100644 index 0000000..ada8e99 --- /dev/null +++ b/src/Documentation/ApigilityDocumentationProviderFactory.php @@ -0,0 +1,19 @@ +get('config'); + + return new ApigilityDocumentationProvider($config); + } +} + diff --git a/src/Documentation/DocumentationProviderInterface.php b/src/Documentation/DocumentationProviderInterface.php new file mode 100644 index 0000000..f9ebbcb --- /dev/null +++ b/src/Documentation/DocumentationProviderInterface.php @@ -0,0 +1,9 @@ + $fieldName . '_sort', 'type' => Type::string(), - 'description' => 'building...', + 'description' => 'Sort the result either ASC or DESC', ]; } @@ -101,14 +101,14 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName] = [ 'name' => $fieldName, 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Equals; same as name: value. DateTime not supported.', ]; // Add filters $fields[$fieldName . '_eq'] = [ 'name' => $fieldName . '_eq', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Equals; same as name: value. DateTime not supported.', ]; } @@ -116,7 +116,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_neq'] = [ 'name' => $fieldName . '_neq', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Not Equals', ]; } @@ -124,7 +124,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_lt'] = [ 'name' => $fieldName . '_lt', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Less Than', ]; } @@ -132,7 +132,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_lte'] = [ 'name' => $fieldName . '_lte', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Less Than or Equal To', ]; } @@ -140,7 +140,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_gt'] = [ 'name' => $fieldName . '_gt', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Greater Than', ]; } @@ -148,7 +148,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_gte'] = [ 'name' => $fieldName . '_gte', 'type' => $graphQLType, - 'description' => 'building...', + 'description' => 'Greater Than or Equal To', ]; } @@ -156,7 +156,10 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_isnull'] = [ 'name' => $fieldName . '_isnull', 'type' => Type::boolean(), - 'description' => 'building...', + 'description' => 'Takes a boolean. If TRUE return results where the field is null. ' + . 'If FALSE returns results where the field is not null. ' + . 'NOTE: acts as "isEmpty" for collection filters. A value of false will ' + . 'be handled as though it were null.', ]; } @@ -164,7 +167,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_in'] = [ 'name' => $fieldName . '_in', 'type' => Type::listOf(Type::nonNull($graphQLType)), - 'description' => 'building...', + 'description' => 'Filter for values in an array', ]; } @@ -172,13 +175,14 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_notin'] = [ 'name' => $fieldName . '_notin', 'type' => Type::listOf(Type::nonNull($graphQLType)), - 'description' => 'building...', + 'description' => 'Filter for values not in an array', ]; } if ($filterManager->has('between')) { $fields[$fieldName . '_between'] = [ 'name' => $fieldName . '_between', + 'description' => 'Filter between `from` and `to` values. Good substitute for DateTime Equals.', 'type' => new FilterTypeNS\Between(['fields' => [ 'from' => [ 'name' => 'from', @@ -197,16 +201,21 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_contains'] = [ 'name' => $fieldName . '_contains', 'type' => Type::string(), + 'description' => 'Strings only. Similar to a Like query as `like \'%value%\'`', ]; $fields[$fieldName . '_startswith'] = [ 'name' => $fieldName . '_startswith', 'type' => Type::string(), + 'documentation' => 'Strings only. ' + . 'A like query from the beginning of the value `like \'value%\'`', ]; $fields[$fieldName . '_endswith'] = [ 'name' => $fieldName . '_endswith', 'type' => Type::string(), + 'documentation' => 'Strings only. ' + . 'A like query from the end of the value `like \'%value\'`', ]; } @@ -214,27 +223,30 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $fields[$fieldName . '_memberof'] = [ 'name' => $fieldName . '_memberof', 'type' => Type::string(), - 'description' => 'building...', + 'description' => 'Matches a value in an array field.', ]; } } $fields[$fieldName . '_distinct'] = [ 'name' => $fieldName . '_distinct', 'type' => Type::boolean(), + 'description' => 'Return a unique list of fieldName. Only one distinct fieldName allowed per filter.', ]; } $fields['_skip'] = [ 'name' => '_skip', 'type' => Type::int(), + 'documentation' => 'Skip forward x records from beginning of data set.', ]; $fields['_limit'] = [ 'name' => '_limit', 'type' => Type::int(), + 'documentation' => 'Limit the number of results to x.', ]; $instance = new FilterType([ - 'name' => str_replace('\\', '_', $requestedName) . 'Filter', + 'name' => str_replace('\\', '_', $requestedName) . '__Filter', 'fields' => function () use ($fields, $references) { foreach ($references as $referenceName => $resolve) { // @codeCoverageIgnoreStart diff --git a/src/Type/DateTimeType.php b/src/Type/DateTimeType.php index 56e4aea..d3c6442 100644 --- a/src/Type/DateTimeType.php +++ b/src/Type/DateTimeType.php @@ -16,6 +16,14 @@ final class DateTimeType extends ScalarType { + /** + * @var string + */ + public $description = +'The `DateTime` scalar type represents datetime data. +The format for the DateTime is ISO-8601 +e.g. 2004-02-12T15:19:21+00:00.'; + /** * @codeCoverageIgnore */ diff --git a/src/Type/EntityTypeAbstractFactory.php b/src/Type/EntityTypeAbstractFactory.php index ca1ca19..df20c1e 100644 --- a/src/Type/EntityTypeAbstractFactory.php +++ b/src/Type/EntityTypeAbstractFactory.php @@ -65,6 +65,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $typeManager = $container->get(TypeManager::class); $criteriaFilterManager = $container->get(FilterManager::class); $criteriaBuilder = $container->get(CriteriaBuilder::class); + $documentationProvider = $container->get('ZF\Doctrine\GraphQL\Documentation\DocumentationProvider'); $hydratorAlias = 'ZF\\Doctrine\\GraphQL\\Hydrator\\' . str_replace('\\', '_', $requestedName); $hydratorExtractTool = $container->get('ZF\\Doctrine\\GraphQL\\Hydrator\\HydratorExtractTool'); $objectManager = $container @@ -309,14 +310,14 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o if ($graphQLType) { $fields[$fieldName] = [ 'type' => $graphQLType, - 'description' => 'building...', + 'description' => $documentationProvider->getField($requestedName, $fieldName), ]; } } $instance = new EntityType([ 'name' => str_replace('\\', '_', $requestedName) . '__' . $options['hydrator_section'], - 'description' => 'testing description', + 'description' => $documentationProvider->getEntity($requestedName), 'fields' => function () use ($fields, $references) { foreach ($references as $referenceName => $resolve) { $fields[$referenceName] = $resolve(); From 40ad197092881ec463444b549817219d59fafe4a Mon Sep 17 00:00:00 2001 From: Tom H Anderson Date: Wed, 27 Jun 2018 18:51:35 -0600 Subject: [PATCH 3/7] Added GraphiQL note to readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 173e169..79060d4 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ This library resolves relationships in Doctrine to provide full GraphQL querying of specified resources and all related entities. Entity metadata is introspected and is therefore Doctrine data driver agnostic. Data is collected via hydrators thereby -allowing full control over each field using hydrator filters and strategies. -Multiple object managers are supported. -Multiple hydrator configurations are supported. +allowing full control over each field using hydrator filters and strategies and naming strategies. +Multiple object managers are supported. Multiple hydrator configurations are supported. +Works with GraphiQL. Doctrine provides easy taversal of your database. Consider the following imaginary query: ```php From a3beb3223986b0016df37c31e165665ad3c6b9c0 Mon Sep 17 00:00:00 2001 From: Tom H Anderson Date: Wed, 27 Jun 2018 19:39:28 -0600 Subject: [PATCH 4/7] phpcs --- src/Documentation/ApigilityDocumentationProvider.php | 9 ++++----- .../ApigilityDocumentationProviderFactory.php | 1 - src/Type/DateTimeType.php | 2 +- src/Type/EntityTypeAbstractFactory.php | 5 +++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Documentation/ApigilityDocumentationProvider.php b/src/Documentation/ApigilityDocumentationProvider.php index 0e70948..f9fde17 100644 --- a/src/Documentation/ApigilityDocumentationProvider.php +++ b/src/Documentation/ApigilityDocumentationProvider.php @@ -12,7 +12,8 @@ public function __construct(array $config) $this->config = $config; } - public function getEntity($entityName) { + public function getEntity($entityName) + { // Documentation for entities is stored in the documentation.php config file. // Fetching all those files is outside the scope of work for this class for now. return 'Doctrine Entity ' . $entityName; @@ -31,8 +32,7 @@ public function getField($entityName, $fieldName) return null; } - foreach ($this->config['zf-rest'] as $controllerName => $restConfig) - { + foreach ($this->config['zf-rest'] as $controllerName => $restConfig) { if ($restConfig['entity_class'] == $entityName) { $inputFilter = $this->config['zf-content-validation'][$controllerName]['input_filter'] ?? null; break; @@ -41,8 +41,7 @@ public function getField($entityName, $fieldName) if ($inputFilter && isset($this->config['input_filter_specs']) - && isset($this->config['input_filter_specs'][$inputFilter])) - { + && isset($this->config['input_filter_specs'][$inputFilter])) { foreach ($this->config['input_filter_specs'][$inputFilter] as $fieldConfig) { if ($fieldConfig['name'] == $fieldName) { $description = $fieldConfig['description'] ?? null; diff --git a/src/Documentation/ApigilityDocumentationProviderFactory.php b/src/Documentation/ApigilityDocumentationProviderFactory.php index ada8e99..29dce6e 100644 --- a/src/Documentation/ApigilityDocumentationProviderFactory.php +++ b/src/Documentation/ApigilityDocumentationProviderFactory.php @@ -16,4 +16,3 @@ public function __invoke( return new ApigilityDocumentationProvider($config); } } - diff --git a/src/Type/DateTimeType.php b/src/Type/DateTimeType.php index d3c6442..14a060f 100644 --- a/src/Type/DateTimeType.php +++ b/src/Type/DateTimeType.php @@ -20,7 +20,7 @@ final class DateTimeType extends ScalarType * @var string */ public $description = -'The `DateTime` scalar type represents datetime data. + 'The `DateTime` scalar type represents datetime data. The format for the DateTime is ISO-8601 e.g. 2004-02-12T15:19:21+00:00.'; diff --git a/src/Type/EntityTypeAbstractFactory.php b/src/Type/EntityTypeAbstractFactory.php index df20c1e..03aca99 100644 --- a/src/Type/EntityTypeAbstractFactory.php +++ b/src/Type/EntityTypeAbstractFactory.php @@ -79,7 +79,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $references = []; $classMetadata = $objectManager->getClassMetadata($requestedName); - + die(get_class($classMetadata)); foreach ($entityFields as $fieldName) { $graphQLType = null; try { @@ -292,7 +292,8 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o } // @codeCoverageIgnoreEnd } - + print_r($fieldMetadata); + die($requestedName); $graphQLType = $this->mapFieldType($fieldMetadata['type']); // Override for datetime if ($fieldMetadata['type'] == 'datetime') { From d1c2c2a7cb52c3a659fa12f322fba616c53d9e03 Mon Sep 17 00:00:00 2001 From: Tom H Anderson Date: Wed, 27 Jun 2018 20:06:19 -0600 Subject: [PATCH 5/7] Use hydrator configuration for documentation. --- src/ConfigProvider.php | 6 ++-- .../ConfigurationSkeletonController.php | 4 +++ .../DocumentationProviderInterface.php | 4 +-- ...atorConfigurationDocumentationProvider.php | 30 +++++++++++++++++++ ...figurationDocumentationProviderFactory.php | 18 +++++++++++ src/Type/EntityTypeAbstractFactory.php | 9 +++--- 6 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 src/Documentation/HydratorConfigurationDocumentationProvider.php create mode 100644 src/Documentation/HydratorConfigurationDocumentationProviderFactory.php diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 19b3d71..c254e82 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -32,7 +32,7 @@ public function getDependencyConfig() 'aliases' => [ 'ZF\Doctrine\GraphQL\Hydrator\HydratorExtractTool' => Hydrator\HydratorExtractToolDefault::class, 'ZF\Doctrine\GraphQL\Documentation\DocumentationProvider' - => Documentation\ApigilityDocumentationProvider::class, + => Documentation\HydratorConfigurationDocumentationProvider::class, ], 'factories' => [ Hydrator\HydratorExtractToolDefault::class => Hydrator\HydratorExtractToolDefaultFactory::class, @@ -55,8 +55,8 @@ public function getDependencyConfig() Type\Loader::class => Type\LoaderFactory::class, Type\TypeManager::class => Type\TypeManagerFactory::class, - Documentation\ApigilityDocumentationProvider::class => - Documentation\ApigilityDocumentationProviderFactory::class, + Documentation\HydratorConfigurationDocumentationProvider::class => + Documentation\HydratorConfigurationDocumentationProviderFactory::class, ], ]; } diff --git a/src/Console/ConfigurationSkeletonController.php b/src/Console/ConfigurationSkeletonController.php index ee2a21e..56bab65 100644 --- a/src/Console/ConfigurationSkeletonController.php +++ b/src/Console/ConfigurationSkeletonController.php @@ -46,7 +46,9 @@ public function indexAction() $strategies = []; $filters = []; + $documentation = ['_entity' => '']; foreach ($classMetadata->getAssociationNames() as $associationName) { + $documentation[$associationName] = ''; $mapping = $classMetadata->getAssociationMapping($associationName); // See comment on NullifyOwningAssociation for details of why this is done @@ -58,6 +60,7 @@ public function indexAction() } foreach ($classMetadata->getFieldNames() as $fieldName) { + $documentation[$fieldName] = ''; $fieldMetadata = $classMetadata->getFieldMapping($fieldName); // Handle special named fields @@ -108,6 +111,7 @@ public function indexAction() 'hydrator' => null, 'strategies' => $strategies, 'filters' => $filters, + 'documentation' => $documentation, ]; } } diff --git a/src/Documentation/DocumentationProviderInterface.php b/src/Documentation/DocumentationProviderInterface.php index f9ebbcb..a5ceac7 100644 --- a/src/Documentation/DocumentationProviderInterface.php +++ b/src/Documentation/DocumentationProviderInterface.php @@ -4,6 +4,6 @@ interface DocumentationProviderInterface { - public function getField($entityName, $fieldName); - public function getEntity($entityName); + public function getField($entityClassName, $fieldName, array $config); + public function getEntity($entityClassName, array $config); } diff --git a/src/Documentation/HydratorConfigurationDocumentationProvider.php b/src/Documentation/HydratorConfigurationDocumentationProvider.php new file mode 100644 index 0000000..cc613da --- /dev/null +++ b/src/Documentation/HydratorConfigurationDocumentationProvider.php @@ -0,0 +1,30 @@ +config = $config; + } + + public function getEntity($entityClassName, array $options) + { + $hydratorAlias = 'ZF\\Doctrine\\GraphQL\\Hydrator\\' . str_replace('\\', '_', $entityClassName); + $config = $this->config['zf-doctrine-graphql-hydrator'][$hydratorAlias][$options['hydrator_section']] ?? null; + + return $config['documentation']['_entity'] ?? null; + } + + public function getField($entityClassName, $fieldName, array $options) + { + $hydratorAlias = 'ZF\\Doctrine\\GraphQL\\Hydrator\\' . str_replace('\\', '_', $entityClassName); + $config = $this->config['zf-doctrine-graphql-hydrator'][$hydratorAlias][$options['hydrator_section']] ?? null; + + return $config['documentation'][$fieldName] ?? null; + } +} diff --git a/src/Documentation/HydratorConfigurationDocumentationProviderFactory.php b/src/Documentation/HydratorConfigurationDocumentationProviderFactory.php new file mode 100644 index 0000000..e52a5e3 --- /dev/null +++ b/src/Documentation/HydratorConfigurationDocumentationProviderFactory.php @@ -0,0 +1,18 @@ +get('config'); + + return new HydratorConfigurationDocumentationProvider($config); + } +} diff --git a/src/Type/EntityTypeAbstractFactory.php b/src/Type/EntityTypeAbstractFactory.php index 03aca99..cf46616 100644 --- a/src/Type/EntityTypeAbstractFactory.php +++ b/src/Type/EntityTypeAbstractFactory.php @@ -79,7 +79,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o $references = []; $classMetadata = $objectManager->getClassMetadata($requestedName); - die(get_class($classMetadata)); + foreach ($entityFields as $fieldName) { $graphQLType = null; try { @@ -292,8 +292,7 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o } // @codeCoverageIgnoreEnd } - print_r($fieldMetadata); - die($requestedName); + $graphQLType = $this->mapFieldType($fieldMetadata['type']); // Override for datetime if ($fieldMetadata['type'] == 'datetime') { @@ -311,14 +310,14 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o if ($graphQLType) { $fields[$fieldName] = [ 'type' => $graphQLType, - 'description' => $documentationProvider->getField($requestedName, $fieldName), + 'description' => $documentationProvider->getField($requestedName, $fieldName, $options), ]; } } $instance = new EntityType([ 'name' => str_replace('\\', '_', $requestedName) . '__' . $options['hydrator_section'], - 'description' => $documentationProvider->getEntity($requestedName), + 'description' => $documentationProvider->getEntity($requestedName, $options), 'fields' => function () use ($fields, $references) { foreach ($references as $referenceName => $resolve) { $fields[$referenceName] = $resolve(); From 43ca3a808fc44e4407c876ed0a836a739d8da2f9 Mon Sep 17 00:00:00 2001 From: Tom H Anderson Date: Wed, 27 Jun 2018 20:08:14 -0600 Subject: [PATCH 6/7] Update apigility doc provider to new interface --- src/Documentation/ApigilityDocumentationProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Documentation/ApigilityDocumentationProvider.php b/src/Documentation/ApigilityDocumentationProvider.php index f9fde17..2dbe875 100644 --- a/src/Documentation/ApigilityDocumentationProvider.php +++ b/src/Documentation/ApigilityDocumentationProvider.php @@ -12,7 +12,7 @@ public function __construct(array $config) $this->config = $config; } - public function getEntity($entityName) + public function getEntity($entityName, array $options) { // Documentation for entities is stored in the documentation.php config file. // Fetching all those files is outside the scope of work for this class for now. @@ -23,7 +23,7 @@ public function getEntity($entityName) * Populate the field documentation based on teh input filter * for the first matching entity found in zf-rest configuration */ - public function getField($entityName, $fieldName) + public function getField($entityName, $fieldName, array $options) { $inputFilter = null; $description = null; From e71cc279de62f4ed1505e67a27331487a9252a50 Mon Sep 17 00:00:00 2001 From: Tom H Anderson Date: Wed, 27 Jun 2018 22:59:10 -0600 Subject: [PATCH 7/7] Do not unit test ApigiltyDoctrineProvider --- src/Documentation/ApigilityDocumentationProvider.php | 3 +++ src/Documentation/ApigilityDocumentationProviderFactory.php | 3 +++ src/Field/FieldResolver.php | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/Documentation/ApigilityDocumentationProvider.php b/src/Documentation/ApigilityDocumentationProvider.php index 2dbe875..8cef3d4 100644 --- a/src/Documentation/ApigilityDocumentationProvider.php +++ b/src/Documentation/ApigilityDocumentationProvider.php @@ -2,6 +2,9 @@ namespace ZF\Doctrine\GraphQL\Documentation; +/** + * @codeCoverageIgnore + */ class ApigilityDocumentationProvider implements DocumentationProviderInterface { diff --git a/src/Documentation/ApigilityDocumentationProviderFactory.php b/src/Documentation/ApigilityDocumentationProviderFactory.php index 29dce6e..3f1047f 100644 --- a/src/Documentation/ApigilityDocumentationProviderFactory.php +++ b/src/Documentation/ApigilityDocumentationProviderFactory.php @@ -4,6 +4,9 @@ use Interop\Container\ContainerInterface; +/** + * @codeCoverageIgnore + */ class ApigilityDocumentationProviderFactory { public function __invoke( diff --git a/src/Field/FieldResolver.php b/src/Field/FieldResolver.php index 8b7493b..d8da15b 100644 --- a/src/Field/FieldResolver.php +++ b/src/Field/FieldResolver.php @@ -46,9 +46,11 @@ public function __invoke($source, $args, Context $context, ResolveInfo $info) $hydratorAlias = 'ZF\\Doctrine\\GraphQL\\Hydrator\\' . str_replace('\\', '_', $entityClassName); // If the hydrator does not exist pass handling to default Executor field resolver + // @codeCoverageIgnoreStart if (! $this->hydratorManager->has($hydratorAlias)) { return Executor::defaultFieldResolver($source, $args, $context, $info); } + // @codeCoverageIgnoreEnd /** * For disabled hydrator cache store only last hydrator result and reuse for consecutive calls