Преглед изворни кода

PHPStan level 6 for remaining DAO classes (#5299)

* PHPStan level 6 FreshRSS_CategoryDAO
Follow-up of https://github.com/FreshRSS/FreshRSS/pull/5298
Contributes to https://github.com/FreshRSS/FreshRSS/issues/4112

* PHPStan Level 6 for FeedDAO and a bit more

* PHPStan Level 6 for tagDAO
Alexandre Alapetite пре 3 година
родитељ
комит
efcc8f387b
6 измењених фајлова са 109 додато и 84 уклоњено
  1. 38 30
      app/Models/CategoryDAO.php
  2. 1 1
      app/Models/Entry.php
  3. 1 1
      app/Models/EntryDAO.php
  4. 32 17
      app/Models/FeedDAO.php
  5. 37 32
      app/Models/TagDAO.php
  6. 0 3
      tests/phpstan-next.txt

+ 38 - 30
app/Models/CategoryDAO.php

@@ -4,7 +4,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
 
 	const DEFAULTCATEGORYID = 1;
 
-	public function resetDefaultCategoryName() {
+	public function resetDefaultCategoryName(): bool {
 		//FreshRSS 1.15.1
 		$stm = $this->pdo->prepare('UPDATE `_category` SET name = :name WHERE id = :id');
 		if ($stm) {
@@ -14,7 +14,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
 		return $stm && $stm->execute();
 	}
 
-	protected function addColumn($name) {
+	protected function addColumn(string $name): bool {
 		if ($this->pdo->inTransaction()) {
 			$this->pdo->commit();
 		}
@@ -90,8 +90,11 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
 		return false;
 	}
 
-	/** @return int|false */
-	public function addCategory($valuesTmp) {
+	/**
+	 * @param array<string,mixed> $valuesTmp
+	 * @return int|false
+	 */
+	public function addCategory(array $valuesTmp) {
 		// TRIM() to provide a type hint as text
 		// No tag of the same name
 		$sql = <<<'SQL'
@@ -124,11 +127,8 @@ SQL;
 		}
 	}
 
-	/**
-	 * @param FreshRSS_Category $category
-	 * @return int|false
-	 */
-	public function addCategoryObject($category) {
+	/** @return int|false */
+	public function addCategoryObject(FreshRSS_Category $category) {
 		$cat = $this->searchByName($category->name());
 		if (!$cat) {
 			$values = [
@@ -142,7 +142,11 @@ SQL;
 		return $cat->id();
 	}
 
-	public function updateCategory($id, $valuesTmp) {
+	/**
+	 * @param array<string,mixed> $valuesTmp
+	 * @return int|false
+	 */
+	public function updateCategory(int $id, array $valuesTmp) {
 		// No tag of the same name
 		$sql = <<<'SQL'
 UPDATE `_category` SET name=?, kind=?, attributes=? WHERE id=?
@@ -174,6 +178,7 @@ SQL;
 		}
 	}
 
+	/** @return int|false */
 	public function updateLastUpdate(int $id, bool $inError = false, int $mtime = 0) {
 		$sql = 'UPDATE `_category` SET `lastUpdate`=?, error=? WHERE id=?';
 		$values = [
@@ -192,7 +197,8 @@ SQL;
 		}
 	}
 
-	public function deleteCategory($id) {
+	/** @return int|false */
+	public function deleteCategory(int $id) {
 		if ($id <= self::DEFAULTCATEGORYID) {
 			return false;
 		}
@@ -208,6 +214,7 @@ SQL;
 		}
 	}
 
+	/** @return iterator<array<string,string|int>> */
 	public function selectAll() {
 		$sql = 'SELECT id, name, kind, `lastUpdate`, error, attributes FROM `_category`';
 		$stm = $this->pdo->query($sql);
@@ -219,9 +226,9 @@ SQL;
 			$info = $this->pdo->errorInfo();
 			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));
-			yield false;
 		}
 	}
 
@@ -258,11 +265,11 @@ SQL;
 		}
 	}
 
+	/** @return array<FreshRSS_Category>|false */
 	public function listSortedCategories(bool $prePopulateFeeds = true, bool $details = false) {
 		$categories = $this->listCategories($prePopulateFeeds, $details);
-
-		if (!is_array($categories)) {
-			return $categories;
+		if ($categories === false) {
+			return false;
 		}
 
 		uasort($categories, static function (FreshRSS_Category $a, FreshRSS_Category $b) {
@@ -330,8 +337,7 @@ SQL;
 		}
 	}
 
-	/** @return FreshRSS_Category|null */
-	public function getDefault() {
+	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);
@@ -381,14 +387,14 @@ SQL;
 		return true;
 	}
 
-	public function count() {
+	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'];
 	}
 
-	public function countFeed(int $id) {
+	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);
@@ -397,7 +403,7 @@ SQL;
 		return $res[0]['count'];
 	}
 
-	public function countNotRead(int $id) {
+	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);
@@ -406,11 +412,8 @@ SQL;
 		return $res[0]['count'];
 	}
 
-	/**
-	 * @param array<FreshRSS_Category> $categories
-	 * @param int $feed_id
-	 */
-	public static function findFeed(array $categories, int $feed_id) {
+	/** @param array<FreshRSS_Category> $categories */
+	public static function findFeed(array $categories, int $feed_id): ?FreshRSS_Feed {
 		foreach ($categories as $category) {
 			foreach ($category->feeds() as $feed) {
 				if ($feed->id() === $feed_id) {
@@ -437,12 +440,13 @@ SQL;
 	}
 
 	/**
-	 * @param array<string,mixed> $listDAO
+	 * @param array<string,array<string,string|int>> $listDAO
 	 * @return array<int,FreshRSS_Category>
 	 */
 	private static function daoToCategoryPrepopulated(array $listDAO) {
 		$list = array();
 		$previousLine = null;
+		/** @var array<string,string|int> */
 		$feedsDao = array();
 		$feedDao = FreshRSS_Factory::createFeedDAO();
 		foreach ($listDAO as $line) {
@@ -481,14 +485,18 @@ SQL;
 		return $list;
 	}
 
-	private static function daoToCategory($listDAO) {
+	/**
+	 * @param array<array<string,string|int>>|array<string,string|int> $listDAO
+	 * @return array<FreshRSS_Category>
+	 */
+	private static function daoToCategory($listDAO): array {
 		$list = array();
 
 		if (!is_array($listDAO)) {
 			$listDAO = array($listDAO);
 		}
 
-		foreach ($listDAO as $key => $dao) {
+		foreach ($listDAO as $dao) {
 			$cat = new FreshRSS_Category(
 				$dao['name']
 			);
@@ -497,7 +505,7 @@ SQL;
 			$cat->_lastUpdate($dao['lastUpdate'] ?? 0);
 			$cat->_error($dao['error'] ?? 0);
 			$cat->_attributes('', isset($dao['attributes']) ? $dao['attributes'] : '');
-			$list[$key] = $cat;
+			$list[] = $cat;
 		}
 
 		return $list;

+ 1 - 1
app/Models/Entry.php

@@ -55,7 +55,7 @@ class FreshRSS_Entry extends Minz_Model {
 		$this->_guid($guid);
 	}
 
-	/** @param array<string,mixed> $dao */
+	/** @param array<string,string|int> $dao */
 	public static function fromArray(array $dao): FreshRSS_Entry {
 		if (empty($dao['content'])) {
 			$dao['content'] = '';

+ 1 - 1
app/Models/EntryDAO.php

@@ -700,7 +700,7 @@ SQL;
 		}
 	}
 
-	/** @return iterator<array<string,mixed>> */
+	/** @return iterator<array<string,string|int>> */
 	public function selectAll() {
 		$sql = 'SELECT id, guid, title, author, '
 			. (static::isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')

+ 32 - 17
app/Models/FeedDAO.php

@@ -2,7 +2,7 @@
 
 class FreshRSS_FeedDAO extends Minz_ModelPdo {
 
-	protected function addColumn(string $name) {
+	protected function addColumn(string $name): bool {
 		if ($this->pdo->inTransaction()) {
 			$this->pdo->commit();
 		}
@@ -34,7 +34,10 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
 		return false;
 	}
 
-	/** @return int|false */
+	/**
+	 * @param array<string,mixed> $valuesTmp
+	 * @return int|false
+	 */
 	public function addFeed(array $valuesTmp) {
 		$sql = 'INSERT INTO `_feed` (url, kind, category, name, website, description, `lastUpdate`, priority, `pathEntries`, `httpAuth`, error, ttl, attributes)
 				VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
@@ -133,7 +136,10 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
 		}
 	}
 
-	/** @return int|false */
+	/**
+	 * @param array<string,mixed> $valuesTmp
+	 * @return int|false
+	 */
 	public function updateFeed(int $id, array $valuesTmp) {
 		if (isset($valuesTmp['name'])) {
 			$valuesTmp['name'] = mb_strcut(trim($valuesTmp['name']), 0, FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE, 'UTF-8');
@@ -177,6 +183,10 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
 		}
 	}
 
+	/**
+	 * @param string|array<mixed>|bool|int|null $value
+	 * @return int|false
+	 */
 	public function updateFeedAttribute(FreshRSS_Feed $feed, string $key, $value) {
 		$feed->_attributes($key, $value);
 		return $this->updateFeed(
@@ -186,6 +196,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
 	}
 
 	/**
+	 * @return int|false
 	 * @see updateCachedValue()
 	 */
 	public function updateLastUpdate(int $id, bool $inError = false, int $mtime = 0) {
@@ -206,11 +217,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
 		}
 	}
 
+	/** @return int|false */
 	public function mute(int $id, bool $value = true) {
 		$sql = 'UPDATE `_feed` SET ttl=' . ($value ? '-' : '') . 'ABS(ttl) WHERE id=' . intval($id);
 		return $this->pdo->exec($sql);
 	}
 
+	/** @return int|false */
 	public function changeCategory(int $idOldCat, int $idNewCat) {
 		$catDAO = FreshRSS_Factory::createCategoryDao();
 		$newCat = $catDAO->searchById($idNewCat);
@@ -273,6 +286,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
 		}
 	}
 
+	/** @return iterator<array<string,string|int>> */
 	public function selectAll() {
 		$sql = <<<'SQL'
 SELECT id, url, kind, category, name, website, description, `lastUpdate`,
@@ -295,10 +309,7 @@ SQL;
 		return $feed[$id] ?? null;
 	}
 
-	/**
-	 * @return FreshRSS_Feed|null
-	 */
-	public function searchByUrl(string $url) {
+	public function searchByUrl(string $url): ?FreshRSS_Feed {
 		$sql = 'SELECT * FROM `_feed` WHERE url=?';
 		$stm = $this->pdo->prepare($sql);
 
@@ -310,10 +321,11 @@ SQL;
 		return $feed == false ? null : $feed;
 	}
 
-	public function listFeedsIds(): array {
+	/** @return array<string>|false */
+	public function listFeedsIds() {
 		$sql = 'SELECT id FROM `_feed`';
 		$stm = $this->pdo->query($sql);
-		return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
+		return $stm ? $stm->fetchAll(PDO::FETCH_COLUMN, 0) : false;
 	}
 
 	/**
@@ -325,7 +337,8 @@ SQL;
 		return self::daoToFeed($stm->fetchAll(PDO::FETCH_ASSOC));
 	}
 
-	public function listFeedsNewestItemUsec($id_feed = null) {
+	/** @return array<string,string> */
+	public function listFeedsNewestItemUsec(?int $id_feed = null) {
 		$sql = 'SELECT id_feed, MAX(id) as newest_item_us FROM `_entry` ';
 		if ($id_feed === null) {
 			$sql .= 'GROUP BY id_feed';
@@ -367,6 +380,7 @@ SQL;
 		}
 	}
 
+	/** @return array<string>|false */
 	public function listTitles(int $id, int $limit = 0) {
 		$sql = 'SELECT title FROM `_entry` WHERE id_feed=:id_feed ORDER BY id DESC'
 			. ($limit < 1 ? '' : ' LIMIT ' . intval($limit));
@@ -402,7 +416,7 @@ SQL;
 		return $feeds;
 	}
 
-	public function countEntries(int $id) {
+	public function countEntries(int $id): int {
 		$sql = 'SELECT COUNT(*) AS count FROM `_entry` WHERE id_feed=?';
 		$stm = $this->pdo->prepare($sql);
 		$values = array($id);
@@ -412,7 +426,7 @@ SQL;
 		return $res[0]['count'];
 	}
 
-	public function countNotRead(int $id) {
+	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);
@@ -529,7 +543,7 @@ SQL;
 		return $affected;
 	}
 
-	public function purge() {
+	public function purge(): bool {
 		$sql = 'DELETE FROM `_entry`';
 		$stm = $this->pdo->prepare($sql);
 		$this->pdo->beginTransaction();
@@ -549,13 +563,14 @@ SQL;
 			return false;
 		}
 
-		$this->pdo->commit();
+		return $this->pdo->commit();
 	}
 
 	/**
+	 * @param array<int,array<string,string|int>>|array<string,string|int> $listDAO
 	 * @return array<FreshRSS_Feed>
 	 */
-	public static function daoToFeed($listDAO, $catID = null): array {
+	public static function daoToFeed(array $listDAO, ?int $catID = null): array {
 		$list = array();
 
 		if (!is_array($listDAO)) {
@@ -570,7 +585,7 @@ SQL;
 				$key = $dao['id'];
 			}
 			if ($catID === null) {
-				$category = isset($dao['category']) ? $dao['category'] : 0;
+				$category = $dao['category'] ?? 0;
 			} else {
 				$category = $catID;
 			}
@@ -599,7 +614,7 @@ SQL;
 		return $list;
 	}
 
-	public function updateTTL() {
+	public function updateTTL(): void {
 		$sql = 'UPDATE `_feed` SET ttl=:new_value WHERE ttl=:old_value';
 		$stm = $this->pdo->prepare($sql);
 		if (!($stm && $stm->execute(array(':new_value' => FreshRSS_Feed::TTL_DEFAULT, ':old_value' => -2)))) {

+ 37 - 32
app/Models/TagDAO.php

@@ -6,7 +6,7 @@ class FreshRSS_TagDAO extends Minz_ModelPdo {
 		return 'IGNORE';
 	}
 
-	public function createTagTable() {
+	public function createTagTable(): bool {
 		$ok = false;
 		$hadTransaction = $this->pdo->inTransaction();
 		if ($hadTransaction) {
@@ -42,7 +42,11 @@ class FreshRSS_TagDAO extends Minz_ModelPdo {
 		return false;
 	}
 
-	public function addTag($valuesTmp) {
+	/**
+	 * @param array<string,string|array<string,mixed>> $valuesTmp
+	 * @return int|false
+	 */
+	public function addTag(array $valuesTmp) {
 		// TRIM() gives a text type hint to PostgreSQL
 		// No category of the same name
 		$sql = <<<'SQL'
@@ -63,7 +67,7 @@ SQL;
 		);
 
 		if ($stm && $stm->execute($values) && $stm->rowCount() > 0) {
-			return $this->pdo->lastInsertId('`_tag_id_seq`');
+			return (int)($this->pdo->lastInsertId('`_tag_id_seq`'));
 		} else {
 			$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
 			Minz_Log::error('SQL error addTag: ' . $info[2]);
@@ -71,10 +75,7 @@ SQL;
 		}
 	}
 
-	/**
-	 * @param FreshRSS_Tag $tag
-	 */
-	public function addTagObject($tag) {
+	public function addTagObject(FreshRSS_Tag $tag): int {
 		$tag0 = $this->searchByName($tag->name());
 		if (!$tag0) {
 			$values = array(
@@ -87,9 +88,10 @@ SQL;
 	}
 
 	/**
-	 * @return integer|false
+	 * @param array<string,string|int|array<string,mixed>> $valuesTmp
+	 * @return int|false
 	 */
-	public function updateTag($id, $valuesTmp) {
+	public function updateTag(int $id, array $valuesTmp) {
 		// No category of the same name
 		$sql = <<<'SQL'
 UPDATE `_tag` SET name=?, attributes=? WHERE id=?
@@ -119,23 +121,21 @@ SQL;
 	}
 
 	/**
-	 * @return integer|false
+	 * @param mixed $value
+	 * @return int|false
 	 */
-	public function updateTagAttribute($tag, $key, $value) {
-		if ($tag instanceof FreshRSS_Tag) {
-			$tag->_attributes($key, $value);
-			return $this->updateTag(
-					$tag->id(),
-					[ 'attributes' => $tag->attributes() ]
-				);
-		}
-		return false;
+	public function updateTagAttribute(FreshRSS_Tag $tag, string $key, $value) {
+		$tag->_attributes($key, $value);
+		return $this->updateTag(
+				$tag->id(),
+				[ 'attributes' => $tag->attributes() ]
+			);
 	}
 
 	/**
-	 * @return integer|false
+	 * @return int|false
 	 */
-	public function deleteTag($id) {
+	public function deleteTag(int $id) {
 		if ($id <= 0) {
 			return false;
 		}
@@ -153,6 +153,7 @@ SQL;
 		}
 	}
 
+	/** @return iterator<array{'id':int,'name':string,'attributes':string}> */
 	public function selectAll() {
 		$sql = 'SELECT id, name, attributes FROM `_tag`';
 		$stm = $this->pdo->query($sql);
@@ -161,6 +162,7 @@ SQL;
 		}
 	}
 
+	/** @return iterator<array{'id_tag':int,'id_entry':string}> */
 	public function selectEntryTag() {
 		$sql = 'SELECT id_tag, id_entry FROM `_entrytag`';
 		$stm = $this->pdo->query($sql);
@@ -169,10 +171,8 @@ SQL;
 		}
 	}
 
-	/**
-	 * @return integer|false
-	 */
-	public function updateEntryTag($oldTagId, $newTagId) {
+	/** @return int|false */
+	public function updateEntryTag(int $oldTagId, int $newTagId) {
 		$sql = <<<'SQL'
 DELETE FROM `_entrytag` WHERE EXISTS (
 	SELECT 1 FROM `_entrytag` AS e
@@ -218,7 +218,8 @@ SQL;
 		return isset($tag[0]) ? $tag[0] : null;
 	}
 
-	public function listTags($precounts = false) {
+	/** @return array<FreshRSS_Tag>|false */
+	public function listTags(bool $precounts = false) {
 		if ($precounts) {
 			$sql = 'SELECT t.id, t.name, count(e.id) AS unreads '
 				 . 'FROM `_tag` t '
@@ -243,7 +244,8 @@ SQL;
 		}
 	}
 
-	public function listTagsNewestItemUsec($id_tag = null) {
+	/** @return array<string,string> */
+	public function listTagsNewestItemUsec(?int $id_tag = null) {
 		$sql = 'SELECT t.id AS id_tag, MAX(e.id) AS newest_item_us '
 			 . 'FROM `_tag` t '
 			 . 'LEFT OUTER JOIN `_entrytag` et ON et.id_tag = t.id '
@@ -321,7 +323,7 @@ SQL;
 		}
 	}
 
-	public function tagEntry(int $id_tag, string $id_entry, bool $checked = true) {
+	public function tagEntry(int $id_tag, string $id_entry, bool $checked = true): bool {
 		if ($checked) {
 			$sql = 'INSERT ' . $this->sqlIgnore() . ' INTO `_entrytag`(id_tag, id_entry) VALUES(?, ?)';
 		} else {
@@ -434,13 +436,16 @@ SQL;
 		return $result;
 	}
 
-	/** @return array<FreshRSS_Tag> */
-	private static function daoToTag($listDAO) {
+	/**
+	 * @param array<array<string,string|int>>|array<string,string|int> $listDAO
+	 * @return array<FreshRSS_Tag>
+	 */
+	private static function daoToTag(array $listDAO) {
 		$list = array();
 		if (!is_array($listDAO)) {
 			$listDAO = array($listDAO);
 		}
-		foreach ($listDAO as $key => $dao) {
+		foreach ($listDAO as $dao) {
 			$tag = new FreshRSS_Tag(
 				$dao['name']
 			);
@@ -451,7 +456,7 @@ SQL;
 			if (isset($dao['unreads'])) {
 				$tag->_nbUnread($dao['unreads']);
 			}
-			$list[$key] = $tag;
+			$list[] = $tag;
 		}
 		return $list;
 	}

+ 0 - 3
tests/phpstan-next.txt

@@ -5,9 +5,6 @@
 # find . -type d -name 'vendor' -prune -o -name '*.php' -exec sh -c 'vendor/bin/phpstan analyse --level 6 --memory-limit 512M {} >/dev/null 2>/dev/null || echo {}' \;
 
 ./app/install.php
-./app/Models/CategoryDAO.php
 ./app/Models/Feed.php
-./app/Models/FeedDAO.php
-./app/Models/TagDAO.php
 ./app/Services/ImportService.php
 ./lib/Minz/Paginator.php