diff --git a/app/code/Magento/GraphQl/Controller/GraphQl.php b/app/code/Magento/GraphQl/Controller/GraphQl.php index c4a0b55de9bf..c04bb7f5775a 100644 --- a/app/code/Magento/GraphQl/Controller/GraphQl.php +++ b/app/code/Magento/GraphQl/Controller/GraphQl.php @@ -111,10 +111,10 @@ public function dispatch(RequestInterface $request) : ResponseInterface $data = $this->jsonSerializer->unserialize($request->getContent()); $query = isset($data['query']) ? $data['query'] : ''; - + $variables = isset($data['variables']) ? $data['variables'] : null; // We have to extract queried field names to avoid instantiation of non necessary fields in webonyx schema // Temporal coupling is required for performance optimization - $this->queryFields->setQuery($query); + $this->queryFields->setQuery($query, $variables); $schema = $this->schemaGenerator->generate(); $result = $this->queryProcessor->process( diff --git a/app/code/Magento/GraphQl/etc/di.xml b/app/code/Magento/GraphQl/etc/di.xml index b2083ea758e5..6acb78f9c7f9 100644 --- a/app/code/Magento/GraphQl/etc/di.xml +++ b/app/code/Magento/GraphQl/etc/di.xml @@ -27,7 +27,7 @@ Magento\Framework\GraphQl\Config\Element\InterfaceFactory Magento\Framework\GraphQl\Config\Element\TypeFactory - Magento\Framework\GraphQl\Config\Element\TypeFactory + Magento\Framework\GraphQl\Config\Element\InputFactory Magento\Framework\GraphQl\Config\Element\EnumFactory @@ -55,24 +55,16 @@ - + - + Magento\Framework\GraphQl\Schema\Type\Output\OutputTypeObject + Magento\Framework\GraphQl\Schema\Type\Input\InputObjectType Magento\Framework\GraphQl\Schema\Type\Output\OutputInterfaceObject Magento\Framework\GraphQl\Schema\Type\Enum\Enum - - - - Magento\Framework\GraphQl\Schema\Type\Input\InputObjectType - Magento\Framework\GraphQl\Schema\Type\Input\InputObjectType - Magento\Framework\GraphQl\Schema\Type\Enum\Enum - - - Magento\Framework\GraphQl\Schema\Type\Output\ElementMapper\FormatterComposite diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQl/Client.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQl/Client.php index 5458b5cfbb73..add0510c6b40 100644 --- a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQl/Client.php +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQl/Client.php @@ -57,8 +57,8 @@ public function postQuery(string $query, array $variables = [], string $operatio $headers = array_merge($headers, ['Accept: application/json', 'Content-Type: application/json']); $requestArray = [ 'query' => $query, - 'variables' => empty($variables) ? $variables : null, - 'operationName' => empty($operationName) ? $operationName : null + 'variables' => !empty($variables) ? $variables : null, + 'operationName' => !empty($operationName) ? $operationName : null ]; $postData = $this->json->jsonEncode($requestArray); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/VariablesSupportQueryTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/VariablesSupportQueryTest.php new file mode 100644 index 000000000000..7448b165fc23 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/VariablesSupportQueryTest.php @@ -0,0 +1,81 @@ +productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_list.php + */ + public function testQueryObjectVariablesSupport() + { + $productSku = 'simple-249'; + $minPrice = 153; + + $query + = <<<'QUERY' +query GetProductsQuery($pageSize: Int, $filterInput: ProductFilterInput, $priceSort: SortEnum) { + products( + pageSize: $pageSize + filter: $filterInput + sort: {price: $priceSort} + ) { + items { + sku + price { + minimalPrice { + amount { + value + currency + } + } + } + } + } +} +QUERY; + + $variables = [ + 'pageSize' => 1, + 'priceSort' => 'ASC', + 'filterInput' => [ + 'min_price' => [ + 'gt' => 150, + ], + ], + ]; + + $response = $this->graphQlQuery($query, $variables); + /** @var \Magento\Catalog\Model\Product $product */ + $product = $this->productRepository->get($productSku, false, null, true); + + self::assertArrayHasKey('products', $response); + self::assertArrayHasKey('items', $response['products']); + self::assertEquals(1, count($response['products']['items'])); + self::assertArrayHasKey(0, $response['products']['items']); + self::assertEquals($product->getSku(), $response['products']['items'][0]['sku']); + self::assertEquals( + $minPrice, + $response['products']['items'][0]['price']['minimalPrice']['amount']['value'] + ); + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Config.php b/lib/internal/Magento/Framework/GraphQl/Config.php index 75b6c64e9d24..ec22b742b1d6 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config.php +++ b/lib/internal/Magento/Framework/GraphQl/Config.php @@ -48,12 +48,7 @@ public function __construct( } /** - * Get a data object with data pertaining to a GraphQL type's structural makeup. - * - * @param string $configElementName - * @return ConfigElementInterface - * @throws \LogicException - * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @inheritdoc */ public function getConfigElement(string $configElementName) : ConfigElementInterface { @@ -67,7 +62,7 @@ public function getConfigElement(string $configElementName) : ConfigElementInter $fieldsInQuery = $this->queryFields->getFieldsUsedInQuery(); if (isset($data['fields'])) { if (!empty($fieldsInQuery)) { - foreach ($data['fields'] as $fieldName => $fieldConfig) { + foreach (array_keys($data['fields']) as $fieldName) { if (!isset($fieldsInQuery[$fieldName])) { unset($data['fields'][$fieldName]); } @@ -81,18 +76,20 @@ public function getConfigElement(string $configElementName) : ConfigElementInter } /** - * Return all type names declared in a GraphQL schema's configuration. - * - * @return string[] + * @inheritdoc */ - public function getDeclaredTypeNames() : array + public function getDeclaredTypes() : array { $types = []; foreach ($this->configData->get(null) as $item) { - if (isset($item['type']) && $item['type'] == 'graphql_type') { - $types[] = $item['name']; + if (isset($item['type'])) { + $types[] = [ + 'name' => $item['name'], + 'type' => $item['type'], + ]; } } + return $types; } } diff --git a/lib/internal/Magento/Framework/GraphQl/Config/Element/Enum.php b/lib/internal/Magento/Framework/GraphQl/Config/Element/Enum.php index b1210e986b77..994ae489af12 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config/Element/Enum.php +++ b/lib/internal/Magento/Framework/GraphQl/Config/Element/Enum.php @@ -37,7 +37,7 @@ class Enum implements ConfigElementInterface public function __construct( string $name, array $values, - string $description = "" + string $description ) { $this->name = $name; $this->values = $values; diff --git a/lib/internal/Magento/Framework/GraphQl/Config/Element/FieldsFactory.php b/lib/internal/Magento/Framework/GraphQl/Config/Element/FieldsFactory.php new file mode 100644 index 000000000000..ca6b67eac3d8 --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Config/Element/FieldsFactory.php @@ -0,0 +1,62 @@ +argumentFactory = $argumentFactory; + $this->fieldFactory = $fieldFactory; + } + + /** + * Create a fields object from a configured array with optional arguments. + * + * Field data must contain name and type. Other values are optional and include required, itemType, description, + * and resolver. Arguments array must be in the format of [$argumentData['name'] => $argumentData]. + * + * @param array $fieldsData + * @return Field[] + */ + public function createFromConfigData( + array $fieldsData + ) : array { + $fields = []; + foreach ($fieldsData as $fieldData) { + $arguments = []; + foreach ($fieldData['arguments'] as $argumentData) { + $arguments[$argumentData['name']] = $this->argumentFactory->createFromConfigData($argumentData); + } + $fields[$fieldData['name']] = $this->fieldFactory->createFromConfigData( + $fieldData, + $arguments + ); + } + return $fields; + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Config/Element/Input.php b/lib/internal/Magento/Framework/GraphQl/Config/Element/Input.php new file mode 100644 index 000000000000..8e86f701672c --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Config/Element/Input.php @@ -0,0 +1,74 @@ +name = $name; + $this->fields = $fields; + $this->description = $description; + } + + /** + * Get the type name. + * + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * Get a list of fields that make up the possible return or input values of a type. + * + * @return Field[] + */ + public function getFields(): array + { + return $this->fields; + } + + /** + * Get a human-readable description of the type. + * + * @return string + */ + public function getDescription(): string + { + return $this->description; + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Config/Element/InputFactory.php b/lib/internal/Magento/Framework/GraphQl/Config/Element/InputFactory.php new file mode 100644 index 000000000000..0e7ccb831a5a --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Config/Element/InputFactory.php @@ -0,0 +1,79 @@ +objectManager = $objectManager; + $this->fieldsFactory = $fieldsFactory; + } + + /** + * Instantiate an object representing 'input' GraphQL config element. + * + * @param array $data + * @return ConfigElementInterface + */ + public function createFromConfigData(array $data): ConfigElementInterface + { + $fields = isset($data['fields']) ? $this->fieldsFactory->createFromConfigData($data['fields']) : []; + + return $this->create( + $data, + $fields + ); + } + + /** + * Create input type object based off array of configured GraphQL InputType data. + * + * Type data must contain name and the type's fields. Optional data includes description. + * + * @param array $typeData + * @param array $fields + * @return Input + */ + private function create( + array $typeData, + array $fields + ): Input { + return $this->objectManager->create( + Input::class, + [ + 'name' => $typeData['name'], + 'fields' => $fields, + 'description' => isset($typeData['description']) ? $typeData['description'] : '' + ] + ); + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Config/Element/InterfaceType.php b/lib/internal/Magento/Framework/GraphQl/Config/Element/InterfaceType.php index 320199c14a6d..73ebd42acfb2 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config/Element/InterfaceType.php +++ b/lib/internal/Magento/Framework/GraphQl/Config/Element/InterfaceType.php @@ -8,7 +8,7 @@ namespace Magento\Framework\GraphQl\Config\Element; /** - * Describes the configured data for a GraphQL interface type. + * Class representing 'interface' GraphQL config element. */ class InterfaceType implements TypeInterface { @@ -42,7 +42,7 @@ public function __construct( string $name, string $typeResolver, array $fields, - string $description = "" + string $description ) { $this->name = $name; $this->fields = $fields; diff --git a/lib/internal/Magento/Framework/GraphQl/Config/Element/Type.php b/lib/internal/Magento/Framework/GraphQl/Config/Element/Type.php index 24ff439db034..20d017cc7106 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config/Element/Type.php +++ b/lib/internal/Magento/Framework/GraphQl/Config/Element/Type.php @@ -8,7 +8,7 @@ namespace Magento\Framework\GraphQl\Config\Element; /** - * Describes all the configured data of an Output or Input type in GraphQL. + * Class representing 'type' GraphQL config element. */ class Type implements TypeInterface { diff --git a/lib/internal/Magento/Framework/GraphQl/Config/Element/TypeFactory.php b/lib/internal/Magento/Framework/GraphQl/Config/Element/TypeFactory.php index c5f3187b0484..5dd477a05089 100644 --- a/lib/internal/Magento/Framework/GraphQl/Config/Element/TypeFactory.php +++ b/lib/internal/Magento/Framework/GraphQl/Config/Element/TypeFactory.php @@ -22,28 +22,20 @@ class TypeFactory implements ConfigElementFactoryInterface private $objectManager; /** - * @var ArgumentFactory + * @var FieldsFactory */ - private $argumentFactory; - - /** - * @var FieldFactory - */ - private $fieldFactory; + private $fieldsFactory; /** * @param ObjectManagerInterface $objectManager - * @param ArgumentFactory $argumentFactory - * @param FieldFactory $fieldFactory + * @param FieldsFactory $fieldsFactory */ public function __construct( ObjectManagerInterface $objectManager, - ArgumentFactory $argumentFactory, - FieldFactory $fieldFactory + FieldsFactory $fieldsFactory ) { $this->objectManager = $objectManager; - $this->argumentFactory = $argumentFactory; - $this->fieldFactory = $fieldFactory; + $this->fieldsFactory = $fieldsFactory; } /** @@ -54,18 +46,8 @@ public function __construct( */ public function createFromConfigData(array $data): ConfigElementInterface { - $fields = []; - $data['fields'] = isset($data['fields']) ? $data['fields'] : []; - foreach ($data['fields'] as $field) { - $arguments = []; - foreach ($field['arguments'] as $argument) { - $arguments[$argument['name']] = $this->argumentFactory->createFromConfigData($argument); - } - $fields[$field['name']] = $this->fieldFactory->createFromConfigData( - $field, - $arguments - ); - } + $fields = isset($data['fields']) ? $this->fieldsFactory->createFromConfigData($data['fields']) : []; + return $this->create( $data, $fields @@ -73,10 +55,10 @@ public function createFromConfigData(array $data): ConfigElementInterface } /** - * Create type object based off array of configured GraphQL Output/InputType data. + * Create type object based off array of configured GraphQL Type data. * * Type data must contain name and the type's fields. Optional data includes 'implements' (i.e. the interfaces - * implemented by the types), and description. An InputType cannot implement an interface. + * implemented by the types), and description. * * @param array $typeData * @param array $fields diff --git a/lib/internal/Magento/Framework/GraphQl/ConfigInterface.php b/lib/internal/Magento/Framework/GraphQl/ConfigInterface.php index c2670967f1db..f7d6cf49e180 100644 --- a/lib/internal/Magento/Framework/GraphQl/ConfigInterface.php +++ b/lib/internal/Magento/Framework/GraphQl/ConfigInterface.php @@ -25,9 +25,11 @@ interface ConfigInterface public function getConfigElement(string $configElementName) : ConfigElementInterface; /** - * Return all type names from a GraphQL schema's configuration. + * Return all type names declared in a GraphQL schema's configuration and their type. * - * @return string[] + * Format is ['name' => 'example value', 'type' = 'example value'] + * + * @return array $types */ - public function getDeclaredTypeNames() : array; + public function getDeclaredTypes() : array; } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/Fields.php b/lib/internal/Magento/Framework/GraphQl/Query/Fields.php index d0bc9591265e..ae1d8d68d5bc 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/Fields.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/Fields.php @@ -24,9 +24,11 @@ class Fields * Set Query for extracting list of fields. * * @param string $query + * @param array|null $variables + * * @return void */ - public function setQuery($query) + public function setQuery($query, array $variables = null) { $queryFields = []; try { @@ -41,6 +43,9 @@ public function setQuery($query) ] ] ); + if (isset($variables)) { + $queryFields = array_merge($queryFields, $this->extractVariables($variables)); + } } catch (\Exception $e) { // If a syntax error is encountered do not collect fields } @@ -62,4 +67,24 @@ public function getFieldsUsedInQuery() { return $this->fieldsUsedInQuery; } + + /** + * Extract and return list of all used fields in GraphQL query's variables + * + * @param array $variables + * + * @return string[] + */ + private function extractVariables(array $variables): array + { + $fields = []; + foreach ($variables as $key => $value) { + if (is_array($value)){ + $fields = array_merge($fields, $this->extractVariables($value)); + } + $fields[$key] = $key; + } + + return $fields; + } } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/FieldEntityAttributesPool.php b/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/FieldEntityAttributesPool.php index e7d14a81b9de..bd9de206ccda 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/FieldEntityAttributesPool.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/FieldEntityAttributesPool.php @@ -38,7 +38,7 @@ public function getEntityAttributesForEntityFromField(string $fieldName) : array if (isset($this->attributesInstances[$fieldName])) { return $this->attributesInstances[$fieldName]->getEntityAttributes(); } else { - throw new \LogicException(sprintf('There is no attrribute class assigned to field %1', $fieldName)); + throw new \LogicException(sprintf('There is no attribute class assigned to field %1', $fieldName)); } } } diff --git a/lib/internal/Magento/Framework/GraphQl/Schema/SchemaGenerator.php b/lib/internal/Magento/Framework/GraphQl/Schema/SchemaGenerator.php index 63fef73186b1..250b80defa6d 100644 --- a/lib/internal/Magento/Framework/GraphQl/Schema/SchemaGenerator.php +++ b/lib/internal/Magento/Framework/GraphQl/Schema/SchemaGenerator.php @@ -8,9 +8,8 @@ namespace Magento\Framework\GraphQl\Schema; use Magento\Framework\GraphQl\ConfigInterface; -use Magento\Framework\GraphQl\Schema\SchemaGeneratorInterface; -use Magento\Framework\GraphQl\Schema\Type\Output\OutputMapper; use Magento\Framework\GraphQl\Schema; +use Magento\Framework\GraphQl\Schema\Type\TypeRegistry; use Magento\Framework\GraphQl\SchemaFactory; /** @@ -24,47 +23,46 @@ class SchemaGenerator implements SchemaGeneratorInterface private $schemaFactory; /** - * @var OutputMapper + * @var ConfigInterface */ - private $outputMapper; + private $config; /** - * @var ConfigInterface + * @var TypeRegistry */ - private $config; + private $typeRegistry; /** * @param SchemaFactory $schemaFactory - * @param OutputMapper $outputMapper * @param ConfigInterface $config + * @param TypeRegistry $typeRegistry */ public function __construct( SchemaFactory $schemaFactory, - OutputMapper $outputMapper, - ConfigInterface $config + ConfigInterface $config, + TypeRegistry $typeRegistry ) { $this->schemaFactory = $schemaFactory; - $this->outputMapper = $outputMapper; $this->config = $config; + $this->typeRegistry = $typeRegistry; } /** - * {@inheritdoc} + * @inheritdoc */ public function generate() : Schema { $schema = $this->schemaFactory->create( [ - 'query' => $this->outputMapper->getOutputType('Query'), - 'mutation' => $this->outputMapper->getOutputType('Mutation'), + 'query' => $this->typeRegistry->get('Query'), + 'mutation' => $this->typeRegistry->get('Mutation'), 'typeLoader' => function ($name) { - return $this->outputMapper->getOutputType($name); + return $this->typeRegistry->get($name); }, 'types' => function () { - //all types should be generated only on introspection $typesImplementors = []; - foreach ($this->config->getDeclaredTypeNames() as $name) { - $typesImplementors [] = $this->outputMapper->getOutputType($name); + foreach ($this->config->getDeclaredTypes() as $type) { + $typesImplementors [] = $this->typeRegistry->get($type['name']); } return $typesImplementors; } diff --git a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputFactory.php b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputFactory.php deleted file mode 100644 index cbbd97cfdb8c..000000000000 --- a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputFactory.php +++ /dev/null @@ -1,60 +0,0 @@ -objectManager = $objectManager; - $this->prototypes = $prototypes; - } - - /** - * @param ConfigElementInterface $configElement - * @return InputTypeInterface - */ - public function create(ConfigElementInterface $configElement) : InputTypeInterface - { - if (!isset($this->typeRegistry[$configElement->getName()])) { - $this->typeRegistry[$configElement->getName()] = - $this->objectManager->create( - $this->prototypes[get_class($configElement)], - [ - 'configElement' => $configElement - ] - ); - } - return $this->typeRegistry[$configElement->getName()]; - } -} diff --git a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputMapper.php b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputMapper.php index d806c0b3e68a..d1f48dada2cb 100644 --- a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputMapper.php +++ b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputMapper.php @@ -9,27 +9,15 @@ use Magento\Framework\GraphQl\Config\Data\WrappedTypeProcessor; use Magento\Framework\GraphQl\Config\Element\Argument; -use Magento\Framework\GraphQl\ConfigInterface; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Schema\Type\ScalarTypes; -use Magento\Framework\GraphQl\Schema\TypeFactory; +use Magento\Framework\GraphQl\Schema\Type\TypeRegistry; +/** + * Prepare argument's metadata for GraphQL schema generation + */ class InputMapper { - /** - * @var InputFactory - */ - private $inputFactory; - - /** - * @var ConfigInterface - */ - private $config; - - /** - * @var TypeFactory - */ - private $typeFactory; - /** * @var ScalarTypes */ @@ -41,24 +29,23 @@ class InputMapper private $wrappedTypeProcessor; /** - * @param InputFactory $inputFactory - * @param ConfigInterface $config - * @param TypeFactory $typeFactory + * @var TypeRegistry + */ + private $typeRegistry; + + /** * @param ScalarTypes $scalarTypes * @param WrappedTypeProcessor $wrappedTypeProcessor + * @param TypeRegistry $typeRegistry */ public function __construct( - InputFactory $inputFactory, - ConfigInterface $config, - TypeFactory $typeFactory, ScalarTypes $scalarTypes, - WrappedTypeProcessor $wrappedTypeProcessor + WrappedTypeProcessor $wrappedTypeProcessor, + TypeRegistry $typeRegistry ) { - $this->inputFactory = $inputFactory; - $this->config = $config; - $this->typeFactory = $typeFactory; $this->scalarTypes = $scalarTypes; $this->wrappedTypeProcessor = $wrappedTypeProcessor; + $this->typeRegistry = $typeRegistry; } /** @@ -66,6 +53,7 @@ public function __construct( * * @param Argument $argument * @return array + * @throws GraphQlInputException */ public function getRepresentation(Argument $argument) : array { @@ -73,8 +61,7 @@ public function getRepresentation(Argument $argument) : array if ($this->scalarTypes->isScalarType($typeName)) { $instance = $this->wrappedTypeProcessor->processScalarWrappedType($argument); } else { - $configElement = $this->config->getConfigElement($typeName); - $instance = $this->inputFactory->create($configElement); + $instance = $this->typeRegistry->get($typeName); $instance = $this->wrappedTypeProcessor->processWrappedType($argument, $instance); } diff --git a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputObjectType.php b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputObjectType.php index ae2d07ade2ad..fa0327f79bc6 100644 --- a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputObjectType.php +++ b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Input/InputObjectType.php @@ -8,21 +8,16 @@ namespace Magento\Framework\GraphQl\Schema\Type\Input; use Magento\Framework\GraphQl\Config\Data\WrappedTypeProcessor; -use Magento\Framework\GraphQl\Config\Element\Type as TypeConfigElement; -use Magento\Framework\GraphQl\ConfigInterface; +use Magento\Framework\GraphQl\Config\Element\Input as InputConfigElement; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Schema\Type\ScalarTypes; -use Magento\Framework\GraphQl\Schema\TypeFactory; +use Magento\Framework\GraphQl\Schema\Type\TypeRegistry; /** * Class InputObjectType */ class InputObjectType extends \Magento\Framework\GraphQl\Schema\Type\InputObjectType { - /** - * @var TypeFactory - */ - private $typeFactory; - /** * @var ScalarTypes */ @@ -34,36 +29,27 @@ class InputObjectType extends \Magento\Framework\GraphQl\Schema\Type\InputObject private $wrappedTypeProcessor; /** - * @var InputFactory + * @var TypeRegistry */ - private $inputFactory; + private $typeRegistry; /** - * @var ConfigInterface - */ - public $graphQlConfig; - - /** - * @param TypeConfigElement $configElement - * @param TypeFactory $typeFactory + * @param InputConfigElement $configElement * @param ScalarTypes $scalarTypes * @param WrappedTypeProcessor $wrappedTypeProcessor - * @param InputFactory $inputFactory - * @param ConfigInterface $graphQlConfig + * @param TypeRegistry $typeRegistry + * @throws GraphQlInputException */ public function __construct( - TypeConfigElement $configElement, - TypeFactory $typeFactory, + InputConfigElement $configElement, ScalarTypes $scalarTypes, WrappedTypeProcessor $wrappedTypeProcessor, - InputFactory $inputFactory, - ConfigInterface $graphQlConfig + TypeRegistry $typeRegistry ) { - $this->typeFactory = $typeFactory; $this->scalarTypes = $scalarTypes; $this->wrappedTypeProcessor = $wrappedTypeProcessor; - $this->inputFactory = $inputFactory; - $this->graphQlConfig = $graphQlConfig; + $this->typeRegistry = $typeRegistry; + $config = [ 'name' => $configElement->getName(), 'description' => $configElement->getDescription() @@ -75,8 +61,7 @@ public function __construct( if ($field->getTypeName() == $configElement->getName()) { $type = $this; } else { - $fieldConfigElement = $this->graphQlConfig->getConfigElement($field->getTypeName()); - $type = $this->inputFactory->create($fieldConfigElement); + $type = $this->typeRegistry->get($field->getTypeName()); } $type = $this->wrappedTypeProcessor->processWrappedType($field, $type); } diff --git a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/ElementMapper/Formatter/Fields.php b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/ElementMapper/Formatter/Fields.php index b54cd4d8ca21..034a5702090d 100644 --- a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/ElementMapper/Formatter/Fields.php +++ b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/ElementMapper/Formatter/Fields.php @@ -16,7 +16,6 @@ use Magento\Framework\GraphQl\Schema\Type\Output\OutputMapper; use Magento\Framework\GraphQl\Schema\Type\OutputTypeInterface; use Magento\Framework\GraphQl\Schema\Type\ScalarTypes; -use Magento\Framework\GraphQl\Schema\TypeFactory; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfoFactory; @@ -40,11 +39,6 @@ class Fields implements FormatterInterface */ private $inputMapper; - /** - * @var TypeFactory - */ - private $typeFactory; - /** * @var ScalarTypes */ @@ -64,7 +58,6 @@ class Fields implements FormatterInterface * @param ObjectManagerInterface $objectManager * @param OutputMapper $outputMapper * @param InputMapper $inputMapper - * @param TypeFactory $typeFactory * @param ScalarTypes $scalarTypes * @param WrappedTypeProcessor $wrappedTypeProcessor * @param ResolveInfoFactory $resolveInfoFactory @@ -73,7 +66,6 @@ public function __construct( ObjectManagerInterface $objectManager, OutputMapper $outputMapper, InputMapper $inputMapper, - TypeFactory $typeFactory, ScalarTypes $scalarTypes, WrappedTypeProcessor $wrappedTypeProcessor, ResolveInfoFactory $resolveInfoFactory @@ -81,14 +73,13 @@ public function __construct( $this->objectManager = $objectManager; $this->outputMapper = $outputMapper; $this->inputMapper = $inputMapper; - $this->typeFactory = $typeFactory; $this->scalarTypes = $scalarTypes; $this->wrappedTypeProcessor = $wrappedTypeProcessor; $this->resolveInfoFactory = $resolveInfoFactory; } /** - * {@inheritDoc} + * @inheritdoc */ public function format(TypeInterface $configElement, OutputTypeInterface $outputType): array { diff --git a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/OutputFactory.php b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/OutputFactory.php deleted file mode 100644 index 81dad11774b0..000000000000 --- a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/OutputFactory.php +++ /dev/null @@ -1,65 +0,0 @@ -objectManager = $objectManager; - $this->prototypes = $prototypes; - } - - /** - * Create output type. - * - * @param ConfigElementInterface $configElement - * @return OutputTypeInterface - */ - public function create(ConfigElementInterface $configElement) : OutputTypeInterface - { - if (!isset($this->typeRegistry[$configElement->getName()])) { - $this->typeRegistry[$configElement->getName()] = - $this->objectManager->create( - $this->prototypes[get_class($configElement)], - [ - 'configElement' => $configElement - ] - ); - } - return $this->typeRegistry[$configElement->getName()]; - } -} diff --git a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/OutputMapper.php b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/OutputMapper.php index b7f4b8a1f60d..046eeb5b1f93 100644 --- a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/OutputMapper.php +++ b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/OutputMapper.php @@ -7,50 +7,28 @@ namespace Magento\Framework\GraphQl\Schema\Type\Output; -use Magento\Framework\GraphQl\ConfigInterface; use Magento\Framework\GraphQl\Schema\Type\OutputTypeInterface; -use Magento\Framework\GraphQl\Schema\TypeFactory; +use Magento\Framework\GraphQl\Schema\Type\TypeRegistry; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\Phrase; /** - * Map type names to their output type/interface classes. + * Map type names to their output type/interface/enum classes. */ class OutputMapper { /** - * @var OutputFactory + * @var TypeRegistry */ - private $outputFactory; + private $typeRegistry; /** - * @var OutputTypeInterface[] - */ - private $outputTypes; - - /** - * @var TypeFactory - */ - private $typeFactory; - - /** - * @var ConfigInterface - */ - private $config; - - /** - * @param OutputFactory $outputFactory - * @param TypeFactory $typeFactory - * @param ConfigInterface $config + * @param TypeRegistry $typeRegistry */ public function __construct( - OutputFactory $outputFactory, - TypeFactory $typeFactory, - ConfigInterface $config + TypeRegistry $typeRegistry ) { - $this->outputFactory = $outputFactory; - $this->config = $config; - $this->typeFactory = $typeFactory; + $this->typeRegistry = $typeRegistry; } /** @@ -62,16 +40,13 @@ public function __construct( */ public function getOutputType($typeName) { - if (!isset($this->outputTypes[$typeName])) { - $configElement = $this->config->getConfigElement($typeName); - $this->outputTypes[$typeName] = $this->outputFactory->create($configElement); - if (!($this->outputTypes[$typeName] instanceof OutputTypeInterface)) { - throw new GraphQlInputException( - new Phrase("Type '{$typeName}' was requested but is not declared in the GraphQL schema.") - ); - } - } + $outputType = $this->typeRegistry->get($typeName); - return $this->outputTypes[$typeName]; + if (!$outputType instanceof OutputTypeInterface) { + throw new GraphQlInputException( + new Phrase("Type '{$typeName}' was requested but is not declared in the GraphQL schema.") + ); + } + return $outputType; } } diff --git a/lib/internal/Magento/Framework/GraphQl/Schema/Type/TypeRegistry.php b/lib/internal/Magento/Framework/GraphQl/Schema/Type/TypeRegistry.php new file mode 100644 index 000000000000..cde8b6b3e446 --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Schema/Type/TypeRegistry.php @@ -0,0 +1,95 @@ +objectManager = $objectManager; + $this->config = $config; + $this->configToTypeMap = $configToTypeMap; + } + + /** + * Get GraphQL type object by type name + * + * @param string $typeName + * @return TypeInterface|InputTypeInterface|OutputTypeInterface + * @throws GraphQlInputException + */ + public function get(string $typeName): TypeInterface + { + if (!isset($this->types[$typeName])) { + $configElement = $this->config->getConfigElement($typeName); + + $configElementClass = get_class($configElement); + if (!isset($this->configToTypeMap[$configElementClass])) { + throw new GraphQlInputException( + new Phrase( + "No mapping to Webonyx type is declared for '%1' config element type.", + [$configElementClass] + ) + ); + } + + $this->types[$typeName] = $this->objectManager->create( + $this->configToTypeMap[$configElementClass], + [ + 'configElement' => $configElement, + ] + ); + + if (!($this->types[$typeName] instanceof TypeInterface)) { + throw new GraphQlInputException( + new Phrase("Type '{$typeName}' was requested but is not declared in the GraphQL schema.") + ); + } + } + return $this->types[$typeName]; + } +}