error != ''; } /** @var bool Whether to render a link to the feed to which the item belongs */ public bool $linkFeed = false; /** @var bool Whether to display the feed to which the item belongs */ public bool $displayFeed = false; /** @var bool Whether to show read / bookmarked indicators on posts */ public bool $showIndicators = false; /** * Constructor * * @param SQLite3 $db The database connection (used to retrieve error information if the query fails) * @param SQLite3Stmt $query The query to retrieve the items for this list * @param string $itemType The type of item being displayed (unread, bookmark, etc.) * @param string $returnURL The URL to which the item page should return once the item has been viewed */ private function __construct(SQLite3 $db, SQLite3Stmt $query, public string $itemType, public string $returnURL = '') { $result = $query->execute(); if (!$result) { $this->error = 'SQLite error: ' . $db->lastErrorMsg(); } else { $this->items = $result; } } /** * Create an item list query * * @param SQLite3 $db The database connection to use to obtain items * @param array $criteria One or more SQL WHERE conditions (will be combined with AND) * @param array $parameters Parameters to be added to the query (key index 0, value index 1; optional) * @return SQLite3Stmt The query, ready to be executed */ private static function makeQuery(SQLite3 $db, array $criteria, array $parameters = []): SQLite3Stmt { $where = empty($criteria) ? '' : 'AND ' . implode(' AND ', $criteria); $sql = <<prepare($sql); $query->bindValue(':userId', $_SESSION[Key::USER_ID]); foreach ($parameters as $param) $query->bindValue($param[0], $param[1]); return $query; } /** * Create an item list with all the current user's bookmarked items * * @param SQLite3 $db The database connection to use to obtain items * @return static An item list with all bookmarked items */ public static function allBookmarked(SQLite3 $db): static { $list = new static($db, self::makeQuery($db, ['item.is_bookmarked = 1']), 'Bookmarked', '/?bookmarked'); $list->linkFeed = true; return $list; } /** * Create an item list with all the current user's unread items * * @param SQLite3 $db The database connection to use to obtain items * @return static An item list with all unread items */ public static function allUnread(SQLite3 $db): static { $list = new static($db, self::makeQuery($db, ['item.is_read = 0']), 'Unread'); $list->linkFeed = true; return $list; } /** * Create an item list with all items for the given feed * * @param int $feedId The ID of the feed for which items should be retrieved * @param SQLite3 $db The database connection to use to obtain items * @return static An item list with all items for the given feed */ public static function allForFeed(int $feedId, SQLite3 $db): static { $list = new static($db, self::makeQuery($db, ['feed.id = :feed'], [[':feed', $feedId]]), '', "/feed/items?id=$feedId"); $list->showIndicators = true; return $list; } /** * Create an item list with unread items for the given feed * * @param int $feedId The ID of the feed for which items should be retrieved * @param SQLite3 $db The database connection to use to obtain items * @return static An item list with unread items for the given feed */ public static function unreadForFeed(int $feedId, SQLite3 $db): static { return new static($db, self::makeQuery($db, ['feed.id = :feed', 'item.is_read = 0'], [[':feed', $feedId]]), 'Unread', "/feed/items?id=$feedId&unread"); } /** * Create an item list with bookmarked items for the given feed * * @param int $feedId The ID of the feed for which items should be retrieved * @param SQLite3 $db The database connection to use to obtain items * @return static An item list with bookmarked items for the given feed */ public static function bookmarkedForFeed(int $feedId, SQLite3 $db): static { return new static($db, self::makeQuery($db, ['feed.id = :feed', 'item.is_bookmarked = 1'], [[':feed', $feedId]]), 'Bookmarked', "/feed/items?id=$feedId&bookmarked"); } /** * Create an item list with items matching given search terms * * @param string $search The item search terms / query * @param bool $isBookmarked Whether to restrict the search to bookmarked items * @param SQLite3 $db The database connection to use to obtain items * @return static An item list match the given search terms */ public static function matchingSearch(string $search, bool $isBookmarked, SQLite3 $db): static { $where = $isBookmarked ? ['item.is_bookmarked = 1'] : []; $where[] = 'item.id IN (SELECT ROWID FROM item_search WHERE content MATCH :search)'; $list = new static($db, self::makeQuery($db, $where, [[':search', $search]]), 'Matching' . ($isBookmarked ? ' Bookmarked' : ''), "/search?search=$search&items=" . ($isBookmarked ? 'bookmarked' : 'all')); $list->showIndicators = true; $list->displayFeed = true; return $list; } /** * Render this item list */ public function render(): void { if ($this->isError()) { ?>

Error retrieving list:
error?>items->fetchArray(SQLITE3_ASSOC); $return = $this->returnURL == '' ? '' : '&from=' . urlencode($this->returnURL); echo '

'; if ($item) { while ($item) { ?>


showIndicators) { if (!$item['is_read']) echo 'Unread   '; if ($item['is_bookmarked']) echo 'Bookmarked   '; } echo '' . date_time($item['as_of']) . ''; if ($this->linkFeed) { echo ' • ' . hx_get("/feed/items?id={$item['feed_id']}&" . strtolower($this->itemType), htmlentities($item['feed_title'])); } elseif ($this->displayFeed) { echo ' • ' . htmlentities($item['feed_title']); } ?> items->fetchArray(SQLITE3_ASSOC); } } else { ?>

There are no itemType)?> items'; } }