1: <?php declare(strict_types=1);
2:
3: namespace Salient\Curler\Pager;
4:
5: use Psr\Http\Message\RequestInterface as PsrRequestInterface;
6: use Salient\Contract\Curler\CurlerInterface;
7: use Salient\Contract\Curler\CurlerPageInterface;
8: use Salient\Contract\Curler\CurlerPagerInterface;
9: use Salient\Contract\Http\Message\ResponseInterface;
10: use Salient\Curler\CurlerPage;
11: use Salient\Http\HttpUtil;
12: use Salient\Http\Uri;
13: use Salient\Utility\Exception\InvalidArgumentTypeException;
14:
15: /**
16: * Follows OData "nextLink" annotations in responses from the endpoint
17: *
18: * @api
19: */
20: final class ODataPager implements CurlerPagerInterface
21: {
22: private ?int $MaxPageSize;
23:
24: /**
25: * @api
26: */
27: public function __construct(?int $maxPageSize = null)
28: {
29: $this->MaxPageSize = $maxPageSize;
30: }
31:
32: /**
33: * @inheritDoc
34: */
35: public function getFirstRequest(
36: PsrRequestInterface $request,
37: CurlerInterface $curler,
38: ?array $query = null
39: ): PsrRequestInterface {
40: if ($this->MaxPageSize === null) {
41: return $request;
42: }
43:
44: $prefs = HttpUtil::getPreferences($request);
45: if (
46: isset($prefs['odata.maxpagesize'])
47: && $prefs['odata.maxpagesize']['value'] === (string) $this->MaxPageSize
48: ) {
49: return $request;
50: }
51:
52: $prefs['odata.maxpagesize']['value'] = (string) $this->MaxPageSize;
53:
54: return $request->withHeader(
55: self::HEADER_PREFER,
56: HttpUtil::mergePreferences($prefs),
57: );
58: }
59:
60: /**
61: * @inheritDoc
62: */
63: public function getPage(
64: $data,
65: PsrRequestInterface $request,
66: ResponseInterface $response,
67: CurlerInterface $curler,
68: ?CurlerPageInterface $previousPage = null,
69: ?int $previousEntities = null,
70: ?array $query = null
71: ): CurlerPageInterface {
72: if (!is_array($data)) {
73: throw new InvalidArgumentTypeException(1, 'data', 'mixed[]', $data);
74: }
75: /** @var array{'@odata.nextLink'?:string,'@nextLink'?:string,value:list<mixed>,...} $data */
76: if ($response->getHeaderLine(self::HEADER_ODATA_VERSION) === '4.0') {
77: $nextLink = $data['@odata.nextLink'] ?? null;
78: } else {
79: $nextLink = $data['@nextLink'] ?? $data['@odata.nextLink'] ?? null;
80: }
81:
82: return new CurlerPage(
83: $data['value'],
84: $nextLink === null
85: ? null
86: : $request->withUri(new Uri($nextLink))
87: );
88: }
89: }
90: