3 namespace Shaarli\Bookmark
;
5 use Shaarli\Bookmark\Exception\InvalidBookmarkException
;
10 * Implementing ArrayAccess, this allows us to use the bookmark list
11 * as an array and iterate over it.
13 * @package Shaarli\Bookmark
15 class BookmarkArray
implements \Iterator
, \Countable
, \ArrayAccess
23 * @var array List of all bookmarks IDS mapped with their array offset.
29 * @var int Position in the $this->keys array (for the Iterator interface)
34 * @var array List of offset keys (for the Iterator interface implementation)
39 * @var array List of all recorded URLs (key=url, value=bookmark offset)
40 * for fast reserve search (url-->bookmark offset)
44 public function __construct()
47 $this->bookmarks
= [];
54 * Countable - Counts elements of an object
56 * @return int Number of bookmarks
58 public function count()
60 return count($this->bookmarks
);
64 * ArrayAccess - Assigns a value to the specified offset
66 * @param int $offset Bookmark ID
67 * @param Bookmark $value instance
69 * @throws InvalidBookmarkException
71 public function offsetSet($offset, $value)
73 if (! $value instanceof Bookmark
74 || $value->getId() === null || empty($value->getUrl())
75 || ($offset !== null && ! is_int($offset)) || ! is_int($value->getId())
76 || $offset !== null && $offset !== $value->getId()
78 throw new InvalidBookmarkException($value);
81 // If the bookmark exists, we reuse the real offset, otherwise new entry
82 if ($offset !== null) {
83 $existing = $this->getBookmarkOffset($offset);
85 $existing = $this->getBookmarkOffset($value->getId());
88 if ($existing !== null) {
91 $offset = count($this->bookmarks
);
94 $this->bookmarks
[$offset] = $value;
95 $this->urls
[$value->getUrl()] = $offset;
96 $this->ids
[$value->getId()] = $offset;
100 * ArrayAccess - Whether or not an offset exists
102 * @param int $offset Bookmark ID
104 * @return bool true if it exists, false otherwise
106 public function offsetExists($offset)
108 return array_key_exists($this->getBookmarkOffset($offset), $this->bookmarks
);
112 * ArrayAccess - Unsets an offset
114 * @param int $offset Bookmark ID
116 public function offsetUnset($offset)
118 $realOffset = $this->getBookmarkOffset($offset);
119 $url = $this->bookmarks
[$realOffset]->getUrl();
120 unset($this->urls
[$url]);
121 unset($this->ids
[$offset]);
122 unset($this->bookmarks
[$realOffset]);
126 * ArrayAccess - Returns the value at specified offset
128 * @param int $offset Bookmark ID
130 * @return Bookmark|null The Bookmark if found, null otherwise
132 public function offsetGet($offset)
134 $realOffset = $this->getBookmarkOffset($offset);
135 return isset($this->bookmarks
[$realOffset]) ? $this->bookmarks
[$realOffset] : null;
139 * Iterator - Returns the current element
141 * @return Bookmark corresponding to the current position
143 public function current()
145 return $this[$this->keys
[$this->position
]];
149 * Iterator - Returns the key of the current element
151 * @return int Bookmark ID corresponding to the current position
153 public function key()
155 return $this->keys
[$this->position
];
159 * Iterator - Moves forward to next element
161 public function next()
167 * Iterator - Rewinds the Iterator to the first element
169 * Entries are sorted by date (latest first)
171 public function rewind()
173 $this->keys
= array_keys($this->ids
);
178 * Iterator - Checks if current position is valid
180 * @return bool true if the current Bookmark ID exists, false otherwise
182 public function valid()
184 return isset($this->keys
[$this->position
]);
188 * Returns a bookmark offset in bookmarks array from its unique ID.
190 * @param int $id Persistent ID of a bookmark.
192 * @return int Real offset in local array, or null if doesn't exist.
194 protected function getBookmarkOffset($id)
196 if (isset($this->ids
[$id])) {
197 return $this->ids
[$id];
203 * Return the next key for bookmark creation.
204 * E.g. If the last ID is 597, the next will be 598.
206 * @return int next ID.
208 public function getNextId()
210 if (!empty($this->ids
)) {
211 return max(array_keys($this->ids
)) +
1;
219 * @return Bookmark|null
221 public function getByUrl($url)
224 && isset($this->urls
[$url])
225 && isset($this->bookmarks
[$this->urls
[$url]])
227 return $this->bookmarks
[$this->urls
[$url]];
233 * Reorder links by creation date (newest first).
235 * Also update the urls and ids mapping arrays.
237 * @param string $order ASC|DESC
239 public function reorder($order = 'DESC')
241 $order = $order === 'ASC' ? -1 : 1;
242 // Reorder array by dates.
243 usort($this->bookmarks
, function ($a, $b) use ($order) {
244 /** @var $a Bookmark */
245 /** @var $b Bookmark */
246 if ($a->isSticky() !== $b->isSticky()) {
247 return $a->isSticky() ? -1 : 1;
249 return $a->getCreated() < $b->getCreated() ? 1 * $order : -1 * $order;
254 foreach ($this->bookmarks
as $key => $bookmark) {
255 $this->urls
[$bookmark->getUrl()] = $key;
256 $this->ids
[$bookmark->getId()] = $key;