aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAlexandre Alapetite <alexandre@alapetite.fr>2023-05-02 14:38:32 +0200
committerGitHub <noreply@github.com>2023-05-02 14:38:32 +0200
commitbd9fa803f1f0c23face77fa1bc550d1198ce5ad6 (patch)
treeedba662e84e70a6b0f23c8379d4ef174f714e999
parent4de1d5efea128e6cc70c71bad9be28d01e851f81 (diff)
downloadfreshrss-bd9fa803f1f0c23face77fa1bc550d1198ce5ad6.tar.gz
freshrss-bd9fa803f1f0c23face77fa1bc550d1198ce5ad6.zip
PHPStan Level 7 complete DAOs (#5354)
* PHPStan Level 7 complete DAOs * Finalise PHPStan Level 7 for CategoryDAO * PHPStan Level 7 for Context and Search * Apply suggestions from code review Co-authored-by: Luc SANCHEZ <4697568+ColonelMoutarde@users.noreply.github.com>
-rw-r--r--app/Controllers/feedController.php6
-rw-r--r--app/Controllers/indexController.php7
-rw-r--r--app/Controllers/statsController.php5
-rw-r--r--app/Models/CategoryDAO.php132
-rw-r--r--app/Models/Context.php18
-rw-r--r--app/Models/Entry.php10
-rw-r--r--app/Models/EntryDAO.php86
-rw-r--r--app/Models/Feed.php5
-rw-r--r--app/Models/FeedDAO.php129
-rw-r--r--app/Models/Search.php24
-rw-r--r--app/Models/TagDAO.php22
-rw-r--r--app/Models/UserQuery.php6
-rw-r--r--app/Services/ExportService.php4
-rwxr-xr-xcli/user-info.php16
-rw-r--r--tests/phpstan-next.txt5
15 files changed, 231 insertions, 244 deletions
diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php
index 76cd3ad83..1974751d0 100644
--- a/app/Controllers/feedController.php
+++ b/app/Controllers/feedController.php
@@ -823,8 +823,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
$feedDAO = FreshRSS_Factory::createFeedDao();
$feed = $feedDAO->searchById($id);
-
- if (!$feed) {
+ if ($feed === null) {
Minz_Request::bad(_t('feedback.sub.feed.not_found'), array());
return;
}
@@ -854,8 +853,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
$entryDAO = FreshRSS_Factory::createEntryDao();
$feed = $feedDAO->searchById($feed_id);
-
- if (!$feed) {
+ if ($feed === null) {
Minz_Request::bad(_t('feedback.sub.feed.not_found'), array());
return;
}
diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php
index 21a94d53d..3f5c419f1 100644
--- a/app/Controllers/indexController.php
+++ b/app/Controllers/indexController.php
@@ -194,7 +194,7 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
$get = FreshRSS_Context::currentGet(true);
if (is_array($get)) {
$type = $get[0];
- $id = $get[1];
+ $id = (int)$get[1];
} else {
$type = $get;
$id = 0;
@@ -219,7 +219,7 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
case 'f':
// We most likely already have the feed object in cache
$feed = FreshRSS_CategoryDAO::findFeed($categories, $id);
- if ($feed == null) {
+ if ($feed === null) {
$feedDAO = FreshRSS_Factory::createFeedDao();
$feed = $feedDAO->searchById($id);
if ($feed == null) {
@@ -290,8 +290,9 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
*/
public function tosAction(): void {
$terms_of_service = file_get_contents(TOS_FILENAME);
- if (!$terms_of_service) {
+ if ($terms_of_service === false) {
Minz_Error::error(404);
+ return;
}
$this->view->terms_of_service = $terms_of_service;
diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php
index afbaccfc5..79facbbf6 100644
--- a/app/Controllers/statsController.php
+++ b/app/Controllers/statsController.php
@@ -155,7 +155,10 @@ class FreshRSS_stats_Controller extends FreshRSS_ActionController {
foreach ($feeds as $feed) {
$feedDAO = FreshRSS_Factory::createFeedDao();
- $feed['favicon'] = $feedDAO->searchById($feed['id'])->favicon();
+ $feedObject = $feedDAO->searchById($feed['id']);
+ if ($feedObject !== null) {
+ $feed['favicon'] = $feedObject->favicon();
+ }
$feedDate->setTimestamp($feed['last_date']);
if ($feedDate >= $lastWeek) {
diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php
index ec7bb45cb..98d45733c 100644
--- a/app/Models/CategoryDAO.php
+++ b/app/Models/CategoryDAO.php
@@ -29,10 +29,15 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
} elseif ('attributes' === $name) { //v1.15.0
$ok = $this->pdo->exec('ALTER TABLE `_category` ADD COLUMN attributes TEXT') !== false;
- $stm = $this->pdo->query('SELECT * FROM `_feed`');
- $feeds = $stm->fetchAll(PDO::FETCH_ASSOC);
+ /** @var array<array{'url':string,'kind':int,'category':int,'name':string,'website':string,'lastUpdate':int,
+ * 'priority':int,'pathEntries':string,'httpAuth':string,'error':int,'ttl':int,'attributes':string}> $feeds */
+ $feeds = $this->fetchAssoc('SELECT * FROM `_feed`') ?? [];
$stm = $this->pdo->prepare('UPDATE `_feed` SET attributes = :attributes WHERE id = :id');
+ if ($stm === false) {
+ Minz_Log::error('SQL error ' . __METHOD__ . json_encode($this->pdo->errorInfo()));
+ return false;
+ }
foreach ($feeds as $feed) {
if (empty($feed['keep_history']) || empty($feed['id'])) {
continue;
@@ -54,9 +59,11 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
} else {
continue;
}
- $stm->bindValue(':id', $feed['id'], PDO::PARAM_INT);
- $stm->bindValue(':attributes', json_encode($attributes, JSON_UNESCAPED_SLASHES));
- $stm->execute();
+ if (!($stm->bindValue(':id', $feed['id'], PDO::PARAM_INT) &&
+ $stm->bindValue(':attributes', json_encode($attributes, JSON_UNESCAPED_SLASHES)) &&
+ $stm->execute())) {
+ Minz_Log::error('SQL error ' . __METHOD__ . json_encode($stm->errorInfo()));
+ }
}
if ($this->pdo->dbType() !== 'sqlite') { //SQLite does not support DROP COLUMN
@@ -91,7 +98,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
}
/**
- * @param array<string,mixed> $valuesTmp
+ * @param array{'name':string,'id'?:int,'kind'?:int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string|array<string,mixed>} $valuesTmp
* @return int|false
*/
public function addCategory(array $valuesTmp) {
@@ -116,7 +123,8 @@ SQL;
);
if ($stm !== false && $stm->execute($values) && $stm->rowCount() > 0) {
- return $this->pdo->lastInsertId('`_category_id_seq`');
+ $catId = $this->pdo->lastInsertId('`_category_id_seq`');
+ return $catId === false ? false : (int)$catId;
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
@@ -143,7 +151,7 @@ SQL;
}
/**
- * @param array{'name':string,'kind':int,'attributes':array<string,mixed>} $valuesTmp
+ * @param array{'name':string,'kind':int,'attributes'?:string|array<string,mixed>} $valuesTmp
* @return int|false
*/
public function updateCategory(int $id, array $valuesTmp) {
@@ -204,8 +212,7 @@ SQL;
}
$sql = 'DELETE FROM `_category` WHERE id=:id';
$stm = $this->pdo->prepare($sql);
- $stm->bindParam(':id', $id, PDO::PARAM_INT);
- if ($stm !== false && $stm->execute()) {
+ if ($stm !== false && $stm->bindParam(':id', $id, PDO::PARAM_INT) && $stm->execute()) {
return $stm->rowCount();
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
@@ -234,36 +241,23 @@ SQL;
public function searchById(int $id): ?FreshRSS_Category {
$sql = 'SELECT * FROM `_category` WHERE id=:id';
- $stm = $this->pdo->prepare($sql);
- if ($stm !== false &&
- $stm->bindParam(':id', $id, PDO::PARAM_INT) &&
- $stm->execute()) {
- $res = $stm->fetchAll(PDO::FETCH_ASSOC);
- $cat = self::daoToCategory($res);
- if (isset($cat[0])) {
- return $cat[0];
- }
- }
- return null;
+ $res = $this->fetchAssoc($sql, ['id' => $id]) ?? [];
+ /** @var array<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $res */
+ $cat = self::daoToCategory($res);
+ return $cat[0] ?? null;
}
- /** @return FreshRSS_Category|null|false */
- public function searchByName(string $name) {
+ public function searchByName(string $name): ?FreshRSS_Category {
$sql = 'SELECT * FROM `_category` WHERE name=:name';
- $res = $this->fetchAssoc($sql, ['name' => $name]);
- if ($res == null) {
- return false;
- }
+ $res = $this->fetchAssoc($sql, ['name' => $name]) ?? [];
+ /** @var array<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $res */
$cat = self::daoToCategory($res);
return $cat[0] ?? null;
}
- /** @return array<FreshRSS_Category>|false */
- public function listSortedCategories(bool $prePopulateFeeds = true, bool $details = false) {
+ /** @return array<FreshRSS_Category> */
+ public function listSortedCategories(bool $prePopulateFeeds = true, bool $details = false): array {
$categories = $this->listCategories($prePopulateFeeds, $details);
- if ($categories === false) {
- return false;
- }
uasort($categories, static function (FreshRSS_Category $a, FreshRSS_Category $b) {
$aPosition = $a->attributes('position');
@@ -281,11 +275,11 @@ SQL;
return $categories;
}
- /** @return array<FreshRSS_Category>|false */
- public function listCategories(bool $prePopulateFeeds = true, bool $details = false) {
+ /** @return array<FreshRSS_Category> */
+ public function listCategories(bool $prePopulateFeeds = true, bool $details = false): array {
if ($prePopulateFeeds) {
$sql = 'SELECT c.id AS c_id, c.name AS c_name, c.kind AS c_kind, c.`lastUpdate` AS c_last_update, c.error AS c_error, c.attributes AS c_attributes, '
- . ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.`cache_nbEntries`, f.`cache_nbUnreads`, f.ttl ')
+ . ($details ? 'f.* ' : 'f.id, f.name, f.url, f.kind, f.website, f.priority, f.error, f.`cache_nbEntries`, f.`cache_nbUnreads`, f.ttl ')
. 'FROM `_category` c '
. 'LEFT OUTER JOIN `_feed` f ON f.category=c.id '
. 'WHERE f.priority >= :priority_normal '
@@ -294,18 +288,22 @@ SQL;
$stm = $this->pdo->prepare($sql);
$values = [ ':priority_normal' => FreshRSS_Feed::PRIORITY_NORMAL ];
if ($stm !== false && $stm->execute($values)) {
- return self::daoToCategoryPrepopulated($stm->fetchAll(PDO::FETCH_ASSOC));
+ $res = $stm->fetchAll(PDO::FETCH_ASSOC) ?: [];
+ /** @var array<array{'c_name':string,'c_id':int,'c_kind':int,'c_last_update':int,'c_error':int|bool,'c_attributes'?:string,
+ * 'id'?:int,'name'?:string,'url'?:string,'kind'?:int,'category'?:int,'website'?:string,'priority'?:int,'error'?:int|bool,'cache_nbEntries'?:int,'cache_nbUnreads'?:int,'ttl'?:int}> $res */
+ return self::daoToCategoryPrepopulated($res);
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->listCategories($prePopulateFeeds, $details);
}
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($info));
- return false;
+ return [];
}
} else {
$res = $this->fetchAssoc('SELECT * FROM `_category` ORDER BY name');
- return $res == null ? false : self::daoToCategory($res);
+ /** @var array<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $res */
+ return $res == null ? [] : self::daoToCategory($res);
}
}
@@ -331,12 +329,9 @@ SQL;
public function getDefault(): ?FreshRSS_Category {
$sql = 'SELECT * FROM `_category` WHERE id=:id';
- $stm = $this->pdo->prepare($sql);
- $stm->bindValue(':id', self::DEFAULTCATEGORYID, PDO::PARAM_INT);
- $stm->execute();
- $res = $stm->fetchAll(PDO::FETCH_ASSOC);
- $cat = self::daoToCategory($res);
-
+ $res = $this->fetchAssoc($sql, [':id' => self::DEFAULTCATEGORYID]);
+ /** @var array<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $res */
+ $cat = self::daoToCategory($res ?? []);
if (isset($cat[0])) {
return $cat[0];
} else {
@@ -369,7 +364,8 @@ SQL;
);
if ($stm !== false && $stm->execute($values)) {
- return $this->pdo->lastInsertId('`_category_id_seq`');
+ $catId = $this->pdo->lastInsertId('`_category_id_seq`');
+ return $catId === false ? false : (int)$catId;
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($info));
@@ -381,27 +377,20 @@ SQL;
public function count(): int {
$sql = 'SELECT COUNT(*) AS count FROM `_category`';
- $stm = $this->pdo->query($sql);
- $res = $stm->fetchAll(PDO::FETCH_ASSOC);
- return $res[0]['count'];
+ $res = $this->fetchColumn($sql, 0);
+ return isset($res[0]) ? (int)$res[0] : -1;
}
public function countFeed(int $id): int {
$sql = 'SELECT COUNT(*) AS count FROM `_feed` WHERE category=:id';
- $stm = $this->pdo->prepare($sql);
- $stm->bindParam(':id', $id, PDO::PARAM_INT);
- $stm->execute();
- $res = $stm->fetchAll(PDO::FETCH_ASSOC);
- return $res[0]['count'];
+ $res = $this->fetchColumn($sql, 0, [':id' => $id]);
+ return isset($res[0]) ? (int)$res[0] : -1;
}
public function countNotRead(int $id): int {
$sql = 'SELECT COUNT(*) AS count FROM `_entry` e INNER JOIN `_feed` f ON e.id_feed=f.id WHERE category=:id AND e.is_read=0';
- $stm = $this->pdo->prepare($sql);
- $stm->bindParam(':id', $id, PDO::PARAM_INT);
- $stm->execute();
- $res = $stm->fetchAll(PDO::FETCH_ASSOC);
- return $res[0]['count'];
+ $res = $this->fetchColumn($sql, 0, [':id' => $id]);
+ return isset($res[0]) ? (int)$res[0] : -1;
}
/** @param array<FreshRSS_Category> $categories */
@@ -432,14 +421,15 @@ SQL;
}
/**
- * @param array<string,array<string,string|int>> $listDAO
+ * @param array<array{'c_name':string,'c_id':int,'c_kind':int,'c_last_update':int,'c_error':int|bool,'c_attributes'?:string,
+ * 'id'?:int,'name'?:string,'url'?:string,'kind'?:int,'website'?:string,'priority'?:int,
+ * 'error'?:int|bool,'cache_nbEntries'?:int,'cache_nbUnreads'?:int,'ttl'?:int}> $listDAO
* @return array<int,FreshRSS_Category>
*/
private static function daoToCategoryPrepopulated(array $listDAO) {
- $list = array();
- $previousLine = null;
- /** @var array<string,string|int> */
- $feedsDao = array();
+ $list = [];
+ $previousLine = [];
+ $feedsDao = [];
$feedDao = FreshRSS_Factory::createFeedDAO();
foreach ($listDAO as $line) {
if (!empty($previousLine['c_id']) && $line['c_id'] !== $previousLine['c_id']) {
@@ -450,10 +440,10 @@ SQL;
);
$cat->_id($previousLine['c_id']);
$cat->_kind($previousLine['c_kind']);
- $cat->_attributes('', $previousLine['c_attributes']);
+ $cat->_attributes('', $previousLine['c_attributes'] ?? '[]');
$list[$previousLine['c_id']] = $cat;
- $feedsDao = array(); //Prepare for next category
+ $feedsDao = []; //Prepare for next category
}
$previousLine = $line;
@@ -470,7 +460,7 @@ SQL;
$cat->_kind($previousLine['c_kind']);
$cat->_lastUpdate($previousLine['c_last_update'] ?? 0);
$cat->_error($previousLine['c_error'] ?? 0);
- $cat->_attributes('', $previousLine['c_attributes']);
+ $cat->_attributes('', $previousLine['c_attributes'] ?? []);
$list[$previousLine['c_id']] = $cat;
}
@@ -478,15 +468,11 @@ SQL;
}
/**
- * @param array<array<string,string|int>>|array<string,string|int> $listDAO
+ * @param array<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $listDAO
* @return array<FreshRSS_Category>
*/
- private static function daoToCategory($listDAO): array {
- $list = array();
-
- if (!is_array($listDAO)) {
- $listDAO = array($listDAO);
- }
+ private static function daoToCategory(array $listDAO): array {
+ $list = [];
foreach ($listDAO as $dao) {
$cat = new FreshRSS_Category(
diff --git a/app/Models/Context.php b/app/Models/Context.php
index 03006cbbf..ce29ebd5c 100644
--- a/app/Models/Context.php
+++ b/app/Models/Context.php
@@ -16,11 +16,11 @@ final class FreshRSS_Context {
*/
public static $system_conf;
/**
- * @var array<FreshRSS_Category>
+ * @var array<int,FreshRSS_Category>
*/
public static $categories = array();
/**
- * @var array<string>
+ * @var array<int,FreshRSS_Tag>
*/
public static $tags = array();
/**
@@ -67,6 +67,7 @@ final class FreshRSS_Context {
*/
public static $state = 0;
/**
+ * @phpstan-var 'ASC'|'DESC'
* @var string
*/
public static $order = 'DESC';
@@ -217,7 +218,8 @@ final class FreshRSS_Context {
}
self::$search = new FreshRSS_BooleanSearch(Minz_Request::paramString('search'));
- self::$order = Minz_Request::paramString('order') ?: self::$user_conf->sort_order;
+ $order = Minz_Request::paramString('order') ?: self::$user_conf->sort_order;
+ self::$order = in_array($order, ['ASC', 'DESC'], true) ? $order : 'DESC';
self::$number = Minz_Request::paramInt('nb') ?: self::$user_conf->posts_per_page;
if (self::$number > self::$user_conf->max_posts_per_rss) {
self::$number = max(
@@ -381,7 +383,7 @@ final class FreshRSS_Context {
if ($feed === null) {
$feedDAO = FreshRSS_Factory::createFeedDao();
$feed = $feedDAO->searchById($id);
- if (!$feed) {
+ if ($feed === null) {
throw new FreshRSS_Context_Exception('Invalid feed: ' . $id);
}
}
@@ -397,9 +399,10 @@ final class FreshRSS_Context {
if (!isset(self::$categories[$id])) {
$catDAO = FreshRSS_Factory::createCategoryDao();
$cat = $catDAO->searchById($id);
- if (!$cat) {
+ if ($cat === null) {
throw new FreshRSS_Context_Exception('Invalid category: ' . $id);
}
+ //self::$categories[$id] = $cat;
} else {
$cat = self::$categories[$id];
}
@@ -412,9 +415,10 @@ final class FreshRSS_Context {
if (!isset(self::$tags[$id])) {
$tagDAO = FreshRSS_Factory::createTagDao();
$tag = $tagDAO->searchById($id);
- if (!$tag) {
+ if ($tag === null) {
throw new FreshRSS_Context_Exception('Invalid tag: ' . $id);
}
+ //self::$tags[$id] = $tag;
} else {
$tag = self::$tags[$id];
}
@@ -541,6 +545,6 @@ final class FreshRSS_Context {
public static function defaultTimeZone(): string {
$timezone = ini_get('date.timezone');
- return $timezone != '' ? $timezone : 'UTC';
+ return $timezone != false ? $timezone : 'UTC';
}
}
diff --git a/app/Models/Entry.php b/app/Models/Entry.php
index c29f84172..8f2d66882 100644
--- a/app/Models/Entry.php
+++ b/app/Models/Entry.php
@@ -350,10 +350,7 @@ HTML;
return $this->is_favorite;
}
- /**
- * @return FreshRSS_Feed|null|false
- */
- public function feed() {
+ public function feed(): ?FreshRSS_Feed {
if ($this->feed === null) {
$feedDAO = FreshRSS_Factory::createFeedDao();
$this->feed = $feedDAO->searchById($this->feedId);
@@ -778,7 +775,10 @@ HTML;
return false;
}
- /** @return 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>} */
+ /**
+ * @return 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 toArray(): array {
return array(
'id' => $this->id(),
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);
diff --git a/app/Models/Feed.php b/app/Models/Feed.php
index c0fce6e4a..6c840942b 100644
--- a/app/Models/Feed.php
+++ b/app/Models/Feed.php
@@ -125,10 +125,7 @@ class FreshRSS_Feed extends Minz_Model {
return $this->hubUrl;
}
- /**
- * @return FreshRSS_Category|null|false
- */
- public function category() {
+ public function category(): ?FreshRSS_Category {
if ($this->category === null) {
$catDAO = FreshRSS_Factory::createCategoryDao();
$this->category = $catDAO->searchById($this->categoryId);
diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php
index 98bcef379..7819bf9b5 100644
--- a/app/Models/FeedDAO.php
+++ b/app/Models/FeedDAO.php
@@ -35,7 +35,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
}
/**
- * @param array<string,mixed> $valuesTmp
+ * @param array{'url':string,'kind':int,'category':int,'name':string,'website':string,'description':string,'lastUpdate':int,'priority'?:int,
+ * 'pathEntries'?:string,'httpAuth':string,'error':int|bool,'ttl'?:int,'attributes'?:string|array<string|mixed>} $valuesTmp
* @return int|false
*/
public function addFeed(array $valuesTmp) {
@@ -69,7 +70,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
);
if ($stm !== false && $stm->execute($values)) {
- return (int)($this->pdo->lastInsertId('`_feed_id_seq`'));
+ $feedId = $this->pdo->lastInsertId('`_feed_id_seq`');
+ return $feedId === false ? false : (int)$feedId;
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
@@ -94,6 +96,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
'website' => $feed->website(),
'description' => $feed->description(),
'lastUpdate' => 0,
+ 'error' => false,
'pathEntries' => $feed->pathEntries(),
'httpAuth' => $feed->httpAuth(),
'ttl' => $feed->ttl(true),
@@ -137,10 +140,12 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
}
/**
- * @param array<string,mixed> $valuesTmp
+ * @param array{'url'?:string,'kind'?:int,'category'?:int,'name'?:string,'website'?:string,'description'?:string,'lastUpdate'?:int,'priority'?:int,
+ * 'pathEntries'?:string,'httpAuth'?:string,'error'?:int,'ttl'?:int,'attributes'?:string|array<string,mixed>} $valuesTmp $valuesTmp
* @return int|false
*/
public function updateFeed(int $id, array $valuesTmp) {
+ $originalValues = $valuesTmp;
if (isset($valuesTmp['name'])) {
$valuesTmp['name'] = mb_strcut(trim($valuesTmp['name']), 0, FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE, 'UTF-8');
}
@@ -176,7 +181,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
- return $this->updateFeed($id, $valuesTmp);
+ return $this->updateFeed($id, $originalValues);
}
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($info) . ' for feed ' . $id);
return false;
@@ -227,7 +232,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
public function changeCategory(int $idOldCat, int $idNewCat) {
$catDAO = FreshRSS_Factory::createCategoryDao();
$newCat = $catDAO->searchById($idNewCat);
- if (!$newCat) {
+ if ($newCat === null) {
$newCat = $catDAO->getDefault();
}
@@ -286,7 +291,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
}
}
- /** @return Traversable<array<string,string|int>> */
+ /** @return Traversable<array{'id':int,'url':string,'kind':int,'category':int,'name':string,'website':string,'description':string,'lastUpdate':int,'priority'?:int,
+ * 'pathEntries'?:string,'httpAuth':string,'error':int|bool,'ttl'?:int,'attributes'?:string}> */
public function selectAll(): Traversable {
$sql = <<<'SQL'
SELECT id, url, kind, category, name, website, description, `lastUpdate`,
@@ -294,6 +300,9 @@ SELECT id, url, kind, category, name, website, description, `lastUpdate`,
FROM `_feed`
SQL;
$stm = $this->pdo->query($sql);
+ if ($stm === false) {
+ return;
+ }
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
yield $row;
}
@@ -305,27 +314,26 @@ SQL;
if ($res == null) {
return null;
}
- $feed = self::daoToFeed($res);
- return $feed[$id] ?? null;
+ /** @var array<int,array{'url':string,'kind':int,'category':int,'name':string,'website':string,'lastUpdate':int,
+ * 'priority'?:int,'pathEntries'?:string,'httpAuth':string,'error':int,'ttl'?:int,'attributes'?:string}> $res */
+ $feeds = self::daoToFeed($res);
+ return $feeds[$id] ?? null;
}
public function searchByUrl(string $url): ?FreshRSS_Feed {
- $sql = 'SELECT * FROM `_feed` WHERE url=?';
- $stm = $this->pdo->prepare($sql);
-
- $values = array($url);
-
- $stm->execute($values);
- $res = $stm->fetchAll(PDO::FETCH_ASSOC);
- $feed = current(self::daoToFeed($res));
- return $feed == false ? null : $feed;
+ $sql = 'SELECT * FROM `_feed` WHERE url=:url';
+ $res = $this->fetchAssoc($sql, [':url' => $url]);
+ /** @var array<int,array{'url':string,'kind':int,'category':int,'name':string,'website':string,'lastUpdate':int,
+ * 'priority'?:int,'pathEntries'?:string,'httpAuth':string,'error':int,'ttl'?:int,'attributes'?:string}> $res */
+ return empty($res[0]) ? null : (current(self::daoToFeed($res)) ?: null);
}
- /** @return array<int>|false */
- public function listFeedsIds() {
+ /** @return array<int> */
+ public function listFeedsIds(): array {
$sql = 'SELECT id FROM `_feed`';
- $stm = $this->pdo->query($sql);
- return $stm ? $stm->fetchAll(PDO::FETCH_COLUMN, 0) : false;
+ /** @var array<int> $res */
+ $res = $this->fetchColumn($sql, 0) ?? [];
+ return $res;
}
/**
@@ -333,8 +341,10 @@ SQL;
*/
public function listFeeds(): array {
$sql = 'SELECT * FROM `_feed` ORDER BY name';
- $stm = $this->pdo->query($sql);
- return self::daoToFeed($stm->fetchAll(PDO::FETCH_ASSOC));
+ $res = $this->fetchAssoc($sql);
+ /** @var array<array{'url':string,'kind':int,'category':int,'name':string,'website':string,'lastUpdate':int,
+ * 'priority':int,'pathEntries':string,'httpAuth':string,'error':int,'ttl':int,'attributes':string}>|null $res */
+ return $res == null ? [] : self::daoToFeed($res);
}
/** @return array<string,string> */
@@ -345,8 +355,11 @@ SQL;
} else {
$sql .= 'WHERE id_feed=' . intval($id_feed);
}
- $stm = $this->pdo->query($sql);
- $res = $stm->fetchAll(PDO::FETCH_ASSOC);
+ $res = $this->fetchAssoc($sql);
+ /** @var array<array{'id_feed':int,'newest_item_us':string}>|null $res */
+ if ($res == null) {
+ return [];
+ }
$newestItemUsec = [];
foreach ($res as $line) {
$newestItemUsec['f_' . $line['id_feed']] = $line['newest_item_us'];
@@ -380,18 +393,13 @@ SQL;
}
}
- /** @return array<string>|false */
- public function listTitles(int $id, int $limit = 0) {
+ /** @return array<string> */
+ public function listTitles(int $id, int $limit = 0): array {
$sql = 'SELECT title FROM `_entry` WHERE id_feed=:id_feed ORDER BY id DESC'
. ($limit < 1 ? '' : ' LIMIT ' . intval($limit));
-
- $stm = $this->pdo->prepare($sql);
- $stm->bindParam(':id_feed', $id, PDO::PARAM_INT);
-
- if ($stm !== false && $stm->execute()) {
- return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
- }
- return false;
+ $res = $this->fetchColumn($sql, 0, [':id_feed' => $id]) ?? [];
+ /** @var array<string> $res */
+ return $res;
}
/**
@@ -399,15 +407,18 @@ SQL;
* @return array<FreshRSS_Feed>
*/
public function listByCategory(int $cat, ?bool $muted = null): array {
- $sql = 'SELECT * FROM `_feed` WHERE category=?';
+ $sql = 'SELECT * FROM `_feed` WHERE category=:category';
if ($muted) {
$sql .= ' AND ttl < 0';
}
- $stm = $this->pdo->prepare($sql);
-
- $stm->execute(array($cat));
+ $res = $this->fetchAssoc($sql, [':category' => $cat]);
+ if ($res == null) {
+ return [];
+ }
- $feeds = self::daoToFeed($stm->fetchAll(PDO::FETCH_ASSOC));
+ /** @var array<int,array{'url':string,'kind':int,'category':int,'name':string,'website':string,'lastUpdate':int,
+ * 'priority'?:int,'pathEntries'?:string,'httpAuth':string,'error':int,'ttl'?:int,'attributes'?:string}> $res */
+ $feeds = self::daoToFeed($res);
usort($feeds, static function (FreshRSS_Feed $a, FreshRSS_Feed $b) {
return strnatcasecmp($a->name(), $b->name());
@@ -417,23 +428,15 @@ SQL;
}
public function countEntries(int $id): int {
- $sql = 'SELECT COUNT(*) AS count FROM `_entry` WHERE id_feed=?';
- $stm = $this->pdo->prepare($sql);
- $values = array($id);
- $stm->execute($values);
- $res = $stm->fetchAll(PDO::FETCH_ASSOC);
-
- return $res[0]['count'];
+ $sql = 'SELECT COUNT(*) AS count FROM `_entry` WHERE id_feed=:id_feed';
+ $res = $this->fetchColumn($sql, 0, ['id_feed' => $id]);
+ return isset($res[0]) ? (int)($res[0]) : -1;
}
public function countNotRead(int $id): int {
- $sql = 'SELECT COUNT(*) AS count FROM `_entry` WHERE id_feed=? AND is_read=0';
- $stm = $this->pdo->prepare($sql);
- $values = array($id);
- $stm->execute($values);
- $res = $stm->fetchAll(PDO::FETCH_ASSOC);
-
- return $res[0]['count'];
+ $sql = 'SELECT COUNT(*) AS count FROM `_entry` WHERE id_feed=:id_feed AND is_read=0';
+ $res = $this->fetchColumn($sql, 0, ['id_feed' => $id]);
+ return isset($res[0]) ? (int)($res[0]) : -1;
}
/**
@@ -525,9 +528,10 @@ SQL;
public function truncate(int $id) {
$sql = 'DELETE FROM `_entry` WHERE id_feed=:id';
$stm = $this->pdo->prepare($sql);
- $stm->bindParam(':id', $id, PDO::PARAM_INT);
$this->pdo->beginTransaction();
- if (!($stm && $stm->execute())) {
+ if (!($stm !== false &&
+ $stm->bindParam(':id', $id, 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();
@@ -535,11 +539,11 @@ SQL;
}
$affected = $stm->rowCount();
- $sql = 'UPDATE `_feed` '
- . 'SET `cache_nbEntries`=0, `cache_nbUnreads`=0, `lastUpdate`=0 WHERE id=:id';
+ $sql = 'UPDATE `_feed` SET `cache_nbEntries`=0, `cache_nbUnreads`=0, `lastUpdate`=0 WHERE id=:id';
$stm = $this->pdo->prepare($sql);
- $stm->bindParam(':id', $id, PDO::PARAM_INT);
- if (!($stm && $stm->execute())) {
+ if (!($stm !== false &&
+ $stm->bindParam(':id', $id, 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();
@@ -574,7 +578,8 @@ SQL;
}
/**
- * @param array<int,array<string,string|int>>|array<string,string|int> $listDAO
+ * @param array<int,array{'id'?:int,'url'?:string,'kind'?:int,'category'?:int,'name'?:string,'website'?:string,'description'?:string,'lastUpdate'?:int,'priority'?:int,
+ * 'pathEntries'?:string,'httpAuth'?:string,'error'?:int|bool,'ttl'?:int,'attributes'?:string,'cache_nbUnreads'?:int,'cache_nbEntries'?:int}> $listDAO
* @return array<int,FreshRSS_Feed>
*/
public static function daoToFeed(array $listDAO, ?int $catID = null): array {
@@ -589,7 +594,7 @@ SQL;
continue;
}
if (isset($dao['id'])) {
- $key = $dao['id'];
+ $key = (int)$dao['id'];
}
if ($catID === null) {
$category = $dao['category'] ?? 0;
diff --git a/app/Models/Search.php b/app/Models/Search.php
index f5b061512..d165b05f0 100644
--- a/app/Models/Search.php
+++ b/app/Models/Search.php
@@ -164,37 +164,37 @@ class FreshRSS_Search {
}
public function getMinDate(): ?int {
- return $this->min_date;
+ return $this->min_date ?: null;
}
public function getNotMinDate(): ?int {
- return $this->not_min_date;
+ return $this->not_min_date ?: null;
}
public function setMinDate(int $value): void {
$this->min_date = $value;
}
public function getMaxDate(): ?int {
- return $this->max_date;
+ return $this->max_date ?: null;
}
public function getNotMaxDate(): ?int {
- return $this->not_max_date;
+ return $this->not_max_date ?: null;
}
public function setMaxDate(int $value): void {
$this->max_date = $value;
}
public function getMinPubdate(): ?int {
- return $this->min_pubdate;
+ return $this->min_pubdate ?: null;
}
public function getNotMinPubdate(): ?int {
- return $this->not_min_pubdate;
+ return $this->not_min_pubdate ?: null;
}
public function getMaxPubdate(): ?int {
- return $this->max_pubdate;
+ return $this->max_pubdate ?: null;
}
public function getNotMaxPubdate(): ?int {
- return $this->not_max_pubdate;
+ return $this->not_max_pubdate ?: null;
}
/** @return array<string>|null */
@@ -518,7 +518,7 @@ class FreshRSS_Search {
$input = str_replace($matches[0], '', $input);
$dates = self::removeEmptyValues($matches['search']);
if (!empty($dates[0])) {
- list($this->min_date, $this->max_date) = parseDateInterval($dates[0]);
+ [$this->min_date, $this->max_date] = parseDateInterval($dates[0]);
}
}
return $input;
@@ -529,7 +529,7 @@ class FreshRSS_Search {
$input = str_replace($matches[0], '', $input);
$dates = self::removeEmptyValues($matches['search']);
if (!empty($dates[0])) {
- list($this->not_min_date, $this->not_max_date) = parseDateInterval($dates[0]);
+ [$this->not_min_date, $this->not_max_date] = parseDateInterval($dates[0]);
}
}
return $input;
@@ -545,7 +545,7 @@ class FreshRSS_Search {
$input = str_replace($matches[0], '', $input);
$dates = self::removeEmptyValues($matches['search']);
if (!empty($dates[0])) {
- list($this->min_pubdate, $this->max_pubdate) = parseDateInterval($dates[0]);
+ [$this->min_pubdate, $this->max_pubdate] = parseDateInterval($dates[0]);
}
}
return $input;
@@ -556,7 +556,7 @@ class FreshRSS_Search {
$input = str_replace($matches[0], '', $input);
$dates = self::removeEmptyValues($matches['search']);
if (!empty($dates[0])) {
- list($this->not_min_pubdate, $this->not_max_pubdate) = parseDateInterval($dates[0]);
+ [$this->not_min_pubdate, $this->not_max_pubdate] = parseDateInterval($dates[0]);
}
}
return $input;
diff --git a/app/Models/TagDAO.php b/app/Models/TagDAO.php
index a675c7e04..133907a3a 100644
--- a/app/Models/TagDAO.php
+++ b/app/Models/TagDAO.php
@@ -67,7 +67,8 @@ SQL;
);
if ($stm !== false && $stm->execute($values) && $stm->rowCount() > 0) {
- return (int)($this->pdo->lastInsertId('`_tag_id_seq`'));
+ $tagId = $this->pdo->lastInsertId('`_tag_id_seq`');
+ return $tagId === false ? false : (int)$tagId;
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($info));
@@ -275,8 +276,7 @@ SQL;
return $newestItemUsec;
}
- /** @return int|false */
- public function count() {
+ public function count(): int {
$sql = 'SELECT COUNT(*) AS count FROM `_tag`';
$stm = $this->pdo->query($sql);
if ($stm !== false) {
@@ -288,25 +288,19 @@ SQL;
return $this->count();
}
Minz_Log::error('SQL error ' . __METHOD__ . json_encode($info));
- return false;
+ return -1;
}
- /**
- * @return int|false
- */
- public function countEntries(int $id) {
+ public function countEntries(int $id): int {
$sql = 'SELECT COUNT(*) AS count FROM `_entrytag` WHERE id_tag=:id_tag';
$res = $this->fetchAssoc($sql, [':id_tag' => $id]);
if ($res == null || !isset($res[0]['count'])) {
- return false;
+ return -1;
}
return (int)$res[0]['count'];
}
- /**
- * @return int|false
- */
- public function countNotRead(?int $id = null) {
+ public function countNotRead(?int $id = null): int {
$sql = <<<'SQL'
SELECT COUNT(*) AS count FROM `_entrytag` et
INNER JOIN `_entry` e ON et.id_entry=e.id
@@ -320,7 +314,7 @@ SQL;
$res = $this->fetchAssoc($sql, $values);
if ($res == null || !isset($res[0]['count'])) {
- return false;
+ return -1;
}
return (int)$res[0]['count'];
}
diff --git a/app/Models/UserQuery.php b/app/Models/UserQuery.php
index f2301ff26..a4cb469fe 100644
--- a/app/Models/UserQuery.php
+++ b/app/Models/UserQuery.php
@@ -128,7 +128,7 @@ class FreshRSS_UserQuery {
throw new FreshRSS_DAO_Exception('Category DAO is not loaded in UserQuery');
}
$category = $this->category_dao->searchById($id);
- if ($category) {
+ if ($category !== null) {
$this->get_name = $category->name();
} else {
$this->deprecated = true;
@@ -146,7 +146,7 @@ class FreshRSS_UserQuery {
throw new FreshRSS_DAO_Exception('Feed DAO is not loaded in UserQuery');
}
$feed = $this->feed_dao->searchById($id);
- if ($feed) {
+ if ($feed !== null) {
$this->get_name = $feed->name();
} else {
$this->deprecated = true;
@@ -164,7 +164,7 @@ class FreshRSS_UserQuery {
throw new FreshRSS_DAO_Exception('Tag DAO is not loaded in UserQuery');
}
$tag = $this->tag_dao->searchById($id);
- if ($tag) {
+ if ($tag !== null) {
$this->get_name = $tag->name();
} else {
$this->deprecated = true;
diff --git a/app/Services/ExportService.php b/app/Services/ExportService.php
index 0d45ba548..d3a3373a5 100644
--- a/app/Services/ExportService.php
+++ b/app/Services/ExportService.php
@@ -94,7 +94,7 @@ class FreshRSS_Export_Service {
*/
public function generateFeedEntries(int $feed_id, int $max_number_entries): ?array {
$feed = $this->feed_dao->searchById($feed_id);
- if (!$feed) {
+ if ($feed === null) {
return null;
}
@@ -127,7 +127,7 @@ class FreshRSS_Export_Service {
* @return array<string,string> Keys are filenames and values are contents.
*/
public function generateAllFeedEntries(int $max_number_entries): array {
- $feed_ids = $this->feed_dao->listFeedsIds() ?: [];
+ $feed_ids = $this->feed_dao->listFeedsIds();
$exported_files = [];
foreach ($feed_ids as $feed_id) {
diff --git a/cli/user-info.php b/cli/user-info.php
index d8b498cc3..a320a4d19 100755
--- a/cli/user-info.php
+++ b/cli/user-info.php
@@ -63,22 +63,8 @@ foreach ($users as $username) {
$nbEntries = $entryDAO->countUnreadRead();
$nbFavorites = $entryDAO->countUnreadReadFavorites();
-
- if ($nbFavorites === false) {
- $nbFavorites = [
- 'all' => -1,
- ];
- }
-
$feedList = $feedDAO->listFeedsIds();
- if ($nbEntries === false) {
- $nbEntries = [
- 'read' => -1,
- 'unread' => -1,
- ];
- }
-
$data = array(
'default' => $username === FreshRSS_Context::$system_conf->default_user ? '*' : '',
'user' => $username,
@@ -87,7 +73,7 @@ foreach ($users as $username) {
'last_user_activity' => FreshRSS_UserDAO::mtime($username),
'database_size' => $databaseDAO->size(),
'categories' => $catDAO->count(),
- 'feeds' => count($feedList === false ? [] : $feedList),
+ 'feeds' => count($feedList),
'reads' => (int)$nbEntries['read'],
'unreads' => (int)$nbEntries['unread'],
'favourites' => (int)$nbFavorites['all'],
diff --git a/tests/phpstan-next.txt b/tests/phpstan-next.txt
index 723ef4ef2..c1c73d43e 100644
--- a/tests/phpstan-next.txt
+++ b/tests/phpstan-next.txt
@@ -8,12 +8,7 @@
./app/Controllers/indexController.php
./app/Controllers/updateController.php
./app/Controllers/userController.php
-./app/Models/CategoryDAO.php
-./app/Models/Context.php
-./app/Models/EntryDAO.php
./app/Models/Feed.php
-./app/Models/FeedDAO.php
-./app/Models/Search.php
./app/Models/Share.php
./app/views/helpers/logs_pagination.phtml
./lib/Minz/Error.php