11<?php
2+ /*
3+ * Copyright 2024 Cloud Creativity Limited
4+ *
5+ * Use of this source code is governed by an MIT-style
6+ * license that can be found in the LICENSE file or at
7+ * https://opensource.org/licenses/MIT.
8+ */
29
310declare (strict_types=1 );
411
512namespace LaravelJsonApi \Eloquent \Pagination \Cursor ;
613
714use Illuminate \Database \Eloquent \Builder ;
815use Illuminate \Database \Eloquent \Relations \Relation ;
9- use Illuminate \Pagination \Cursor as LaravelCursor ;
1016use LaravelJsonApi \Contracts \Schema \ID ;
1117use LaravelJsonApi \Core \Schema \IdParser ;
1218
13- class CursorBuilder
19+ final class CursorBuilder
1420{
15- private Builder |Relation $ query ;
16-
17- private ID $ id ;
18-
19- private string $ keyName ;
21+ /**
22+ * @var string
23+ */
24+ private readonly string $ keyName ;
2025
26+ /**
27+ * @var string
28+ */
2129 private string $ direction ;
2230
31+ /**
32+ * @var int|null
33+ */
2334 private ?int $ defaultPerPage = null ;
2435
36+ /**
37+ * @var bool
38+ */
2539 private bool $ withTotal ;
2640
41+ /**
42+ * @var bool
43+ */
2744 private bool $ keySort = true ;
2845
29- private CursorParser $ parser ;
46+ /**
47+ * @var CursorParser
48+ */
49+ private readonly CursorParser $ parser ;
3050
3151 /**
3252 * CursorBuilder constructor.
3353 *
34- * @param Builder|Relation $query
35- * the column to use for the cursor
36- * @param string|null $key
37- * the key column that the before/after cursors related to
54+ * @param Builder|Relation $query the column to use for the cursor
55+ * @param ID $id
56+ * @param string|null $key the key column that the before/after cursors related to
3857 */
39- public function __construct ($ query , ID $ id , string $ key = null )
40- {
41- if (!$ query instanceof Builder && !$ query instanceof Relation) {
42- throw new \InvalidArgumentException ('Expecting an Eloquent query builder or relation. ' );
43- }
44-
45- $ this ->query = $ query ;
46- $ this ->id = $ id ;
47- $ this ->keyName = $ key ?: $ this ->guessKey ();
58+ public function __construct (
59+ private readonly Builder |Relation $ query ,
60+ private readonly ID $ id ,
61+ ?string $ key = null
62+ ) {
63+ $ this ->keyName = $ key ?: $ this ->id ->key ();
4864 $ this ->parser = new CursorParser (IdParser::make ($ this ->id ), $ this ->keyName );
4965 }
5066
@@ -62,8 +78,11 @@ public function withDefaultPerPage(?int $perPage): self
6278 return $ this ;
6379 }
6480
65-
66- public function withKeySort (bool $ keySort ): self
81+ /**
82+ * @param bool $keySort
83+ * @return $this
84+ */
85+ public function withKeySort (bool $ keySort = true ): self
6786 {
6887 $ this ->keySort = $ keySort ;
6988
@@ -86,6 +105,10 @@ public function withDirection(string $direction): self
86105 throw new \InvalidArgumentException ('Unexpected query direction. ' );
87106 }
88107
108+ /**
109+ * @param bool $withTotal
110+ * @return $this
111+ */
89112 public function withTotal (bool $ withTotal ): self
90113 {
91114 $ this ->withTotal = $ withTotal ;
@@ -103,12 +126,20 @@ public function paginate(Cursor $cursor, array $columns = ['*']): CursorPaginato
103126 $ this ->applyKeySort ();
104127
105128 $ total = $ this ->getTotal ();
106- $ laravelPaginator = $ this ->query ->cursorPaginate ($ cursor ->getLimit (), $ columns , 'cursor ' , $ this ->parser ->decode ($ cursor ));
129+ $ laravelPaginator = $ this ->query ->cursorPaginate (
130+ $ cursor ->getLimit (),
131+ $ columns ,
132+ 'cursor ' ,
133+ $ this ->parser ->decode ($ cursor ),
134+ );
107135 $ paginator = new CursorPaginator ($ this ->parser , $ laravelPaginator , $ cursor , $ total );
108136
109137 return $ paginator ->withCurrentPath ();
110138 }
111139
140+ /**
141+ * @return void
142+ */
112143 private function applyKeySort (): void
113144 {
114145 if (!$ this ->keySort ) {
@@ -125,35 +156,17 @@ private function applyKeySort(): void
125156 }
126157 }
127158
159+ /**
160+ * @return int|null
161+ */
128162 private function getTotal (): ?int
129163 {
130164 return $ this ->withTotal ? $ this ->query ->count () : null ;
131165 }
132166
133- private function convertCursor (Cursor $ cursor ): ?LaravelCursor
134- {
135- $ encodedCursor = $ cursor ->isBefore () ? $ cursor ->getBefore () : $ cursor ->getAfter ();
136- if (!is_string ($ encodedCursor )) {
137- return null ;
138- }
139-
140- $ parameters = json_decode (base64_decode (str_replace (['- ' , '_ ' ], ['+ ' , '/ ' ], $ encodedCursor )), true );
141-
142- if (json_last_error () !== JSON_ERROR_NONE ) {
143- return null ;
144- }
145-
146- $ pointsToNextItems = $ parameters ['_pointsToNextItems ' ];
147- unset($ parameters ['_pointsToNextItems ' ]);
148- if (isset ($ parameters [$ this ->keyName ])) {
149- $ parameters [$ this ->keyName ] = IdParser::make ($ this ->id )->decode (
150- (string ) $ parameters [$ this ->keyName ],
151- );
152- }
153-
154- return new LaravelCursor ($ parameters , $ pointsToNextItems );
155- }
156-
167+ /**
168+ * @return int
169+ */
157170 private function getDefaultPerPage (): int
158171 {
159172 if (is_int ($ this ->defaultPerPage )) {
@@ -162,12 +175,4 @@ private function getDefaultPerPage(): int
162175
163176 return $ this ->query ->getModel ()->getPerPage ();
164177 }
165-
166- /**
167- * Guess the key to use for the cursor.
168- */
169- private function guessKey (): string
170- {
171- return $ this ->id ?->key() ?? $ this ->query ->getModel ()->getKeyName ();
172- }
173178}
0 commit comments