]> git.immae.eu Git - github/shaarli/Shaarli.git/blobdiff - application/bookmark/Bookmark.php
Apply PHP Code Beautifier on source code for linter automatic fixes
[github/shaarli/Shaarli.git] / application / bookmark / Bookmark.php
index 1beb8be2e127a2b0b905e71e256b0279f8018598..b592722fba47a5046786fac3d6501ba0e07b12d5 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Shaarli\Bookmark;
 
 use DateTime;
@@ -52,32 +54,37 @@ class Bookmark
     /** @var bool True if the bookmark can only be seen while logged in */
     protected $private;
 
+    /** @var mixed[] Available to store any additional content for a bookmark. Currently used for search highlight. */
+    protected $additionalContent = [];
+
     /**
      * Initialize a link from array data. Especially useful to create a Bookmark from former link storage format.
      *
-     * @param array $data
+     * @param array  $data
+     * @param string $tagsSeparator Tags separator loaded from the config file.
+     *                              This is a context data, and it should *never* be stored in the Bookmark object.
      *
      * @return $this
      */
-    public function fromArray($data)
+    public function fromArray(array $data, string $tagsSeparator = ' '): Bookmark
     {
-        $this->id = $data['id'];
-        $this->shortUrl = $data['shorturl'];
-        $this->url = $data['url'];
-        $this->title = $data['title'];
-        $this->description = $data['description'];
-        $this->thumbnail = isset($data['thumbnail']) ? $data['thumbnail'] : null;
-        $this->sticky = isset($data['sticky']) ? $data['sticky'] : false;
-        $this->created = $data['created'];
+        $this->id = $data['id'] ?? null;
+        $this->shortUrl = $data['shorturl'] ?? null;
+        $this->url = $data['url'] ?? null;
+        $this->title = $data['title'] ?? null;
+        $this->description = $data['description'] ?? null;
+        $this->thumbnail = $data['thumbnail'] ?? null;
+        $this->sticky = $data['sticky'] ?? false;
+        $this->created = $data['created'] ?? null;
         if (is_array($data['tags'])) {
             $this->tags = $data['tags'];
         } else {
-            $this->tags = preg_split('/\s+/', $data['tags'], -1, PREG_SPLIT_NO_EMPTY);
+            $this->tags = tags_str2array($data['tags'] ?? '', $tagsSeparator);
         }
         if (! empty($data['updated'])) {
             $this->updated = $data['updated'];
         }
-        $this->private = $data['private'] ? true : false;
+        $this->private = ($data['private'] ?? false) ? true : false;
 
         return $this;
     }
@@ -93,24 +100,29 @@ class Bookmark
      *   - the URL with the permalink
      *   - the title with the URL
      *
+     * Also make sure that we do not save search highlights in the datastore.
+     *
      * @throws InvalidBookmarkException
      */
-    public function validate()
+    public function validate(): void
     {
-        if ($this->id === null
+        if (
+            $this->id === null
             || ! is_int($this->id)
             || empty($this->shortUrl)
             || empty($this->created)
-            || ! $this->created instanceof DateTimeInterface
         ) {
             throw new InvalidBookmarkException($this);
         }
         if (empty($this->url)) {
-            $this->url = '/shaare/'. $this->shortUrl;
+            $this->url = '/shaare/' . $this->shortUrl;
         }
         if (empty($this->title)) {
             $this->title = $this->url;
         }
+        if (array_key_exists('search_highlight', $this->additionalContent)) {
+            unset($this->additionalContent['search_highlight']);
+        }
     }
 
     /**
@@ -119,11 +131,11 @@ class Bookmark
      *   - created: with the current datetime
      *   - shortUrl: with a generated small hash from the date and the given ID
      *
-     * @param int $id
+     * @param int|null $id
      *
      * @return Bookmark
      */
-    public function setId($id)
+    public function setId(?int $id): Bookmark
     {
         $this->id = $id;
         if (empty($this->created)) {
@@ -139,9 +151,9 @@ class Bookmark
     /**
      * Get the Id.
      *
-     * @return int
+     * @return int|null
      */
-    public function getId()
+    public function getId(): ?int
     {
         return $this->id;
     }
@@ -149,9 +161,9 @@ class Bookmark
     /**
      * Get the ShortUrl.
      *
-     * @return string
+     * @return string|null
      */
-    public function getShortUrl()
+    public function getShortUrl(): ?string
     {
         return $this->shortUrl;
     }
@@ -159,9 +171,9 @@ class Bookmark
     /**
      * Get the Url.
      *
-     * @return string
+     * @return string|null
      */
-    public function getUrl()
+    public function getUrl(): ?string
     {
         return $this->url;
     }
@@ -171,7 +183,7 @@ class Bookmark
      *
      * @return string
      */
-    public function getTitle()
+    public function getTitle(): ?string
     {
         return $this->title;
     }
@@ -181,7 +193,7 @@ class Bookmark
      *
      * @return string
      */
-    public function getDescription()
+    public function getDescription(): string
     {
         return ! empty($this->description) ? $this->description : '';
     }
@@ -191,7 +203,7 @@ class Bookmark
      *
      * @return DateTimeInterface
      */
-    public function getCreated()
+    public function getCreated(): ?DateTimeInterface
     {
         return $this->created;
     }
@@ -201,7 +213,7 @@ class Bookmark
      *
      * @return DateTimeInterface
      */
-    public function getUpdated()
+    public function getUpdated(): ?DateTimeInterface
     {
         return $this->updated;
     }
@@ -209,11 +221,11 @@ class Bookmark
     /**
      * Set the ShortUrl.
      *
-     * @param string $shortUrl
+     * @param string|null $shortUrl
      *
      * @return Bookmark
      */
-    public function setShortUrl($shortUrl)
+    public function setShortUrl(?string $shortUrl): Bookmark
     {
         $this->shortUrl = $shortUrl;
 
@@ -223,14 +235,14 @@ class Bookmark
     /**
      * Set the Url.
      *
-     * @param string $url
-     * @param array  $allowedProtocols
+     * @param string|null $url
+     * @param string[]    $allowedProtocols
      *
      * @return Bookmark
      */
-    public function setUrl($url, $allowedProtocols = [])
+    public function setUrl(?string $url, array $allowedProtocols = []): Bookmark
     {
-        $url = trim($url);
+        $url = $url !== null ? trim($url) : '';
         if (! empty($url)) {
             $url = whitelist_protocols($url, $allowedProtocols);
         }
@@ -242,13 +254,13 @@ class Bookmark
     /**
      * Set the Title.
      *
-     * @param string $title
+     * @param string|null $title
      *
      * @return Bookmark
      */
-    public function setTitle($title)
+    public function setTitle(?string $title): Bookmark
     {
-        $this->title = trim($title);
+        $this->title = $title !== null ? trim($title) : '';
 
         return $this;
     }
@@ -256,11 +268,11 @@ class Bookmark
     /**
      * Set the Description.
      *
-     * @param string $description
+     * @param string|null $description
      *
      * @return Bookmark
      */
-    public function setDescription($description)
+    public function setDescription(?string $description): Bookmark
     {
         $this->description = $description;
 
@@ -271,11 +283,11 @@ class Bookmark
      * Set the Created.
      * Note: you shouldn't set this manually except for special cases (like bookmark import)
      *
-     * @param DateTimeInterface $created
+     * @param DateTimeInterface|null $created
      *
      * @return Bookmark
      */
-    public function setCreated($created)
+    public function setCreated(?DateTimeInterface $created): Bookmark
     {
         $this->created = $created;
 
@@ -285,11 +297,11 @@ class Bookmark
     /**
      * Set the Updated.
      *
-     * @param DateTimeInterface $updated
+     * @param DateTimeInterface|null $updated
      *
      * @return Bookmark
      */
-    public function setUpdated($updated)
+    public function setUpdated(?DateTimeInterface $updated): Bookmark
     {
         $this->updated = $updated;
 
@@ -301,7 +313,7 @@ class Bookmark
      *
      * @return bool
      */
-    public function isPrivate()
+    public function isPrivate(): bool
     {
         return $this->private ? true : false;
     }
@@ -309,11 +321,11 @@ class Bookmark
     /**
      * Set the Private.
      *
-     * @param bool $private
+     * @param bool|null $private
      *
      * @return Bookmark
      */
-    public function setPrivate($private)
+    public function setPrivate(?bool $private): Bookmark
     {
         $this->private = $private ? true : false;
 
@@ -323,9 +335,9 @@ class Bookmark
     /**
      * Get the Tags.
      *
-     * @return array
+     * @return string[]
      */
-    public function getTags()
+    public function getTags(): array
     {
         return is_array($this->tags) ? $this->tags : [];
     }
@@ -333,13 +345,18 @@ class Bookmark
     /**
      * Set the Tags.
      *
-     * @param array $tags
+     * @param string[]|null $tags
      *
      * @return Bookmark
      */
-    public function setTags($tags)
+    public function setTags(?array $tags): Bookmark
     {
-        $this->setTagsString(implode(' ', $tags));
+        $this->tags = array_map(
+            function (string $tag): string {
+                return $tag[0] === '-' ? substr($tag, 1) : $tag;
+            },
+            tags_filter($tags, ' ')
+        );
 
         return $this;
     }
@@ -357,23 +374,41 @@ class Bookmark
     /**
      * Set the Thumbnail.
      *
-     * @param string|bool $thumbnail Thumbnail's URL - false if no thumbnail could be found
+     * @param string|bool|null $thumbnail Thumbnail's URL - false if no thumbnail could be found
      *
      * @return Bookmark
      */
-    public function setThumbnail($thumbnail)
+    public function setThumbnail($thumbnail): Bookmark
     {
         $this->thumbnail = $thumbnail;
 
         return $this;
     }
 
+    /**
+     * Return true if:
+     *   - the bookmark's thumbnail is not already set to false (= not found)
+     *   - it's not a note
+     *   - it's an HTTP(S) link
+     *   - the thumbnail has not yet be retrieved (null) or its associated cache file doesn't exist anymore
+     *
+     * @return bool True if the bookmark's thumbnail needs to be retrieved.
+     */
+    public function shouldUpdateThumbnail(): bool
+    {
+        return $this->thumbnail !== false
+            && !$this->isNote()
+            && startsWith(strtolower($this->url), 'http')
+            && (null === $this->thumbnail || !is_file($this->thumbnail))
+        ;
+    }
+
     /**
      * Get the Sticky.
      *
      * @return bool
      */
-    public function isSticky()
+    public function isSticky(): bool
     {
         return $this->sticky ? true : false;
     }
@@ -381,11 +416,11 @@ class Bookmark
     /**
      * Set the Sticky.
      *
-     * @param bool $sticky
+     * @param bool|null $sticky
      *
      * @return Bookmark
      */
-    public function setSticky($sticky)
+    public function setSticky(?bool $sticky): Bookmark
     {
         $this->sticky = $sticky ? true : false;
 
@@ -393,17 +428,19 @@ class Bookmark
     }
 
     /**
-     * @return string Bookmark's tags as a string, separated by a space
+     * @param string $separator Tags separator loaded from the config file.
+     *
+     * @return string Bookmark's tags as a string, separated by a separator
      */
-    public function getTagsString()
+    public function getTagsString(string $separator = ' '): string
     {
-        return implode(' ', $this->getTags());
+        return tags_array2str($this->getTags(), $separator);
     }
 
     /**
      * @return bool
      */
-    public function isNote()
+    public function isNote(): bool
     {
         // We check empty value to get a valid result if the link has not been saved yet
         return empty($this->url) || startsWith($this->url, '/shaare/') || $this->url[0] === '?';
@@ -416,33 +453,65 @@ class Bookmark
      *   - multiple spaces will be removed
      *   - trailing dash in tags will be removed
      *
-     * @param string $tags
+     * @param string|null $tags
+     * @param string      $separator Tags separator loaded from the config file.
      *
      * @return $this
      */
-    public function setTagsString($tags)
+    public function setTagsString(?string $tags, string $separator = ' '): Bookmark
     {
-        // Remove first '-' char in tags.
-        $tags = preg_replace('/(^| )\-/', '$1', $tags);
-        // Explode all tags separted by spaces or commas
-        $tags = preg_split('/[\s,]+/', $tags);
-        // Remove eventual empty values
-        $tags = array_values(array_filter($tags));
+        $this->setTags(tags_str2array($tags, $separator));
 
-        $this->tags = $tags;
+        return $this;
+    }
+
+    /**
+     * Get entire additionalContent array.
+     *
+     * @return mixed[]
+     */
+    public function getAdditionalContent(): array
+    {
+        return $this->additionalContent;
+    }
+
+    /**
+     * Set a single entry in additionalContent, by key.
+     *
+     * @param string     $key
+     * @param mixed|null $value Any type of value can be set.
+     *
+     * @return $this
+     */
+    public function addAdditionalContentEntry(string $key, $value): self
+    {
+        $this->additionalContent[$key] = $value;
 
         return $this;
     }
 
+    /**
+     * Get a single entry in additionalContent, by key.
+     *
+     * @param string $key
+     * @param mixed|null $default
+     *
+     * @return mixed|null can be any type or even null.
+     */
+    public function getAdditionalContentEntry(string $key, $default = null)
+    {
+        return array_key_exists($key, $this->additionalContent) ? $this->additionalContent[$key] : $default;
+    }
+
     /**
      * Rename a tag in tags list.
      *
      * @param string $fromTag
      * @param string $toTag
      */
-    public function renameTag($fromTag, $toTag)
+    public function renameTag(string $fromTag, string $toTag): void
     {
-        if (($pos = array_search($fromTag, $this->tags)) !== false) {
+        if (($pos = array_search($fromTag, $this->tags ?? [])) !== false) {
             $this->tags[$pos] = trim($toTag);
         }
     }
@@ -452,9 +521,9 @@ class Bookmark
      *
      * @param string $tag
      */
-    public function deleteTag($tag)
+    public function deleteTag(string $tag): void
     {
-        if (($pos = array_search($tag, $this->tags)) !== false) {
+        if (($pos = array_search($tag, $this->tags ?? [])) !== false) {
             unset($this->tags[$pos]);
             $this->tags = array_values($this->tags);
         }