From b1d24fbdb7d1cc948c946295035dad6df550fb7e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 27 Dec 2024 12:12:49 +0100 Subject: PHPStan 2.0 (#7131) * PHPStan 2.0 fix https://github.com/FreshRSS/FreshRSS/issues/6989 https://github.com/phpstan/phpstan/releases/tag/2.0.0 https://github.com/phpstan/phpstan/blob/2.0.x/UPGRADING.md * More * More * Done * fix i18n CLI * Restore a PHPStan Next test For work towards PHPStan Level 10 * 4 more on Level 10 * fix getTagsForEntry * API at Level 10 * More Level 10 * Finish Minz at Level 10 * Finish CLI at Level 10 * Finish Controllers at Level 10 * More Level 10 * More * Pass bleedingEdge * Clean PHPStan options and add TODOs * Level 10 for main config * More * Consitency array vs. list * Sanitize themes get_infos * Simplify TagDAO->getTagsForEntries() * Finish reportAnyTypeWideningInVarTag * Prepare checkBenevolentUnionTypes and checkImplicitMixed * Fixes * Refix * Another fix * Casing of __METHOD__ constant --- app/Models/CategoryDAO.php | 98 ++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 46 deletions(-) (limited to 'app/Models/CategoryDAO.php') diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 6b563b0a8..556179800 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -19,7 +19,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { if ($this->pdo->inTransaction()) { $this->pdo->commit(); } - Minz_Log::warning(__method__ . ': ' . $name); + Minz_Log::warning(__METHOD__ . ': ' . $name); try { if ($name === 'kind') { //v1.20.0 return $this->pdo->exec('ALTER TABLE `_category` ADD COLUMN kind SMALLINT DEFAULT 0') !== false; @@ -30,8 +30,8 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { } elseif ('attributes' === $name) { //v1.15.0 $ok = $this->pdo->exec('ALTER TABLE `_category` ADD COLUMN attributes TEXT') !== false; - /** @var array $feeds */ + /** @var list $feeds */ $feeds = $this->fetchAssoc('SELECT * FROM `_feed`') ?? []; $stm = $this->pdo->prepare('UPDATE `_feed` SET attributes = :attributes WHERE id = :id'); @@ -51,15 +51,17 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { if (!is_array($attributes)) { $attributes = []; } + $archiving = is_array($attributes['archiving'] ?? null) ? $attributes['archiving'] : []; if ($keepHistory > 0) { - $attributes['archiving']['keep_min'] = (int)$keepHistory; + $archiving['keep_min'] = (int)$keepHistory; } elseif ($keepHistory == -1) { //Infinite - $attributes['archiving']['keep_period'] = false; - $attributes['archiving']['keep_max'] = false; - $attributes['archiving']['keep_min'] = false; + $archiving['keep_period'] = false; + $archiving['keep_max'] = false; + $archiving['keep_min'] = false; } else { continue; } + $attributes['archiving'] = $archiving; if (!($stm->bindValue(':id', $feed['id'], PDO::PARAM_INT) && $stm->bindValue(':attributes', json_encode($attributes, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)) && $stm->execute())) { @@ -78,12 +80,12 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $ok; } } catch (Exception $e) { - Minz_Log::error(__method__ . ': ' . $e->getMessage()); + Minz_Log::error(__METHOD__ . ': ' . $e->getMessage()); } return false; } - /** @param array $errorInfo */ + /** @param array{0:string,1:int,2:string} $errorInfo */ protected function autoUpdateDb(array $errorInfo): bool { if (isset($errorInfo[0])) { if ($errorInfo[0] === FreshRSS_DatabaseDAO::ER_BAD_FIELD_ERROR || $errorInfo[0] === FreshRSS_DatabaseDAOPGSQL::UNDEFINED_COLUMN) { @@ -99,7 +101,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { } /** - * @param array{'name':string,'id'?:int,'kind'?:int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string|array} $valuesTmp + * @param array{name:string,id?:int,kind?:int,lastUpdate?:int,error?:int|bool,attributes?:string|array} $valuesTmp */ public function addCategory(array $valuesTmp): int|false { // TRIM() to provide a type hint as text @@ -127,6 +129,7 @@ SQL; return $catId === false ? false : (int)$catId; } else { $info = $stm === false ? $this->pdo->errorInfo() : $stm->errorInfo(); + /** @var array{0:string,1:int,2:string} $info */ if ($this->autoUpdateDb($info)) { return $this->addCategory($valuesTmp); } @@ -150,7 +153,7 @@ SQL; } /** - * @param array{'name':string,'kind':int,'attributes'?:array|mixed|null} $valuesTmp + * @param array{name:string,kind:int,attributes?:array|mixed|null} $valuesTmp */ public function updateCategory(int $id, array $valuesTmp): int|false { // No tag of the same name @@ -176,6 +179,7 @@ SQL; return $stm->rowCount(); } else { $info = $stm === false ? $this->pdo->errorInfo() : $stm->errorInfo(); + /** @var array{0:string,1:int,2:string} $info */ if ($this->autoUpdateDb($info)) { return $this->updateCategory($id, $valuesTmp); } @@ -217,21 +221,22 @@ SQL; } } - /** @return Traversable}> */ + /** @return Traversable}> */ public function selectAll(): Traversable { $sql = 'SELECT id, name, kind, `lastUpdate`, error, attributes FROM `_category`'; $stm = $this->pdo->query($sql); if ($stm !== false) { while ($row = $stm->fetch(PDO::FETCH_ASSOC)) { - /** @var array{'id':int,'name':string,'kind':int,'lastUpdate':int,'error':int,'attributes'?:array} $row */ + /** @var array{id:int,name:string,kind:int,lastUpdate:int,error:int,attributes?:array} $row */ yield $row; } } else { $info = $this->pdo->errorInfo(); + /** @var array{0:string,1:int,2:string} $info */ if ($this->autoUpdateDb($info)) { yield from $this->selectAll(); } else { - Minz_Log::error(__method__ . ' error: ' . json_encode($info)); + Minz_Log::error(__METHOD__ . ' error: ' . json_encode($info)); } } } @@ -239,24 +244,24 @@ SQL; public function searchById(int $id): ?FreshRSS_Category { $sql = 'SELECT * FROM `_category` WHERE id=:id'; $res = $this->fetchAssoc($sql, ['id' => $id]) ?? []; - /** @var array $res */ - $categories = self::daoToCategories($res); + /** @var array $res */ + $categories = self::daoToCategories($res); // @phpstan-ignore varTag.type return reset($categories) ?: null; } public function searchByName(string $name): ?FreshRSS_Category { $sql = 'SELECT * FROM `_category` WHERE name=:name'; $res = $this->fetchAssoc($sql, ['name' => $name]) ?? []; - /** @var array $res */ - $categories = self::daoToCategories($res); + /** @var array $res */ + $categories = self::daoToCategories($res); // @phpstan-ignore varTag.type return reset($categories) ?: null; } - /** @return array */ + /** @return list */ public function listSortedCategories(bool $prePopulateFeeds = true, bool $details = false): array { $categories = $this->listCategories($prePopulateFeeds, $details); - uasort($categories, static function (FreshRSS_Category $a, FreshRSS_Category $b) { + usort($categories, static function (FreshRSS_Category $a, FreshRSS_Category $b) { $aPosition = $a->attributeInt('position'); $bPosition = $b->attributeInt('position'); if ($aPosition === $bPosition) { @@ -272,7 +277,7 @@ SQL; return $categories; } - /** @return array */ + /** @return list */ 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, ' @@ -286,11 +291,12 @@ SQL; $values = [ ':priority' => FreshRSS_Feed::PRIORITY_CATEGORY ]; if ($stm !== false && $stm->execute($values)) { $res = $stm->fetchAll(PDO::FETCH_ASSOC) ?: []; - /** @var array $res */ + /** @var list $res */ return self::daoToCategoriesPrepopulated($res); } else { $info = $stm === false ? $this->pdo->errorInfo() : $stm->errorInfo(); + /** @var array{0:string,1:int,2:string} $info */ if ($this->autoUpdateDb($info)) { return $this->listCategories($prePopulateFeeds, $details); } @@ -298,13 +304,13 @@ SQL; return []; } } else { - $res = $this->fetchAssoc('SELECT * FROM `_category` ORDER BY name'); - /** @var array $res */ - return empty($res) ? [] : self::daoToCategories($res); + $res = $this->fetchAssoc('SELECT * FROM `_category` ORDER BY name') ?? []; + /** @var list $res */ + return empty($res) ? [] : self::daoToCategories($res); // @phpstan-ignore varTag.type } } - /** @return array */ + /** @return list */ public function listCategoriesOrderUpdate(int $defaultCacheDuration = 86400, int $limit = 0): array { $sql = 'SELECT * FROM `_category` WHERE kind = :kind AND `lastUpdate` < :lu ORDER BY `lastUpdate`' . ($limit < 1 ? '' : ' LIMIT ' . $limit); @@ -313,9 +319,12 @@ SQL; $stm->bindValue(':kind', FreshRSS_Category::KIND_DYNAMIC_OPML, PDO::PARAM_INT) && $stm->bindValue(':lu', time() - $defaultCacheDuration, PDO::PARAM_INT) && $stm->execute()) { - return self::daoToCategories($stm->fetchAll(PDO::FETCH_ASSOC)); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + /** @var list $res */ + return self::daoToCategories($res); } else { $info = $stm !== false ? $stm->errorInfo() : $this->pdo->errorInfo(); + /** @var array{0:string,1:int,2:string} $info */ if ($this->autoUpdateDb($info)) { return $this->listCategoriesOrderUpdate($defaultCacheDuration, $limit); } @@ -327,10 +336,10 @@ SQL; public function getDefault(): ?FreshRSS_Category { $sql = 'SELECT * FROM `_category` WHERE id=:id'; $res = $this->fetchAssoc($sql, [':id' => self::DEFAULTCATEGORYID]) ?? []; - /** @var array $res */ - $categories = self::daoToCategories($res); - if (isset($categories[self::DEFAULTCATEGORYID])) { - return $categories[self::DEFAULTCATEGORYID]; + /** @var array $res */ + $categories = self::daoToCategories($res); // @phpstan-ignore varTag.type + if (isset($categories[0])) { + return $categories[0]; } else { if (FreshRSS_Context::$isCli) { fwrite(STDERR, 'FreshRSS database error: Default category not found!' . "\n"); @@ -388,7 +397,7 @@ SQL; return isset($res[0]) ? (int)$res[0] : -1; } - /** @return array */ + /** @return list */ public function listTitles(int $id, int $limit = 0): array { $sql = <<<'SQL' SELECT e.title FROM `_entry` e @@ -398,15 +407,15 @@ SQL; SQL; $sql .= ($limit < 1 ? '' : ' LIMIT ' . intval($limit)); $res = $this->fetchColumn($sql, 0, [':id_category' => $id]) ?? []; - /** @var array $res */ + /** @var list $res */ return $res; } /** - * @param array $listDAO - * @return array + * @param array $listDAO + * @return list */ private static function daoToCategoriesPrepopulated(array $listDAO): array { $list = []; @@ -414,8 +423,6 @@ SQL; $feedsDao = []; $feedDao = FreshRSS_Factory::createFeedDao(); foreach ($listDAO as $line) { - FreshRSS_DatabaseDAO::pdoInt($line, ['c_id', 'c_kind', 'c_last_update', 'c_error', - 'id', 'kind', 'priority', 'error', 'cache_nbEntries', 'cache_nbUnreads', 'ttl']); if (!empty($previousLine['c_id']) && $line['c_id'] !== $previousLine['c_id']) { // End of the current category, we add it to the $list $cat = new FreshRSS_Category( @@ -425,7 +432,7 @@ SQL; ); $cat->_kind($previousLine['c_kind']); $cat->_attributes($previousLine['c_attributes'] ?? '[]'); - $list[$cat->id()] = $cat; + $list[] = $cat; $feedsDao = []; //Prepare for next category } @@ -445,20 +452,19 @@ SQL; $cat->_lastUpdate($previousLine['c_last_update'] ?? 0); $cat->_error($previousLine['c_error'] ?? 0); $cat->_attributes($previousLine['c_attributes'] ?? []); - $list[$cat->id()] = $cat; + $list[] = $cat; } return $list; } /** - * @param array $listDAO - * @return array + * @param array $listDAO + * @return list */ private static function daoToCategories(array $listDAO): array { $list = []; foreach ($listDAO as $dao) { - FreshRSS_DatabaseDAO::pdoInt($dao, ['id', 'kind', 'lastUpdate', 'error']); $cat = new FreshRSS_Category( $dao['name'], $dao['id'] @@ -467,7 +473,7 @@ SQL; $cat->_lastUpdate($dao['lastUpdate'] ?? 0); $cat->_error($dao['error'] ?? 0); $cat->_attributes($dao['attributes'] ?? ''); - $list[$cat->id()] = $cat; + $list[] = $cat; } return $list; } -- cgit v1.2.3