@@ -61,8 +61,7 @@ final class KeysetPaginator implements PaginatorInterface
6161 * @var int Maximum number of items per page.
6262 */
6363 private int $ pageSize = self ::DEFAULT_PAGE_SIZE ;
64- private ?string $ firstValue = null ;
65- private ?string $ lastValue = null ;
64+ private ?PageToken $ token = null ;
6665 private ?string $ currentFirstValue = null ;
6766 private ?string $ currentLastValue = null ;
6867
@@ -139,20 +138,16 @@ public function __clone()
139138 $ this ->currentLastValue = null ;
140139 }
141140
142- public function withNextPageToken (? string $ token ): static
141+ public function withToken (? PageToken $ token ): static
143142 {
144143 $ new = clone $ this ;
145- $ new ->firstValue = null ;
146- $ new ->lastValue = $ token ;
144+ $ new ->token = $ token ;
147145 return $ new ;
148146 }
149147
150- public function withPreviousPageToken (? string $ token ): static
148+ public function getToken ( ): ? PageToken
151149 {
152- $ new = clone $ this ;
153- $ new ->firstValue = $ token ;
154- $ new ->lastValue = null ;
155- return $ new ;
150+ return $ this ->token ;
156151 }
157152
158153 public function withPageSize (int $ pageSize ): static
@@ -201,19 +196,19 @@ public function read(): iterable
201196 /** @infection-ignore-all Any value more one in line below will be ignored into `readData()` method */
202197 $ dataReader = $ this ->dataReader ->withLimit ($ this ->pageSize + 1 );
203198
204- if ($ this ->isGoingToPreviousPage () ) {
199+ if ($ this ->token ?->isPrevious === true ) {
205200 $ sort = $ this ->reverseSort ($ sort );
206201 $ dataReader = $ dataReader ->withSort ($ sort );
207202 }
208203
209- if ($ this ->isGoingSomewhere () ) {
204+ if ($ this ->token !== null ) {
210205 $ dataReader = $ dataReader ->withFilter ($ this ->getFilter ($ sort ));
211206 $ this ->hasPreviousPage = $ this ->previousPageExist ($ dataReader , $ sort );
212207 }
213208
214209 $ data = $ this ->readData ($ dataReader , $ sort );
215210
216- if ($ this ->isGoingToPreviousPage () ) {
211+ if ($ this ->token ?->isPrevious === true ) {
217212 $ data = $ this ->reverseData ($ data );
218213 }
219214
@@ -240,14 +235,18 @@ public function getCurrentPageSize(): int
240235 return count ($ this ->readCache );
241236 }
242237
243- public function getPreviousPageToken (): ?string
238+ public function getPreviousToken (): ?PageToken
244239 {
245- return $ this ->isOnFirstPage () ? null : $ this ->currentFirstValue ;
240+ return $ this ->isOnFirstPage ()
241+ ? null
242+ : ($ this ->currentFirstValue === null ? null : PageToken::previous ($ this ->currentFirstValue ));
246243 }
247244
248- public function getNextPageToken (): ?string
245+ public function getNextToken (): ?PageToken
249246 {
250- return $ this ->isOnLastPage () ? null : $ this ->currentLastValue ;
247+ return $ this ->isOnLastPage ()
248+ ? null
249+ : ($ this ->currentLastValue === null ? null : PageToken::next ($ this ->currentLastValue ));
251250 }
252251
253252 public function isSortable (): bool
@@ -269,7 +268,7 @@ public function getSort(): ?Sort
269268
270269 public function isOnFirstPage (): bool
271270 {
272- if ($ this ->lastValue === null && $ this -> firstValue === null ) {
271+ if ($ this ->token === null ) {
273272 return true ;
274273 }
275274
@@ -354,7 +353,10 @@ private function previousPageExist(ReadableDataInterface $dataReader, Sort $sort
354353
355354 private function getFilter (Sort $ sort ): FilterInterface
356355 {
357- $ value = $ this ->getValue ();
356+ /**
357+ * @psalm-var PageToken $this->token The code calling this method must ensure that page token is not null.
358+ */
359+ $ value = $ this ->token ->value ;
358360 [$ field , $ sorting ] = $ this ->getFieldAndSortingFromSort ($ sort );
359361
360362 $ filter = $ sorting === SORT_ASC ? new GreaterThan ($ field , $ value ) : new LessThan ($ field , $ value );
@@ -375,7 +377,10 @@ private function getFilter(Sort $sort): FilterInterface
375377
376378 private function getReverseFilter (Sort $ sort ): FilterInterface
377379 {
378- $ value = $ this ->getValue ();
380+ /**
381+ * @psalm-var PageToken $this->token The code calling this method must ensure that page token is not null.
382+ */
383+ $ value = $ this ->token ->value ;
379384 [$ field , $ sorting ] = $ this ->getFieldAndSortingFromSort ($ sort );
380385
381386 $ filter = $ sorting === SORT_ASC ? new LessThanOrEqual ($ field , $ value ) : new GreaterThanOrEqual ($ field , $ value );
@@ -394,15 +399,6 @@ private function getReverseFilter(Sort $sort): FilterInterface
394399 );
395400 }
396401
397- /**
398- * @psalm-suppress NullableReturnStatement, InvalidNullableReturnType, PossiblyNullArgument The code calling this
399- * method must ensure that at least one of the properties `$firstValue` or `$lastValue` is not `null`.
400- */
401- private function getValue (): string
402- {
403- return $ this ->isGoingToPreviousPage () ? $ this ->firstValue : $ this ->lastValue ;
404- }
405-
406402 private function reverseSort (Sort $ sort ): Sort
407403 {
408404 $ order = $ sort ->getOrder ();
@@ -426,14 +422,4 @@ private function getFieldAndSortingFromSort(Sort $sort): array
426422 reset ($ order ) === 'asc ' ? SORT_ASC : SORT_DESC ,
427423 ];
428424 }
429-
430- private function isGoingToPreviousPage (): bool
431- {
432- return $ this ->firstValue !== null && $ this ->lastValue === null ;
433- }
434-
435- private function isGoingSomewhere (): bool
436- {
437- return $ this ->firstValue !== null || $ this ->lastValue !== null ;
438- }
439425}
0 commit comments