]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - application/bookmark/BookmarkArray.php
Apply PHP Code Beautifier on source code for linter automatic fixes
[github/shaarli/Shaarli.git] / application / bookmark / BookmarkArray.php
CommitLineData
336a28fa
A
1<?php
2
efb7d21b
A
3declare(strict_types=1);
4
336a28fa
A
5namespace Shaarli\Bookmark;
6
7use Shaarli\Bookmark\Exception\InvalidBookmarkException;
8
9/**
10 * Class BookmarkArray
11 *
12 * Implementing ArrayAccess, this allows us to use the bookmark list
13 * as an array and iterate over it.
14 *
15 * @package Shaarli\Bookmark
16 */
17class BookmarkArray implements \Iterator, \Countable, \ArrayAccess
18{
19 /**
20 * @var Bookmark[]
21 */
22 protected $bookmarks;
23
24 /**
25 * @var array List of all bookmarks IDS mapped with their array offset.
26 * Map: id->offset.
27 */
28 protected $ids;
29
30 /**
31 * @var int Position in the $this->keys array (for the Iterator interface)
32 */
33 protected $position;
34
35 /**
36 * @var array List of offset keys (for the Iterator interface implementation)
37 */
38 protected $keys;
39
40 /**
41 * @var array List of all recorded URLs (key=url, value=bookmark offset)
42 * for fast reserve search (url-->bookmark offset)
43 */
44 protected $urls;
45
46 public function __construct()
47 {
48 $this->ids = [];
49 $this->bookmarks = [];
50 $this->keys = [];
51 $this->urls = [];
52 $this->position = 0;
53 }
54
55 /**
56 * Countable - Counts elements of an object
57 *
58 * @return int Number of bookmarks
59 */
60 public function count()
61 {
62 return count($this->bookmarks);
63 }
64
65 /**
66 * ArrayAccess - Assigns a value to the specified offset
67 *
68 * @param int $offset Bookmark ID
69 * @param Bookmark $value instance
70 *
71 * @throws InvalidBookmarkException
72 */
73 public function offsetSet($offset, $value)
74 {
53054b2b
A
75 if (
76 ! $value instanceof Bookmark
336a28fa
A
77 || $value->getId() === null || empty($value->getUrl())
78 || ($offset !== null && ! is_int($offset)) || ! is_int($value->getId())
79 || $offset !== null && $offset !== $value->getId()
80 ) {
81 throw new InvalidBookmarkException($value);
82 }
83
84 // If the bookmark exists, we reuse the real offset, otherwise new entry
85 if ($offset !== null) {
86 $existing = $this->getBookmarkOffset($offset);
87 } else {
88 $existing = $this->getBookmarkOffset($value->getId());
89 }
90
91 if ($existing !== null) {
92 $offset = $existing;
93 } else {
94 $offset = count($this->bookmarks);
95 }
96
97 $this->bookmarks[$offset] = $value;
98 $this->urls[$value->getUrl()] = $offset;
99 $this->ids[$value->getId()] = $offset;
100 }
101
102 /**
103 * ArrayAccess - Whether or not an offset exists
104 *
105 * @param int $offset Bookmark ID
106 *
107 * @return bool true if it exists, false otherwise
108 */
109 public function offsetExists($offset)
110 {
111 return array_key_exists($this->getBookmarkOffset($offset), $this->bookmarks);
112 }
113
114 /**
115 * ArrayAccess - Unsets an offset
116 *
117 * @param int $offset Bookmark ID
118 */
119 public function offsetUnset($offset)
120 {
121 $realOffset = $this->getBookmarkOffset($offset);
122 $url = $this->bookmarks[$realOffset]->getUrl();
123 unset($this->urls[$url]);
cf92b4dd 124 unset($this->ids[$offset]);
336a28fa
A
125 unset($this->bookmarks[$realOffset]);
126 }
127
128 /**
129 * ArrayAccess - Returns the value at specified offset
130 *
131 * @param int $offset Bookmark ID
132 *
133 * @return Bookmark|null The Bookmark if found, null otherwise
134 */
135 public function offsetGet($offset)
136 {
137 $realOffset = $this->getBookmarkOffset($offset);
138 return isset($this->bookmarks[$realOffset]) ? $this->bookmarks[$realOffset] : null;
139 }
140
141 /**
142 * Iterator - Returns the current element
143 *
144 * @return Bookmark corresponding to the current position
145 */
146 public function current()
147 {
148 return $this[$this->keys[$this->position]];
149 }
150
151 /**
152 * Iterator - Returns the key of the current element
153 *
154 * @return int Bookmark ID corresponding to the current position
155 */
156 public function key()
157 {
158 return $this->keys[$this->position];
159 }
160
161 /**
162 * Iterator - Moves forward to next element
163 */
164 public function next()
165 {
166 ++$this->position;
167 }
168
169 /**
170 * Iterator - Rewinds the Iterator to the first element
171 *
172 * Entries are sorted by date (latest first)
173 */
174 public function rewind()
175 {
176 $this->keys = array_keys($this->ids);
177 $this->position = 0;
178 }
179
180 /**
181 * Iterator - Checks if current position is valid
182 *
183 * @return bool true if the current Bookmark ID exists, false otherwise
184 */
185 public function valid()
186 {
187 return isset($this->keys[$this->position]);
188 }
189
190 /**
191 * Returns a bookmark offset in bookmarks array from its unique ID.
192 *
efb7d21b 193 * @param int|null $id Persistent ID of a bookmark.
336a28fa
A
194 *
195 * @return int Real offset in local array, or null if doesn't exist.
196 */
efb7d21b 197 protected function getBookmarkOffset(?int $id): ?int
336a28fa 198 {
efb7d21b 199 if ($id !== null && isset($this->ids[$id])) {
336a28fa
A
200 return $this->ids[$id];
201 }
202 return null;
203 }
204
205 /**
206 * Return the next key for bookmark creation.
207 * E.g. If the last ID is 597, the next will be 598.
208 *
209 * @return int next ID.
210 */
efb7d21b 211 public function getNextId(): int
336a28fa
A
212 {
213 if (!empty($this->ids)) {
214 return max(array_keys($this->ids)) + 1;
215 }
216 return 0;
217 }
218
219 /**
efb7d21b 220 * @param string $url
336a28fa
A
221 *
222 * @return Bookmark|null
223 */
efb7d21b 224 public function getByUrl(string $url): ?Bookmark
336a28fa 225 {
53054b2b
A
226 if (
227 ! empty($url)
336a28fa
A
228 && isset($this->urls[$url])
229 && isset($this->bookmarks[$this->urls[$url]])
230 ) {
231 return $this->bookmarks[$this->urls[$url]];
232 }
233 return null;
234 }
235
236 /**
237 * Reorder links by creation date (newest first).
238 *
239 * Also update the urls and ids mapping arrays.
240 *
a8e210fa
A
241 * @param string $order ASC|DESC
242 * @param bool $ignoreSticky If set to true, sticky bookmarks won't be first
336a28fa 243 */
a8e210fa 244 public function reorder(string $order = 'DESC', bool $ignoreSticky = false): void
336a28fa
A
245 {
246 $order = $order === 'ASC' ? -1 : 1;
247 // Reorder array by dates.
a8e210fa 248 usort($this->bookmarks, function ($a, $b) use ($order, $ignoreSticky) {
336a28fa
A
249 /** @var $a Bookmark */
250 /** @var $b Bookmark */
a8e210fa 251 if (false === $ignoreSticky && $a->isSticky() !== $b->isSticky()) {
336a28fa
A
252 return $a->isSticky() ? -1 : 1;
253 }
254 return $a->getCreated() < $b->getCreated() ? 1 * $order : -1 * $order;
255 });
256
257 $this->urls = [];
258 $this->ids = [];
259 foreach ($this->bookmarks as $key => $bookmark) {
260 $this->urls[$bookmark->getUrl()] = $key;
261 $this->ids[$bookmark->getId()] = $key;
262 }
263 }
264}