Add strict types for bookmarks management

Parameters typing and using strict types overall increase the codebase
quality by enforcing the a given parameter will have the expected type.

It also removes the need to unnecessary unit tests checking methods
behavior with invalid input.
This commit is contained in:
ArthurHoaro 2020-10-02 17:50:59 +02:00
parent 29c31b7ec6
commit efb7d21b52
19 changed files with 209 additions and 285 deletions

View file

@ -89,12 +89,12 @@ public static function formatLink($bookmark, $indexUrl)
* If no URL is provided, it will generate a local note URL. * If no URL is provided, it will generate a local note URL.
* If no title is provided, it will use the URL as title. * If no title is provided, it will use the URL as title.
* *
* @param array $input Request Link. * @param array|null $input Request Link.
* @param bool $defaultPrivate Request Link. * @param bool $defaultPrivate Setting defined if a bookmark is private by default.
* *
* @return Bookmark instance. * @return Bookmark instance.
*/ */
public static function buildBookmarkFromRequest($input, $defaultPrivate): Bookmark public static function buildBookmarkFromRequest(?array $input, bool $defaultPrivate): Bookmark
{ {
$bookmark = new Bookmark(); $bookmark = new Bookmark();
$url = ! empty($input['url']) ? cleanup_url($input['url']) : ''; $url = ! empty($input['url']) ? cleanup_url($input['url']) : '';

View file

@ -96,11 +96,12 @@ public function getLinks($request, $response)
*/ */
public function getLink($request, $response, $args) public function getLink($request, $response, $args)
{ {
if (!$this->bookmarkService->exists($args['id'])) { $id = is_integer_mixed($args['id']) ? (int) $args['id'] : null;
if ($id === null || ! $this->bookmarkService->exists($id)) {
throw new ApiLinkNotFoundException(); throw new ApiLinkNotFoundException();
} }
$index = index_url($this->ci['environment']); $index = index_url($this->ci['environment']);
$out = ApiUtils::formatLink($this->bookmarkService->get($args['id']), $index); $out = ApiUtils::formatLink($this->bookmarkService->get($id), $index);
return $response->withJson($out, 200, $this->jsonStyle); return $response->withJson($out, 200, $this->jsonStyle);
} }
@ -115,7 +116,7 @@ public function getLink($request, $response, $args)
*/ */
public function postLink($request, $response) public function postLink($request, $response)
{ {
$data = $request->getParsedBody(); $data = (array) ($request->getParsedBody() ?? []);
$bookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links')); $bookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links'));
// duplicate by URL, return 409 Conflict // duplicate by URL, return 409 Conflict
if (! empty($bookmark->getUrl()) if (! empty($bookmark->getUrl())
@ -148,7 +149,8 @@ public function postLink($request, $response)
*/ */
public function putLink($request, $response, $args) public function putLink($request, $response, $args)
{ {
if (! $this->bookmarkService->exists($args['id'])) { $id = is_integer_mixed($args['id']) ? (int) $args['id'] : null;
if ($id === null || !$this->bookmarkService->exists($id)) {
throw new ApiLinkNotFoundException(); throw new ApiLinkNotFoundException();
} }
@ -159,7 +161,7 @@ public function putLink($request, $response, $args)
// duplicate URL on a different link, return 409 Conflict // duplicate URL on a different link, return 409 Conflict
if (! empty($requestBookmark->getUrl()) if (! empty($requestBookmark->getUrl())
&& ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl())) && ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl()))
&& $dup->getId() != $args['id'] && $dup->getId() != $id
) { ) {
return $response->withJson( return $response->withJson(
ApiUtils::formatLink($dup, $index), ApiUtils::formatLink($dup, $index),
@ -168,7 +170,7 @@ public function putLink($request, $response, $args)
); );
} }
$responseBookmark = $this->bookmarkService->get($args['id']); $responseBookmark = $this->bookmarkService->get($id);
$responseBookmark = ApiUtils::updateLink($responseBookmark, $requestBookmark); $responseBookmark = ApiUtils::updateLink($responseBookmark, $requestBookmark);
$this->bookmarkService->set($responseBookmark); $this->bookmarkService->set($responseBookmark);
@ -189,10 +191,11 @@ public function putLink($request, $response, $args)
*/ */
public function deleteLink($request, $response, $args) public function deleteLink($request, $response, $args)
{ {
if (! $this->bookmarkService->exists($args['id'])) { $id = is_integer_mixed($args['id']) ? (int) $args['id'] : null;
if ($id === null || !$this->bookmarkService->exists($id)) {
throw new ApiLinkNotFoundException(); throw new ApiLinkNotFoundException();
} }
$bookmark = $this->bookmarkService->get($args['id']); $bookmark = $this->bookmarkService->get($id);
$this->bookmarkService->remove($bookmark); $this->bookmarkService->remove($bookmark);
return $response->withStatus(204); return $response->withStatus(204);

View file

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Shaarli\Bookmark; namespace Shaarli\Bookmark;
use DateTime; use DateTime;
@ -59,25 +61,25 @@ class Bookmark
* *
* @return $this * @return $this
*/ */
public function fromArray($data) public function fromArray(array $data): Bookmark
{ {
$this->id = $data['id']; $this->id = $data['id'] ?? null;
$this->shortUrl = $data['shorturl']; $this->shortUrl = $data['shorturl'] ?? null;
$this->url = $data['url']; $this->url = $data['url'] ?? null;
$this->title = $data['title']; $this->title = $data['title'] ?? null;
$this->description = $data['description']; $this->description = $data['description'] ?? null;
$this->thumbnail = isset($data['thumbnail']) ? $data['thumbnail'] : null; $this->thumbnail = $data['thumbnail'] ?? null;
$this->sticky = isset($data['sticky']) ? $data['sticky'] : false; $this->sticky = $data['sticky'] ?? false;
$this->created = $data['created']; $this->created = $data['created'] ?? null;
if (is_array($data['tags'])) { if (is_array($data['tags'])) {
$this->tags = $data['tags']; $this->tags = $data['tags'];
} else { } else {
$this->tags = preg_split('/\s+/', $data['tags'], -1, PREG_SPLIT_NO_EMPTY); $this->tags = preg_split('/\s+/', $data['tags'] ?? '', -1, PREG_SPLIT_NO_EMPTY);
} }
if (! empty($data['updated'])) { if (! empty($data['updated'])) {
$this->updated = $data['updated']; $this->updated = $data['updated'];
} }
$this->private = $data['private'] ? true : false; $this->private = ($data['private'] ?? false) ? true : false;
return $this; return $this;
} }
@ -95,13 +97,12 @@ public function fromArray($data)
* *
* @throws InvalidBookmarkException * @throws InvalidBookmarkException
*/ */
public function validate() public function validate(): void
{ {
if ($this->id === null if ($this->id === null
|| ! is_int($this->id) || ! is_int($this->id)
|| empty($this->shortUrl) || empty($this->shortUrl)
|| empty($this->created) || empty($this->created)
|| ! $this->created instanceof DateTimeInterface
) { ) {
throw new InvalidBookmarkException($this); throw new InvalidBookmarkException($this);
} }
@ -119,11 +120,11 @@ public function validate()
* - created: with the current datetime * - created: with the current datetime
* - shortUrl: with a generated small hash from the date and the given ID * - shortUrl: with a generated small hash from the date and the given ID
* *
* @param int $id * @param int|null $id
* *
* @return Bookmark * @return Bookmark
*/ */
public function setId($id) public function setId(?int $id): Bookmark
{ {
$this->id = $id; $this->id = $id;
if (empty($this->created)) { if (empty($this->created)) {
@ -139,9 +140,9 @@ public function setId($id)
/** /**
* Get the Id. * Get the Id.
* *
* @return int * @return int|null
*/ */
public function getId() public function getId(): ?int
{ {
return $this->id; return $this->id;
} }
@ -149,9 +150,9 @@ public function getId()
/** /**
* Get the ShortUrl. * Get the ShortUrl.
* *
* @return string * @return string|null
*/ */
public function getShortUrl() public function getShortUrl(): ?string
{ {
return $this->shortUrl; return $this->shortUrl;
} }
@ -159,9 +160,9 @@ public function getShortUrl()
/** /**
* Get the Url. * Get the Url.
* *
* @return string * @return string|null
*/ */
public function getUrl() public function getUrl(): ?string
{ {
return $this->url; return $this->url;
} }
@ -171,7 +172,7 @@ public function getUrl()
* *
* @return string * @return string
*/ */
public function getTitle() public function getTitle(): ?string
{ {
return $this->title; return $this->title;
} }
@ -181,7 +182,7 @@ public function getTitle()
* *
* @return string * @return string
*/ */
public function getDescription() public function getDescription(): string
{ {
return ! empty($this->description) ? $this->description : ''; return ! empty($this->description) ? $this->description : '';
} }
@ -191,7 +192,7 @@ public function getDescription()
* *
* @return DateTimeInterface * @return DateTimeInterface
*/ */
public function getCreated() public function getCreated(): ?DateTimeInterface
{ {
return $this->created; return $this->created;
} }
@ -201,7 +202,7 @@ public function getCreated()
* *
* @return DateTimeInterface * @return DateTimeInterface
*/ */
public function getUpdated() public function getUpdated(): ?DateTimeInterface
{ {
return $this->updated; return $this->updated;
} }
@ -209,11 +210,11 @@ public function getUpdated()
/** /**
* Set the ShortUrl. * Set the ShortUrl.
* *
* @param string $shortUrl * @param string|null $shortUrl
* *
* @return Bookmark * @return Bookmark
*/ */
public function setShortUrl($shortUrl) public function setShortUrl(?string $shortUrl): Bookmark
{ {
$this->shortUrl = $shortUrl; $this->shortUrl = $shortUrl;
@ -223,14 +224,14 @@ public function setShortUrl($shortUrl)
/** /**
* Set the Url. * Set the Url.
* *
* @param string $url * @param string|null $url
* @param array $allowedProtocols * @param string[] $allowedProtocols
* *
* @return Bookmark * @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)) { if (! empty($url)) {
$url = whitelist_protocols($url, $allowedProtocols); $url = whitelist_protocols($url, $allowedProtocols);
} }
@ -242,13 +243,13 @@ public function setUrl($url, $allowedProtocols = [])
/** /**
* Set the Title. * Set the Title.
* *
* @param string $title * @param string|null $title
* *
* @return Bookmark * @return Bookmark
*/ */
public function setTitle($title) public function setTitle(?string $title): Bookmark
{ {
$this->title = trim($title); $this->title = $title !== null ? trim($title) : '';
return $this; return $this;
} }
@ -256,11 +257,11 @@ public function setTitle($title)
/** /**
* Set the Description. * Set the Description.
* *
* @param string $description * @param string|null $description
* *
* @return Bookmark * @return Bookmark
*/ */
public function setDescription($description) public function setDescription(?string $description): Bookmark
{ {
$this->description = $description; $this->description = $description;
@ -271,11 +272,11 @@ public function setDescription($description)
* Set the Created. * Set the Created.
* Note: you shouldn't set this manually except for special cases (like bookmark import) * Note: you shouldn't set this manually except for special cases (like bookmark import)
* *
* @param DateTimeInterface $created * @param DateTimeInterface|null $created
* *
* @return Bookmark * @return Bookmark
*/ */
public function setCreated($created) public function setCreated(?DateTimeInterface $created): Bookmark
{ {
$this->created = $created; $this->created = $created;
@ -285,11 +286,11 @@ public function setCreated($created)
/** /**
* Set the Updated. * Set the Updated.
* *
* @param DateTimeInterface $updated * @param DateTimeInterface|null $updated
* *
* @return Bookmark * @return Bookmark
*/ */
public function setUpdated($updated) public function setUpdated(?DateTimeInterface $updated): Bookmark
{ {
$this->updated = $updated; $this->updated = $updated;
@ -301,7 +302,7 @@ public function setUpdated($updated)
* *
* @return bool * @return bool
*/ */
public function isPrivate() public function isPrivate(): bool
{ {
return $this->private ? true : false; return $this->private ? true : false;
} }
@ -309,11 +310,11 @@ public function isPrivate()
/** /**
* Set the Private. * Set the Private.
* *
* @param bool $private * @param bool|null $private
* *
* @return Bookmark * @return Bookmark
*/ */
public function setPrivate($private) public function setPrivate(?bool $private): Bookmark
{ {
$this->private = $private ? true : false; $this->private = $private ? true : false;
@ -323,9 +324,9 @@ public function setPrivate($private)
/** /**
* Get the Tags. * Get the Tags.
* *
* @return array * @return string[]
*/ */
public function getTags() public function getTags(): array
{ {
return is_array($this->tags) ? $this->tags : []; return is_array($this->tags) ? $this->tags : [];
} }
@ -333,13 +334,13 @@ public function getTags()
/** /**
* Set the Tags. * Set the Tags.
* *
* @param array $tags * @param string[]|null $tags
* *
* @return Bookmark * @return Bookmark
*/ */
public function setTags($tags) public function setTags(?array $tags): Bookmark
{ {
$this->setTagsString(implode(' ', $tags)); $this->setTagsString(implode(' ', $tags ?? []));
return $this; return $this;
} }
@ -357,11 +358,11 @@ public function getThumbnail()
/** /**
* Set the Thumbnail. * 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 * @return Bookmark
*/ */
public function setThumbnail($thumbnail) public function setThumbnail($thumbnail): Bookmark
{ {
$this->thumbnail = $thumbnail; $this->thumbnail = $thumbnail;
@ -373,7 +374,7 @@ public function setThumbnail($thumbnail)
* *
* @return bool * @return bool
*/ */
public function isSticky() public function isSticky(): bool
{ {
return $this->sticky ? true : false; return $this->sticky ? true : false;
} }
@ -381,11 +382,11 @@ public function isSticky()
/** /**
* Set the Sticky. * Set the Sticky.
* *
* @param bool $sticky * @param bool|null $sticky
* *
* @return Bookmark * @return Bookmark
*/ */
public function setSticky($sticky) public function setSticky(?bool $sticky): Bookmark
{ {
$this->sticky = $sticky ? true : false; $this->sticky = $sticky ? true : false;
@ -395,7 +396,7 @@ public function setSticky($sticky)
/** /**
* @return string Bookmark's tags as a string, separated by a space * @return string Bookmark's tags as a string, separated by a space
*/ */
public function getTagsString() public function getTagsString(): string
{ {
return implode(' ', $this->getTags()); return implode(' ', $this->getTags());
} }
@ -403,7 +404,7 @@ public function getTagsString()
/** /**
* @return bool * @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 // 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] === '?'; return empty($this->url) || startsWith($this->url, '/shaare/') || $this->url[0] === '?';
@ -416,14 +417,14 @@ public function isNote()
* - multiple spaces will be removed * - multiple spaces will be removed
* - trailing dash in tags will be removed * - trailing dash in tags will be removed
* *
* @param string $tags * @param string|null $tags
* *
* @return $this * @return $this
*/ */
public function setTagsString($tags) public function setTagsString(?string $tags): Bookmark
{ {
// Remove first '-' char in tags. // Remove first '-' char in tags.
$tags = preg_replace('/(^| )\-/', '$1', $tags); $tags = preg_replace('/(^| )\-/', '$1', $tags ?? '');
// Explode all tags separted by spaces or commas // Explode all tags separted by spaces or commas
$tags = preg_split('/[\s,]+/', $tags); $tags = preg_split('/[\s,]+/', $tags);
// Remove eventual empty values // Remove eventual empty values
@ -440,7 +441,7 @@ public function setTagsString($tags)
* @param string $fromTag * @param string $fromTag
* @param string $toTag * @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); $this->tags[$pos] = trim($toTag);
@ -452,7 +453,7 @@ public function renameTag($fromTag, $toTag)
* *
* @param string $tag * @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]); unset($this->tags[$pos]);

View file

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Shaarli\Bookmark; namespace Shaarli\Bookmark;
use Shaarli\Bookmark\Exception\InvalidBookmarkException; use Shaarli\Bookmark\Exception\InvalidBookmarkException;
@ -187,13 +189,13 @@ public function valid()
/** /**
* Returns a bookmark offset in bookmarks array from its unique ID. * Returns a bookmark offset in bookmarks array from its unique ID.
* *
* @param int $id Persistent ID of a bookmark. * @param int|null $id Persistent ID of a bookmark.
* *
* @return int Real offset in local array, or null if doesn't exist. * @return int Real offset in local array, or null if doesn't exist.
*/ */
protected function getBookmarkOffset($id) protected function getBookmarkOffset(?int $id): ?int
{ {
if (isset($this->ids[$id])) { if ($id !== null && isset($this->ids[$id])) {
return $this->ids[$id]; return $this->ids[$id];
} }
return null; return null;
@ -205,7 +207,7 @@ protected function getBookmarkOffset($id)
* *
* @return int next ID. * @return int next ID.
*/ */
public function getNextId() public function getNextId(): int
{ {
if (!empty($this->ids)) { if (!empty($this->ids)) {
return max(array_keys($this->ids)) + 1; return max(array_keys($this->ids)) + 1;
@ -214,11 +216,11 @@ public function getNextId()
} }
/** /**
* @param $url * @param string $url
* *
* @return Bookmark|null * @return Bookmark|null
*/ */
public function getByUrl($url) public function getByUrl(string $url): ?Bookmark
{ {
if (! empty($url) if (! empty($url)
&& isset($this->urls[$url]) && isset($this->urls[$url])

View file

@ -1,9 +1,10 @@
<?php <?php
declare(strict_types=1);
namespace Shaarli\Bookmark; namespace Shaarli\Bookmark;
use DateTime;
use Exception; use Exception;
use malkusch\lock\mutex\Mutex; use malkusch\lock\mutex\Mutex;
use Shaarli\Bookmark\Exception\BookmarkNotFoundException; use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
@ -54,7 +55,7 @@ class BookmarkFileService implements BookmarkServiceInterface
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function __construct(ConfigManager $conf, History $history, Mutex $mutex, $isLoggedIn) public function __construct(ConfigManager $conf, History $history, Mutex $mutex, bool $isLoggedIn)
{ {
$this->conf = $conf; $this->conf = $conf;
$this->history = $history; $this->history = $history;
@ -96,7 +97,7 @@ public function __construct(ConfigManager $conf, History $history, Mutex $mutex,
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function findByHash($hash) public function findByHash(string $hash): Bookmark
{ {
$bookmark = $this->bookmarkFilter->filter(BookmarkFilter::$FILTER_HASH, $hash); $bookmark = $this->bookmarkFilter->filter(BookmarkFilter::$FILTER_HASH, $hash);
// PHP 7.3 introduced array_key_first() to avoid this hack // PHP 7.3 introduced array_key_first() to avoid this hack
@ -111,7 +112,7 @@ public function findByHash($hash)
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function findByUrl($url) public function findByUrl(string $url): ?Bookmark
{ {
return $this->bookmarks->getByUrl($url); return $this->bookmarks->getByUrl($url);
} }
@ -120,10 +121,10 @@ public function findByUrl($url)
* @inheritDoc * @inheritDoc
*/ */
public function search( public function search(
$request = [], array $request = [],
$visibility = null, string $visibility = null,
$caseSensitive = false, bool $caseSensitive = false,
$untaggedOnly = false, bool $untaggedOnly = false,
bool $ignoreSticky = false bool $ignoreSticky = false
) { ) {
if ($visibility === null) { if ($visibility === null) {
@ -131,8 +132,8 @@ public function search(
} }
// Filter bookmark database according to parameters. // Filter bookmark database according to parameters.
$searchtags = isset($request['searchtags']) ? $request['searchtags'] : ''; $searchTags = isset($request['searchtags']) ? $request['searchtags'] : '';
$searchterm = isset($request['searchterm']) ? $request['searchterm'] : ''; $searchTerm = isset($request['searchterm']) ? $request['searchterm'] : '';
if ($ignoreSticky) { if ($ignoreSticky) {
$this->bookmarks->reorder('DESC', true); $this->bookmarks->reorder('DESC', true);
@ -140,7 +141,7 @@ public function search(
return $this->bookmarkFilter->filter( return $this->bookmarkFilter->filter(
BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
[$searchtags, $searchterm], [$searchTags, $searchTerm],
$caseSensitive, $caseSensitive,
$visibility, $visibility,
$untaggedOnly $untaggedOnly
@ -150,7 +151,7 @@ public function search(
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function get($id, $visibility = null) public function get(int $id, string $visibility = null): Bookmark
{ {
if (! isset($this->bookmarks[$id])) { if (! isset($this->bookmarks[$id])) {
throw new BookmarkNotFoundException(); throw new BookmarkNotFoundException();
@ -173,20 +174,17 @@ public function get($id, $visibility = null)
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function set($bookmark, $save = true) public function set(Bookmark $bookmark, bool $save = true): Bookmark
{ {
if (true !== $this->isLoggedIn) { if (true !== $this->isLoggedIn) {
throw new Exception(t('You\'re not authorized to alter the datastore')); throw new Exception(t('You\'re not authorized to alter the datastore'));
} }
if (! $bookmark instanceof Bookmark) {
throw new Exception(t('Provided data is invalid'));
}
if (! isset($this->bookmarks[$bookmark->getId()])) { if (! isset($this->bookmarks[$bookmark->getId()])) {
throw new BookmarkNotFoundException(); throw new BookmarkNotFoundException();
} }
$bookmark->validate(); $bookmark->validate();
$bookmark->setUpdated(new \DateTime()); $bookmark->setUpdated(new DateTime());
$this->bookmarks[$bookmark->getId()] = $bookmark; $this->bookmarks[$bookmark->getId()] = $bookmark;
if ($save === true) { if ($save === true) {
$this->save(); $this->save();
@ -198,15 +196,12 @@ public function set($bookmark, $save = true)
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function add($bookmark, $save = true) public function add(Bookmark $bookmark, bool $save = true): Bookmark
{ {
if (true !== $this->isLoggedIn) { if (true !== $this->isLoggedIn) {
throw new Exception(t('You\'re not authorized to alter the datastore')); throw new Exception(t('You\'re not authorized to alter the datastore'));
} }
if (! $bookmark instanceof Bookmark) { if (!empty($bookmark->getId())) {
throw new Exception(t('Provided data is invalid'));
}
if (! empty($bookmark->getId())) {
throw new Exception(t('This bookmarks already exists')); throw new Exception(t('This bookmarks already exists'));
} }
$bookmark->setId($this->bookmarks->getNextId()); $bookmark->setId($this->bookmarks->getNextId());
@ -223,14 +218,11 @@ public function add($bookmark, $save = true)
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function addOrSet($bookmark, $save = true) public function addOrSet(Bookmark $bookmark, bool $save = true): Bookmark
{ {
if (true !== $this->isLoggedIn) { if (true !== $this->isLoggedIn) {
throw new Exception(t('You\'re not authorized to alter the datastore')); throw new Exception(t('You\'re not authorized to alter the datastore'));
} }
if (! $bookmark instanceof Bookmark) {
throw new Exception('Provided data is invalid');
}
if ($bookmark->getId() === null) { if ($bookmark->getId() === null) {
return $this->add($bookmark, $save); return $this->add($bookmark, $save);
} }
@ -240,14 +232,11 @@ public function addOrSet($bookmark, $save = true)
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function remove($bookmark, $save = true) public function remove(Bookmark $bookmark, bool $save = true): void
{ {
if (true !== $this->isLoggedIn) { if (true !== $this->isLoggedIn) {
throw new Exception(t('You\'re not authorized to alter the datastore')); throw new Exception(t('You\'re not authorized to alter the datastore'));
} }
if (! $bookmark instanceof Bookmark) {
throw new Exception(t('Provided data is invalid'));
}
if (! isset($this->bookmarks[$bookmark->getId()])) { if (! isset($this->bookmarks[$bookmark->getId()])) {
throw new BookmarkNotFoundException(); throw new BookmarkNotFoundException();
} }
@ -262,7 +251,7 @@ public function remove($bookmark, $save = true)
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function exists($id, $visibility = null) public function exists(int $id, string $visibility = null): bool
{ {
if (! isset($this->bookmarks[$id])) { if (! isset($this->bookmarks[$id])) {
return false; return false;
@ -285,7 +274,7 @@ public function exists($id, $visibility = null)
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function count($visibility = null) public function count(string $visibility = null): int
{ {
return count($this->search([], $visibility)); return count($this->search([], $visibility));
} }
@ -293,7 +282,7 @@ public function count($visibility = null)
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function save() public function save(): void
{ {
if (true !== $this->isLoggedIn) { if (true !== $this->isLoggedIn) {
// TODO: raise an Exception instead // TODO: raise an Exception instead
@ -308,7 +297,7 @@ public function save()
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function bookmarksCountPerTag($filteringTags = [], $visibility = null) public function bookmarksCountPerTag(array $filteringTags = [], string $visibility = null): array
{ {
$bookmarks = $this->search(['searchtags' => $filteringTags], $visibility); $bookmarks = $this->search(['searchtags' => $filteringTags], $visibility);
$tags = []; $tags = [];
@ -344,13 +333,14 @@ public function bookmarksCountPerTag($filteringTags = [], $visibility = null)
$keys = array_keys($tags); $keys = array_keys($tags);
$tmpTags = array_combine($keys, $keys); $tmpTags = array_combine($keys, $keys);
array_multisort($tags, SORT_DESC, $tmpTags, SORT_ASC, $tags); array_multisort($tags, SORT_DESC, $tmpTags, SORT_ASC, $tags);
return $tags; return $tags;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function days() public function days(): array
{ {
$bookmarkDays = []; $bookmarkDays = [];
foreach ($this->search() as $bookmark) { foreach ($this->search() as $bookmark) {
@ -365,7 +355,7 @@ public function days()
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function filterDay($request) public function filterDay(string $request)
{ {
$visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC; $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC;
@ -375,7 +365,7 @@ public function filterDay($request)
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function initialize() public function initialize(): void
{ {
$initializer = new BookmarkInitializer($this); $initializer = new BookmarkInitializer($this);
$initializer->initialize(); $initializer->initialize();
@ -388,7 +378,7 @@ public function initialize()
/** /**
* Handles migration to the new database format (BookmarksArray). * Handles migration to the new database format (BookmarksArray).
*/ */
protected function migrate() protected function migrate(): void
{ {
$bookmarkDb = new LegacyLinkDB( $bookmarkDb = new LegacyLinkDB(
$this->conf->get('resource.datastore'), $this->conf->get('resource.datastore'),

View file

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Shaarli\Bookmark; namespace Shaarli\Bookmark;
use Exception; use Exception;
@ -77,8 +79,13 @@ public function __construct($bookmarks)
* *
* @throws BookmarkNotFoundException * @throws BookmarkNotFoundException
*/ */
public function filter($type, $request, $casesensitive = false, $visibility = 'all', $untaggedonly = false) public function filter(
{ string $type,
$request,
bool $casesensitive = false,
string $visibility = 'all',
bool $untaggedonly = false
) {
if (!in_array($visibility, ['all', 'public', 'private'])) { if (!in_array($visibility, ['all', 'public', 'private'])) {
$visibility = 'all'; $visibility = 'all';
} }
@ -128,7 +135,7 @@ public function filter($type, $request, $casesensitive = false, $visibility = 'a
* *
* @return Bookmark[] filtered bookmarks. * @return Bookmark[] filtered bookmarks.
*/ */
private function noFilter($visibility = 'all') private function noFilter(string $visibility = 'all')
{ {
if ($visibility === 'all') { if ($visibility === 'all') {
return $this->bookmarks; return $this->bookmarks;
@ -151,11 +158,11 @@ private function noFilter($visibility = 'all')
* *
* @param string $smallHash permalink hash. * @param string $smallHash permalink hash.
* *
* @return array $filtered array containing permalink data. * @return Bookmark[] $filtered array containing permalink data.
* *
* @throws \Shaarli\Bookmark\Exception\BookmarkNotFoundException if the smallhash doesn't match any link. * @throws BookmarkNotFoundException if the smallhash doesn't match any link.
*/ */
private function filterSmallHash($smallHash) private function filterSmallHash(string $smallHash)
{ {
foreach ($this->bookmarks as $key => $l) { foreach ($this->bookmarks as $key => $l) {
if ($smallHash == $l->getShortUrl()) { if ($smallHash == $l->getShortUrl()) {
@ -186,9 +193,9 @@ private function filterSmallHash($smallHash)
* @param string $searchterms search query. * @param string $searchterms search query.
* @param string $visibility Optional: return only all/private/public bookmarks. * @param string $visibility Optional: return only all/private/public bookmarks.
* *
* @return array search results. * @return Bookmark[] search results.
*/ */
private function filterFulltext($searchterms, $visibility = 'all') private function filterFulltext(string $searchterms, string $visibility = 'all')
{ {
if (empty($searchterms)) { if (empty($searchterms)) {
return $this->noFilter($visibility); return $this->noFilter($visibility);
@ -268,7 +275,7 @@ private function filterFulltext($searchterms, $visibility = 'all')
* *
* @return string generated regex fragment * @return string generated regex fragment
*/ */
private static function tag2regex($tag) private static function tag2regex(string $tag): string
{ {
$len = strlen($tag); $len = strlen($tag);
if (!$len || $tag === "-" || $tag === "*") { if (!$len || $tag === "-" || $tag === "*") {
@ -314,13 +321,13 @@ private static function tag2regex($tag)
* You can specify one or more tags, separated by space or a comma, e.g. * You can specify one or more tags, separated by space or a comma, e.g.
* print_r($mydb->filterTags('linux programming')); * print_r($mydb->filterTags('linux programming'));
* *
* @param string $tags list of tags separated by commas or blank spaces. * @param string|array $tags list of tags, separated by commas or blank spaces if passed as string.
* @param bool $casesensitive ignore case if false. * @param bool $casesensitive ignore case if false.
* @param string $visibility Optional: return only all/private/public bookmarks. * @param string $visibility Optional: return only all/private/public bookmarks.
* *
* @return array filtered bookmarks. * @return Bookmark[] filtered bookmarks.
*/ */
public function filterTags($tags, $casesensitive = false, $visibility = 'all') public function filterTags($tags, bool $casesensitive = false, string $visibility = 'all')
{ {
// get single tags (we may get passed an array, even though the docs say different) // get single tags (we may get passed an array, even though the docs say different)
$inputTags = $tags; $inputTags = $tags;
@ -396,9 +403,9 @@ public function filterTags($tags, $casesensitive = false, $visibility = 'all')
* *
* @param string $visibility return only all/private/public bookmarks. * @param string $visibility return only all/private/public bookmarks.
* *
* @return array filtered bookmarks. * @return Bookmark[] filtered bookmarks.
*/ */
public function filterUntagged($visibility) public function filterUntagged(string $visibility)
{ {
$filtered = []; $filtered = [];
foreach ($this->bookmarks as $key => $link) { foreach ($this->bookmarks as $key => $link) {
@ -427,11 +434,11 @@ public function filterUntagged($visibility)
* @param string $day day to filter. * @param string $day day to filter.
* @param string $visibility return only all/private/public bookmarks. * @param string $visibility return only all/private/public bookmarks.
* @return array all link matching given day. * @return Bookmark[] all link matching given day.
* *
* @throws Exception if date format is invalid. * @throws Exception if date format is invalid.
*/ */
public function filterDay($day, $visibility) public function filterDay(string $day, string $visibility)
{ {
if (!checkDateFormat('Ymd', $day)) { if (!checkDateFormat('Ymd', $day)) {
throw new Exception('Invalid date format'); throw new Exception('Invalid date format');
@ -460,9 +467,9 @@ public function filterDay($day, $visibility)
* @param string $tags string containing a list of tags. * @param string $tags string containing a list of tags.
* @param bool $casesensitive will convert everything to lowercase if false. * @param bool $casesensitive will convert everything to lowercase if false.
* *
* @return array filtered tags string. * @return string[] filtered tags string.
*/ */
public static function tagsStrToArray($tags, $casesensitive) public static function tagsStrToArray(string $tags, bool $casesensitive): array
{ {
// We use UTF-8 conversion to handle various graphemes (i.e. cyrillic, or greek) // We use UTF-8 conversion to handle various graphemes (i.e. cyrillic, or greek)
$tagsOut = $casesensitive ? $tags : mb_convert_case($tags, MB_CASE_LOWER, 'UTF-8'); $tagsOut = $casesensitive ? $tags : mb_convert_case($tags, MB_CASE_LOWER, 'UTF-8');

View file

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Shaarli\Bookmark; namespace Shaarli\Bookmark;
use malkusch\lock\mutex\Mutex; use malkusch\lock\mutex\Mutex;
@ -61,7 +63,7 @@ public function __construct(ConfigManager $conf, Mutex $mutex = null)
/** /**
* Reads database from disk to memory * Reads database from disk to memory
* *
* @return BookmarkArray instance * @return Bookmark[]
* *
* @throws NotWritableDataStoreException Data couldn't be loaded * @throws NotWritableDataStoreException Data couldn't be loaded
* @throws EmptyDataStoreException Datastore file exists but does not contain any bookmark * @throws EmptyDataStoreException Datastore file exists but does not contain any bookmark
@ -101,7 +103,7 @@ public function read()
/** /**
* Saves the database from memory to disk * Saves the database from memory to disk
* *
* @param BookmarkArray $links instance. * @param Bookmark[] $links
* *
* @throws NotWritableDataStoreException the datastore is not writable * @throws NotWritableDataStoreException the datastore is not writable
*/ */

View file

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Shaarli\Bookmark; namespace Shaarli\Bookmark;
/** /**
@ -23,7 +25,7 @@ class BookmarkInitializer
* *
* @param BookmarkServiceInterface $bookmarkService * @param BookmarkServiceInterface $bookmarkService
*/ */
public function __construct($bookmarkService) public function __construct(BookmarkServiceInterface $bookmarkService)
{ {
$this->bookmarkService = $bookmarkService; $this->bookmarkService = $bookmarkService;
} }
@ -31,7 +33,7 @@ public function __construct($bookmarkService)
/** /**
* Initialize the data store with default bookmarks * Initialize the data store with default bookmarks
*/ */
public function initialize() public function initialize(): void
{ {
$bookmark = new Bookmark(); $bookmark = new Bookmark();
$bookmark->setTitle('quicksilver (loop) on Vimeo ' . t('(private bookmark with thumbnail demo)')); $bookmark->setTitle('quicksilver (loop) on Vimeo ' . t('(private bookmark with thumbnail demo)'));

View file

@ -1,7 +1,8 @@
<?php <?php
namespace Shaarli\Bookmark; declare(strict_types=1);
namespace Shaarli\Bookmark;
use Shaarli\Bookmark\Exception\BookmarkNotFoundException; use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
use Shaarli\Bookmark\Exception\NotWritableDataStoreException; use Shaarli\Bookmark\Exception\NotWritableDataStoreException;
@ -10,6 +11,9 @@
* Class BookmarksService * Class BookmarksService
* *
* This is the entry point to manipulate the bookmark DB. * This is the entry point to manipulate the bookmark DB.
*
* Regarding return types of a list of bookmarks, it can either be an array or an ArrayAccess implementation,
* so until PHP 8.0 is the minimal supported version with union return types it cannot be explicitly added.
*/ */
interface BookmarkServiceInterface interface BookmarkServiceInterface
{ {
@ -18,51 +22,51 @@ interface BookmarkServiceInterface
* *
* @param string $hash * @param string $hash
* *
* @return mixed * @return Bookmark
* *
* @throws \Exception * @throws \Exception
*/ */
public function findByHash($hash); public function findByHash(string $hash): Bookmark;
/** /**
* @param $url * @param $url
* *
* @return Bookmark|null * @return Bookmark|null
*/ */
public function findByUrl($url); public function findByUrl(string $url): ?Bookmark;
/** /**
* Search bookmarks * Search bookmarks
* *
* @param mixed $request * @param array $request
* @param string $visibility * @param ?string $visibility
* @param bool $caseSensitive * @param bool $caseSensitive
* @param bool $untaggedOnly * @param bool $untaggedOnly
* @param bool $ignoreSticky * @param bool $ignoreSticky
* *
* @return Bookmark[] * @return Bookmark[]
*/ */
public function search( public function search(
$request = [], array $request = [],
$visibility = null, string $visibility = null,
$caseSensitive = false, bool $caseSensitive = false,
$untaggedOnly = false, bool $untaggedOnly = false,
bool $ignoreSticky = false bool $ignoreSticky = false
); );
/** /**
* Get a single bookmark by its ID. * Get a single bookmark by its ID.
* *
* @param int $id Bookmark ID * @param int $id Bookmark ID
* @param string $visibility all|public|private e.g. with public, accessing a private bookmark will throw an * @param ?string $visibility all|public|private e.g. with public, accessing a private bookmark will throw an
* exception * exception
* *
* @return Bookmark * @return Bookmark
* *
* @throws BookmarkNotFoundException * @throws BookmarkNotFoundException
* @throws \Exception * @throws \Exception
*/ */
public function get($id, $visibility = null); public function get(int $id, string $visibility = null);
/** /**
* Updates an existing bookmark (depending on its ID). * Updates an existing bookmark (depending on its ID).
@ -75,7 +79,7 @@ public function get($id, $visibility = null);
* @throws BookmarkNotFoundException * @throws BookmarkNotFoundException
* @throws \Exception * @throws \Exception
*/ */
public function set($bookmark, $save = true); public function set(Bookmark $bookmark, bool $save = true): Bookmark;
/** /**
* Adds a new bookmark (the ID must be empty). * Adds a new bookmark (the ID must be empty).
@ -87,7 +91,7 @@ public function set($bookmark, $save = true);
* *
* @throws \Exception * @throws \Exception
*/ */
public function add($bookmark, $save = true); public function add(Bookmark $bookmark, bool $save = true): Bookmark;
/** /**
* Adds or updates a bookmark depending on its ID: * Adds or updates a bookmark depending on its ID:
@ -101,7 +105,7 @@ public function add($bookmark, $save = true);
* *
* @throws \Exception * @throws \Exception
*/ */
public function addOrSet($bookmark, $save = true); public function addOrSet(Bookmark $bookmark, bool $save = true): Bookmark;
/** /**
* Deletes a bookmark. * Deletes a bookmark.
@ -111,51 +115,51 @@ public function addOrSet($bookmark, $save = true);
* *
* @throws \Exception * @throws \Exception
*/ */
public function remove($bookmark, $save = true); public function remove(Bookmark $bookmark, bool $save = true): void;
/** /**
* Get a single bookmark by its ID. * Get a single bookmark by its ID.
* *
* @param int $id Bookmark ID * @param int $id Bookmark ID
* @param string $visibility all|public|private e.g. with public, accessing a private bookmark will throw an * @param ?string $visibility all|public|private e.g. with public, accessing a private bookmark will throw an
* exception * exception
* *
* @return bool * @return bool
*/ */
public function exists($id, $visibility = null); public function exists(int $id, string $visibility = null): bool;
/** /**
* Return the number of available bookmarks for given visibility. * Return the number of available bookmarks for given visibility.
* *
* @param string $visibility public|private|all * @param ?string $visibility public|private|all
* *
* @return int Number of bookmarks * @return int Number of bookmarks
*/ */
public function count($visibility = null); public function count(string $visibility = null): int;
/** /**
* Write the datastore. * Write the datastore.
* *
* @throws NotWritableDataStoreException * @throws NotWritableDataStoreException
*/ */
public function save(); public function save(): void;
/** /**
* Returns the list tags appearing in the bookmarks with the given tags * Returns the list tags appearing in the bookmarks with the given tags
* *
* @param array $filteringTags tags selecting the bookmarks to consider * @param array|null $filteringTags tags selecting the bookmarks to consider
* @param string $visibility process only all/private/public bookmarks * @param string|null $visibility process only all/private/public bookmarks
* *
* @return array tag => bookmarksCount * @return array tag => bookmarksCount
*/ */
public function bookmarksCountPerTag($filteringTags = [], $visibility = 'all'); public function bookmarksCountPerTag(array $filteringTags = [], ?string $visibility = null): array;
/** /**
* Returns the list of days containing articles (oldest first) * Returns the list of days containing articles (oldest first)
* *
* @return array containing days (in format YYYYMMDD). * @return array containing days (in format YYYYMMDD).
*/ */
public function days(); public function days(): array;
/** /**
* Returns the list of articles for a given day. * Returns the list of articles for a given day.
@ -166,10 +170,10 @@ public function days();
* *
* @throws BookmarkNotFoundException * @throws BookmarkNotFoundException
*/ */
public function filterDay($request); public function filterDay(string $request);
/** /**
* Creates the default database after a fresh install. * Creates the default database after a fresh install.
*/ */
public function initialize(); public function initialize(): void;
} }

View file

@ -102,7 +102,7 @@ public function buildData(string $feedType, ?array $userInput)
} }
// Optionally filter the results: // Optionally filter the results:
$linksToDisplay = $this->linkDB->search($userInput, null, false, false, true); $linksToDisplay = $this->linkDB->search($userInput ?? [], null, false, false, true);
$nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput); $nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput);

View file

@ -52,7 +52,7 @@ public function ajaxUpdate(Request $request, Response $response, array $args): R
} }
try { try {
$bookmark = $this->container->bookmarkService->get($id); $bookmark = $this->container->bookmarkService->get((int) $id);
} catch (BookmarkNotFoundException $e) { } catch (BookmarkNotFoundException $e) {
return $response->withStatus(404); return $response->withStatus(404);
} }

View file

@ -118,7 +118,7 @@ public function checkLoginState($clientIpId)
* *
* @return true when the user is logged in, false otherwise * @return true when the user is logged in, false otherwise
*/ */
public function isLoggedIn() public function isLoggedIn(): bool
{ {
if ($this->openShaarli) { if ($this->openShaarli) {
return true; return true;

View file

@ -89,14 +89,6 @@ public function testAddLink()
$this->assertEquals(History::CREATED, $actual['event']); $this->assertEquals(History::CREATED, $actual['event']);
$this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
$this->assertEquals(1, $actual['id']); $this->assertEquals(1, $actual['id']);
$history = new History(self::$historyFilePath);
$bookmark = (new Bookmark())->setId('str');
$history->addLink($bookmark);
$actual = $history->getHistory()[0];
$this->assertEquals(History::CREATED, $actual['event']);
$this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
$this->assertEquals('str', $actual['id']);
} }
// /** // /**

View file

@ -90,19 +90,6 @@ public function testArrayAccessAddBadEntryOffset()
$array['nope'] = $bookmark; $array['nope'] = $bookmark;
} }
/**
* Test adding a bad entry: invalid ID type
*/
public function testArrayAccessAddBadEntryIdType()
{
$this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
$array = new BookmarkArray();
$bookmark = (new Bookmark())->setId('nope');
$bookmark->validate();
$array[] = $bookmark;
}
/** /**
* Test adding a bad entry: ID/offset not consistent * Test adding a bad entry: ID/offset not consistent
*/ */

View file

@ -264,17 +264,6 @@ public function testAddLoggedOut()
$this->publicLinkDB->add(new Bookmark()); $this->publicLinkDB->add(new Bookmark());
} }
/**
* Test add() method with an entry which is not a bookmark instance
*/
public function testAddNotABookmark()
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage('Provided data is invalid');
$this->privateLinkDB->add(['title' => 'hi!']);
}
/** /**
* Test add() method with a Bookmark already containing an ID * Test add() method with a Bookmark already containing an ID
*/ */
@ -412,17 +401,6 @@ public function testSetLoggedOut()
$this->publicLinkDB->set(new Bookmark()); $this->publicLinkDB->set(new Bookmark());
} }
/**
* Test set() method with an entry which is not a bookmark instance
*/
public function testSetNotABookmark()
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage('Provided data is invalid');
$this->privateLinkDB->set(['title' => 'hi!']);
}
/** /**
* Test set() method with a Bookmark without an ID defined. * Test set() method with a Bookmark without an ID defined.
*/ */
@ -496,17 +474,6 @@ public function testAddOrSetLoggedOut()
$this->publicLinkDB->addOrSet(new Bookmark()); $this->publicLinkDB->addOrSet(new Bookmark());
} }
/**
* Test addOrSet() method with an entry which is not a bookmark instance
*/
public function testAddOrSetNotABookmark()
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage('Provided data is invalid');
$this->privateLinkDB->addOrSet(['title' => 'hi!']);
}
/** /**
* Test addOrSet() method for a bookmark without any field set and without writing the data store * Test addOrSet() method for a bookmark without any field set and without writing the data store
*/ */
@ -564,17 +531,6 @@ public function testRemoveLoggedOut()
$this->publicLinkDB->remove($bookmark); $this->publicLinkDB->remove($bookmark);
} }
/**
* Test remove() method with an entry which is not a bookmark instance
*/
public function testRemoveNotABookmark()
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage('Provided data is invalid');
$this->privateLinkDB->remove(['title' => 'hi!']);
}
/** /**
* Test remove() method with a Bookmark with an unknown ID * Test remove() method with a Bookmark with an unknown ID
*/ */

View file

@ -153,25 +153,6 @@ public function testValidateNotValidNoId()
$this->assertContainsPolyfill('- ID: '. PHP_EOL, $exception->getMessage()); $this->assertContainsPolyfill('- ID: '. PHP_EOL, $exception->getMessage());
} }
/**
* Test validate() with a a bookmark with a non integer ID.
*/
public function testValidateNotValidStringId()
{
$bookmark = new Bookmark();
$bookmark->setId('str');
$bookmark->setShortUrl('abc');
$bookmark->setCreated(\DateTime::createFromFormat('Ymd_His', '20190514_200102'));
$exception = null;
try {
$bookmark->validate();
} catch (InvalidBookmarkException $e) {
$exception = $e;
}
$this->assertNotNull($exception);
$this->assertContainsPolyfill('- ID: str'. PHP_EOL, $exception->getMessage());
}
/** /**
* Test validate() with a a bookmark without short url. * Test validate() with a a bookmark without short url.
*/ */
@ -210,25 +191,6 @@ public function testValidateNotValidNoCreated()
$this->assertContainsPolyfill('- Created: '. PHP_EOL, $exception->getMessage()); $this->assertContainsPolyfill('- Created: '. PHP_EOL, $exception->getMessage());
} }
/**
* Test validate() with a a bookmark with a bad created datetime.
*/
public function testValidateNotValidBadCreated()
{
$bookmark = new Bookmark();
$bookmark->setId(1);
$bookmark->setShortUrl('abc');
$bookmark->setCreated('hi!');
$exception = null;
try {
$bookmark->validate();
} catch (InvalidBookmarkException $e) {
$exception = $e;
}
$this->assertNotNull($exception);
$this->assertContainsPolyfill('- Created: Not a DateTime object'. PHP_EOL, $exception->getMessage());
}
/** /**
* Test setId() and make sure that default fields are generated. * Test setId() and make sure that default fields are generated.
*/ */

View file

@ -356,6 +356,10 @@ public function testDeleteBookmarkFromBookmarklet(): void
; ;
$response = new Response(); $response = new Response();
$this->container->bookmarkService->method('get')->with('123')->willReturn(
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
);
$this->container->formatterFactory = $this->createMock(FormatterFactory::class); $this->container->formatterFactory = $this->createMock(FormatterFactory::class);
$this->container->formatterFactory $this->container->formatterFactory
->expects(static::once()) ->expects(static::once())

View file

@ -66,23 +66,27 @@ public function testSaveBookmark(): void
$this->container->bookmarkService $this->container->bookmarkService
->expects(static::once()) ->expects(static::once())
->method('addOrSet') ->method('addOrSet')
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
static::assertFalse($save); static::assertFalse($save);
$checkBookmark($bookmark); $checkBookmark($bookmark);
$bookmark->setId($id); $bookmark->setId($id);
return $bookmark;
}) })
; ;
$this->container->bookmarkService $this->container->bookmarkService
->expects(static::once()) ->expects(static::once())
->method('set') ->method('set')
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
static::assertTrue($save); static::assertTrue($save);
$checkBookmark($bookmark); $checkBookmark($bookmark);
static::assertSame($id, $bookmark->getId()); static::assertSame($id, $bookmark->getId());
return $bookmark;
}) })
; ;
@ -155,21 +159,25 @@ public function testSaveExistingBookmark(): void
$this->container->bookmarkService $this->container->bookmarkService
->expects(static::once()) ->expects(static::once())
->method('addOrSet') ->method('addOrSet')
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
static::assertFalse($save); static::assertFalse($save);
$checkBookmark($bookmark); $checkBookmark($bookmark);
return $bookmark;
}) })
; ;
$this->container->bookmarkService $this->container->bookmarkService
->expects(static::once()) ->expects(static::once())
->method('set') ->method('set')
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
static::assertTrue($save); static::assertTrue($save);
$checkBookmark($bookmark); $checkBookmark($bookmark);
static::assertSame($id, $bookmark->getId()); static::assertSame($id, $bookmark->getId());
return $bookmark;
}) })
; ;
@ -230,8 +238,10 @@ public function testSaveBookmarkWithThumbnail(): void
$this->container->bookmarkService $this->container->bookmarkService
->expects(static::once()) ->expects(static::once())
->method('addOrSet') ->method('addOrSet')
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): void { ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): Bookmark {
static::assertSame($thumb, $bookmark->getThumbnail()); static::assertSame($thumb, $bookmark->getThumbnail());
return $bookmark;
}) })
; ;

View file

@ -89,8 +89,10 @@ public function testAjaxUpdateValid(): void
$this->container->bookmarkService $this->container->bookmarkService
->expects(static::once()) ->expects(static::once())
->method('set') ->method('set')
->willReturnCallback(function (Bookmark $bookmark) use ($thumb) { ->willReturnCallback(function (Bookmark $bookmark) use ($thumb): Bookmark {
static::assertSame($thumb, $bookmark->getThumbnail()); static::assertSame($thumb, $bookmark->getThumbnail());
return $bookmark;
}) })
; ;