From bd9fa803f1f0c23face77fa1bc550d1198ce5ad6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 2 May 2023 14:38:32 +0200 Subject: 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> --- app/Models/CategoryDAO.php | 132 ++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 73 deletions(-) (limited to 'app/Models/CategoryDAO.php') 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 $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 $valuesTmp + * @param array{'name':string,'id'?:int,'kind'?:int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string|array} $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} $valuesTmp + * @param array{'name':string,'kind':int,'attributes'?:string|array} $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 $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 $res */ $cat = self::daoToCategory($res); return $cat[0] ?? null; } - /** @return array|false */ - public function listSortedCategories(bool $prePopulateFeeds = true, bool $details = false) { + /** @return array */ + 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|false */ - public function listCategories(bool $prePopulateFeeds = true, bool $details = false) { + /** @return array */ + 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 $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 $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 $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 $categories */ @@ -432,14 +421,15 @@ SQL; } /** - * @param array> $listDAO + * @param array $listDAO * @return array */ private static function daoToCategoryPrepopulated(array $listDAO) { - $list = array(); - $previousLine = null; - /** @var array */ - $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 $listDAO + * @param array $listDAO * @return array */ - 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( -- cgit v1.2.3