diff --git a/src/Type/Builder/ArgConfig.php b/src/Type/Builder/ArgConfig.php new file mode 100644 index 000000000..fe14fbbfb --- /dev/null +++ b/src/Type/Builder/ArgConfig.php @@ -0,0 +1,21 @@ +addConfig('defaultValue', $defaultValue, false); + + return $this; + } +} diff --git a/src/Type/Builder/ArgsConfig.php b/src/Type/Builder/ArgsConfig.php new file mode 100644 index 000000000..7f2623bf9 --- /dev/null +++ b/src/Type/Builder/ArgsConfig.php @@ -0,0 +1,29 @@ +addConfig('args', $argConfig->build()); + } + + public function addArg($name, $type, $defaultValue = null, $description = null) + { + $argConfig = ArgConfig::create() + ->name($name) + ->type($type) + ->defaultValue($defaultValue) + ->description($description); + + return $this->addArgConfig($argConfig); + } + + public function build() + { + $args = parent::build(); + + return isset($args['args']) ? $args['args'] : []; + } +} diff --git a/src/Type/Builder/Config.php b/src/Type/Builder/Config.php new file mode 100644 index 000000000..051329cf9 --- /dev/null +++ b/src/Type/Builder/Config.php @@ -0,0 +1,43 @@ +config = []; + } + + /** + * @return static + */ + public static function create() + { + return new static(); + } + + protected function addConfig($name, $value, $append = true) + { + if (!$append) { + $this->config[$name] = $value; + } else { + if (!isset($this->config[$name])) { + $this->config[$name] = []; + } + $this->config[$name][] = $value; + } + + return $this; + } + + public function build() + { + return $this->config; + } +} diff --git a/src/Type/Builder/FieldConfig.php b/src/Type/Builder/FieldConfig.php new file mode 100644 index 000000000..ccda138d0 --- /dev/null +++ b/src/Type/Builder/FieldConfig.php @@ -0,0 +1,61 @@ +addConfig('resolve', $resolve, false); + } + + /** + * @param callable|null $complexity + * + * @return $this + */ + public function complexity(callable $complexity = null) + { + return $this->addConfig('complexity', $complexity, false); + } + + /** + * @param string|null $deprecationReason + * @return $this + */ + public function deprecationReason($deprecationReason = null) + { + return $this->addConfig('deprecationReason', $deprecationReason, false); + } + + /** + * @param ArgConfig $arg + * + * @return $this + */ + public function addArg(ArgConfig $arg) + { + return $this->addConfig('args', $arg->build()); + } + + /** + * @param ArgsConfig $args + * + * @return $this + */ + public function addArgs(ArgsConfig $args) + { + foreach ($args->build() as $arg) { + $this->addConfig('args', $arg); + } + return $this; + } +} diff --git a/src/Type/Builder/FieldsConfig.php b/src/Type/Builder/FieldsConfig.php new file mode 100644 index 000000000..516ed7342 --- /dev/null +++ b/src/Type/Builder/FieldsConfig.php @@ -0,0 +1,15 @@ +addConfig('fields', $fieldConfig->build()); + } + + public function addField($name, $type, $description = null, ArgsConfig $args = null, callable $resolve = null, callable $complexity = null) + { + return $this->pushField($name, $type, $description, $args, $resolve, $complexity); + } + + public function addDeprecatedField($name, $type, $deprecationReason, $description = null, ArgsConfig $args = null, callable $resolve = null, callable $complexity = null) + { + return $this->pushField($name, $type, $description, $args, $resolve, $complexity, $deprecationReason); + } + + protected function pushField($name, $type, $description = null, ArgsConfig $args = null, callable $resolve = null, callable $complexity = null, $deprecationReason = null) + { + $fieldConfig = FieldConfig::create() + ->name($name) + ->type($type); + + if (null !== $resolve) { + $fieldConfig->resolve($resolve); + } + + if (null !== $description) { + $fieldConfig->description($description); + } + + if (null !== $args) { + $fieldConfig->addArgs($args); + } + + if (null !== $complexity) { + $fieldConfig->complexity($complexity); + } + + if (null !== $deprecationReason) { + $fieldConfig->deprecationReason($deprecationReason); + } + + return $this->addFieldConfig($fieldConfig); + } +} diff --git a/src/Type/Builder/NameDescriptionConfigTrait.php b/src/Type/Builder/NameDescriptionConfigTrait.php new file mode 100644 index 000000000..134b6619d --- /dev/null +++ b/src/Type/Builder/NameDescriptionConfigTrait.php @@ -0,0 +1,35 @@ +addConfig('name', $name, false); + + return $this; + } + + /** + * @param string|null $description + * + * @return $this + */ + public function description($description) + { + $this->addConfig('description', $description, false); + + return $this; + } +} diff --git a/src/Type/Builder/ObjectTypeConfig.php b/src/Type/Builder/ObjectTypeConfig.php new file mode 100644 index 000000000..fb2ac4496 --- /dev/null +++ b/src/Type/Builder/ObjectTypeConfig.php @@ -0,0 +1,78 @@ +addConfig('interfaces', [], false); + foreach ($interfaces as $interface) { + $this->addInterface($interface); + } + + return $this; + } + + /** + * @param callable|FieldsConfig $fields + * + * @return $this + */ + public function fields($fields) + { + if ($fields instanceof FieldsConfig) { + $this->addConfig('fields', $fields->build(), false); + } elseif ($fields) { + $this->addConfig('fields', $fields, false); + } + + return $this; + } + + /** + * @param InterfaceType $interface + * + * @return $this + */ + public function addInterface(InterfaceType $interface) + { + $this->addConfig('interfaces', $interface); + + return $this; + } + + /** + * @param callable|null $isTypeOf + * + * @return $this + */ + public function isTypeOf(callable $isTypeOf = null) + { + $this->addConfig('isTypeOf', $isTypeOf, false); + + return $this; + } + + /** + * @param callable|null $resolveField + * + * @return $this + */ + public function resolveField(callable $resolveField = null) + { + $this->addConfig('resolveField', $resolveField, false); + + return $this; + } +} diff --git a/src/Type/Builder/TypeConfigTrait.php b/src/Type/Builder/TypeConfigTrait.php new file mode 100644 index 000000000..79e55042f --- /dev/null +++ b/src/Type/Builder/TypeConfigTrait.php @@ -0,0 +1,25 @@ +addConfig('type', $type, false); + + return $this; + } +} diff --git a/tests/Type/Builder/ObjectTypeConfigTest.php b/tests/Type/Builder/ObjectTypeConfigTest.php new file mode 100644 index 000000000..f7c8be8b2 --- /dev/null +++ b/tests/Type/Builder/ObjectTypeConfigTest.php @@ -0,0 +1,224 @@ +field1Resolver = function () { + return 'resolve it!'; + }; + $this->isTypeOf = function () { + return true; + }; + $this->interface = new InterfaceType(['name' => 'Foo', 'fields' => ['field2' => ['type' => Type::nonNull(Type::string())]]]); + } + + public function testBuildUsingAddField() + { + $args = ArgsConfig::create() + ->addArg('arg1', Type::boolean(), true, 'description arg1') + ->addArg('arg2', Type::string(), 'defaultVal', 'description arg2'); + + $config = ObjectTypeConfig::create() + ->name('TypeName') + ->description('My new Object') + ->interfaces([$this->interface]) + ->addField('field1', Type::string(), 'description field1', $args, $this->field1Resolver) + ->addField('field2', Type::nonNull(Type::string())) + ->addDeprecatedField('deprecatedField', Type::string(), 'This field is deprecated.') + ->isTypeOf($this->isTypeOf) + ->resolveField(); + + $this->assertConfig($config); + } + + public function testBuildUsingFields() + { + $args = ArgsConfig::create() + ->addArg('arg1', Type::boolean(), true, 'description arg1') + ->addArg('arg2', Type::string(), 'defaultVal', 'description arg2'); + + $fields = FieldsConfig::create() + ->addField('field1', Type::string(), 'description field1', $args, $this->field1Resolver) + ->addField('field2', Type::nonNull(Type::string())) + ; + $config = ObjectTypeConfig::create() + ->name('TypeName') + ->description('My new Object') + ->interfaces([$this->interface]) + ->fields($fields) + ->addDeprecatedField('deprecatedField', Type::string(), 'This field is deprecated.') + ->isTypeOf($this->isTypeOf) + ->resolveField(); + + $this->assertConfig($config); + } + + public function testBuildUsingFieldConfig() + { + $args = ArgsConfig::create() + ->addArg('arg1', Type::boolean(), true, 'description arg1') + ->addArg('arg2', Type::string(), 'defaultVal', 'description arg2'); + + $fields = FieldsConfig::create(); + + $fields->addFieldConfig( + FieldConfig::create() + ->name('field1')->type(Type::string())->description('description field1') + ->addArgs($args)->resolve($this->field1Resolver) + ) + ->addFieldConfig(FieldConfig::create()->name('field2')->type(Type::nonNull(Type::string()))); + ; + $config = ObjectTypeConfig::create() + ->name('TypeName') + ->description('My new Object') + ->interfaces([$this->interface]) + ->fields($fields) + ->addDeprecatedField('deprecatedField', Type::string(), 'This field is deprecated.') + ->isTypeOf($this->isTypeOf) + ->resolveField(); + + $this->assertConfig($config); + } + + public function testFieldsAsCallable() + { + $fields = function () { + return []; + }; + + $config = ObjectTypeConfig::create() + ->name('TypeName') + ->fields($fields); + + $this->assertEquals( + [ + 'name' => 'TypeName', + 'fields' => $fields, + ], + $config->build() + ); + } + + public function testFieldWithComplexity() + { + $complexity = function () { + return 2000; + }; + + $config = ObjectTypeConfig::create() + ->name('TypeName') + ->addFieldConfig( + FieldConfig::create() + ->name('field1') + ->addArg(ArgConfig::create()->name('arg1')->type(Type::string())) + ->type(Type::string()) + ->complexity($complexity) + ) + ; + + $this->assertEquals( + [ + 'name' => 'TypeName', + 'fields' => [ + [ + 'name' => 'field1', + 'type' => Type::string(), + 'args' => [ + [ + 'name' => 'arg1', + 'type' => Type::string(), + ], + ], + 'complexity' => $complexity + ] + ], + ], + $config->build() + ); + } + + public function testFieldsWithComplexity() + { + $complexity = function () { + return 2000; + }; + + $fields = FieldsConfig::create() + ->addField('field1', Type::string(), null, null, null, $complexity) + ; + + $this->assertEquals( + [ + [ + 'name' => 'field1', + 'type' => Type::string(), + 'complexity' => $complexity + ] + ], + $fields->build() + ); + } + + private function assertConfig(Config $config) + { + $this->assertEquals( + [ + 'name' => 'TypeName', + 'description' => 'My new Object', + 'interfaces' => [$this->interface], + 'fields' => [ + [ + 'name' => 'field1', + 'type' => Type::string(), + 'description' => 'description field1', + 'resolve' => $this->field1Resolver, + 'args' => [ + [ + 'name' => 'arg1', + 'type' => Type::boolean(), + 'description' => 'description arg1', + 'defaultValue' => true, + ], + [ + 'name' => 'arg2', + 'type' => Type::string(), + 'description' => 'description arg2', + 'defaultValue' => 'defaultVal', + ], + ], + ], + [ + 'name' => 'field2', + 'type' => Type::nonNull(Type::string()), + ], + [ + 'name' => 'deprecatedField', + 'type' => Type::string(), + 'deprecationReason' => 'This field is deprecated.', + ], + ], + 'isTypeOf' => $this->isTypeOf, + 'resolveField' => null, + ], + $config->build() + ); + } +}