From 8769cb7729778700dc1c0581879b06f9c671af15 Mon Sep 17 00:00:00 2001 From: Nigel Green Date: Mon, 30 Jul 2018 15:39:03 +0100 Subject: [PATCH 1/2] Updated PaginationType to allow custom fields to be injected --- src/Rebing/GraphQL/Support/PaginationType.php | 22 +++++++++++++------ src/config/config.php | 8 +++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Rebing/GraphQL/Support/PaginationType.php b/src/Rebing/GraphQL/Support/PaginationType.php index 423a3a48..164b4401 100644 --- a/src/Rebing/GraphQL/Support/PaginationType.php +++ b/src/Rebing/GraphQL/Support/PaginationType.php @@ -12,14 +12,22 @@ class PaginationType extends ObjectType { public function __construct($typeName, $customName = null) { $name = $customName ?: $typeName . '_pagination'; + $paginator = config('graphql.custom_paginators.' . $name); + + $fields = $paginator ? $paginator::getPaginationFields() : []; + $config = [ 'name' => $name, - 'fields' => array_merge($this->getPaginationFields(), [ - 'data' => [ - 'type' => GraphQLType::listOf(GraphQL::type($typeName)), - 'resolve' => function(LengthAwarePaginator $data) { return $data->getCollection(); }, - ], - ]) + 'fields' => array_merge( + $this->getPaginationFields(), + $fields, + [ + 'data' => [ + 'type' => GraphQLType::listOf(GraphQL::type($typeName)), + 'resolve' => function(LengthAwarePaginator $data) { return $data->getCollection(); }, + ], + ] + ) ]; parent::__construct($config); @@ -61,4 +69,4 @@ protected function getPaginationFields() ]; } -} \ No newline at end of file +} diff --git a/src/config/config.php b/src/config/config.php index 4946bea9..d052b25b 100644 --- a/src/config/config.php +++ b/src/config/config.php @@ -139,6 +139,14 @@ 'disable_introspection' => false ], + // You can define custom paginators to override the out-of-the-box fields + // Useful if you want to inject some parameters of your own that apply at the top + // level of the collection rather than to each instance returned. Can also use this + // to add in more of the Laravel pagination data (e.g. last_page). + 'custom_paginators' => [ + // 'my_custom_pagination' => \Path\To\Your\CustomPagination::class, + ], + /* * Config for GraphiQL (see (https://github.com/graphql/graphiql). */ From e9601796e2226d2fa8635ed24de86be1091ba3be Mon Sep 17 00:00:00 2001 From: Nigel Green Date: Wed, 8 Aug 2018 15:40:28 +0100 Subject: [PATCH 2/2] Updated name of project in composer.json --- docs/advanced.md | 84 ++++++++++++++++++- src/Rebing/GraphQL/Support/PaginationType.php | 6 +- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/docs/advanced.md b/docs/advanced.md index f9b86f44..8a05977c 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -454,12 +454,94 @@ Query `posts(limit:10,page:1){data{id},total,per_page}` might return ... ], "total": 21, - "per_page": 10" + "per_page": 10 ] } } ``` +Note that you need to add in the extra 'data' object when you request paginated resources as the returned data gives you +the paginated resources in a data object at the same level as the returned pagination metadata. + +#### Customising the pagination results +You can add in additional metadata results alongside the Laravel 'standard' ones. To keep the Posts theme going, we could +create some additional metadata to show the total number of posts, comments and likes for the posts returned in the paginated +results. + +First, create a class that returns the custom fields you want to see: + +``` +use Illuminate\Pagination\LengthAwarePaginator; +use GraphQL\Type\Definition\Type as GraphQLType; + +class MyCustomPaginationFields +{ + public static function getPaginationFields() + { + return [ + // Pass through a User object that we can use to calculate the totals + 'totals_for_user' => [ + 'type' => \GraphQL::type('total'), + 'description' => 'Total posts, comments and likes for the result set', + 'resolve' => function () { + return app()->make('App\User'); + }, + 'selectable' => false, + ], + // Add in the 'last page' value from the Laravel Paginator + 'last_page' => [ + 'type' => GraphQLType::nonNull(GraphQLType::int()), + 'description' => 'Last page of the result set', + 'resolve' => function (LengthAwarePaginator $data) { + return $data->lastPage(); + }, + 'selectable' => false, + ], + ]; + } +} +``` + +Then add a config entry to map this class: + +``` +'custom_paginators' => [ + 'post_pagination' => \Namespace\Of\The\MyCustomPaginationFields::class, +], +``` +You can now query against the new fields in the same way as for the core pagination metadata. We could now extend the example +query from earlier to get the new fields. + +Query: `posts(limit:10,page:1){data{id},totals_for_user,total,per_page,last_page}`: + +``` +{ + "data": { + "posts: [ + "data": [ + {"id": 3}, + {"id": 5}, + ... + ], + "totals_for_user": [ + {"posts": 12}, + {"comments": 42}, + {"likes": 101} + ], + "total": 21, + "per_page": 10, + "last_page": 3 + ] + } +} +``` + + +If you want to change the name of a default field to fit with users expectations (maybe you want 'total_records' rather +than 'total'), just copy the entry for the field you want to replace (they're in Rebing/GraphQL/Support/PaginationType.php) +and add it to your custom class. + + ### Batching You can send multiple queries (or mutations) at once by grouping them together. Therefore, instead of creating two HTTP requests: diff --git a/src/Rebing/GraphQL/Support/PaginationType.php b/src/Rebing/GraphQL/Support/PaginationType.php index 164b4401..24bffa85 100644 --- a/src/Rebing/GraphQL/Support/PaginationType.php +++ b/src/Rebing/GraphQL/Support/PaginationType.php @@ -12,15 +12,15 @@ class PaginationType extends ObjectType { public function __construct($typeName, $customName = null) { $name = $customName ?: $typeName . '_pagination'; - $paginator = config('graphql.custom_paginators.' . $name); - $fields = $paginator ? $paginator::getPaginationFields() : []; + $customPaginator = config('graphql.custom_paginators.' . $name, null); + $customFields = $customPaginator ? $customPaginator::getPaginationFields() : []; $config = [ 'name' => $name, 'fields' => array_merge( $this->getPaginationFields(), - $fields, + $customFields, [ 'data' => [ 'type' => GraphQLType::listOf(GraphQL::type($typeName)),