|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace DutchCodingCompany\CursorPagination\Pagination; |
|
4
|
|
|
|
|
5
|
|
|
use GraphQL\Language\AST\FieldDefinitionNode; |
|
6
|
|
|
use GraphQL\Language\AST\ObjectTypeDefinitionNode; |
|
7
|
|
|
use Nuwave\Lighthouse\Pagination\PaginationType; |
|
8
|
|
|
use Nuwave\Lighthouse\Schema\AST\ASTHelper; |
|
9
|
|
|
use Nuwave\Lighthouse\Schema\AST\PartialParser; |
|
10
|
|
|
|
|
11
|
|
|
class PaginationManipulator extends \Nuwave\Lighthouse\Pagination\PaginationManipulator |
|
12
|
|
|
{ |
|
13
|
|
|
|
|
14
|
|
|
/** |
|
15
|
|
|
* Transform the definition for a field to a field with pagination. |
|
16
|
|
|
* |
|
17
|
|
|
* This makes either an offset-based Paginator or a cursor-based Connection. |
|
18
|
|
|
* The types in between are automatically generated and applied to the schema. |
|
19
|
|
|
* |
|
20
|
|
|
* @param \Nuwave\Lighthouse\Pagination\PaginationType $paginationType |
|
21
|
|
|
*/ |
|
22
|
|
|
public function transformToPaginatedField( |
|
23
|
|
|
PaginationType $paginationType, |
|
24
|
|
|
FieldDefinitionNode &$fieldDefinition, |
|
25
|
|
|
ObjectTypeDefinitionNode &$parentType, |
|
26
|
|
|
?int $defaultCount = null, |
|
27
|
|
|
?int $maxCount = null, |
|
28
|
|
|
?ObjectTypeDefinitionNode $edgeType = null |
|
29
|
|
|
): void { |
|
30
|
|
|
if ($paginationType->isConnection()) { |
|
31
|
|
|
$this->registerConnection($fieldDefinition, $parentType, $defaultCount, $maxCount, $edgeType); |
|
32
|
|
|
} else { |
|
33
|
|
|
$this->registerPaginator($fieldDefinition, $parentType, $defaultCount, $maxCount); |
|
34
|
|
|
} |
|
35
|
|
|
} |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* Register connection with schema. |
|
39
|
|
|
*/ |
|
40
|
|
|
protected function registerConnection( |
|
41
|
|
|
FieldDefinitionNode &$fieldDefinition, |
|
42
|
|
|
ObjectTypeDefinitionNode &$parentType, |
|
43
|
|
|
?int $defaultCount = null, |
|
44
|
|
|
?int $maxCount = null, |
|
45
|
|
|
?ObjectTypeDefinitionNode $edgeType = null |
|
46
|
|
|
): void { |
|
47
|
|
|
// Register cursor specific pagination type |
|
48
|
|
|
$this->addCursorPaginationInfoType(); |
|
49
|
|
|
|
|
50
|
|
|
$fieldTypeName = ASTHelper::getUnderlyingTypeName($fieldDefinition); |
|
51
|
|
|
|
|
52
|
|
|
if ($edgeType) { |
|
53
|
|
|
$connectionEdgeName = $edgeType->name->value; |
|
54
|
|
|
$connectionTypeName = "{$connectionEdgeName}Connection"; |
|
55
|
|
|
} else { |
|
56
|
|
|
$connectionEdgeName = "{$fieldTypeName}Edge"; |
|
57
|
|
|
$connectionTypeName = "{$fieldTypeName}Connection"; |
|
58
|
|
|
} |
|
59
|
|
|
|
|
60
|
|
|
$connectionFieldName = addslashes(ConnectionField::class); |
|
61
|
|
|
$connectionType = PartialParser::objectTypeDefinition(/** @lang GraphQL */ <<<GRAPHQL |
|
62
|
|
|
"A paginated list of $fieldTypeName edges." |
|
63
|
|
|
type $connectionTypeName { |
|
64
|
|
|
"Pagination information about the list of edges." |
|
65
|
|
|
pageInfo: CursorPageInfo! @field(resolver: "{$connectionFieldName}@pageInfoResolver") |
|
66
|
|
|
|
|
67
|
|
|
"A list of $fieldTypeName edges." |
|
68
|
|
|
edges: [$connectionEdgeName] @field(resolver: "{$connectionFieldName}@edgeResolver") |
|
69
|
|
|
} |
|
70
|
|
|
GRAPHQL |
|
71
|
|
|
); |
|
72
|
|
|
$this->addPaginationWrapperType($connectionType); |
|
73
|
|
|
|
|
74
|
|
|
$connectionEdge = $edgeType |
|
75
|
|
|
?? $this->documentAST->types[$connectionEdgeName] |
|
76
|
|
|
?? PartialParser::objectTypeDefinition(/** @lang GraphQL */ <<<GRAPHQL |
|
77
|
|
|
"An edge that contains a node of type $fieldTypeName and a cursor." |
|
78
|
|
|
type $connectionEdgeName { |
|
79
|
|
|
"The $fieldTypeName node." |
|
80
|
|
|
node: $fieldTypeName |
|
81
|
|
|
} |
|
82
|
|
|
GRAPHQL |
|
83
|
|
|
); |
|
84
|
|
|
$this->documentAST->setTypeDefinition($connectionEdge); |
|
85
|
|
|
|
|
86
|
|
|
$inputValueDefinitions = [ |
|
87
|
|
|
self::countArgument('first', $defaultCount, $maxCount), |
|
88
|
|
|
"\"A cursor after which elements are returned.\"\nafter: String", |
|
89
|
|
|
]; |
|
90
|
|
|
|
|
91
|
|
|
$connectionArguments = PartialParser::inputValueDefinitions($inputValueDefinitions); |
|
92
|
|
|
|
|
93
|
|
|
$fieldDefinition->arguments = ASTHelper::mergeNodeList($fieldDefinition->arguments, $connectionArguments); |
|
94
|
|
|
$fieldDefinition->type = PartialParser::namedType($connectionTypeName); |
|
95
|
|
|
$parentType->fields = ASTHelper::mergeNodeList($parentType->fields, [$fieldDefinition]); |
|
|
|
|
|
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
/** |
|
99
|
|
|
* Add the types required for pagination. |
|
100
|
|
|
*/ |
|
101
|
|
|
protected function addCursorPaginationInfoType(): void |
|
102
|
|
|
{ |
|
103
|
|
|
$this->documentAST->setTypeDefinition( |
|
104
|
|
|
PartialParser::objectTypeDefinition(/** @lang GraphQL */ ' |
|
105
|
|
|
"Pagination information about the corresponding list of items." |
|
106
|
|
|
type CursorPageInfo { |
|
107
|
|
|
"When paginating forwards, the cursor to continue." |
|
108
|
|
|
after: String |
|
109
|
|
|
|
|
110
|
|
|
"When paginating forwards, are there more items?" |
|
111
|
|
|
hasAfter: Boolean! |
|
112
|
|
|
|
|
113
|
|
|
"Total number of node in connection." |
|
114
|
|
|
total: Int |
|
115
|
|
|
|
|
116
|
|
|
"Count of nodes in current request." |
|
117
|
|
|
count: Int |
|
118
|
|
|
|
|
119
|
|
|
} |
|
120
|
|
|
') |
|
121
|
|
|
); |
|
122
|
|
|
} |
|
123
|
|
|
} |
|
124
|
|
|
|
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..