aboutsummaryrefslogblamecommitdiffhomepage
path: root/application/bookmark/Bookmark.php
blob: 90ff5b16a44e2df3dced5cc840dd26a40383a601 (plain) (tree)
1
2
3
4
5
6




                           
                      






































                                                                             
                                                   

                       
                                          


















                                                                                                                 

                                                                                 
































                                                                                                     
                                                            






















































































                                                                               
                                








                                
                                






































































                                                                                            
                                        












                                        
                                        




























































                                                        
                               















































































































                                                                                        
<?php

namespace Shaarli\Bookmark;

use DateTime;
use DateTimeInterface;
use Shaarli\Bookmark\Exception\InvalidBookmarkException;

/**
 * Class Bookmark
 *
 * This class represent a single Bookmark with all its attributes.
 * Every bookmark should manipulated using this, before being formatted.
 *
 * @package Shaarli\Bookmark
 */
class Bookmark
{
    /** @var string Date format used in string (former ID format) */
    const LINK_DATE_FORMAT = 'Ymd_His';

    /** @var int Bookmark ID */
    protected $id;

    /** @var string Permalink identifier */
    protected $shortUrl;

    /** @var string Bookmark's URL - $shortUrl prefixed with `?` for notes */
    protected $url;

    /** @var string Bookmark's title */
    protected $title;

    /** @var string Raw bookmark's description */
    protected $description;

    /** @var array List of bookmark's tags */
    protected $tags;

    /** @var string Thumbnail's URL - false if no thumbnail could be found */
    protected $thumbnail;

    /** @var bool Set to true if the bookmark is set as sticky */
    protected $sticky;

    /** @var DateTimeInterface Creation datetime */
    protected $created;

    /** @var DateTimeInterface datetime */
    protected $updated;

    /** @var bool True if the bookmark can only be seen while logged in */
    protected $private;

    /**
     * Initialize a link from array data. Especially useful to create a Bookmark from former link storage format.
     *
     * @param array $data
     *
     * @return $this
     */
    public function fromArray($data)
    {
        $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'];
        if (is_array($data['tags'])) {
            $this->tags = $data['tags'];
        } else {
            $this->tags = preg_split('/\s+/', $data['tags'], -1, PREG_SPLIT_NO_EMPTY);
        }
        if (! empty($data['updated'])) {
            $this->updated = $data['updated'];
        }
        $this->private = $data['private'] ? true : false;

        return $this;
    }

    /**
     * Make sure that the current instance of Bookmark is valid and can be saved into the data store.
     * A valid link requires:
     *   - an integer ID
     *   - a short URL (for permalinks)
     *   - a creation date
     *
     * This function also initialize optional empty fields:
     *   - the URL with the permalink
     *   - the title with the URL
     *
     * @throws InvalidBookmarkException
     */
    public function validate()
    {
        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 = '?'. $this->shortUrl;
        }
        if (empty($this->title)) {
            $this->title = $this->url;
        }
    }

    /**
     * Set the Id.
     * If they're not already initialized, this function also set:
     *   - created: with the current datetime
     *   - shortUrl: with a generated small hash from the date and the given ID
     *
     * @param int $id
     *
     * @return Bookmark
     */
    public function setId($id)
    {
        $this->id = $id;
        if (empty($this->created)) {
            $this->created = new DateTime();
        }
        if (empty($this->shortUrl)) {
            $this->shortUrl = link_small_hash($this->created, $this->id);
        }

        return $this;
    }

    /**
     * Get the Id.
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Get the ShortUrl.
     *
     * @return string
     */
    public function getShortUrl()
    {
        return $this->shortUrl;
    }

    /**
     * Get the Url.
     *
     * @return string
     */
    public function getUrl()
    {
        return $this->url;
    }

    /**
     * Get the Title.
     *
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * Get the Description.
     *
     * @return string
     */
    public function getDescription()
    {
        return ! empty($this->description) ? $this->description : '';
    }

    /**
     * Get the Created.
     *
     * @return DateTimeInterface
     */
    public function getCreated()
    {
        return $this->created;
    }

    /**
     * Get the Updated.
     *
     * @return DateTimeInterface
     */
    public function getUpdated()
    {
        return $this->updated;
    }

    /**
     * Set the ShortUrl.
     *
     * @param string $shortUrl
     *
     * @return Bookmark
     */
    public function setShortUrl($shortUrl)
    {
        $this->shortUrl = $shortUrl;

        return $this;
    }

    /**
     * Set the Url.
     *
     * @param string $url
     * @param array  $allowedProtocols
     *
     * @return Bookmark
     */
    public function setUrl($url, $allowedProtocols = [])
    {
        $url = trim($url);
        if (! empty($url)) {
            $url = whitelist_protocols($url, $allowedProtocols);
        }
        $this->url = $url;

        return $this;
    }

    /**
     * Set the Title.
     *
     * @param string $title
     *
     * @return Bookmark
     */
    public function setTitle($title)
    {
        $this->title = trim($title);

        return $this;
    }

    /**
     * Set the Description.
     *
     * @param string $description
     *
     * @return Bookmark
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Set the Created.
     * Note: you shouldn't set this manually except for special cases (like bookmark import)
     *
     * @param DateTimeInterface $created
     *
     * @return Bookmark
     */
    public function setCreated($created)
    {
        $this->created = $created;

        return $this;
    }

    /**
     * Set the Updated.
     *
     * @param DateTimeInterface $updated
     *
     * @return Bookmark
     */
    public function setUpdated($updated)
    {
        $this->updated = $updated;

        return $this;
    }

    /**
     * Get the Private.
     *
     * @return bool
     */
    public function isPrivate()
    {
        return $this->private ? true : false;
    }

    /**
     * Set the Private.
     *
     * @param bool $private
     *
     * @return Bookmark
     */
    public function setPrivate($private)
    {
        $this->private = $private ? true : false;

        return $this;
    }

    /**
     * Get the Tags.
     *
     * @return array
     */
    public function getTags()
    {
        return is_array($this->tags) ? $this->tags : [];
    }

    /**
     * Set the Tags.
     *
     * @param array $tags
     *
     * @return Bookmark
     */
    public function setTags($tags)
    {
        $this->setTagsString(implode(' ', $tags));

        return $this;
    }

    /**
     * Get the Thumbnail.
     *
     * @return string|bool|null
     */
    public function getThumbnail()
    {
        return !$this->isNote() ? $this->thumbnail : false;
    }

    /**
     * Set the Thumbnail.
     *
     * @param string|bool $thumbnail
     *
     * @return Bookmark
     */
    public function setThumbnail($thumbnail)
    {
        $this->thumbnail = $thumbnail;

        return $this;
    }

    /**
     * Get the Sticky.
     *
     * @return bool
     */
    public function isSticky()
    {
        return $this->sticky ? true : false;
    }

    /**
     * Set the Sticky.
     *
     * @param bool $sticky
     *
     * @return Bookmark
     */
    public function setSticky($sticky)
    {
        $this->sticky = $sticky ? true : false;

        return $this;
    }

    /**
     * @return string Bookmark's tags as a string, separated by a space
     */
    public function getTagsString()
    {
        return implode(' ', $this->getTags());
    }

    /**
     * @return bool
     */
    public function isNote()
    {
        // We check empty value to get a valid result if the link has not been saved yet
        return empty($this->url) || $this->url[0] === '?';
    }

    /**
     * Set tags from a string.
     * Note:
     *   - tags must be separated whether by a space or a comma
     *   - multiple spaces will be removed
     *   - trailing dash in tags will be removed
     *
     * @param string $tags
     *
     * @return $this
     */
    public function setTagsString($tags)
    {
        // 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->tags = $tags;

        return $this;
    }

    /**
     * Rename a tag in tags list.
     *
     * @param string $fromTag
     * @param string $toTag
     */
    public function renameTag($fromTag, $toTag)
    {
        if (($pos = array_search($fromTag, $this->tags)) !== false) {
            $this->tags[$pos] = trim($toTag);
        }
    }

    /**
     * Delete a tag from tags list.
     *
     * @param string $tag
     */
    public function deleteTag($tag)
    {
        if (($pos = array_search($tag, $this->tags)) !== false) {
            unset($this->tags[$pos]);
            $this->tags = array_values($this->tags);
        }
    }
}