basic async-interop support; generator consumer missing
[m6w6/seekat] / lib / API / Links.php
1 <?php
2
3 namespace seekat\API;
4
5 use seekat\Exception\UnexpectedValueException;
6 use http\ {
7 Header,
8 Params,
9 QueryString,
10 Url
11 };
12 use Serializable;
13
14 final class Links implements Serializable
15 {
16 /**
17 * Parsed "Link" relations
18 * @var Params
19 */
20 private $params;
21
22 /**
23 * Parsed "Link" relations
24 * @var array
25 */
26 private $relations = [];
27
28 /**
29 * Parse the hypermedia link header
30 *
31 * @param Header $links The Link header
32 * @throws UnexpectedValueException
33 */
34 function __construct(Header $links = null) {
35 if ($links) {
36 if (strcasecmp($links->name, "Link")) {
37 throw new UnexpectedValueException("Expected 'Link' header, got: '{$links->name}'");
38 }
39 $this->unserialize($links->value);
40 }
41 }
42
43 /**
44 * @return string
45 */
46 function __toString() : string {
47 return $this->serialize();
48 }
49
50 /**
51 * @return string
52 */
53 function serialize() {
54 return (string) $this->params;
55 }
56
57 /**
58 * @param string $links
59 */
60 function unserialize($links) {
61 $this->params = new Params($links, ",", ";", "=",
62 Params::PARSE_RFC5988 | Params::PARSE_ESCAPED);
63 if ($this->params->params) {
64 foreach ($this->params->params as $link => $param) {
65 $this->relations[$param["arguments"]["rel"]] = new Url($link);
66 }
67 }
68 }
69
70 /**
71 * Receive the link header's parsed relations
72 *
73 * @return array
74 */
75 function getRelations() : array {
76 return $this->relations;
77 }
78
79 /**
80 * Get the URL of the link's "next" relation
81 *
82 * Returns the link's "last" relation if it exists and "next" is not set.
83 *
84 * @return Url
85 */
86 function getNext() {
87 if (isset($this->relations["next"])) {
88 return $this->relations["next"];
89 }
90 if (isset($this->relations["last"])) {
91 return $this->relations["last"];
92 }
93 return null;
94 }
95
96 /**
97 * Get the URL of the link's "prev" relation
98 *
99 * Returns the link's "first" relation if it exists and "prev" is not set.
100 *
101 * @return Url
102 */
103 function getPrev() {
104 if (isset($this->relations["prev"])) {
105 return $this->relations["prev"];
106 }
107 if (isset($this->relations["first"])) {
108 return $this->relations["first"];
109 }
110 return null;
111 }
112
113 /**
114 * Get the URL of the link's "last" relation
115 *
116 * @return Url
117 */
118 function getLast() {
119 if (isset($this->relations["last"])) {
120 return $this->relations["last"];
121 }
122 return null;
123 }
124
125 /**
126 * Get the URL of the link's "first" relation
127 *
128 * @return Url
129 */
130 function getFirst() {
131 if (isset($this->relations["first"])) {
132 return $this->relations["first"];
133 }
134 return null;
135 }
136
137 /**
138 * Get the page sequence of the current link's relation
139 *
140 * @param string $which The relation of which to extract the page
141 * @return int The current page sequence
142 */
143 function getPage($which) {
144 if (($link = $this->{"get$which"}())) {
145 $url = new Url($link, null, 0);
146 $qry = new QueryString($url->query);
147 return $qry->getInt("page", 1);
148 }
149 return 1;
150 }
151 }