Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Add Directive types #580

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion src/Schema/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
use SilverStripe\ORM\ArrayLib;
use Exception;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\GraphQL\Schema\Type\Directive;
use TypeError;

/**
Expand All @@ -62,6 +63,7 @@ class Schema implements ConfigurationApplier
const UNIONS = 'unions';
const ENUMS = 'enums';
const SCALARS = 'scalars';
const DIRECTIVES = 'directives';
const QUERY_TYPE = 'Query';
const MUTATION_TYPE = 'Mutation';
const ALL = '*';
Expand Down Expand Up @@ -108,6 +110,11 @@ class Schema implements ConfigurationApplier
*/
private array $scalars = [];

/**
* @var Directive[]
*/
private array $directives = [];

private Type $queryType;

private Type $mutationType;
Expand Down Expand Up @@ -151,6 +158,7 @@ public function applyConfig(array $schemaConfig): Schema
self::MODELS,
self::ENUMS,
self::SCALARS,
self::DIRECTIVES,
self::SCHEMA_CONFIG,
'execute',
self::SOURCE,
Expand All @@ -166,6 +174,7 @@ public function applyConfig(array $schemaConfig): Schema
$models = $schemaConfig[self::MODELS] ?? [];
$enums = $schemaConfig[self::ENUMS] ?? [];
$scalars = $schemaConfig[self::SCALARS] ?? [];
$directives = $schemaConfig[self::DIRECTIVES] ?? [];
$config = $schemaConfig[self::SCHEMA_CONFIG] ?? [];


Expand Down Expand Up @@ -249,6 +258,13 @@ public function applyConfig(array $schemaConfig): Schema
$this->addScalar($scalar);
}

static::assertValidConfig($directives);
foreach ($directives as $directiveName => $directiveConfig) {
static::assertValidConfig($directiveConfig, ['name', 'description', 'args', 'locations']);
$directive = Directive::create($directiveName, $directiveConfig);
$this->addDirective($directive);
}

$this->applyProceduralUpdates($config['execute'] ?? []);

return $this;
Expand Down Expand Up @@ -569,7 +585,8 @@ public function createStoreableSchema(): StorableSchema
self::ENUMS => $this->getEnums(),
self::INTERFACES => $this->getInterfaces(),
self::UNIONS => $this->getUnions(),
self::SCALARS => $this->getScalars()
self::SCALARS => $this->getScalars(),
self::DIRECTIVES => $this->getDirectives()
],
$this->getConfig()
);
Expand Down Expand Up @@ -757,6 +774,22 @@ public function removeScalar(string $name): self
return $this;
}

public function getDirectives(): array
{
return $this->directives;
}

public function getDirective(string $name): ?Directive
{
return $this->directives[$name] ?? null;
}

public function addDirective(Directive $directive): self
{
$this->directives[$directive->getName()] = $directive;
return $this;
}

/**
* @throws SchemaBuilderException
*/
Expand Down
1 change: 1 addition & 0 deletions src/Schema/SchemaBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ private static function getSchemaConfigFromSource(string $schemaKey, string $dir
Schema::INTERFACES => [],
Schema::UNIONS => [],
Schema::SCALARS => [],
Schema::DIRECTIVES => [],
];

$finder = new Finder();
Expand Down
21 changes: 19 additions & 2 deletions src/Schema/StorableSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\GraphQL\Schema\Exception\SchemaBuilderException;
use SilverStripe\GraphQL\Schema\Interfaces\SchemaValidator;
use SilverStripe\GraphQL\Schema\Type\Directive;
use SilverStripe\GraphQL\Schema\Type\Enum;
use SilverStripe\GraphQL\Schema\Type\InterfaceType;
use SilverStripe\GraphQL\Schema\Type\Scalar;
Expand Down Expand Up @@ -50,6 +51,11 @@ class StorableSchema implements SchemaValidator
*/
private array $scalars;

/**
* @var Directive[]
*/
private array $directives;

private SchemaConfig $config;

public function __construct(array $config = [], ?SchemaConfig $context = null)
Expand All @@ -59,6 +65,7 @@ public function __construct(array $config = [], ?SchemaConfig $context = null)
$this->interfaces = $config[Schema::INTERFACES] ?? [];
$this->unions = $config[Schema::UNIONS] ?? [];
$this->scalars = $config[Schema::SCALARS] ?? [];
$this->directives = $config[Schema::DIRECTIVES] ?? [];
$this->config = $context ?: SchemaConfig::create();
}

Expand Down Expand Up @@ -102,6 +109,14 @@ public function getScalars(): array
return $this->scalars;
}

/**
* @return Directive[]
*/
public function getDirectives(): array
{
return $this->directives;
}

public function getConfig(): SchemaConfig
{
return $this->config;
Expand Down Expand Up @@ -137,7 +152,8 @@ public function validate(): void
array_keys($this->enums ?? []),
array_keys($this->interfaces ?? []),
array_keys($this->unions ?? []),
array_keys($this->scalars ?? [])
array_keys($this->scalars ?? []),
array_keys($this->directives ?? [])
);
$dupes = [];
foreach (array_count_values($allNames ?? []) as $val => $count) {
Expand Down Expand Up @@ -170,7 +186,8 @@ public function validate(): void
$this->enums,
$this->interfaces,
$this->unions,
$this->scalars
$this->scalars,
$this->directives
);
/* @var SchemaValidator $validator */
foreach ($validators as $validator) {
Expand Down
23 changes: 17 additions & 6 deletions src/Schema/Storage/CodeGenerationStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace SilverStripe\GraphQL\Schema\Storage;

use Exception;
use GraphQL\GraphQL;
use GraphQL\Type\Schema as GraphQLSchema;
use GraphQL\Type\SchemaConfig as GraphQLSchemaConfig;
use Psr\Log\LoggerInterface;
Expand All @@ -29,6 +30,7 @@ class CodeGenerationStore implements SchemaStorageInterface
use Configurable;

const TYPE_CLASS_NAME = 'Types';
const DIRECTIVE_CLASS_NAME = 'Directives';

/**
* @config
Expand Down Expand Up @@ -137,6 +139,8 @@ public function persistSchema(StorableSchema $schema): void
'typeClassName' => self::TYPE_CLASS_NAME,
'namespace' => $this->getNamespace(),
'obfuscator' => $obfuscator,
'directiveClassName' => self::DIRECTIVE_CLASS_NAME,
'directives' => $schema->getDirectives()
];

$config = $schema->getConfig()->toArray();
Expand All @@ -146,10 +150,10 @@ public function persistSchema(StorableSchema $schema): void
$fs->dumpFile(
$configFile,
'<?php ' .
PHP_EOL .
'return ' .
var_export($config, true) .
';'
PHP_EOL .
'return ' .
var_export($config, true) .
';'
Comment on lines -149 to +156
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this change made? It seems unrelated

);
} catch (IOException $e) {
throw new RuntimeException(sprintf(
Expand All @@ -164,7 +168,8 @@ public function persistSchema(StorableSchema $schema): void
$schema->getEnums(),
$schema->getInterfaces(),
$schema->getUnions(),
$schema->getScalars()
$schema->getScalars(),
$schema->getDirectives(),
);
$encoder = Encoder::create(Path::join($templateDir, 'registry.inc.php'), $allComponents, $globals);
$code = $encoder->encode();
Expand All @@ -185,13 +190,14 @@ public function persistSchema(StorableSchema $schema): void
'Unions' => 'union.inc.php',
'Enums' => 'enum.inc.php',
'Scalars' => 'scalar.inc.php',
'Directives' => 'directive.inc.php',
];
$touched = [];
$built = [];
$total = 0;
foreach ($fields as $field => $template) {
$method = 'get' . $field;
/* @var Type|InterfaceType|UnionType|Enum $type */
/* @var Type|InterfaceType|UnionType|Enum|Directive $type */
foreach ($schema->$method() as $type) {
$total++;
$name = $type->getName();
Expand Down Expand Up @@ -311,6 +317,11 @@ function (string $name) use ($registryClass) {

$schemaConfig->setTypes($typeObjs);

$directivesClass = $this->getClassName(self::DIRECTIVE_CLASS_NAME);
$directives = call_user_func([$directivesClass, Schema::DIRECTIVES]);
$directives = array_merge(GraphQL::getStandardDirectives(), $directives);
$schemaConfig->setDirectives($directives);

$this->graphqlSchema = new GraphQLSchema($schemaConfig);

return $this->graphqlSchema;
Expand Down
43 changes: 43 additions & 0 deletions src/Schema/Storage/templates/directive.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/* @var object $scope */
/* @var \SilverStripe\GraphQL\Schema\Type\Directive $directive */
/* @var array $globals */
?>
<?php $directive = $scope; ?>
namespace <?=$globals['namespace']; ?>;

use GraphQL\Type\Definition\Directive;

// @type:<?=$directive->getName(); ?>

class <?=$globals['obfuscator']->obfuscate($directive->getName()) ?> extends Directive
{
public function __construct()
{
parent::__construct([
'name' => '<?=$directive->getName() ?>',
<?php if (!empty($directive->getDescription())) : ?>
'description' => '<?=addslashes($directive->getDescription()); ?>',
<?php endif; ?>

'locations' => [
<?php foreach ($directive->getLocations() as $location) : ?>
'<?=$location; ?>',
<?php endforeach; ?>
], // locations
<?php if (!empty($directive->getArgs())) : ?>
'args' => [
<?php foreach ($directive->getArgs() as $arg) : ?>
[
'name' => '<?=$arg->getName(); ?>',
'type' => <?=$arg->getEncodedType()->encode(); ?>,
<?php if ($arg->getDefaultValue() !== null) : ?>
'defaultValue' => <?=var_export($arg->getDefaultValue(), true); ?>,
<?php endif; ?>
], // arg
<?php endforeach; ?>
], // args
<?php endif; ?>
]);
}
}
24 changes: 24 additions & 0 deletions src/Schema/Storage/templates/registry.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,27 @@ public static function <?=$component->getName(); ?>() { return static::get('<?=$
<?php endforeach; ?>

}

Copy link
Author

@marwan38 marwan38 Apr 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably breaks some PSR specs, I'm not sure if it matters here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You say "this" on a comment on an empty line... but I assume you are actually referring to having multiple classes defined in the same file?

That does break PSR1 (see the PSR1 spec).
Ideally each of these templates should be explicitly for a single class.

One approach would be to reuse the same template file (with only one clsas definition) for both of these since they're practically identical, and just add appropriate conditional statements. e.g. type.inc.php uses a lot of conditional logic to build its class.

class <?=$globals['directiveClassName']; ?> extends AbstractTypeRegistry
{
protected static $types = [];

protected static function getSourceDirectory(): string
{
return __DIR__;
}

protected static function getSourceNamespace(): string
{
return __NAMESPACE__;
}

public static function directives() {
return [
<?php foreach ($globals['directives'] as $directive) : ?>
static::get('<?=$directive->getName(); ?>'),
<?php endforeach; ?>
];
}

}
Loading