Skip to content

Commit

Permalink
Provide pagination in scaffolded queries
Browse files Browse the repository at this point in the history
  • Loading branch information
Uncle Cheese committed Jan 20, 2017
1 parent f634fdf commit d92d3ad
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 132 deletions.
31 changes: 5 additions & 26 deletions src/Scaffolding/Creators/OperationCreatorTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,20 @@

namespace SilverStripe\GraphQL\Scaffolding\Creators;

use SilverStripe\GraphQL\Scaffolding\ResolverInterface;
use SilverStripe\GraphQL\Manager;

/**
* Injects Operation creator features into mutations and queries, which are different inheritance chains
*/
trait OperationCreatorTrait
{
use PolymorphicResolverTrait;

/**
* @var string
*/
protected $typeName;

/**
* @var \Closure|SilverStripe\GraphQL\ResolverInterface
*/
protected $resolver;

/**
* @var string
*/
Expand Down Expand Up @@ -67,29 +63,12 @@ public function args()
}

/**
* Overload the getResolver() method to be aware of the ResolverInterface option
* Overload the getResolver() method to be aware of the polymorphic resolvers
* @return mixed
*/
protected function getResolver()
public function getResolver()
{
$resolver = $this->resolver;

return function () use ($resolver) {
$args = func_get_args();
if (is_callable($resolver)) {
return call_user_func_array($resolver, $args);
} else {
if ($resolver instanceof ResolverInterface) {
return call_user_func_array([$resolver, 'resolve'], $args);
} else {
throw new \Exception(sprintf(
'%s resolver must be a closure or implement %s',
__CLASS__,
ResolverInterface::class
));
}
}
};
return $this->createResolverFunction();
}

}
61 changes: 61 additions & 0 deletions src/Scaffolding/Creators/PaginatedQueryOperationCreator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace SilverStripe\GraphQL\Scaffolding\Creators;

use SilverStripe\GraphQL\Pagination\PaginatedQueryCreator;
use SilverStripe\GraphQL\Pagination\Connection;
use SilverStripe\GraphQL\Manager;

class PaginatedQueryOperationCreator extends PaginatedQueryCreator
{

use PolymorphicResolverTrait;

/**
* @var string
*/
protected $operationName;

/**
* @param Manager $manager
* @param Connection $connection
* @param string $operationName
* @param string $typeName
* @param Callable|ResolverInterface $resolver
*/
public function __construct(Manager $manager, Connection $connection, $operationName, $typeName, $resolver)
{
$this->connection = $connection;
$this->resolver = $resolver;
$this->operationName = $operationName;

parent::__construct($manager);

$this->connection
->setConnectionType(function() use ($typeName) {
return $this->manager->getType($typeName);
})
->setConnectionResolver($this->createResolverFunction());
}

/**
* @return array
*/
public function attributes()
{
return [
'name' => $this->operationName
];
}

/**
* This method usually builds a new Connection interface, but since it is
* assigned in the constructor of this class, it's overloaded as a simple accessor
*
* @return SilverStripe\GraphQL\Pagination\Connection;
*/
public function connection()
{
return $this->connection;
}
}
35 changes: 35 additions & 0 deletions src/Scaffolding/Creators/PolymorphicResolverTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace SilverStripe\GraphQL\Scaffolding\Creators;

use SilverStripe\GraphQL\Scaffolding\ResolverInterface;

trait PolymorphicResolverTrait
{
/**
* @var \Closure|SilverStripe\GraphQL\ResolverInterface
*/
protected $resolver;

protected function createResolverFunction()
{
$resolver = $this->resolver;

return function () use ($resolver) {
$args = func_get_args();
if (is_callable($resolver)) {
return call_user_func_array($resolver, $args);
} else {
if ($resolver instanceof ResolverInterface) {
return call_user_func_array([$resolver, 'resolve'], $args);
} else {
throw new \Exception(sprintf(
'%s resolver must be a closure or implement %s',
__CLASS__,
ResolverInterface::class
));
}
}
};
}
}
8 changes: 7 additions & 1 deletion src/Scaffolding/Scaffolders/CreateOperationScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\Type;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Config\Config;
use SilverStripe\GraphQL\Scaffolding\Util\TypeParser;
use SilverStripe\GraphQL\Manager;
use Exception;
Expand Down Expand Up @@ -69,7 +70,12 @@ protected function generateInputType()
$instance = $this->getDataObjectInstance();

// Setup default input args.. Placeholder!
$db = $instance->db();
$db = (array) Config::inst()->get(
$this->dataObjectClass,
'db',
Config::INHERITED
);

unset($db['ID']);

foreach ($db as $dbFieldName => $dbFieldType) {
Expand Down
5 changes: 4 additions & 1 deletion src/Scaffolding/Scaffolders/GraphQLScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,13 @@ public static function createFromConfig($config)
);
}
$args = isset($fieldSettings['args']) ? (array)$fieldSettings['args'] : [];
$scaffolder->dataObject($dataObjectClass)
$operation = $scaffolder->dataObject($dataObjectClass)
->$method($fieldName)
->setResolver($fieldSettings['resolver'])
->addArgs($args);
if($group === 'queries' && isset($fieldSettings['paginate'])) {
$operation->setUsePagination((boolean) $fieldSettings['paginate']);
}
}
}
}
Expand Down
58 changes: 58 additions & 0 deletions src/Scaffolding/Scaffolders/QueryScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,35 @@

use SilverStripe\GraphQL\Manager;
use SilverStripe\GraphQL\Scaffolding\Creators\QueryOperationCreator;
use SilverStripe\GraphQL\Scaffolding\Creators\PaginatedQueryOperationCreator;
use SilverStripe\GraphQL\Pagination\Connection;

/**
* Scaffolds a GraphQL query field
*/
class QueryScaffolder extends OperationScaffolder implements ManagerMutatorInterface, ScaffolderInterface
{

/**
* @var boolean
*/
protected $usePagination = true;

/**
* @var array
*/
protected $sortableFields = [];

/**
* @param boolean $bool
*/
public function setUsePagination($bool)
{
$this->usePagination = (boolean) $bool;

return $this;
}

/**
* @param Manager $manager
*/
Expand All @@ -23,12 +45,48 @@ public function addToManager(Manager $manager)
);
}

/**
* @param array $fields
*/
public function addSortableFields($fields)
{
$this->sortableFields = array_unique(
array_merge(
$this->sortableFields,
(array) $fields
)
);

return $this;
}

/**
* Creates a Connection for pagination
* @return Connection
*/
protected function createConnection()
{
return Connection::create($this->operationName)
->setArgs($this->createArgs())
->setSortableFields($this->sortableFields);
}

/**
* @param Manager $manager
* @return QueryOperationCreator
*/
public function getCreator(Manager $manager)
{
if($this->usePagination) {
return new PaginatedQueryOperationCreator(
$manager,
$this->createConnection(),
$this->operationName,
$this->typeName,
$this->resolver
);
}

return new QueryOperationCreator(
$manager,
$this->operationName,
Expand Down
16 changes: 2 additions & 14 deletions src/Scaffolding/Scaffolders/ReadOperationScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ public function __construct($dataObjectClass)
{
$this->dataObjectClass = $dataObjectClass;

// default args of some sort
$this->args = [
'Limit' => 'Int=20',
'Sort' => 'String'
];

$typeName = $this->getDataObjectInstance()->plural_name();
$typeName = str_replace(' ', '', $typeName);
$typeName = ucfirst($typeName);
Expand All @@ -37,14 +31,8 @@ public function __construct($dataObjectClass)

$this->setResolver(function ($object, array $args, $context, $info) {
$list = DataList::create($this->dataObjectClass);
$list = $list->limit($args['Limit']);
if (isset($args['Sort'])) {
$list = $list->sort($args['Sort']);
}

return $list->filterbyCallback(function ($item, $list) {
return $item->canView();
});

return $list;
});

}
Expand Down
8 changes: 7 additions & 1 deletion src/Scaffolding/Scaffolders/UpdateOperationScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use SilverStripe\GraphQL\Scaffolding\Resolvers\Update;
use GraphQL\Type\Definition\InputObjectType;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Config\Config;
use SilverStripe\GraphQL\Scaffolding\Util\TypeParser;
use SilverStripe\ORM\DataList;
use SilverStripe\GraphQL\Manager;
Expand Down Expand Up @@ -85,7 +86,12 @@ protected function generateInputType()
$instance = $this->getDataObjectInstance();

// Setup default input args.. Placeholder!
$db = $instance->db();
$db = (array) Config::inst()->get(
$this->dataObjectClass,
'db',
Config::INHERITED
);

unset($db['ID']);

foreach ($db as $dbFieldName => $dbFieldType) {
Expand Down
Loading

0 comments on commit d92d3ad

Please sign in to comment.