diff options
Diffstat (limited to 'app/Models')
| -rw-r--r-- | app/Models/Category.php | 2 | ||||
| -rw-r--r-- | app/Models/CategoryDAO.php | 2 | ||||
| -rw-r--r-- | app/Models/Context.php | 2 | ||||
| -rw-r--r-- | app/Models/Entry.php | 148 | ||||
| -rw-r--r-- | app/Models/EntryDAO.php | 11 | ||||
| -rw-r--r-- | app/Models/Feed.php | 35 | ||||
| -rw-r--r-- | app/Models/FeedDAO.php | 24 | ||||
| -rw-r--r-- | app/Models/TagDAO.php | 2 | ||||
| -rw-r--r-- | app/Models/View.php | 2 |
9 files changed, 173 insertions, 55 deletions
diff --git a/app/Models/Category.php b/app/Models/Category.php index d75d7e21e..e5da764d3 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -219,7 +219,7 @@ class FreshRSS_Category extends Minz_Model { foreach ($dryRunCategory->feeds() as $dryRunFeed) { if (empty($existingFeeds[$dryRunFeed->url()])) { // The feed does not exist in the current category, so add that feed - $dryRunFeed->_category($this->id()); + $dryRunFeed->_categoryId($this->id()); $ok &= ($feedDAO->addFeedObject($dryRunFeed) !== false); } else { $existingFeed = $existingFeeds[$dryRunFeed->url()]; diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index cef8e6d63..e9b873d72 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -108,7 +108,7 @@ SQL; $valuesTmp['name'], ); - if ($stm && $stm->execute($values)) { + if ($stm && $stm->execute($values) && $stm->rowCount() > 0) { return $this->pdo->lastInsertId('`_category_id_seq`'); } else { $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo(); diff --git a/app/Models/Context.php b/app/Models/Context.php index ab855966b..db8dd1f09 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -299,7 +299,7 @@ class FreshRSS_Context { } } self::$current_get['feed'] = $id; - self::$current_get['category'] = $feed->category(); + self::$current_get['category'] = $feed->categoryId(); self::$name = $feed->name(); self::$description = $feed->description(); self::$get_unread = $feed->nbNotRead(); diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 72e59e38c..e383f9060 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -31,6 +31,7 @@ class FreshRSS_Entry extends Minz_Model { * @var bool|null */ private $is_read; + /** @var bool|null */ private $is_favorite; /** @@ -213,17 +214,22 @@ class FreshRSS_Entry extends Minz_Model { public function isFavorite() { return $this->is_favorite; } - public function feed($object = false) { - if ($object) { - if ($this->feed == null) { - $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->feed = $feedDAO->searchById($this->feedId); - } - return $this->feed; - } else { - return $this->feedId; + + /** + * @return FreshRSS_Feed|null|false + */ + public function feed() { + if ($this->feed === null) { + $feedDAO = FreshRSS_Factory::createFeedDao(); + $this->feed = $feedDAO->searchById($this->feedId); } + return $this->feed; } + + public function feedId(): int { + return $this->feedId; + } + public function tags($asString = false) { if ($asString) { return $this->tags == null ? '' : '#' . implode(' #', $this->tags); @@ -331,18 +337,21 @@ class FreshRSS_Entry extends Minz_Model { $this->is_read = $value === null ? null : (bool)$value; } public function _isFavorite($value) { - $this->is_favorite = $value; + $this->is_favorite = $value === null ? null : (bool)$value; } - public function _feed($value) { - if ($value != null) { - $this->feed = $value; - $this->feedId = $this->feed->id(); - } + + /** @param FreshRSS_Feed|null $feed */ + public function _feed($feed) { + $this->feed = $feed; + $this->feedId = $this->feed == null ? 0 : $this->feed->id(); } - private function _feedId($value) { + + /** @param int|string $id */ + private function _feedId($id) { $this->feed = null; - $this->feedId = intval($value); + $this->feedId = intval($id); } + public function _tags($value) { $this->hash = ''; if (!is_array($value)) { @@ -558,7 +567,7 @@ class FreshRSS_Entry extends Minz_Model { public function loadCompleteContent(bool $force = false): bool { // Gestion du contenu // Trying to fetch full article content even when feeds do not propose it - $feed = $this->feed(true); + $feed = $this->feed(); if ($feed != null && trim($feed->pathEntries()) != '') { $entryDAO = FreshRSS_Factory::createEntryDao(); $entry = $force ? null : $entryDAO->searchByGuid($this->feedId, $this->guid); @@ -613,9 +622,110 @@ class FreshRSS_Entry extends Minz_Model { 'hash' => $this->hash(), 'is_read' => $this->isRead(), 'is_favorite' => $this->isFavorite(), - 'id_feed' => $this->feed(), + 'id_feed' => $this->feedId(), 'tags' => $this->tags(true), 'attributes' => $this->attributes(), ); } + + /** + * Integer format conversion for Google Reader API format + * @param string|int $dec Decimal number + * @return string 64-bit hexa http://code.google.com/p/google-reader-api/wiki/ItemId + */ + private static function dec2hex($dec): string { + return PHP_INT_SIZE < 8 ? // 32-bit ? + str_pad(gmp_strval(gmp_init($dec, 10), 16), 16, '0', STR_PAD_LEFT) : + str_pad(dechex($dec), 16, '0', STR_PAD_LEFT); + } + + /** + * N.B.: To avoid expensive lookups, ensure to set `$entry->_feed($feed)` before calling this function. + * N.B.: You might have to populate `$entry->_tags()` prior to calling this function. + * @param string $mode Set to `'compat'` to use an alternative Unicode representation for problematic HTML special characters not decoded by some clients; + * set to `'freshrss'` for using FreshRSS additions for internal use (e.g. export/import). + * @return array<string,mixed> A representation of this entry in a format compatible with Google Reader API + */ + public function toGReader(string $mode = ''): array { + + $feed = $this->feed(); + $category = $feed == null ? null : $feed->category(); + + $item = [ + 'id' => 'tag:google.com,2005:reader/item/' . self::dec2hex($this->id()), + 'crawlTimeMsec' => substr($this->dateAdded(true, true), 0, -3), + 'timestampUsec' => '' . $this->dateAdded(true, true), //EasyRSS & Reeder + 'published' => $this->date(true), + // 'updated' => $this->date(true), + 'title' => $this->title(), + 'summary' => ['content' => $this->content()], + 'canonical' => [ + ['href' => htmlspecialchars_decode($this->link(), ENT_QUOTES)], + ], + 'alternate' => [ + [ + 'href' => htmlspecialchars_decode($this->link(), ENT_QUOTES), + 'type' => 'text/html', + ], + ], + 'categories' => [ + 'user/-/state/com.google/reading-list', + ], + 'origin' => [ + 'streamId' => 'feed/' . $this->feedId, + ], + ]; + if ($mode === 'compat') { + $item['title'] = escapeToUnicodeAlternative($this->title(), false); + } elseif ($mode === 'freshrss') { + $item['guid'] = $this->guid(); + unset($item['summary']); + $item['content'] = ['content' => $this->content()]; + } + if ($category != null && $mode !== 'freshrss') { + $item['categories'][] = 'user/-/label/' . htmlspecialchars_decode($category->name(), ENT_QUOTES); + } + if ($feed != null) { + $item['origin']['htmlUrl'] = htmlspecialchars_decode($feed->website()); + $item['origin']['title'] = $feed->name(); //EasyRSS + if ($mode === 'compat') { + $item['origin']['title'] = escapeToUnicodeAlternative($feed->name(), true); + } elseif ($mode === 'freshrss') { + $item['origin']['feedUrl'] = htmlspecialchars_decode($feed->url()); + } + } + foreach ($this->enclosures() as $enclosure) { + if (!empty($enclosure['url']) && !empty($enclosure['type'])) { + $media = [ + 'href' => $enclosure['url'], + 'type' => $enclosure['type'], + ]; + if (!empty($enclosure['length'])) { + $media['length'] = intval($enclosure['length']); + } + $item['enclosure'][] = $media; + } + } + $author = $this->authors(true); + $author = trim($author, '; '); + if ($author != '') { + if ($mode === 'compat') { + $item['author'] = escapeToUnicodeAlternative($author, false); + } else { + $item['author'] = $author; + } + } + if ($this->isRead()) { + $item['categories'][] = 'user/-/state/com.google/read'; + } elseif ($mode === 'freshrss') { + $item['categories'][] = 'user/-/state/com.google/unread'; + } + if ($this->isFavorite()) { + $item['categories'][] = 'user/-/state/com.google/starred'; + } + foreach ($this->tags() as $tagName) { + $item['categories'][] = 'user/-/label/' . htmlspecialchars_decode($tagName, ENT_QUOTES); + } + return $item; + } } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 5faaac1fb..d69702c60 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -218,6 +218,9 @@ SQL; if (!isset($valuesTmp['is_read'])) { $valuesTmp['is_read'] = null; } + if (!isset($valuesTmp['is_favorite'])) { + $valuesTmp['is_favorite'] = null; + } if ($this->updateEntryPrepared === null) { $sql = 'UPDATE `_entry` ' @@ -226,6 +229,7 @@ SQL; . ', link=:link, date=:date, `lastSeen`=:last_seen' . ', hash=' . static::sqlHexDecode(':hash') . ', is_read=COALESCE(:is_read, is_read)' + . ', is_favorite=COALESCE(:is_favorite, is_favorite)' . ', tags=:tags, attributes=:attributes ' . 'WHERE id_feed=:id_feed AND guid=:guid'; $this->updateEntryPrepared = $this->pdo->prepare($sql); @@ -254,6 +258,11 @@ SQL; } else { $this->updateEntryPrepared->bindValue(':is_read', $valuesTmp['is_read'] ? 1 : 0, PDO::PARAM_INT); } + if ($valuesTmp['is_favorite'] === null) { + $this->updateEntryPrepared->bindValue(':is_favorite', null, PDO::PARAM_NULL); + } else { + $this->updateEntryPrepared->bindValue(':is_favorite', $valuesTmp['is_favorite'] ? 1 : 0, PDO::PARAM_INT); + } $this->updateEntryPrepared->bindParam(':id_feed', $valuesTmp['id_feed'], PDO::PARAM_INT); $valuesTmp['tags'] = mb_strcut($valuesTmp['tags'], 0, 1023, 'UTF-8'); $valuesTmp['tags'] = safe_utf8($valuesTmp['tags']); @@ -1102,7 +1111,7 @@ SQL; . ($limit > 0 ? ' LIMIT ' . intval($limit) : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ } - public function listWhereRaw($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, + private function listWhereRaw($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filters = null, $date_min = 0) { list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filters, $date_min); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index e39109b49..4de61167b 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -39,7 +39,9 @@ class FreshRSS_Feed extends Minz_Model { /** @var int */ private $kind = 0; /** @var int */ - private $category = 1; + private $categoryId = 1; + /** @var FreshRSS_Category|null */ + private $category; /** @var int */ private $nbEntries = -1; /** @var int */ @@ -119,9 +121,22 @@ class FreshRSS_Feed extends Minz_Model { public function hubUrl(): string { return $this->hubUrl; } - public function category(): int { + + /** + * @return FreshRSS_Category|null|false + */ + public function category() { + if ($this->category === null) { + $catDAO = FreshRSS_Factory::createCategoryDao(); + $this->category = $catDAO->searchById($this->categoryId); + } return $this->category; } + + public function categoryId(): int { + return $this->categoryId; + } + public function entries() { Minz_Log::warning(__method__ . ' is deprecated since FreshRSS 1.16.1!'); $simplePie = $this->load(false, true); @@ -253,10 +268,16 @@ class FreshRSS_Feed extends Minz_Model { $this->kind = $value; } - /** @param int $value */ - public function _category($value) { - $value = intval($value); - $this->category = $value >= 0 ? $value : 0; + /** @param FreshRSS_Category|null $cat */ + public function _category($cat) { + $this->category = $cat; + $this->categoryId = $this->category == null ? 0 : $this->category->id(); + } + + /** @param int|string $id */ + public function _categoryId($id) { + $this->category = null; + $this->categoryId = intval($id); } public function _name(string $value) { @@ -700,7 +721,7 @@ class FreshRSS_Feed extends Minz_Model { $archiving = $this->attributes('archiving'); if ($archiving == null) { $catDAO = FreshRSS_Factory::createCategoryDao(); - $category = $catDAO->searchById($this->category()); + $category = $catDAO->searchById($this->categoryId); $archiving = $category == null ? null : $category->attributes('archiving'); if ($archiving == null) { $archiving = FreshRSS_Context::$user_conf->archiving; diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 8d54e7be2..233d2a715 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -82,7 +82,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { 'id' => $feed->id(), 'url' => $feed->url(), 'kind' => $feed->kind(), - 'category' => $feed->category(), + 'category' => $feed->categoryId(), 'name' => $feed->name(), 'website' => $feed->website(), 'description' => $feed->description(), @@ -341,26 +341,6 @@ SQL; } /** - * For API - */ - public function arrayFeedCategoryNames(): array { - $sql = <<<'SQL' -SELECT f.id, f.name, c.name as c_name FROM `_feed` f -INNER JOIN `_category` c ON c.id = f.category -SQL; - $stm = $this->pdo->query($sql); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $feedCategoryNames = array(); - foreach ($res as $line) { - $feedCategoryNames[$line['id']] = array( - 'name' => $line['name'], - 'c_name' => $line['c_name'], - ); - } - return $feedCategoryNames; - } - - /** * Use $defaultCacheDuration == -1 to return all feeds, without filtering them by TTL. * @return array<FreshRSS_Feed> */ @@ -596,7 +576,7 @@ SQL; $myFeed = new FreshRSS_Feed($dao['url'] ?? '', false); $myFeed->_kind($dao['kind'] ?? FreshRSS_Feed::KIND_RSS); - $myFeed->_category($category); + $myFeed->_categoryId($category); $myFeed->_name($dao['name']); $myFeed->_website($dao['website'] ?? '', false); $myFeed->_description($dao['description'] ?? ''); diff --git a/app/Models/TagDAO.php b/app/Models/TagDAO.php index 49abbdefd..f232b2f9f 100644 --- a/app/Models/TagDAO.php +++ b/app/Models/TagDAO.php @@ -61,7 +61,7 @@ SQL; $valuesTmp['name'], ); - if ($stm && $stm->execute($values)) { + if ($stm && $stm->execute($values) && $stm->rowCount() > 0) { return $this->pdo->lastInsertId('`_tag_id_seq`'); } else { $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo(); diff --git a/app/Models/View.php b/app/Models/View.php index 0169f130a..ab1780405 100644 --- a/app/Models/View.php +++ b/app/Models/View.php @@ -72,8 +72,6 @@ class FreshRSS_View extends Minz_View { // Export / Import public $content; - public $entriesRaw; - public $entriesId; public $entryIdsTagNames; public $list_title; public $queryId; |
