Compare commits

..

No commits in common. "1e9b99c7a635cddf4c0561a5bf85ecc426d7927a" and "e7d7d18f77680a6cdbe97359024b4ac261d7a189" have entirely different histories.

25 changed files with 630 additions and 61913 deletions

1
.gitignore vendored
View File

@ -1 +0,0 @@
node_modules

View File

@ -1 +0,0 @@
vendor

View File

@ -1,11 +0,0 @@
{
"printWidth": 120,
"tabWidth": 2,
"singleQuote": true,
"semi": true,
"trailingComma": "es5",
"arrowParens": "always",
"phpVersion": "7.1"
}

17
.vscode/settings.json vendored
View File

@ -1,17 +0,0 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[php]":
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
},
"search.exclude": {
"**/vendor": true,
"**/node_modules": true,
"yarn.lock": true,
"package.json": true,
"tsconfig.json": true,
".*": true,
},
}

View File

@ -17,15 +17,15 @@ class Plugin extends PluginBase
{
return [
'settings' => [
'label' => 'germanairlinesva.graphql::lang.settings.label',
'label' => 'germanairlinesva.graphql::lang.settings.label',
'description' => 'germanairlinesva.graphql::lang.settings.description',
'category' => 'system::lang.system.categories.cms',
'icon' => 'icon-compress',
'class' => 'GermanAirlinesVa\Graphql\Models\Settings',
'order' => 1000,
'keywords' => 'graphql',
'permissions' => ['germanairlinesva.graphql.schemas'],
],
'category' => 'system::lang.system.categories.cms',
'icon' => 'icon-compress',
'class' => 'GermanAirlinesVa\Graphql\Models\Settings',
'order' => 1000,
'keywords' => 'graphql',
'permissions' => ['germanairlinesva.graphql.schemas']
]
];
}
@ -48,22 +48,28 @@ class Plugin extends PluginBase
$packages = Config::get($pluginNamespace . '::packages');
// Boot each package
foreach ($packages as $name => $options) {
foreach ($packages as $name => $options)
{
// Setup the configuration for the package, pulling from this plugin's config
if (!empty($options['config']) && !empty($options['config_namespace'])) {
if (!empty($options['config']) && !empty($options['config_namespace']))
{
Config::set($options['config_namespace'], $options['config']);
}
// Register any Service Providers for the package
if (!empty($options['providers'])) {
foreach ($options['providers'] as $provider) {
if (!empty($options['providers']))
{
foreach ($options['providers'] as $provider)
{
App::register($provider);
}
}
// Register any Aliases for the package
if (!empty($options['aliases'])) {
foreach ($options['aliases'] as $alias => $path) {
if (!empty($options['aliases']))
{
foreach ($options['aliases'] as $alias => $path)
{
$aliasLoader->alias($alias, $path);
}
}
@ -72,3 +78,4 @@ class Plugin extends PluginBase
return $packages;
}
}

File diff suppressed because one or more lines are too long

View File

@ -6,17 +6,19 @@ use Illuminate\Http\Request;
use Nuwave\Lighthouse\Support\Contracts\CreatesContext as LighthouseCreatesContext;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
class CreatesContext implements LighthouseCreatesContext
{
/**
* Generate GraphQL context.
*
* @param Request $request
*
* @return GraphQLContext
*/
public function generate(Request $request): GraphQLContext
{
return new SchemaContext($request);
}
/**
* Generate GraphQL context.
*
* @param Request $request
*
* @return GraphQLContext
*/
public function generate(Request $request): GraphQLContext
{
return new SchemaContext($request);
}
}

View File

@ -5,34 +5,42 @@ namespace GermanAirlinesVa\Graphql\Classes;
use Lang;
use Cms\Classes\Page;
class Graph extends Page
{
/**
* @var string The container name associated with the model.
*/
protected $dirName = 'graphs';
/**
* @var array The attributes that are mass assignable.
*/
protected $fillable = ['title', 'description', 'markup', 'settings', 'code'];
/**
* @var string The container name associated with the model.
*/
protected $dirName = 'graphs';
/**
* @var array The rules to be applied to the data.
*/
public $rules = [
'title' => 'required',
];
/**
* @var array The attributes that are mass assignable.
*/
protected $fillable = [
'title',
'description',
'markup',
'settings',
'code'
];
public function getCodeClassParent(): string
{
return GraphCode::class;
}
/**
* @var array The rules to be applied to the data.
*/
public $rules = [
'title' => 'required'
];
public function runComponents()
{
foreach ($this->components as $component) {
$component->onRun();
public function getCodeClassParent() : string {
return GraphCode::class;
}
}
public function runComponents()
{
foreach ($this->components as $component) {
$component->onRun();
}
}
}

View File

@ -8,46 +8,48 @@ use October\Rain\Extension\Extendable;
*/
class GraphCode extends CodeBase
{
public $graph;
/**
* Creates the object instance.
* @param \GermanAirlinesVa\Graphql\Classes\Graph $graph Specifies the Headstart graph.
* @param null
* @param \GermanAirlinesVa\Graphql\Classes\GraphController $controller Specifies the Graph controller.
*/
public function __construct($graph, $layout, $controller)
{
$this->graph = $graph;
$this->controller = $controller;
public $graph;
Extendable::__construct();
}
/**
* Creates the object instance.
* @param \GermanAirlinesVa\Graphql\Classes\Graph $graph Specifies the Headstart graph.
* @param null
* @param \GermanAirlinesVa\Graphql\Classes\GraphController $controller Specifies the Graph controller.
*/
public function __construct($graph, $layout, $controller)
{
$this->graph = $graph;
$this->controller = $controller;
public function __get($name)
{
if (isset($this->graph->components[$name]) || isset($this->layout->components[$name])) {
return $this[$name];
Extendable::__construct();
}
if (($value = $this->graph->{$name}) !== null) {
return $value;
public function __get($name)
{
if (isset($this->graph->components[$name]) || isset($this->layout->components[$name])) {
return $this[$name];
}
if (($value = $this->graph->{$name}) !== null) {
return $value;
}
if (array_key_exists($name, $this->controller->vars)) {
return $this[$name];
}
return null;
}
if (array_key_exists($name, $this->controller->vars)) {
return $this[$name];
public function __set($name, $value)
{
return $this->graph->{$name} = $value;
}
return null;
}
public function __isset($name)
{
return isset($this->graph->{$name});
}
public function __set($name, $value)
{
return $this->graph->{$name} = $value;
}
public function __isset($name)
{
return isset($this->graph->{$name});
}
}

View File

@ -8,109 +8,111 @@ use Cms\Classes\Controller;
use Cms\Classes\CmsException;
use Cms\Classes\ComponentManager;
class GraphController // extends Controller
class GraphController// extends Controller
{
protected $graph;
/**
* @var self Cache of self
*/
protected static $instance;
protected $graph;
/**
* Creates the controller.
*/
public function __construct($graph, $args)
{
$this->graph = $graph;
$this->router = new GraphRouter($args);
/**
* @var self Cache of self
*/
protected static $instance;
self::$instance = $this;
}
/**
* Returns an existing instance of the controller.
* If the controller doesn't exists, returns null.
* @return mixed Returns the controller object or null.
*/
public static function getController()
{
return self::$instance;
}
/**
* Creates the controller.
*/
public function __construct($graph, $args)
{
$this->graph = $graph;
$this->router = new GraphRouter($args);
public function component($alias)
{
if (isset($this->graph->components[$alias])) {
return $this->graph->components[$alias];
self::$instance = $this;
}
foreach ($this->graph->settings['components'] as $component => $properties) {
[$name, $component_alias] = strpos($component, ' ') ? explode(' ', $component) : [$component, $component];
/**
* Returns an existing instance of the controller.
* If the controller doesn't exists, returns null.
* @return mixed Returns the controller object or null.
*/
public static function getController()
{
return self::$instance;
}
if ($component_alias == $alias) {
// make component
$manager = ComponentManager::instance();
if (!($componentObj = $manager->makeComponent($name, null, $properties))) {
throw new CmsException(
Lang::get('cms::lang.component.not_found', [
'name' => $name,
])
);
public function component($alias) {
if (isset($this->graph->components[$alias])) {
return $this->graph->components[$alias];
}
$this->setComponentPropertiesFromParams($componentObj, $this->router->getParameters());
$componentObj->init();
foreach ($this->graph->settings['components'] as $component => $properties) {
list($name, $component_alias) = strpos($component, ' ')
? explode(' ', $component)
: [$component, $component];
$componentObj->alias = $alias;
$this->graph->components[$alias] = $componentObj;
if ($component_alias == $alias) {
// make component
$manager = ComponentManager::instance();
return $componentObj;
}
}
}
if (!$componentObj = $manager->makeComponent($name, null, $properties)) {
throw new CmsException(Lang::get('cms::lang.component.not_found', ['name' => $name]));
}
/**
* Sets component property values from partial parameters.
* The property values should be defined as {{ param }}.
* @param ComponentBase $component The component object.
* @param array $parameters Specifies the partial parameters.
*/
protected function setComponentPropertiesFromParams($component, $parameters = [])
{
$properties = $component->getProperties();
$routerParameters = $this->router->getParameters();
$this->setComponentPropertiesFromParams($componentObj, $this->router->getParameters());
$componentObj->init();
foreach ($properties as $propertyName => $propertyValue) {
if (is_array($propertyValue)) {
continue;
}
$componentObj->alias = $alias;
$this->graph->components[$alias] = $componentObj;
$matches = [];
if (preg_match('/^\{\{([^\}]+)\}\}$/', $propertyValue, $matches)) {
$paramName = trim($matches[1]);
if (substr($paramName, 0, 1) == ':') {
$routeParamName = substr($paramName, 1);
$newPropertyValue = $routerParameters[$routeParamName] ?? null;
} else {
$newPropertyValue = $parameters[$paramName] ?? null;
return $componentObj;
}
}
$component->setProperty($propertyName, $newPropertyValue);
$component->setExternalPropertyName($propertyName, $paramName);
}
}
}
/**
* Returns a routing parameter.
* @param string $name Routing parameter name.
* @param string $default Default to use if none is found.
* @return string
*/
public function param($name, $default = null)
{
return $this->router->getParameter($name, $default);
}
/**
* Sets component property values from partial parameters.
* The property values should be defined as {{ param }}.
* @param ComponentBase $component The component object.
* @param array $parameters Specifies the partial parameters.
*/
protected function setComponentPropertiesFromParams($component, $parameters = [])
{
$properties = $component->getProperties();
$routerParameters = $this->router->getParameters();
foreach ($properties as $propertyName => $propertyValue) {
if (is_array($propertyValue)) {
continue;
}
$matches = [];
if (preg_match('/^\{\{([^\}]+)\}\}$/', $propertyValue, $matches)) {
$paramName = trim($matches[1]);
if (substr($paramName, 0, 1) == ':') {
$routeParamName = substr($paramName, 1);
$newPropertyValue = $routerParameters[$routeParamName] ?? null;
}
else {
$newPropertyValue = $parameters[$paramName] ?? null;
}
$component->setProperty($propertyName, $newPropertyValue);
$component->setExternalPropertyName($propertyName, $paramName);
}
}
}
/**
* Returns a routing parameter.
* @param string $name Routing parameter name.
* @param string $default Default to use if none is found.
* @return string
*/
public function param($name, $default = null)
{
return $this->router->getParameter($name, $default);
}
}

View File

@ -7,35 +7,38 @@ use Cms\Classes\Router;
class GraphRouter //extends Router
{
/**
* @var array A list of parameters names and values extracted from the URL pattern and URL string.
*/
protected $parameters = [];
public function __construct($parameters)
{
$this->parameters = $parameters;
}
/**
* @var array A list of parameters names and values extracted from the URL pattern and URL string.
*/
protected $parameters = [];
/**
* Returns the current routing parameters.
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
/**
* Returns a routing parameter.
* @return array
*/
public function getParameter($name, $default = null)
{
if (isset($this->parameters[$name]) && !empty($this->parameters[$name])) {
return $this->parameters[$name];
public function __construct($parameters)
{
$this->parameters = $parameters;
}
/**
* Returns the current routing parameters.
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
/**
* Returns a routing parameter.
* @return array
*/
public function getParameter($name, $default = null)
{
if (isset($this->parameters[$name]) && !empty($this->parameters[$name])) {
return $this->parameters[$name];
}
return $default;
}
return $default;
}
}

View File

@ -9,12 +9,14 @@ use GermanAirlinesVa\Graphql\Classes\CreatesContext as GraphqlCreatesContext;
use October\Rain\Support\ServiceProvider;
class GraphqlServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(ProvidesResolver::class, GraphqlProvidesResolver::class);
$this->app->singleton(CreatesContext::class, GraphqlCreatesContext::class);
$this->app->singleton(SchemaSourceProvider::class, GraphqlSchemaSourceProvider::class);
}
class GraphqlServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind(ProvidesResolver::class, GraphqlProvidesResolver::class);
$this->app->singleton(CreatesContext::class, GraphqlCreatesContext::class);
$this->app->singleton(SchemaSourceProvider::class, GraphqlSchemaSourceProvider::class);
}
}

View File

@ -6,32 +6,34 @@ use GraphQL\Type\Definition\ResolveInfo;
use Cms\Classes\CodeParser;
use Nuwave\Lighthouse\Schema\ResolverProvider as LighthouseResolverProvider;
class ResolverProvider extends LighthouseResolverProvider
{
/**
* Provide a field resolver in case no resolver directive is defined for a field.
*
* @param \Nuwave\Lighthouse\Schema\Values\FieldValue $fieldValue
* @return \Closure
*/
public function provideResolver(FieldValue $fieldValue): Closure
{
return function ($root, array $args, $context, ResolveInfo $resolveInfo) use ($fieldValue) {
$fieldName = $fieldValue->getFieldName();
// use local graph resolver in code section if existent
if ($graphObj = $context->source->findGraph($fieldName)) {
/* @var $graphObj \GermanAirlinesVa\Graphql\Classes\Graph */
$parser = new CodeParser($graphObj);
$codeObj = $parser->source($graphObj, null, new GraphController($graphObj, $args));
$resolveMethod = 'resolve' . studly_case($fieldName);
if (method_exists($codeObj, $resolveMethod)) {
return $codeObj->$resolveMethod($root, $args, $context, $resolveInfo);
}
}
class ResolverProvider extends LighthouseResolverProvider {
/**
* Provide a field resolver in case no resolver directive is defined for a field.
*
* @param \Nuwave\Lighthouse\Schema\Values\FieldValue $fieldValue
* @return \Closure
*/
public function provideResolver(FieldValue $fieldValue): Closure
{
return function ($root, array $args, $context, ResolveInfo $resolveInfo) use ($fieldValue) {
$fieldName = $fieldValue->getFieldName();
// use local graph resolver in code section if existent
if ($graphObj = $context->source->findGraph($fieldName)) {
/* @var $graphObj \GermanAirlinesVa\Graphql\Classes\Graph */
$parser = new CodeParser($graphObj);
$codeObj = $parser->source($graphObj, null, new GraphController($graphObj, $args));
$resolveMethod = 'resolve' . studly_case($fieldName);
if (method_exists($codeObj, $resolveMethod)) {
return $codeObj->$resolveMethod($root, $args, $context, $resolveInfo);
}
}
// default resolver
return parent::provideResolver($fieldValue)($root, $args, $context, $resolveInfo);
};
}
// default resolver
return parent::provideResolver($fieldValue)($root, $args, $context, $resolveInfo);
};
}
}

View File

@ -6,37 +6,39 @@ use Cms\Classes\Theme;
class Schema extends Theme
{
/**
* Returns the absolute theme path.
* @param string $dirName Optional theme directory. Defaults to $this->getDirName()
* @return string
*/
public function getPath(?string $dirName = null): string
{
if (!$dirName) {
$dirName = $this->getDirName();
/**
* Returns the absolute theme path.
* @param string $dirName Optional theme directory. Defaults to $this->getDirName()
* @return string
*/
public function getPath(?string $dirName = null): string
{
if (!$dirName) {
$dirName = $this->getDirName();
}
return base_path() . '/' . $dirName;
}
return base_path() . '/' . $dirName;
}
/**
* Returns a list of graphs in the template.
* @param boolean $skipCache Indicates if the pages should be reloaded from the disk bypassing the cache.
* @return array Returns an array of Nocio\Headstart\Classes\Graph objects.
*/
public function listGraphs($skipCache = false)
{
return Graph::listInTheme($this, $skipCache);
}
/**
* Returns a list of graphs in the template.
* @param boolean $skipCache Indicates if the pages should be reloaded from the disk bypassing the cache.
* @return array Returns an array of Nocio\Headstart\Classes\Graph objects.
*/
public function listGraphs($skipCache = false)
{
return Graph::listInTheme($this, $skipCache);
}
/**
* Returns the active theme code.
*
* @return string
* If the theme doesn't exist, returns null.
*/
public static function getActiveThemeCode(): ?string
{
return 'graphql';
}
/**
* Returns the active theme code.
*
* @return string
* If the theme doesn't exist, returns null.
*/
public static function getActiveThemeCode(): ?string
{
return 'graphql';
}
}

View File

@ -7,20 +7,24 @@ use Nuwave\Lighthouse\Schema\Context;
use Illuminate\Http\Request;
use Nuwave\Lighthouse\Schema\Source\SchemaSourceProvider;
class SchemaContext extends Context
{
public $source;
/**
* Create new context.
*
* @param Request $request
* @param $source
*/
public function __construct(Request $request)
{
parent::__construct($request);
public $source;
/**
* Create new context.
*
* @param Request $request
* @param $source
*/
public function __construct(Request $request)
{
parent::__construct($request);
$this->source = App::make(SchemaSourceProvider::class);
}
$this->source = App::make(SchemaSourceProvider::class);
}
}

View File

@ -11,64 +11,66 @@ use Cms\Classes\ComponentPartial;
class SchemaSourceProvider implements LighthouseSchemaSourceProvider
{
protected $fieldGraphMapCacheKey = 'graphql-schema-field-graph-map';
/**
* @var Schema
*/
public $template;
protected $fieldGraphMapCacheKey = 'graphql-schema-field-graph-map';
/**
* @var string
*/
protected $rootSchemaPath;
/**
* @var Schema
*/
public $template;
/**
* @var array
* Collects graphs and their parsed schema
*/
protected $graphMap;
/**
* @var string
*/
protected $rootSchemaPath;
/**
* @var array
* Maps field names to graphs
*/
protected $fieldGraphMap;
/**
* @var array
* Collects graphs and their parsed schema
*/
protected $graphMap;
/**
* SchemaSource constructor.
*
* @param string|null $template
*/
public function __construct($template = null)
{
$this->template = Schema::load(is_string($template) ? $template : 'graphql');
$this->rootSchemaPath = $this->template->getPath();
}
/**
* @var array
* Maps field names to graphs
*/
protected $fieldGraphMap;
/**
* Set schema root path.
*
* @param string $path
*
* @return SchemaSourceProvider
*/
public function setRootPath(string $path): self
{
$this->rootSchemaPath = $path;
return $this;
}
/**
* SchemaSource constructor.
*
* @param string|null $template
*/
public function __construct($template = null)
{
$this->template = Schema::load(is_string($template) ? $template : 'graphql');
$this->rootSchemaPath = $this->template->getPath();
}
/**
* Stitch together schema documents and return the result as a string.
*
* @return string
*/
public function getSchemaString(): string
{
// root types
$schema = '
/**
* Set schema root path.
*
* @param string $path
*
* @return SchemaSourceProvider
*/
public function setRootPath(string $path): self
{
$this->rootSchemaPath = $path;
return $this;
}
/**
* Stitch together schema documents and return the result as a string.
*
* @return string
*/
public function getSchemaString(): string
{
// root types
$schema = '
type Query {
dummy: Boolean
}
@ -77,141 +79,143 @@ class SchemaSourceProvider implements LighthouseSchemaSourceProvider
dummy: Boolean
}
';
// schema
$schema .= collect($this->getGraphMap())->implode('schema', '');
return $schema;
}
public function findGraph($fieldName, $findOrFail = false)
{
if (!isset($this->getFieldGraphMap()[$fieldName])) {
if ($findOrFail) {
throw new Error("Could not find graph of field '{$fieldName}'.");
}
return null;
// schema
$schema .= collect($this->getGraphMap())->implode('schema', '');
return $schema;
}
$name = $this->getFieldGraphMap()[$fieldName];
if (isset($this->graphMap[$name])) {
// if available, use already instantiated graph objects in memory
return $this->graphMap[$name]['graph'];
}
return Graph::loadCached($this->template, $name);
}
public function getFieldGraphMap()
{
if (!is_null($this->fieldGraphMap)) {
return $this->fieldGraphMap;
}
// restore from cache
$cacheable = true;
if ($cacheable) {
$map = Cache::get($this->fieldGraphMapCacheKey, false);
if ($map && ($map = @unserialize(@base64_decode($map))) && is_array($map)) {
$this->fieldGraphMap = $map;
return $this->fieldGraphMap;
}
}
// rebuild mapping
$this->fieldGraphMap = [];
foreach ($this->getGraphMap() as $key => $element) {
if (empty(trim($element['schema']))) {
continue;
}
// parse the AST to collect fields mapping
$ast = Parser::parse($element['schema'], ['noLocation' => true]);
$fields = collect($ast->definitions)
->filter(function ($node) {
// we only consider the root types since their fields are unique
return $node->name->value == 'Query' || $node->name->value == 'Mutation';
})
->flatMap(function ($node) {
// collect field names
return collect($node->fields)->map(function ($field) {
return $field->name->value;
});
});
// map as [$field_name => $graph_filename]
$this->fieldGraphMap = array_merge($this->fieldGraphMap, array_fill_keys($fields->toArray(), $key));
}
// cache mapping
if ($cacheable) {
Cache::put($this->fieldGraphMapCacheKey, base64_encode(serialize($this->fieldGraphMap)), 10);
}
return $this->fieldGraphMap;
}
public function getGraphMap()
{
if (!is_null($this->graphMap)) {
return $this->graphMap;
}
$this->graphMap = [];
$component_re = '/{%\s*component\s+["|\'](.*)["|\']\s*%}/m';
$component_str = [$this, 'getComponentSchemaString'];
foreach ($this->template->listGraphs() as $graph) {
/* @var $graph \GermanAirlinesVa\Graphql\Classes\Graph */
$markup = $graph->markup;
$schema = preg_replace_callback(
$component_re,
function (array $matches) use ($graph, $component_str) {
$matched_alias = $matches[1];
foreach ($graph->settings['components'] as $component => $properties) {
// find component by alias
[$name, $alias] = strpos($component, ' ') ? explode(' ', $component) : [$component, $component];
if ($alias == $matched_alias) {
// resolve component schema
return $component_str($name, $alias);
public function findGraph($fieldName, $findOrFail=false) {
if (!isset($this->getFieldGraphMap()[$fieldName])) {
if ($findOrFail) {
throw new Error("Could not find graph of field '{$fieldName}'.");
}
}
// if not found, remove
return '';
},
$markup
);
$this->graphMap[$graph->getFileName()] = [
'graph' => $graph,
'schema' => $schema,
];
return null;
}
$name = $this->getFieldGraphMap()[$fieldName];
if (isset($this->graphMap[$name])) {
// if available, use already instantiated graph objects in memory
return $this->graphMap[$name]['graph'];
}
return Graph::loadCached($this->template, $name);
}
return $this->graphMap;
}
public function getFieldGraphMap() {
if (! is_null($this->fieldGraphMap)) {
return $this->fieldGraphMap;
}
public function getComponentSchemaString($componentName, $alias)
{
$manager = ComponentManager::instance();
$componentObj = $manager->makeComponent($componentName);
if ($partial = ComponentPartial::load($componentObj, 'schema.graphqls')) {
$content = $partial->getContent();
$content = str_replace('__SELF__', $alias, $content);
// restore from cache
return $content;
} else {
return "# {$componentName} does not provide a default schema definition";
$cacheable = true;
if ($cacheable) {
$map = Cache::get($this->fieldGraphMapCacheKey, false);
if (
$map &&
($map = @unserialize(@base64_decode($map))) &&
is_array($map)
) {
$this->fieldGraphMap = $map;
return $this->fieldGraphMap;
}
}
// rebuild mapping
$this->fieldGraphMap = [];
foreach ($this->getGraphMap() as $key => $element) {
if (empty(trim($element['schema']))) {
continue;
}
// parse the AST to collect fields mapping
$ast = Parser::parse($element['schema'], ['noLocation' => true]);
$fields = collect($ast->definitions)
->filter(function ($node) {
// we only consider the root types since their fields are unique
return $node->name->value == 'Query' || $node->name->value == 'Mutation';
})
->flatMap(function ($node) {
// collect field names
return collect($node->fields)->map(function($field) {
return $field->name->value;
});
});
// map as [$field_name => $graph_filename]
$this->fieldGraphMap = array_merge($this->fieldGraphMap, array_fill_keys($fields->toArray(), $key));
}
// cache mapping
if ($cacheable) {
Cache::put(
$this->fieldGraphMapCacheKey,
base64_encode(serialize($this->fieldGraphMap)),
10
);
}
return $this->fieldGraphMap;
}
public function getGraphMap() {
if (!is_null($this->graphMap)) {
return $this->graphMap;
}
$this->graphMap = [];
$component_re = '/{%\s*component\s+["|\'](.*)["|\']\s*%}/m';
$component_str = [$this, 'getComponentSchemaString'];
foreach ($this->template->listGraphs() as $graph) {
/* @var $graph \GermanAirlinesVa\Graphql\Classes\Graph */
$markup = $graph->markup;
$schema = preg_replace_callback($component_re, function(array $matches) use ($graph, $component_str) {
$matched_alias = $matches[1];
foreach ($graph->settings['components'] as $component => $properties) {
// find component by alias
list($name, $alias) = strpos($component, ' ')
? explode(' ', $component)
: [$component, $component];
if ($alias == $matched_alias) {
// resolve component schema
return $component_str($name, $alias);
}
}
// if not found, remove
return '';
}, $markup);
$this->graphMap[$graph->getFileName()] = [
'graph' => $graph,
'schema' => $schema
];
}
return $this->graphMap;
}
public function getComponentSchemaString($componentName, $alias) {
$manager = ComponentManager::instance();
$componentObj = $manager->makeComponent($componentName);
if ($partial = ComponentPartial::load($componentObj, 'schema.graphqls')) {
$content = $partial->getContent();
$content = str_replace('__SELF__', $alias, $content);
return $content;
} else {
return "# {$componentName} does not provide a default schema definition";
}
}
public function clearCache() {
Cache::forget($this->fieldGraphMapCacheKey);
}
}
public function clearCache()
{
Cache::forget($this->fieldGraphMapCacheKey);
}
}

View File

@ -4,13 +4,17 @@ use Cms\Classes\Theme;
use GermanAirlinesVa\Graphql\Models\Settings;
return [
'packages' => [
'nuwave/lighthouse' => [
'config_namespace' => 'lighthouse',
'providers' => ['Nuwave\Lighthouse\LighthouseServiceProvider'],
'aliases' => [],
'config' => [
/*
'packages' => [
'nuwave/lighthouse' => [
'config_namespace' => 'lighthouse',
'providers' => [
'Nuwave\Lighthouse\LighthouseServiceProvider'
],
'aliases' => [
],
'config' => [
/*
|--------------------------------------------------------------------------
| Route Configuration
|--------------------------------------------------------------------------
@ -21,27 +25,27 @@ return [
|
*/
'route' => [
/*
* The URI the endpoint responds to, e.g. mydomain.com/graphql.
*/
'uri' => 'graphql',
'route' => [
/*
* The URI the endpoint responds to, e.g. mydomain.com/graphql.
*/
'uri' => 'graphql',
/*
* Lighthouse creates a named route for convenient URL generation and redirects.
*/
'name' => 'graphql',
/*
* Lighthouse creates a named route for convenient URL generation and redirects.
*/
'name' => 'graphql',
/*
*
* Beware that middleware defined here runs before the GraphQL execution phase,
* so you have to take extra care to return spec-compliant error responses.
* To apply middleware on a field level, use the @middleware directive.
*/
'middleware' => [\Nuwave\Lighthouse\Support\Http\Middleware\AcceptJson::class],
],
/*
*
* Beware that middleware defined here runs before the GraphQL execution phase,
* so you have to take extra care to return spec-compliant error responses.
* To apply middleware on a field level, use the @middleware directive.
*/
'middleware' => [\Nuwave\Lighthouse\Support\Http\Middleware\AcceptJson::class]
],
/*
/*
|--------------------------------------------------------------------------
| Schema Declaration
|--------------------------------------------------------------------------
@ -52,11 +56,11 @@ return [
|
*/
'schema' => [
'register' => '',
],
'schema' => [
'register' => '',
],
/*
/*
|--------------------------------------------------------------------------
| Schema Cache
|--------------------------------------------------------------------------
@ -67,13 +71,13 @@ return [
|
*/
'cache' => [
'enable' => Settings::get('enable_cache', false),
'key' => env('GRAPHQL_CACHE_KEY', 'graphql-schema'),
'ttl' => env('GRAPHQL_CACHE_TTL', null),
],
'cache' => [
'enable' => Settings::get('enable_cache', false),
'key' => env('GRAPHQL_CACHE_KEY', 'graphql-schema'),
'ttl' => env('GRAPHQL_CACHE_TTL', null),
],
/*
/*
|--------------------------------------------------------------------------
| Namespaces
|--------------------------------------------------------------------------
@ -84,18 +88,18 @@ return [
|
*/
'namespaces' => [
'models' => 'Graphql\\Models',
'queries' => 'Graphql\\Queries',
'mutations' => 'Graphql\\Mutations',
'subscriptions' => 'Graphql\\Subscriptions',
'interfaces' => 'Graphql\\Interfaces',
'unions' => 'Graphql\\Unions',
'scalars' => 'Graphql\\Scalars',
'directives' => ['GermanAirlinesVa\\Graphql\\GraphQL\\Directives', 'Graphql\\Directives'],
],
'namespaces' => [
'models' => 'Graphql\\Models',
'queries' => 'Graphql\\Queries',
'mutations' => 'Graphql\\Mutations',
'subscriptions' => 'Graphql\\Subscriptions',
'interfaces' => 'Graphql\\Interfaces',
'unions' => 'Graphql\\Unions',
'scalars' => 'Graphql\\Scalars',
'directives' => ['GermanAirlinesVa\\Graphql\\GraphQL\\Directives', 'Graphql\\Directives'],
],
/*
/*
|--------------------------------------------------------------------------
| Security
|--------------------------------------------------------------------------
@ -105,13 +109,13 @@ return [
|
*/
'security' => [
'max_query_complexity' => \GraphQL\Validator\Rules\QueryComplexity::DISABLED,
'max_query_depth' => \GraphQL\Validator\Rules\QueryDepth::DISABLED,
'disable_introspection' => \GraphQL\Validator\Rules\DisableIntrospection::DISABLED,
],
'security' => [
'max_query_complexity' => \GraphQL\Validator\Rules\QueryComplexity::DISABLED,
'max_query_depth' => \GraphQL\Validator\Rules\QueryDepth::DISABLED,
'disable_introspection' => \GraphQL\Validator\Rules\DisableIntrospection::DISABLED,
],
/*
/*
|--------------------------------------------------------------------------
| Pagination
|--------------------------------------------------------------------------
@ -122,9 +126,9 @@ return [
|
*/
'paginate_max_count' => null,
'paginate_max_count' => null,
/*
/*
|--------------------------------------------------------------------------
| Pagination Amount Argument
|--------------------------------------------------------------------------
@ -135,9 +139,9 @@ return [
|
*/
'pagination_amount_argument' => 'first',
'pagination_amount_argument' => 'first',
/*
/*
|--------------------------------------------------------------------------
| Debug
|--------------------------------------------------------------------------
@ -147,9 +151,9 @@ return [
|
*/
'debug' => \GraphQL\Error\Debug::INCLUDE_DEBUG_MESSAGE | \GraphQL\Error\Debug::INCLUDE_TRACE,
'debug' => \GraphQL\Error\Debug::INCLUDE_DEBUG_MESSAGE | \GraphQL\Error\Debug::INCLUDE_TRACE,
/*
/*
|--------------------------------------------------------------------------
| Error Handlers
|--------------------------------------------------------------------------
@ -160,9 +164,11 @@ return [
|
*/
'error_handlers' => [\Nuwave\Lighthouse\Execution\ExtensionErrorHandler::class],
'error_handlers' => [
\Nuwave\Lighthouse\Execution\ExtensionErrorHandler::class,
],
/*
/*
|--------------------------------------------------------------------------
| Global ID
|--------------------------------------------------------------------------
@ -172,9 +178,9 @@ return [
|
*/
'global_id_field' => 'id',
'global_id_field' => 'id',
/*
/*
|--------------------------------------------------------------------------
| Batched Queries
|--------------------------------------------------------------------------
@ -184,9 +190,9 @@ return [
|
*/
'batched_queries' => Settings::get('batched_queries', true),
'batched_queries' => Settings::get('batched_queries', true),
/*
/*
|--------------------------------------------------------------------------
| Transactional Mutations
|--------------------------------------------------------------------------
@ -196,9 +202,9 @@ return [
|
*/
'transactional_mutations' => true,
'transactional_mutations' => true,
/*
/*
|--------------------------------------------------------------------------
| GraphQL Subscriptions
|--------------------------------------------------------------------------
@ -208,39 +214,39 @@ return [
|
*/
'subscriptions' => [
/*
* Determines if broadcasts should be queued by default.
*/
'queue_broadcasts' => env('LIGHTHOUSE_QUEUE_BROADCASTS', true),
'subscriptions' => [
/*
* Determines if broadcasts should be queued by default.
*/
'queue_broadcasts' => env('LIGHTHOUSE_QUEUE_BROADCASTS', true),
/*
* Default subscription storage.
*
* Any Laravel supported cache driver options are available here.
*/
'storage' => env('LIGHTHOUSE_SUBSCRIPTION_STORAGE', 'redis'),
/*
* Default subscription storage.
*
* Any Laravel supported cache driver options are available here.
*/
'storage' => env('LIGHTHOUSE_SUBSCRIPTION_STORAGE', 'redis'),
/*
* Default subscription broadcaster.
*/
'broadcaster' => env('LIGHTHOUSE_BROADCASTER', 'pusher'),
/*
* Default subscription broadcaster.
*/
'broadcaster' => env('LIGHTHOUSE_BROADCASTER', 'pusher'),
/*
* Subscription broadcasting drivers with config options.
*/
'broadcasters' => [
'log' => [
'driver' => 'log',
],
'pusher' => [
'driver' => 'pusher',
'routes' => \Nuwave\Lighthouse\Subscriptions\SubscriptionRouter::class . '@pusher',
'connection' => 'pusher',
],
],
],
],
],
],
/*
* Subscription broadcasting drivers with config options.
*/
'broadcasters' => [
'log' => [
'driver' => 'log',
],
'pusher' => [
'driver' => 'pusher',
'routes' => \Nuwave\Lighthouse\Subscriptions\SubscriptionRouter::class.'@pusher',
'connection' => 'pusher',
],
],
],
]
]
]
];

View File

@ -1,18 +0,0 @@
<?php namespace GermanAirlinesVa\Graphql\Controllers;
use Backend\Classes\Controller;
use BackendMenu;
class Playground extends Controller
{
public function __construct()
{
parent::__construct();
BackendMenu::setContext('GermanAirlinesVa.Graphql', 'menu', 'playground');
}
public function index()
{
}
}

View File

@ -1,2 +0,0 @@
<div id="mount"></div>
<script type="text/javascript" src="/plugins/germanairlinesva/graphql/assets/js/graphiql.js"></script>

View File

@ -1,16 +1,16 @@
<?php
if (!function_exists('join_paths')) {
function join_paths()
{
$paths = [];
if(!function_exists("join_paths")) {
function join_paths()
{
$paths = array();
foreach (func_get_args() as $arg) {
if ($arg !== '') {
$paths[] = $arg;
}
foreach (func_get_args() as $arg) {
if ($arg !== '') {
$paths[] = $arg;
}
}
return preg_replace('#/+#', '/', join('/', $paths));
}
return preg_replace('#/+#', '/', join('/', $paths));
}
}

View File

@ -1,33 +1,31 @@
<?php return [
'plugin' => [
'name' => 'GraphQL',
'description' => '',
],
'menu' => [
'playground' => 'GraphiQL',
],
'permission' => [
'tab' => [
'schemas' => 'Schemas',
'plugin' => [
'name' => 'GraphQL',
'description' => '',
],
'label' => [
'schemas' => 'Manage schemas',
'menu' => [
'main' => 'GraphQL',
],
],
'settings' => [
'label' => 'German Airlines VA - GraphQL',
'description' => 'Configure GrapQL',
'general' => 'General',
'engine' => 'Engine',
'enable_cache' => [
'label' => 'Enable Schema Cache',
'comment' =>
'A large part of the Schema generation is parsing the various graph definition into an AST. These operations are pretty expensive so it is recommended to enable caching in production mode.',
'permission' => [
'tab' => [
'schemas' => 'Schemas',
],
'label' => [
'schemas' => 'Manage schemas',
],
],
'batched_queries' => [
'label' => 'Batched Queries',
'comment' =>
'GraphQL query batching means sending multiple queries to the server in one request. You may set this flag to process/deny batched queries.',
],
],
'settings' => [
'label' => 'German Airlines VA - GraphQL',
'description' => 'Configure GrapQL',
'general' => 'General',
'engine' => 'Engine',
'enable_cache' => [
'label' => 'Enable Schema Cache',
'comment' => 'A large part of the Schema generation is parsing the various graph definition into an AST. These operations are pretty expensive so it is recommended to enable caching in production mode.'
],
'batched_queries' => [
'label' => 'Batched Queries',
'comment' => 'GraphQL query batching means sending multiple queries to the server in one request. You may set this flag to process/deny batched queries.'
]
],
];

View File

@ -3,11 +3,13 @@
use Cms\Classes\Theme;
use Model;
class Settings extends Model
{
public $implement = ['System.Behaviors.SettingsModel'];
public $implement = ['System.Behaviors.SettingsModel'];
public $settingsCode = 'germanairlinesva_graphql_settings';
public $settingsCode = 'germanairlinesva_graphql_settings';
public $settingsFields = 'fields.yaml';
public $settingsFields = 'fields.yaml';
}

View File

@ -1,15 +0,0 @@
{
"name": "graphql",
"version": "1.0.0",
"main": "Plugin.php",
"repository": "https://git.hofmannnet.myhome-server.de/GermanAirlines/GermanAirlinesVA-GraphQL.git",
"author": "German Airlines VA",
"license": "MIT",
"devDependencies": {
"@prettier/plugin-php": "^0.16.3",
"prettier": "^2.3.0"
},
"scripts": {
"format": "prettier --write './**/*.{php,html}'"
}
}

View File

@ -8,8 +8,3 @@ permissions:
schemas:
tab: 'germanairlinesva.graphql::lang.permission.tab.schemas'
label: 'germanairlinesva.graphql::lang.permission.label.schemas'
navigation:
menu:
label: 'germanairlinesva.graphql::lang.menu.playground'
url: germanairlinesva/graphql/playground
icon: icon-database

View File

@ -1,52 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@prettier/plugin-php@^0.16.3":
version "0.16.3"
resolved "https://registry.yarnpkg.com/@prettier/plugin-php/-/plugin-php-0.16.3.tgz#74867210079ba3c0c3ae843029d76e25ff0aadf3"
integrity sha512-DNidzeGpP+/wmcCAZNSHxgoAnhEosYG+no4jJRqln19e1o3Okpuir/2JMxb07VCwdG50IWjtNgVwNPVl4uj0Hg==
dependencies:
linguist-languages "^7.5.1"
mem "^8.0.0"
php-parser "3.0.2"
linguist-languages@^7.5.1:
version "7.15.0"
resolved "https://registry.yarnpkg.com/linguist-languages/-/linguist-languages-7.15.0.tgz#a93bed6b93015d8133622cb05da6296890862bfa"
integrity sha512-qkSSNDjDDycZ2Wcw+GziNBB3nNo3ddYUInM/PL8Amgwbd9RQ/BKGj2/1d6mdxKgBFnUqZuaDbkIwkE4KUwwmtQ==
map-age-cleaner@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
dependencies:
p-defer "^1.0.0"
mem@^8.0.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/mem/-/mem-8.1.1.tgz#cf118b357c65ab7b7e0817bdf00c8062297c0122"
integrity sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==
dependencies:
map-age-cleaner "^0.1.3"
mimic-fn "^3.1.0"
mimic-fn@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74"
integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==
p-defer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
php-parser@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/php-parser/-/php-parser-3.0.2.tgz#a86dbbc110e57378cba71ab4cd9b0d18f3872ac3"
integrity sha512-a7y1+odEGsceLDLpu7oNyspZ0pK8FMWJOoim4/yd82AtnEZNLdCLZ67arnOQZ9K0lHJiSp4/7lVUpGELVxE14w==
prettier@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18"
integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==