IMPR: Move GraphQL to cms-niceties repo

This commit is contained in:
Tony Air 2023-10-24 22:20:50 +02:00
parent 2a07cf6763
commit 306bc5e7dd
10 changed files with 0 additions and 470 deletions

View File

@ -1,37 +0,0 @@
---
Name: app-graphql
After:
- app-basics
Only:
classexists: 'SilverStripe\GraphQL\Schema\Schema'
---
SilverStripe\Core\Injector\Injector:
SilverStripe\GraphQL\Schema\Registry\PluginRegistry:
constructor:
- 'App\GraphQL\URLLinkablePlugin'
SilverStripe\Control\Director:
rules:
graphql:
Controller: '%$SilverStripe\GraphQL\Controller.default'
Schema: default
SilverStripe\GraphQL\Schema\Schema:
schemas:
'*':
config:
max_query_nodes: 250 # default 500
max_query_depth: 20 # default 15
max_query_complexity: 200 # default unlimited
default:
src:
- app/_graphql
SilverStripe\GraphQLDevTools\Controller:
# show two schemas
schemas:
- default
- admin
# default schema that is selected
default_schema: default

View File

@ -1,16 +0,0 @@
app:
# Load everything in our MyApp\Models\ namespace that has the Versioned extension
# unless the filename ends with .secret.php
load:
namespaceLoader:
include:
- App\Models\*
extensionLoader:
include:
- SilverStripe\Versioned\Versioned
apply:
fields:
'*': true
operations:
read: true
readOne: true

View File

@ -1,30 +0,0 @@
modelConfig:
Page:
plugins:
inheritance: true
operations:
read:
plugins:
readVersion: false
paginateList: false
readOne:
plugins:
getByLink:
after: filter
DNADesign\Elemental\Models\ElementalArea:
plugins:
inheritance: true
operations:
read:
plugins:
readVersion: false
paginateList: false
DNADesign\Elemental\Models\BaseElement:
plugins:
inheritance: true
operations:
read:
plugins:
readVersion: false
paginateList: false

View File

View File

@ -1,49 +0,0 @@
Page:
fields:
id: true
className: true
urlSegment: true
parentID: true
title: true
sort: true
CSSClass: true
MainContent:
type: String
showInMenus: Boolean
showInSearch: Boolean
url:
type: String
link:
type: String
requestlink:
type: String
children: "[Page]"
elementalArea:
type: ElementalArea
operations:
read: true
readOne:
plugins:
getByLink:
after: filter
DNADesign\Elemental\Models\ElementalArea:
fields:
id: true
elements:
plugins:
paginateList: false
operations:
read: true
readOne: true
DNADesign\Elemental\Models\BaseElement:
fields:
id: true
title: true
showTitle: true
className: true
forTemplate: true
operations:
readOne: true
read: true

View File

@ -1,4 +0,0 @@
queries:
readMenu:
type: '[PageInterface]'
resolver: [ 'App\GraphQL\MenuResolver', 'resolveMenu' ]

View File

View File

@ -1,37 +0,0 @@
<?php
namespace App\GraphQL;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ORM\Filterable;
class MenuResolver
{
public static function resolveLinksFilter(Filterable $list, array $args, array $context)
{
var_dump($context);
die('aaaa');
return $list;
}
public static function resolveMenu(): array
{
$pages = SiteTree::get()->filter('ParentID', '0');
$results = self::getFields($pages);
return $results;
}
protected static function getFields($pages): array
{
$results = [];
foreach ($pages as $p) {
$results[] = [
'id' => $p->ID,
'title' => $p->Title,
'children' => self::getFields($p->Children()),
];
}
return $results;
}
}

View File

@ -1,277 +0,0 @@
<?php
namespace App\GraphQL;
use GraphQL\Type\Definition\ResolveInfo;
use SilverStripe\CMS\Controllers\ModelAsController;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\Director;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Dev\Debug;
use SilverStripe\GraphQL\Controller;
use SilverStripe\GraphQL\Schema\DataObject\Plugin\QueryFilter\QueryFilter;
use SilverStripe\GraphQL\Schema\Exception\SchemaBuilderException;
use SilverStripe\GraphQL\Schema\Field\ModelQuery;
use SilverStripe\GraphQL\Schema\Interfaces\ModelQueryPlugin;
use SilverStripe\GraphQL\Schema\Schema;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\View\ArrayData;
use SilverStripe\View\SSViewer;
if (!interface_exists(ModelQueryPlugin::class)) {
return;
}
class URLLinkablePlugin implements ModelQueryPlugin
{
use Configurable;
use Injectable;
public const IDENTIFIER = 'getByURL';
/**
* @var string
* @config
*/
private static $single_field_name = 'url';
/**
* @var string
* @config
*/
private static $list_field_name = 'urls';
/**
* @var array
*/
private static $resolver = [__CLASS__, 'applyURLFilter'];
/**
* @return string
*/
public function getIdentifier(): string
{
return self::IDENTIFIER;
}
/**
* @param ModelQuery $query
* @param Schema $schema
* @param array $config
*/
public function apply(ModelQuery $query, Schema $schema, array $config = []): void
{
$class = $query->getModel()->getSourceClass();
// Only site trees have the get_by_link capability
if ($class !== SiteTree::class && !is_subclass_of($class, SiteTree::class)) {
return;
}
$singleFieldName = $this->config()->get('single_field_name');
$listFieldName = $this->config()->get('list_field_name');
$fieldName = $query->isList() ? $listFieldName : $singleFieldName;
$type = $query->isList() ? '[String]' : 'String';
$query->addArg($fieldName, $type);
$query->addResolverAfterware(
$config['resolver'] ?? static::config()->get('resolver')
);
}
/**
* @param array $context
* @return callable
*/
public static function applyURLFilter($obj, array $args, array $context, ResolveInfo $info)
{
$url = self::getURL($args);
if (!$url) {
return $obj;
}
$controller = self::getURLController($url);
$obj = $controller->data();
$obj->GraphQLContent = self::RenderTemplate($obj, $controller);
$result = ArrayList::create();
$result->push($obj);
return $result;
}
protected static function getURL($args)
{
$singleFieldName = static::config()->get('single_field_name');
$listFieldName = static::config()->get('list_field_name');
$filterLink = $args['filter'][$singleFieldName] ?? ($args['filter'][$listFieldName] ?? null);
$argLink = $args[$singleFieldName] ?? ($args[$listFieldName] ?? null);
$linkData = $filterLink ?: $argLink;
if (!$linkData) {
return false;
}
$url = $linkData['eq'];
if ($url === '/') {
return '/home';
}
return $url;
}
protected static function getURLController($url)
{
$curr = Controller::curr();
$req = clone $curr->getRequest();
$req->setUrl($url);
$req->match('$URLSegment//$Action/$ID/$OtherID', true);
$controller = ModelAsController::create();
$controller->setRequest($req);
// ContentController
$result = $controller->getNestedController();
$result->setRequest($req);
/** @var SiteTree $child */
$action = $req->param('Action');
if ($action) {
$child = self::findChild($action, $result);
if ($child) {
$result = $child;
}
}
return $result;
}
// look recursively for a child page with URLSegment
protected static function findChild($action, $controller)
{
$req = $controller->getRequest();
$child = SiteTree::get()->filter([
'ParentID' => $controller->ID,
'URLSegment' => $action,
])->first();
if ($child) {
$req->shiftAllParams();
$req->shift();
$controller = ModelAsController::controller_for($child);
$controller->setRequest($req);
$action = $req->param('Action');
if ($action) {
return self::findChild($action, $controller);
}
}
return $controller;
}
// AJAX/GraphQL helper
protected static function RenderTemplate($page, $ctl)
{
$object = $page;
$req = $ctl->getRequest();
$actionParam = $req->param('Action');
Director::set_current_page($object);
$match = self::findAction($ctl, $req);
$req->match($match['rule'], true);
$action = $match['action'];
$action = ($action === 'handleAction') ? $actionParam : $action;
$action = $action && $ctl->hasAction($action) ? $action : 'index';
// find templates
$tpl = 'Page';
$tpls = SSViewer::get_templates_by_class($object->ClassName, '', \Page::class);
foreach ($tpls as $tpl) {
if (is_array($tpl)) {
continue;
}
$a_tpl = explode('\\', $tpl);
$last_name = array_pop($a_tpl);
$a_tpl[] = 'Layout';
$a_tpl[] = $last_name;
$a_tpl = implode('\\', $a_tpl);
if (SSViewer::hasTemplate($a_tpl)) {
$tpl = $a_tpl;
break;
}
}
//
$tpl = is_array($tpl) ? 'Page' : $tpl;
$tpl = ($tpl !== 'Page') ? $tpl : 'Layout/Page';
// a little dirty way to make forms working
//Controller::curr()->config()->set('url_segment', $object->AbsoluteLink());
//$ctl->doInit();
$mResult = $ctl->$action($req);
if (is_array($mResult) || is_a($mResult, ArrayData::class)) {
$ctl->customise($mResult);
}
$layout = $ctl->renderWith([$tpl.'_'.$action, $tpl]);
return $ctl
->customise(['Layout' => $layout])
->renderWith('GraphQLPage');
}
protected static function findAction($controller, $request)
{
$handlerClass = $controller::class;
// We stop after RequestHandler; in other words, at ViewableData
while ($handlerClass && $handlerClass != ViewableData::class) {
$urlHandlers = Config::inst()->get($handlerClass, 'url_handlers', Config::UNINHERITED);
if ($urlHandlers) {
foreach ($urlHandlers as $rule => $action) {
if (isset($_REQUEST['debug_request'])) {
$class = static::class;
$remaining = $request->remaining();
Debug::message("Testing '{$rule}' with '{$remaining}' on {$class}");
}
if ($request->match($rule, true)) {
if (isset($_REQUEST['debug_request'])) {
$class = static::class;
$latestParams = var_export($request->latestParams(), true);
Debug::message(
"Rule '{$rule}' matched to action '{$action}' on {$class}. " . "Latest request params: {$latestParams}"
);
}
return [
'rule' => $rule,
'action' => $action,
];
}
}
}
$handlerClass = get_parent_class($handlerClass ?? '');
}
return null;
}
}

View File

@ -97,26 +97,6 @@ class Page extends SiteTree
return str_replace(['\\'], '-', $this->getField('ClassName'));
}
// AJAX/GraphQL helper
public function MainContent()
{
$object = $this;
return isset($object->GraphQLContent) ? $object->GraphQLContent : null;
}
public function getRequestLink($action = null)
{
$curr = Controller::curr();
if ($curr::class === GraphQLController::class) {
$vars = json_decode($curr->getRequest()->getBody(), true)['variables'];
if (isset($vars['url'])) {
return $vars['url'];
}
}
return null;
}
protected function onBeforeWrite()
{
parent::onBeforeWrite();