Skip to content

Commit 00aa085

Browse files
a70537952Mikk Mihkel Nurges
authored andcommitted
Support custom PaginationType & Enhance Upload Type & Fix Privacy and SelectFields no working on Paginate (#169)
* add custom pagination type * update advanced.md * add getInstance to UploadType for singleton, fix parse value cause error * update documentation * fix Privacy & SelectFields no working on Paginate * check is pagination by instance instead of name * fix mutation error * use pagination type instead of custom pagination type & optimize selectFields check is pagination type * selectFields check pagination field type by instance * remove unused $parentTypeName * add accessibility of typeName and dataKey to paginationType
1 parent c7a2a87 commit 00aa085

File tree

7 files changed

+152
-11
lines changed

7 files changed

+152
-11
lines changed

Readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ class UserProfilePhotoMutation extends Mutation
503503
return [
504504
'profilePicture' => [
505505
'name' => 'profilePicture',
506-
'type' => new UploadType($this->attributes['name']),
506+
'type' => UploadType::getInstance(),
507507
'rules' => ['required', 'image', 'max:1500'],
508508
],
509509
];

docs/advanced.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,127 @@ If you want to change the name of a default field to fit with users expectations
552552
than 'total'), just copy the entry for the field you want to replace (they're in Rebing/GraphQL/Support/PaginationType.php)
553553
and add it to your custom class.
554554

555+
#### Custom Pagination Type
556+
If pagination cant fulfill you needs, you might want to custom your own pagination type.<br/>
557+
Replace default **pagination_type** inside graphql config and use your own pagination type class.
558+
```php
559+
'pagination_type' => \Rebing\GraphQL\Support\PaginationType::class,
560+
```
561+
Example usage of custom pagination_type: <br>
562+
<br/>
563+
If you want pagination info under **cursor** rather than same level with **data** ,<br>
564+
**Result of default pagination type:**
565+
```
566+
{
567+
"user": {
568+
"data": [],
569+
"total": 0 // pagination info
570+
}
571+
}
572+
```
573+
**Result of custom pagination type:**
574+
```
575+
{
576+
"user": {
577+
"items": [],
578+
"cursor": {
579+
"total": 0, // pagination info
580+
}
581+
}
582+
}
583+
```
584+
you will need to create your own **Custom Pagination Type**
585+
<br/>
586+
**Example of PaginationType.php**
587+
```php
588+
<?php
589+
590+
namespace App\GraphQL\Pagination;
591+
592+
use GraphQL\Type\Definition\ObjectType;
593+
use GraphQL\Type\Definition\Type as GraphQLType;
594+
use Illuminate\Pagination\LengthAwarePaginator;
595+
use Rebing\GraphQL\Support\Facades\GraphQL;
596+
597+
class PaginationType extends ObjectType
598+
{
599+
//custom object-types, reference https://webonyx.github.io/graphql-php/type-system/object-types/#recurring-and-circular-types
600+
private static $PaginationCursorType;
601+
public function __construct($typeName, $customName = null)
602+
{
603+
$name = $customName ?: $typeName . 'Pagination';
604+
$config = [
605+
'name' => $name,
606+
'fields' => array_merge(
607+
[
608+
'cursor' => [ // we want pagination info under cursor rather than same level with data
609+
'type' => GraphQLType::nonNull(self::$PaginationCursorType ?: (self::$PaginationCursorType = new PaginationCursorType())),
610+
'resolve' => function (LengthAwarePaginator $paginator) {
611+
return $paginator;
612+
},
613+
]
614+
],
615+
[
616+
'data' => [
617+
'type' => GraphQLType::listOf(GraphQL::type($typeName)),
618+
'resolve' => function (LengthAwarePaginator $data) {
619+
return $data->getCollection();
620+
},
621+
],
622+
]
623+
)
624+
];
625+
parent::__construct($config);
626+
}
627+
}
628+
```
629+
**Example of PaginationCursorType.php**
630+
```php
631+
<?php
555632

633+
namespace App\GraphQL\Pagination;
634+
635+
use GraphQL\Type\Definition\ObjectType;
636+
use Illuminate\Pagination\LengthAwarePaginator;
637+
use GraphQL\Type\Definition\Type as GraphQLType;
638+
639+
class PaginationCursorType extends ObjectType
640+
{
641+
public function __construct()
642+
{
643+
// See https://laravel.com/api/5.6/Illuminate/Pagination/LengthAwarePaginator.html for more fields.
644+
parent::__construct([
645+
'fields' => [
646+
'total' => [
647+
'type' => GraphQLType::nonNull(GraphQLType::int()),
648+
'resolve' => function (LengthAwarePaginator $paginator) {
649+
return $paginator->total();
650+
},
651+
],
652+
'perPage' => [
653+
'type' => GraphQLType::nonNull(GraphQLType::int()),
654+
'resolve' => function (LengthAwarePaginator $paginator) {
655+
return $paginator->perPage();
656+
},
657+
],
658+
'currentPage' => [
659+
'type' => GraphQLType::nonNull(GraphQLType::int()),
660+
'resolve' => function (LengthAwarePaginator $paginator) {
661+
return $paginator->currentPage();
662+
},
663+
],
664+
'hasPages' => [
665+
'type' => GraphQLType::nonNull(GraphQLType::boolean()),
666+
'resolve' => function (LengthAwarePaginator $paginator) {
667+
return $paginator->hasMorePages();
668+
},
669+
],
670+
],
671+
]);
672+
}
673+
}
674+
675+
```
556676
### Batching
557677

558678
You can send multiple queries (or mutations) at once by grouping them together. Therefore, instead of creating two HTTP requests:

src/Rebing/GraphQL/GraphQL.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,8 @@ public function paginate($typeName, $customName = null)
268268

269269
if(!isset($this->typesInstances[$name]))
270270
{
271-
$this->typesInstances[$name] = new PaginationType($typeName, $customName);
271+
$paginationType = config('graphql.pagination_type', PaginationType::class);
272+
$this->typesInstances[$name] = new $paginationType($typeName, $customName);
272273
}
273274

274275
return $this->typesInstances[$name];

src/Rebing/GraphQL/Support/PaginationType.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99

1010
class PaginationType extends ObjectType {
1111

12+
public $typeName;
13+
public $dataKey = 'data';
14+
1215
public function __construct($typeName, $customName = null)
1316
{
14-
$name = $customName ?: $typeName . '_pagination';
17+
$this->typeName = $typeName;
18+
$name = $customName ?: $this->typeName . '_pagination';
1519

1620
$customPaginator = config('graphql.custom_paginators.' . $name, null);
1721
$customFields = $customPaginator ? $customPaginator::getPaginationFields() : [];
@@ -22,8 +26,8 @@ public function __construct($typeName, $customName = null)
2226
$this->getPaginationFields(),
2327
$customFields,
2428
[
25-
'data' => [
26-
'type' => GraphQLType::listOf(GraphQL::type($typeName)),
29+
$this->dataKey => [
30+
'type' => GraphQLType::listOf(GraphQL::type($this->typeName)),
2731
'resolve' => function(LengthAwarePaginator $data) { return $data->getCollection(); },
2832
],
2933
]

src/Rebing/GraphQL/Support/SelectFields.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,15 @@ public function __construct(ResolveInfo $info, $parentType, array $args)
3838
if( ! is_null($info->fieldNodes[0]->selectionSet))
3939
{
4040
self::$args = $args;
41+
$requestedFields = $info->getFieldSelection(5);
42+
$paginationType = config('graphql.pagination_type', PaginationType::class);
4143

42-
$fields = self::getSelectableFieldsAndRelations($info->getFieldSelection(5), $parentType);
44+
if ($parentType instanceof $paginationType) {
45+
$requestedFields = $requestedFields[$parentType->dataKey];
46+
$parentType = $info->schema->getType($parentType->typeName);
47+
}
48+
49+
$fields = self::getSelectableFieldsAndRelations($requestedFields, $parentType);
4350

4451
$this->select = $fields[0];
4552
$this->relations = $fields[1];

src/Rebing/GraphQL/Support/UploadType.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ class UploadType extends ScalarType {
1414
* @var string
1515
*/
1616
public $name = 'Upload';
17-
1817
/**
1918
* @var string
2019
*/
@@ -50,10 +49,6 @@ public function serialize($value)
5049
*/
5150
public function parseValue($value)
5251
{
53-
if (!$value instanceof UploadedFile) {
54-
throw new \UnexpectedValueException('Could not get uploaded file, be sure to conform to GraphQL multipart request specification. Instead got: ' . Utils::printSafe($value));
55-
}
56-
5752
return $value;
5853
}
5954

@@ -68,4 +63,12 @@ public function parseLiteral($valueNode, ?array $variables = NULL)
6863
{
6964
throw new Error('`Upload` cannot be hardcoded in query, be sure to conform to GraphQL multipart request specification. Instead got: ' . $valueNode->kind, [$valueNode]);
7065
}
66+
67+
public static function getInstance() {
68+
static $inst = null;
69+
if ($inst === null) {
70+
$inst = new UploadType();
71+
}
72+
return $inst;
73+
}
7174
}

src/config/config.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@
164164
// 'my_custom_pagination' => \Path\To\Your\CustomPagination::class,
165165
],
166166

167+
/*
168+
* You can define your own pagination type.
169+
* Reference \Rebing\GraphQL\Support\PaginationType::class
170+
*/
171+
'pagination_type' => \Rebing\GraphQL\Support\PaginationType::class,
172+
167173
/*
168174
* Config for GraphiQL (see (https://github.com/graphql/graphiql).
169175
*/

0 commit comments

Comments
 (0)