Skip to content

Commit

Permalink
API Add Directive types
Browse files Browse the repository at this point in the history
Directives are part of the GraphQL specification, this PR adds the Directive
type. Follow up PRs would be needed to fully utilise the spec.
  • Loading branch information
Marwan Mustafa Fikrat committed Apr 13, 2024
1 parent 6b22696 commit 9c0fea3
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 10 deletions.
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) .
';'
);
} 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; ?>

}

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

0 comments on commit 9c0fea3

Please sign in to comment.