3 declare(strict_types
=1);
5 namespace Shaarli\Bookmark
;
9 use Shaarli\Bookmark\Exception\InvalidBookmarkException
;
14 * This class represent a single Bookmark with all its attributes.
15 * Every bookmark should manipulated using this, before being formatted.
17 * @package Shaarli\Bookmark
21 /** @var string Date format used in string (former ID format) */
22 const LINK_DATE_FORMAT
= 'Ymd_His';
24 /** @var int Bookmark ID */
27 /** @var string Permalink identifier */
30 /** @var string Bookmark's URL - $shortUrl prefixed with `?` for notes */
33 /** @var string Bookmark's title */
36 /** @var string Raw bookmark's description */
37 protected $description;
39 /** @var array List of bookmark's tags */
42 /** @var string|bool|null Thumbnail's URL - initialized at null, false if no thumbnail could be found */
45 /** @var bool Set to true if the bookmark is set as sticky */
48 /** @var DateTimeInterface Creation datetime */
51 /** @var DateTimeInterface datetime */
54 /** @var bool True if the bookmark can only be seen while logged in */
58 * Initialize a link from array data. Especially useful to create a Bookmark from former link storage format.
64 public function fromArray(array $data): Bookmark
66 $this->id
= $data['id'] ?? null;
67 $this->shortUrl
= $data['shorturl'] ?? null;
68 $this->url
= $data['url'] ?? null;
69 $this->title
= $data['title'] ?? null;
70 $this->description
= $data['description'] ?? null;
71 $this->thumbnail
= $data['thumbnail'] ?? null;
72 $this->sticky
= $data['sticky'] ?? false;
73 $this->created
= $data['created'] ?? null;
74 if (is_array($data['tags'])) {
75 $this->tags
= $data['tags'];
77 $this->tags
= preg_split('/\s+/', $data['tags'] ?? '', -1, PREG_SPLIT_NO_EMPTY
);
79 if (! empty($data['updated'])) {
80 $this->updated
= $data['updated'];
82 $this->private = ($data['private'] ?? false) ? true : false;
88 * Make sure that the current instance of Bookmark is valid and can be saved into the data store.
89 * A valid link requires:
91 * - a short URL (for permalinks)
94 * This function also initialize optional empty fields:
95 * - the URL with the permalink
96 * - the title with the URL
98 * @throws InvalidBookmarkException
100 public function validate(): void
102 if ($this->id
=== null
103 || ! is_int($this->id
)
104 || empty($this->shortUrl
)
105 || empty($this->created
)
107 throw new InvalidBookmarkException($this);
109 if (empty($this->url
)) {
110 $this->url
= '/shaare/'. $this->shortUrl
;
112 if (empty($this->title
)) {
113 $this->title
= $this->url
;
119 * If they're not already initialized, this function also set:
120 * - created: with the current datetime
121 * - shortUrl: with a generated small hash from the date and the given ID
123 * @param int|null $id
127 public function setId(?int $id): Bookmark
130 if (empty($this->created
)) {
131 $this->created
= new DateTime();
133 if (empty($this->shortUrl
)) {
134 $this->shortUrl
= link_small_hash($this->created
, $this->id
);
145 public function getId(): ?int
153 * @return string|null
155 public function getShortUrl(): ?string
157 return $this->shortUrl
;
163 * @return string|null
165 public function getUrl(): ?string
175 public function getTitle(): ?string
181 * Get the Description.
185 public function getDescription(): string
187 return ! empty($this->description
) ? $this->description
: '';
193 * @return DateTimeInterface
195 public function getCreated(): ?DateTimeInterface
197 return $this->created
;
203 * @return DateTimeInterface
205 public function getUpdated(): ?DateTimeInterface
207 return $this->updated
;
213 * @param string|null $shortUrl
217 public function setShortUrl(?string $shortUrl): Bookmark
219 $this->shortUrl
= $shortUrl;
227 * @param string|null $url
228 * @param string[] $allowedProtocols
232 public function setUrl(?string $url, array $allowedProtocols = []): Bookmark
234 $url = $url !== null ? trim($url) : '';
236 $url = whitelist_protocols($url, $allowedProtocols);
246 * @param string|null $title
250 public function setTitle(?string $title): Bookmark
252 $this->title
= $title !== null ? trim($title) : '';
258 * Set the Description.
260 * @param string|null $description
264 public function setDescription(?string $description): Bookmark
266 $this->description
= $description;
273 * Note: you shouldn't set this manually except for special cases (like bookmark import)
275 * @param DateTimeInterface|null $created
279 public function setCreated(?DateTimeInterface
$created): Bookmark
281 $this->created
= $created;
289 * @param DateTimeInterface|null $updated
293 public function setUpdated(?DateTimeInterface
$updated): Bookmark
295 $this->updated
= $updated;
305 public function isPrivate(): bool
307 return $this->private ? true : false;
313 * @param bool|null $private
317 public function setPrivate(?bool $private): Bookmark
319 $this->private = $private ? true : false;
329 public function getTags(): array
331 return is_array($this->tags
) ? $this->tags
: [];
337 * @param string[]|null $tags
341 public function setTags(?array $tags): Bookmark
343 $this->setTagsString(implode(' ', $tags ?? []));
351 * @return string|bool|null Thumbnail's URL - initialized at null, false if no thumbnail could be found
353 public function getThumbnail()
355 return !$this->isNote() ? $this->thumbnail
: false;
361 * @param string|bool|null $thumbnail Thumbnail's URL - false if no thumbnail could be found
365 public function setThumbnail($thumbnail): Bookmark
367 $this->thumbnail
= $thumbnail;
377 public function isSticky(): bool
379 return $this->sticky
? true : false;
385 * @param bool|null $sticky
389 public function setSticky(?bool $sticky): Bookmark
391 $this->sticky
= $sticky ? true : false;
397 * @return string Bookmark's tags as a string, separated by a space
399 public function getTagsString(): string
401 return implode(' ', $this->getTags());
407 public function isNote(): bool
409 // We check empty value to get a valid result if the link has not been saved yet
410 return empty($this->url
) || startsWith($this->url
, '/shaare/') || $this->url
[0] === '?';
414 * Set tags from a string.
416 * - tags must be separated whether by a space or a comma
417 * - multiple spaces will be removed
418 * - trailing dash in tags will be removed
420 * @param string|null $tags
424 public function setTagsString(?string $tags): Bookmark
426 // Remove first '-' char in tags.
427 $tags = preg_replace('/(^| )\-/', '$1', $tags ?? '');
428 // Explode all tags separted by spaces or commas
429 $tags = preg_split('/[\s
,]+
/', $tags);
430 // Remove eventual empty values
431 $tags = array_values(array_filter($tags));
439 * Rename a tag in tags list.
441 * @param string $fromTag
442 * @param string $toTag
444 public function renameTag(string $fromTag, string $toTag): void
446 if (($pos = array_search($fromTag, $this->tags)) !== false) {
447 $this->tags[$pos] = trim($toTag);
452 * Delete a tag from tags list.
456 public function deleteTag(string $tag): void
458 if (($pos = array_search($tag, $this->tags)) !== false) {
459 unset($this->tags[$pos]);
460 $this->tags = array_values($this->tags);