summaryrefslogtreecommitdiff
path: root/app/Models
diff options
context:
space:
mode:
Diffstat (limited to 'app/Models')
-rw-r--r--app/Models/Category.php2
-rw-r--r--app/Models/CategoryDAO.php2
-rw-r--r--app/Models/Context.php2
-rw-r--r--app/Models/Entry.php148
-rw-r--r--app/Models/EntryDAO.php11
-rw-r--r--app/Models/Feed.php35
-rw-r--r--app/Models/FeedDAO.php24
-rw-r--r--app/Models/TagDAO.php2
-rw-r--r--app/Models/View.php2
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;