GraphiQL in Backend

This commit is contained in:
Gogs 2021-06-02 15:46:20 +02:00
parent e7d7d18f77
commit a65593b4f9
24 changed files with 61895 additions and 617 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

1
.prettierignore Normal file
View File

@ -0,0 +1 @@
vendor

11
.prettierrc Normal file
View File

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

17
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,17 @@
{
"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

@ -24,8 +24,8 @@ class Plugin extends PluginBase
'class' => 'GermanAirlinesVa\Graphql\Models\Settings', 'class' => 'GermanAirlinesVa\Graphql\Models\Settings',
'order' => 1000, 'order' => 1000,
'keywords' => 'graphql', 'keywords' => 'graphql',
'permissions' => ['germanairlinesva.graphql.schemas'] 'permissions' => ['germanairlinesva.graphql.schemas'],
] ],
]; ];
} }
@ -48,28 +48,22 @@ class Plugin extends PluginBase
$packages = Config::get($pluginNamespace . '::packages'); $packages = Config::get($pluginNamespace . '::packages');
// Boot each package // 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 // 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']); Config::set($options['config_namespace'], $options['config']);
} }
// Register any Service Providers for the package // Register any Service Providers for the package
if (!empty($options['providers'])) if (!empty($options['providers'])) {
{ foreach ($options['providers'] as $provider) {
foreach ($options['providers'] as $provider)
{
App::register($provider); App::register($provider);
} }
} }
// Register any Aliases for the package // Register any Aliases for the package
if (!empty($options['aliases'])) if (!empty($options['aliases'])) {
{ foreach ($options['aliases'] as $alias => $path) {
foreach ($options['aliases'] as $alias => $path)
{
$aliasLoader->alias($alias, $path); $aliasLoader->alias($alias, $path);
} }
} }
@ -78,4 +72,3 @@ class Plugin extends PluginBase
return $packages; return $packages;
} }
} }

61205
assets/js/graphiql.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -6,10 +6,8 @@ use Illuminate\Http\Request;
use Nuwave\Lighthouse\Support\Contracts\CreatesContext as LighthouseCreatesContext; use Nuwave\Lighthouse\Support\Contracts\CreatesContext as LighthouseCreatesContext;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext; use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
class CreatesContext implements LighthouseCreatesContext class CreatesContext implements LighthouseCreatesContext
{ {
/** /**
* Generate GraphQL context. * Generate GraphQL context.
* *

View File

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

View File

@ -8,7 +8,6 @@ use October\Rain\Extension\Extendable;
*/ */
class GraphCode extends CodeBase class GraphCode extends CodeBase
{ {
public $graph; public $graph;
/** /**
@ -51,5 +50,4 @@ class GraphCode extends CodeBase
{ {
return isset($this->graph->{$name}); return isset($this->graph->{$name});
} }
} }

View File

@ -8,10 +8,8 @@ use Cms\Classes\Controller;
use Cms\Classes\CmsException; use Cms\Classes\CmsException;
use Cms\Classes\ComponentManager; use Cms\Classes\ComponentManager;
class GraphController // extends Controller class GraphController // extends Controller
{ {
protected $graph; protected $graph;
/** /**
@ -19,7 +17,6 @@ class GraphController// extends Controller
*/ */
protected static $instance; protected static $instance;
/** /**
* Creates the controller. * Creates the controller.
*/ */
@ -41,22 +38,25 @@ class GraphController// extends Controller
return self::$instance; return self::$instance;
} }
public function component($alias) { public function component($alias)
{
if (isset($this->graph->components[$alias])) { if (isset($this->graph->components[$alias])) {
return $this->graph->components[$alias]; return $this->graph->components[$alias];
} }
foreach ($this->graph->settings['components'] as $component => $properties) { foreach ($this->graph->settings['components'] as $component => $properties) {
list($name, $component_alias) = strpos($component, ' ') [$name, $component_alias] = strpos($component, ' ') ? explode(' ', $component) : [$component, $component];
? explode(' ', $component)
: [$component, $component];
if ($component_alias == $alias) { if ($component_alias == $alias) {
// make component // make component
$manager = ComponentManager::instance(); $manager = ComponentManager::instance();
if (!$componentObj = $manager->makeComponent($name, null, $properties)) { if (!($componentObj = $manager->makeComponent($name, null, $properties))) {
throw new CmsException(Lang::get('cms::lang.component.not_found', ['name' => $name])); throw new CmsException(
Lang::get('cms::lang.component.not_found', [
'name' => $name,
])
);
} }
$this->setComponentPropertiesFromParams($componentObj, $this->router->getParameters()); $this->setComponentPropertiesFromParams($componentObj, $this->router->getParameters());
@ -93,8 +93,7 @@ class GraphController// extends Controller
if (substr($paramName, 0, 1) == ':') { if (substr($paramName, 0, 1) == ':') {
$routeParamName = substr($paramName, 1); $routeParamName = substr($paramName, 1);
$newPropertyValue = $routerParameters[$routeParamName] ?? null; $newPropertyValue = $routerParameters[$routeParamName] ?? null;
} } else {
else {
$newPropertyValue = $parameters[$paramName] ?? null; $newPropertyValue = $parameters[$paramName] ?? null;
} }
@ -114,5 +113,4 @@ class GraphController// extends Controller
{ {
return $this->router->getParameter($name, $default); return $this->router->getParameter($name, $default);
} }
} }

View File

@ -7,7 +7,6 @@ use Cms\Classes\Router;
class GraphRouter //extends Router class GraphRouter //extends Router
{ {
/** /**
* @var array A list of parameters names and values extracted from the URL pattern and URL string. * @var array A list of parameters names and values extracted from the URL pattern and URL string.
*/ */
@ -27,7 +26,6 @@ class GraphRouter //extends Router
return $this->parameters; return $this->parameters;
} }
/** /**
* Returns a routing parameter. * Returns a routing parameter.
* @return array * @return array
@ -40,5 +38,4 @@ class GraphRouter //extends Router
return $default; return $default;
} }
} }

View File

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

View File

@ -6,9 +6,8 @@ use GraphQL\Type\Definition\ResolveInfo;
use Cms\Classes\CodeParser; use Cms\Classes\CodeParser;
use Nuwave\Lighthouse\Schema\ResolverProvider as LighthouseResolverProvider; use Nuwave\Lighthouse\Schema\ResolverProvider as LighthouseResolverProvider;
class ResolverProvider extends LighthouseResolverProvider
class ResolverProvider extends LighthouseResolverProvider { {
/** /**
* Provide a field resolver in case no resolver directive is defined for a field. * Provide a field resolver in case no resolver directive is defined for a field.
* *
@ -35,5 +34,4 @@ class ResolverProvider extends LighthouseResolverProvider {
return parent::provideResolver($fieldValue)($root, $args, $context, $resolveInfo); return parent::provideResolver($fieldValue)($root, $args, $context, $resolveInfo);
}; };
} }
} }

View File

@ -6,7 +6,6 @@ use Cms\Classes\Theme;
class Schema extends Theme class Schema extends Theme
{ {
/** /**
* Returns the absolute theme path. * Returns the absolute theme path.
* @param string $dirName Optional theme directory. Defaults to $this->getDirName() * @param string $dirName Optional theme directory. Defaults to $this->getDirName()
@ -40,5 +39,4 @@ class Schema extends Theme
{ {
return 'graphql'; return 'graphql';
} }
} }

View File

@ -7,10 +7,8 @@ use Nuwave\Lighthouse\Schema\Context;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Nuwave\Lighthouse\Schema\Source\SchemaSourceProvider; use Nuwave\Lighthouse\Schema\Source\SchemaSourceProvider;
class SchemaContext extends Context class SchemaContext extends Context
{ {
public $source; public $source;
/** /**
@ -25,6 +23,4 @@ class SchemaContext extends Context
$this->source = App::make(SchemaSourceProvider::class); $this->source = App::make(SchemaSourceProvider::class);
} }
} }

View File

@ -11,7 +11,6 @@ use Cms\Classes\ComponentPartial;
class SchemaSourceProvider implements LighthouseSchemaSourceProvider class SchemaSourceProvider implements LighthouseSchemaSourceProvider
{ {
protected $fieldGraphMapCacheKey = 'graphql-schema-field-graph-map'; protected $fieldGraphMapCacheKey = 'graphql-schema-field-graph-map';
/** /**
@ -36,7 +35,6 @@ class SchemaSourceProvider implements LighthouseSchemaSourceProvider
*/ */
protected $fieldGraphMap; protected $fieldGraphMap;
/** /**
* SchemaSource constructor. * SchemaSource constructor.
* *
@ -84,7 +82,8 @@ class SchemaSourceProvider implements LighthouseSchemaSourceProvider
return $schema; return $schema;
} }
public function findGraph($fieldName, $findOrFail=false) { public function findGraph($fieldName, $findOrFail = false)
{
if (!isset($this->getFieldGraphMap()[$fieldName])) { if (!isset($this->getFieldGraphMap()[$fieldName])) {
if ($findOrFail) { if ($findOrFail) {
throw new Error("Could not find graph of field '{$fieldName}'."); throw new Error("Could not find graph of field '{$fieldName}'.");
@ -103,7 +102,8 @@ class SchemaSourceProvider implements LighthouseSchemaSourceProvider
return Graph::loadCached($this->template, $name); return Graph::loadCached($this->template, $name);
} }
public function getFieldGraphMap() { public function getFieldGraphMap()
{
if (!is_null($this->fieldGraphMap)) { if (!is_null($this->fieldGraphMap)) {
return $this->fieldGraphMap; return $this->fieldGraphMap;
} }
@ -114,11 +114,7 @@ class SchemaSourceProvider implements LighthouseSchemaSourceProvider
if ($cacheable) { if ($cacheable) {
$map = Cache::get($this->fieldGraphMapCacheKey, false); $map = Cache::get($this->fieldGraphMapCacheKey, false);
if ( if ($map && ($map = @unserialize(@base64_decode($map))) && is_array($map)) {
$map &&
($map = @unserialize(@base64_decode($map))) &&
is_array($map)
) {
$this->fieldGraphMap = $map; $this->fieldGraphMap = $map;
return $this->fieldGraphMap; return $this->fieldGraphMap;
} }
@ -154,17 +150,14 @@ class SchemaSourceProvider implements LighthouseSchemaSourceProvider
// cache mapping // cache mapping
if ($cacheable) { if ($cacheable) {
Cache::put( Cache::put($this->fieldGraphMapCacheKey, base64_encode(serialize($this->fieldGraphMap)), 10);
$this->fieldGraphMapCacheKey,
base64_encode(serialize($this->fieldGraphMap)),
10
);
} }
return $this->fieldGraphMap; return $this->fieldGraphMap;
} }
public function getGraphMap() { public function getGraphMap()
{
if (!is_null($this->graphMap)) { if (!is_null($this->graphMap)) {
return $this->graphMap; return $this->graphMap;
} }
@ -176,13 +169,13 @@ class SchemaSourceProvider implements LighthouseSchemaSourceProvider
/* @var $graph \GermanAirlinesVa\Graphql\Classes\Graph */ /* @var $graph \GermanAirlinesVa\Graphql\Classes\Graph */
$markup = $graph->markup; $markup = $graph->markup;
$schema = preg_replace_callback($component_re, function(array $matches) use ($graph, $component_str) { $schema = preg_replace_callback(
$component_re,
function (array $matches) use ($graph, $component_str) {
$matched_alias = $matches[1]; $matched_alias = $matches[1];
foreach ($graph->settings['components'] as $component => $properties) { foreach ($graph->settings['components'] as $component => $properties) {
// find component by alias // find component by alias
list($name, $alias) = strpos($component, ' ') [$name, $alias] = strpos($component, ' ') ? explode(' ', $component) : [$component, $component];
? explode(' ', $component)
: [$component, $component];
if ($alias == $matched_alias) { if ($alias == $matched_alias) {
// resolve component schema // resolve component schema
return $component_str($name, $alias); return $component_str($name, $alias);
@ -190,18 +183,21 @@ class SchemaSourceProvider implements LighthouseSchemaSourceProvider
} }
// if not found, remove // if not found, remove
return ''; return '';
}, $markup); },
$markup
);
$this->graphMap[$graph->getFileName()] = [ $this->graphMap[$graph->getFileName()] = [
'graph' => $graph, 'graph' => $graph,
'schema' => $schema 'schema' => $schema,
]; ];
} }
return $this->graphMap; return $this->graphMap;
} }
public function getComponentSchemaString($componentName, $alias) { public function getComponentSchemaString($componentName, $alias)
{
$manager = ComponentManager::instance(); $manager = ComponentManager::instance();
$componentObj = $manager->makeComponent($componentName); $componentObj = $manager->makeComponent($componentName);
if ($partial = ComponentPartial::load($componentObj, 'schema.graphqls')) { if ($partial = ComponentPartial::load($componentObj, 'schema.graphqls')) {
@ -214,8 +210,8 @@ class SchemaSourceProvider implements LighthouseSchemaSourceProvider
} }
} }
public function clearCache() { public function clearCache()
{
Cache::forget($this->fieldGraphMapCacheKey); Cache::forget($this->fieldGraphMapCacheKey);
} }
} }

View File

@ -7,13 +7,9 @@ return [
'packages' => [ 'packages' => [
'nuwave/lighthouse' => [ 'nuwave/lighthouse' => [
'config_namespace' => 'lighthouse', 'config_namespace' => 'lighthouse',
'providers' => [ 'providers' => ['Nuwave\Lighthouse\LighthouseServiceProvider'],
'Nuwave\Lighthouse\LighthouseServiceProvider' 'aliases' => [],
],
'aliases' => [
],
'config' => [ 'config' => [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Route Configuration | Route Configuration
@ -42,7 +38,7 @@ return [
* so you have to take extra care to return spec-compliant error responses. * so you have to take extra care to return spec-compliant error responses.
* To apply middleware on a field level, use the @middleware directive. * To apply middleware on a field level, use the @middleware directive.
*/ */
'middleware' => [\Nuwave\Lighthouse\Support\Http\Middleware\AcceptJson::class] 'middleware' => [\Nuwave\Lighthouse\Support\Http\Middleware\AcceptJson::class],
], ],
/* /*
@ -164,9 +160,7 @@ return [
| |
*/ */
'error_handlers' => [ 'error_handlers' => [\Nuwave\Lighthouse\Execution\ExtensionErrorHandler::class],
\Nuwave\Lighthouse\Execution\ExtensionErrorHandler::class,
],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -246,7 +240,7 @@ return [
], ],
], ],
], ],
] ],
] ],
] ],
]; ];

View File

@ -0,0 +1,18 @@
<?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

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

View File

@ -1,9 +1,9 @@
<?php <?php
if(!function_exists("join_paths")) { if (!function_exists('join_paths')) {
function join_paths() function join_paths()
{ {
$paths = array(); $paths = [];
foreach (func_get_args() as $arg) { foreach (func_get_args() as $arg) {
if ($arg !== '') { if ($arg !== '') {

View File

@ -21,11 +21,13 @@
'engine' => 'Engine', 'engine' => 'Engine',
'enable_cache' => [ 'enable_cache' => [
'label' => 'Enable Schema 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.' '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' => [ 'batched_queries' => [
'label' => '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.' '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,7 +3,6 @@
use Cms\Classes\Theme; use Cms\Classes\Theme;
use Model; use Model;
class Settings extends Model class Settings extends Model
{ {
public $implement = ['System.Behaviors.SettingsModel']; public $implement = ['System.Behaviors.SettingsModel'];
@ -11,5 +10,4 @@ class Settings extends Model
public $settingsCode = 'germanairlinesva_graphql_settings'; public $settingsCode = 'germanairlinesva_graphql_settings';
public $settingsFields = 'fields.yaml'; public $settingsFields = 'fields.yaml';
} }

15
package.json Normal file
View File

@ -0,0 +1,15 @@
{
"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}'"
}
}

52
yarn.lock Normal file
View File

@ -0,0 +1,52 @@
# 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==