aboutsummaryrefslogtreecommitdiff
path: root/app/Models/CategoryDAO.php
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2024-12-27 12:12:49 +0100
committerGravatar GitHub <noreply@github.com> 2024-12-27 12:12:49 +0100
commitb1d24fbdb7d1cc948c946295035dad6df550fb7e (patch)
tree7b4365a04097a779659474fbb9281a9661512522 /app/Models/CategoryDAO.php
parent897e4a3f4a273d50c28157edb67612b2d7fa2e6f (diff)
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
Diffstat (limited to 'app/Models/CategoryDAO.php')
-rw-r--r--app/Models/CategoryDAO.php98
1 files changed, 52 insertions, 46 deletions
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<array{'id':int,'url':string,'kind':int,'category':int,'name':string,'website':string,'lastUpdate':int,
- * 'priority':int,'pathEntries':string,'httpAuth':string,'error':int,'keep_history':?int,'ttl':int,'attributes':string}> $feeds */
+ /** @var list<array{id:int,url:string,kind:int,category:int,name:string,website:string,lastUpdate:int,
+ * priority:int,pathEntries:string,httpAuth:string,error:int,keep_history:?int,ttl:int,attributes:string}> $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<string|int> $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<string,mixed>} $valuesTmp
+ * @param array{name:string,id?:int,kind?:int,lastUpdate?:int,error?:int|bool,attributes?:string|array<string,mixed>} $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<string,mixed>|mixed|null} $valuesTmp
+ * @param array{name:string,kind:int,attributes?:array<string,mixed>|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<array{'id':int,'name':string,'kind':int,'lastUpdate':int,'error':int,'attributes'?:array<string,mixed>}> */
+ /** @return Traversable<array{id:int,name:string,kind:int,lastUpdate:int,error:int,attributes?:array<string,mixed>}> */
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<string,mixed>} $row */
+ /** @var array{id:int,name:string,kind:int,lastUpdate:int,error:int,attributes?:array<string,mixed>} $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<array{'name':string,'id':int,'kind':int,'lastUpdate':int,'error':int|bool,'attributes':string}> $res */
- $categories = self::daoToCategories($res);
+ /** @var array<array{name:string,id:int,kind:int,lastUpdate?:int,error:int|bool,attributes?:string}> $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<array{'name':string,'id':int,'kind':int,'lastUpdate':int,'error':int|bool,'attributes':string}> $res */
- $categories = self::daoToCategories($res);
+ /** @var array<array{name:string,id:int,kind:int,lastUpdate:int,error:int|bool,attributes:string}> $res */
+ $categories = self::daoToCategories($res); // @phpstan-ignore varTag.type
return reset($categories) ?: null;
}
- /** @return array<int,FreshRSS_Category> */
+ /** @return list<FreshRSS_Category> */
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<int,FreshRSS_Category> */
+ /** @return list<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, '
@@ -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<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,'attributes'?:string,'cache_nbEntries'?:int,'cache_nbUnreads'?:int,'ttl'?:int}> $res */
+ /** @var list<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,attributes?:string,cache_nbEntries?:int,cache_nbUnreads?:int,ttl?:int}> $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<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $res */
- return empty($res) ? [] : self::daoToCategories($res);
+ $res = $this->fetchAssoc('SELECT * FROM `_category` ORDER BY name') ?? [];
+ /** @var list<array{name:string,id:int,kind:int,lastUpdate?:int,error?:int|bool,attributes?:string}> $res */
+ return empty($res) ? [] : self::daoToCategories($res); // @phpstan-ignore varTag.type
}
}
- /** @return array<int,FreshRSS_Category> */
+ /** @return list<FreshRSS_Category> */
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<array{name:string,id:int,kind:int,lastUpdate:int,error?:int|bool,attributes?:string}> $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<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $res */
- $categories = self::daoToCategories($res);
- if (isset($categories[self::DEFAULTCATEGORYID])) {
- return $categories[self::DEFAULTCATEGORYID];
+ /** @var array<array{name:string,id:int,kind:int,lastUpdate?:int,error?:int|bool,attributes?:string}> $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<int,string> */
+ /** @return list<string> */
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<int,string> $res */
+ /** @var list<string> $res */
return $res;
}
/**
- * @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,'attributes'?:string,'cache_nbEntries'?:int,'cache_nbUnreads'?:int,'ttl'?:int}> $listDAO
- * @return array<int,FreshRSS_Category>
+ * @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,attributes?:string,cache_nbEntries?:int,cache_nbUnreads?:int,ttl?:int}> $listDAO
+ * @return list<FreshRSS_Category>
*/
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<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $listDAO
- * @return array<int,FreshRSS_Category>
+ * @param array<array{name:string,id:int,kind:int,lastUpdate?:int,error?:int|bool,attributes?:string}> $listDAO
+ * @return list<FreshRSS_Category>
*/
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;
}