aboutsummaryrefslogtreecommitdiff
path: root/app/Models/EntryDAO.php
diff options
context:
space:
mode:
Diffstat (limited to 'app/Models/EntryDAO.php')
-rw-r--r--app/Models/EntryDAO.php86
1 files changed, 52 insertions, 34 deletions
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index af89e9c52..8d32e86f9 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -120,7 +120,8 @@ SQL;
*/
private $addEntryPrepared = false;
- /** @param array<string,string|int> $valuesTmp */
+ /** @param array{'id':string,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,'hash':string,
+ * 'is_read':bool|int|null,'is_favorite':bool|int|null,'id_feed':int,'tags':string,'attributes':array<string,mixed>} $valuesTmp */
public function addEntry(array $valuesTmp, bool $useTmpTable = true): bool {
if ($this->addEntryPrepared == null) {
$sql = static::sqlIgnoreConflict(
@@ -220,7 +221,8 @@ SQL;
/** @var PDOStatement|null */
private $updateEntryPrepared = null;
- /** @param array<string,string|int> $valuesTmp */
+ /** @param array{'id':string,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,'hash':string,
+ * 'is_read':bool|int|null,'is_favorite':bool|int|null,'id_feed':int,'tags':string,'attributes':array<string,mixed>} $valuesTmp */
public function updateEntry(array $valuesTmp): bool {
if (!isset($valuesTmp['is_read'])) {
$valuesTmp['is_read'] = null;
@@ -239,7 +241,7 @@ SQL;
. ', 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);
+ $this->updateEntryPrepared = $this->pdo->prepare($sql) ?: null;
}
if ($this->updateEntryPrepared) {
$valuesTmp['guid'] = substr($valuesTmp['guid'], 0, 760);
@@ -578,8 +580,9 @@ SQL;
. 'SET `cache_nbUnreads`=`cache_nbUnreads`-' . $affected
. ' WHERE id=:id';
$stm = $this->pdo->prepare($sql);
- $stm->bindParam(':id', $id_feed, PDO::PARAM_INT);
- if (!($stm && $stm->execute())) {
+ if (!($stm !== false &&
+ $stm->bindParam(':id', $id_feed, PDO::PARAM_INT) &&
+ $stm->execute())) {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($info));
$this->pdo->rollBack();
@@ -667,7 +670,7 @@ SQL;
//==Inclusions==
$sql .= ' AND (1=0';
- if (!empty($options['keep_period'])) {
+ if (!empty($options['keep_period']) && is_string($options['keep_period'])) {
$sql .= ' OR `lastSeen` < :max_last_seen';
$now = new DateTime('now');
$now->sub(new DateInterval($options['keep_period']));
@@ -696,12 +699,15 @@ SQL;
}
}
- /** @return Traversable<array<string,string|int>> */
+ /** @return Traversable<array{'id':string,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,
+ * 'hash':string,'is_read':?bool,'is_favorite':?bool,'id_feed':int,'tags':string,'attributes':array<string,mixed>}> */
public function selectAll(): Traversable {
- $sql = 'SELECT id, guid, title, author, '
- . (static::isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
- . ', link, date, `lastSeen`, ' . static::sqlHexEncode('hash') . ' AS hash, is_read, is_favorite, id_feed, tags, attributes '
- . 'FROM `_entry`';
+ $content = static::isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content';
+ $hash = static::sqlHexEncode('hash');
+ $sql = <<<SQL
+SELECT id, guid, title, author, {$content}, link, date, `lastSeen`, {$hash} AS hash, is_read, is_favorite, id_feed, tags, attributes
+FROM `_entry`
+SQL;
$stm = $this->pdo->query($sql);
if ($stm != false) {
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
@@ -998,7 +1004,10 @@ SQL;
return [ $values, $search ];
}
- /** @return array{0:array<int|string>,1:string} */
+ /**
+ * @param 'ASC'|'DESC' $order
+ * @return array{0:array<int|string>,1:string}
+ */
protected function sqlListEntriesWhere(string $alias = '', ?FreshRSS_BooleanSearch $filters = null,
int $state = FreshRSS_Entry::STATE_ALL,
string $order = 'DESC', string $firstId = '', int $date_min = 0) {
@@ -1048,6 +1057,7 @@ SQL;
/**
* @phpstan-param 'a'|'A'|'s'|'S'|'c'|'f'|'t'|'T'|'ST' $type
* @param int $id category/feed/tag ID
+ * @param 'ASC'|'DESC' $order
* @return array{0:array<int|string>,1:string}
*/
private function sqlListWhere(string $type = 'a', int $id = 0, int $state = FreshRSS_Entry::STATE_ALL,
@@ -1111,23 +1121,25 @@ SQL;
/**
* @phpstan-param 'a'|'A'|'s'|'S'|'c'|'f'|'t'|'T'|'ST' $type
+ * @param 'ASC'|'DESC' $order
* @param int $id category/feed/tag ID
* @return PDOStatement|false
*/
private function listWhereRaw(string $type = 'a', int $id = 0, int $state = FreshRSS_Entry::STATE_ALL,
string $order = 'DESC', int $limit = 1, string $firstId = '', ?FreshRSS_BooleanSearch $filters = null,
int $date_min = 0) {
- list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filters, $date_min);
-
- $sql = 'SELECT e0.id, e0.guid, e0.title, e0.author, '
- . (static::isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
- . ', e0.link, e0.date, e0.is_read, e0.is_favorite, e0.id_feed, e0.tags, e0.attributes '
- . 'FROM `_entry` e0 '
- . 'INNER JOIN ('
- . $sql
- . ') e2 ON e2.id=e0.id '
- . 'ORDER BY e0.id ' . $order;
+ [$values, $sql] = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filters, $date_min);
+ if ($order !== 'DESC' && $order !== 'ASC') {
+ $order = 'DESC';
+ }
+ $content = static::isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content';
+ $sql = <<<SQL
+SELECT e0.id, e0.guid, e0.title, e0.author, {$content}, e0.link, e0.date, e0.is_read, e0.is_favorite, e0.id_feed, e0.tags, e0.attributes
+FROM `_entry` e0
+INNER JOIN ({$sql}) e2 ON e2.id=e0.id
+ORDER BY e0.id {$order}
+SQL;
$stm = $this->pdo->prepare($sql);
if ($stm !== false && $stm->execute($values)) {
return $stm;
@@ -1142,7 +1154,9 @@ SQL;
}
/**
+ * @phpstan-param 'a'|'A'|'s'|'S'|'c'|'f'|'t'|'T'|'ST' $type
* @param int $id category/feed/tag ID
+ * @param 'ASC'|'DESC' $order
* @return Traversable<FreshRSS_Entry>
*/
public function listWhere(string $type = 'a', int $id = 0, int $state = FreshRSS_Entry::STATE_ALL,
@@ -1160,6 +1174,7 @@ SQL;
/**
* @param array<string> $ids
+ * @param 'ASC'|'DESC' $order
* @return Traversable<FreshRSS_Entry>
*/
public function listByIds(array $ids, string $order = 'DESC'): Traversable {
@@ -1179,7 +1194,6 @@ SQL;
if ($order !== 'DESC' && $order !== 'ASC') {
$order = 'DESC';
}
-
$content = static::isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content';
$repeats = str_repeat('?,', count($ids) - 1) . '?';
$sql = <<<SQL
@@ -1188,9 +1202,10 @@ FROM `_entry`
WHERE id IN ({$repeats})
ORDER BY id {$order}
SQL;
-
$stm = $this->pdo->prepare($sql);
- $stm->execute($ids);
+ if ($stm === false || !$stm->execute($ids)) {
+ return;
+ }
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
/** @var array{'id':string,'id_feed':int,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,
* 'is_read':int,'is_favorite':int,'tags':string,'attributes'?:string} $row */
@@ -1201,6 +1216,7 @@ SQL;
/**
* @phpstan-param 'a'|'A'|'s'|'S'|'c'|'f'|'t'|'T'|'ST' $type
* @param int $id category/feed/tag ID
+ * @param 'ASC'|'DESC' $order
* @return array<numeric-string>|null
*/
public function listIdsWhere(string $type = 'a', int $id = 0, int $state = FreshRSS_Entry::STATE_ALL,
@@ -1292,8 +1308,8 @@ SQL;
}
}
- /** @return array<string,int>|false */
- public function countUnreadRead() {
+ /** @return array<string,int> */
+ public function countUnreadRead(): array {
$sql = <<<'SQL'
SELECT COUNT(e.id) AS count FROM `_entry` e
INNER JOIN `_feed` f ON e.id_feed=f.id
@@ -1304,8 +1320,8 @@ SELECT COUNT(e.id) AS count FROM `_entry` e
WHERE f.priority > 0 AND e.is_read=0
SQL;
$res = $this->fetchColumn($sql, 0);
- if ($res == null) {
- return false;
+ if ($res === null) {
+ return ['all' => -1, 'unread' => -1, 'read' => -1];
}
rsort($res);
$all = (int)($res[0] ?? 0);
@@ -1329,15 +1345,17 @@ SQL;
$sql .= ' INNER JOIN `_feed` f ON e.id_feed=f.id';
}
$sql .= ' WHERE e.is_read=0';
+ $values = [];
if ($minPriority !== null) {
$sql .= ' AND f.priority > :priority';
+ $values[':priority'] = $minPriority;
}
- $res = $this->fetchColumn($sql, 0, [':priority' => $minPriority]);
+ $res = $this->fetchColumn($sql, 0, $values);
return isset($res[0]) ? (int)($res[0]) : -1;
}
- /** @return array<string,int>|false */
- public function countUnreadReadFavorites() {
+ /** @return array{'all':int,'read':int,'unread':int} */
+ public function countUnreadReadFavorites(): array {
$sql = <<<'SQL'
SELECT c FROM (
SELECT COUNT(e1.id) AS c, 1 AS o
@@ -1359,8 +1377,8 @@ SQL;
':priority_normal1' => FreshRSS_Feed::PRIORITY_NORMAL,
':priority_normal2' => FreshRSS_Feed::PRIORITY_NORMAL,
]);
- if ($res == null) {
- return false;
+ if ($res === null) {
+ return ['all' => -1, 'unread' => -1, 'read' => -1];
}
rsort($res);