PHP 8.3 #[\Override] (#6273)

* PHP 8.3 #[\Override]
https://php.watch/versions/8.3/override-attr

With PHPStan `checkMissingOverrideMethodAttribute` https://phpstan.org/config-reference#checkmissingoverridemethodattribute

And modified the call to phpstan-next on the model of https://github.com/FreshRSS/Extensions/pull/228 (more robust than the find method, which gave some strange errors)

* Update extension example accordingly
This commit is contained in:
Alexandre Alapetite 2024-04-10 15:33:43 +02:00 committed by GitHub
parent 8280e3d88e
commit 350edf398c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 128 additions and 30 deletions

View File

@ -12,6 +12,7 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
* underlying framework.
*
*/
#[\Override]
public function firstAction(): void {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(403);

View File

@ -10,6 +10,7 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
* the common boilerplate for every action. It is triggered by the
* underlying framework.
*/
#[\Override]
public function firstAction(): void {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(403);

View File

@ -16,6 +16,7 @@ class FreshRSS_entry_Controller extends FreshRSS_ActionController {
* the common boilerplate for every action. It is triggered by the
* underlying framework.
*/
#[\Override]
public function firstAction(): void {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(403);

View File

@ -10,6 +10,7 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController {
* the common boiler plate for every action. It is triggered by the
* underlying framework.
*/
#[\Override]
public function firstAction(): void {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(403);

View File

@ -10,6 +10,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
* the common boiler plate for every action. It is triggered by the
* underlying framework.
*/
#[\Override]
public function firstAction(): void {
if (!FreshRSS_Auth::hasAccess()) {
// Token is useful in the case that anonymous refresh is forbidden

View File

@ -15,6 +15,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController {
* the common boilerplate for every action. It is triggered by the
* underlying framework.
*/
#[\Override]
public function firstAction(): void {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(403);

View File

@ -6,6 +6,7 @@ declare(strict_types=1);
*/
class FreshRSS_index_Controller extends FreshRSS_ActionController {
#[\Override]
public function firstAction(): void {
$this->view->html_url = Minz_Url::display(['c' => 'index', 'a' => 'index'], 'html', 'root');
}

View File

@ -12,6 +12,7 @@ class FreshRSS_javascript_Controller extends FreshRSS_ActionController {
parent::__construct(FreshRSS_ViewJavascript::class);
}
#[\Override]
public function firstAction(): void {
$this->view->_layout(null);
}

View File

@ -20,6 +20,7 @@ class FreshRSS_stats_Controller extends FreshRSS_ActionController {
* the common boilerplate for every action. It is triggered by the
* underlying framework.
*/
#[\Override]
public function firstAction(): void {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(403);

View File

@ -10,6 +10,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
* the common boilerplate for every action. It is triggered by the
* underlying framework.
*/
#[\Override]
public function firstAction(): void {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(403);

View File

@ -16,6 +16,7 @@ class FreshRSS_tag_Controller extends FreshRSS_ActionController {
* the common boilerplate for every action. It is triggered by the
* underlying framework.
*/
#[\Override]
public function firstAction(): void {
// If ajax request, we do not print layout
$this->ajax = Minz_Request::paramBoolean('ajax');

View File

@ -113,6 +113,7 @@ class FreshRSS_update_Controller extends FreshRSS_ActionController {
return $return == 0 ? true : 'Git error: ' . $line;
}
#[\Override]
public function firstAction(): void {
if (!FreshRSS_Auth::hasAccess('admin')) {
Minz_Error::error(403);

View File

@ -291,6 +291,7 @@ class FreshRSS_BooleanSearch {
$this->searches[] = $search;
}
#[\Override]
public function __toString(): string {
return $this->getRawInput();
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
class FreshRSS_CategoryDAOSQLite extends FreshRSS_CategoryDAO {
/** @param array<int|string> $errorInfo */
#[\Override]
protected function autoUpdateDb(array $errorInfo): bool {
if ($tableInfo = $this->pdo->query("PRAGMA table_info('category')")) {
$columns = $tableInfo->fetchAll(PDO::FETCH_COLUMN, 1);

View File

@ -10,6 +10,7 @@ class FreshRSS_DatabaseDAOPGSQL extends FreshRSS_DatabaseDAOSQLite {
public const UNDEFINED_COLUMN = '42703';
public const UNDEFINED_TABLE = '42P01';
#[\Override]
public function tablesAreCorrect(): bool {
$db = FreshRSS_Context::systemConf()->db;
$sql = 'SELECT * FROM pg_catalog.pg_tables where tableowner=:tableowner';
@ -34,6 +35,7 @@ class FreshRSS_DatabaseDAOPGSQL extends FreshRSS_DatabaseDAOSQLite {
}
/** @return array<array<string,string|int|bool|null>> */
#[\Override]
public function getSchema(string $table): array {
$sql = <<<'SQL'
SELECT column_name AS field, data_type AS type, column_default AS default, is_nullable AS null
@ -47,6 +49,7 @@ SQL;
* @param array<string,string|int|bool|null> $dao
* @return array{'name':string,'type':string,'notnull':bool,'default':mixed}
*/
#[\Override]
public function daoToSchema(array $dao): array {
return [
'name' => (string)($dao['field']),
@ -56,6 +59,7 @@ SQL;
];
}
#[\Override]
public function size(bool $all = false): int {
if ($all) {
$db = FreshRSS_Context::systemConf()->db;
@ -75,7 +79,7 @@ SQL;
return (int)($res[0] ?? -1);
}
#[\Override]
public function optimize(): bool {
$ok = true;
$tables = ['category', 'feed', 'entry', 'entrytmp', 'tag', 'entrytag'];

View File

@ -6,6 +6,7 @@ declare(strict_types=1);
*/
class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
#[\Override]
public function tablesAreCorrect(): bool {
$sql = 'SELECT name FROM sqlite_master WHERE type="table"';
$stm = $this->pdo->query($sql);
@ -30,18 +31,21 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
}
/** @return array<array<string,string|int|bool|null>> */
#[\Override]
public function getSchema(string $table): array {
$sql = 'PRAGMA table_info(' . $table . ')';
$stm = $this->pdo->query($sql);
return $stm ? $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC) ?: []) : [];
}
#[\Override]
public function entryIsCorrect(): bool {
return $this->checkTable('entry', [
'id', 'guid', 'title', 'author', 'content', 'link', 'date', 'lastSeen', 'hash', 'is_read', 'is_favorite', 'id_feed', 'tags',
]);
}
#[\Override]
public function entrytmpIsCorrect(): bool {
return $this->checkTable('entrytmp', [
'id', 'guid', 'title', 'author', 'content', 'link', 'date', 'lastSeen', 'hash', 'is_read', 'is_favorite', 'id_feed', 'tags'
@ -52,6 +56,7 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
* @param array<string,string|int|bool|null> $dao
* @return array{'name':string,'type':string,'notnull':bool,'default':mixed}
*/
#[\Override]
public function daoToSchema(array $dao): array {
return [
'name' => (string)$dao['name'],
@ -61,6 +66,7 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
];
}
#[\Override]
public function size(bool $all = false): int {
$sum = 0;
if ($all) {
@ -73,6 +79,7 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
return $sum;
}
#[\Override]
public function optimize(): bool {
$ok = $this->pdo->exec('VACUUM') !== false;
if (!$ok) {

View File

@ -3,23 +3,28 @@ declare(strict_types=1);
class FreshRSS_EntryDAOPGSQL extends FreshRSS_EntryDAOSQLite {
#[\Override]
public static function hasNativeHex(): bool {
return true;
}
#[\Override]
public static function sqlHexDecode(string $x): string {
return 'decode(' . $x . ", 'hex')";
}
#[\Override]
public static function sqlHexEncode(string $x): string {
return 'encode(' . $x . ", 'hex')";
}
#[\Override]
public static function sqlIgnoreConflict(string $sql): string {
return rtrim($sql, ' ;') . ' ON CONFLICT DO NOTHING';
}
/** @param array<string|int> $errorInfo */
#[\Override]
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) {
@ -34,6 +39,7 @@ class FreshRSS_EntryDAOPGSQL extends FreshRSS_EntryDAOSQLite {
return false;
}
#[\Override]
public function commitNewEntries(): bool {
//TODO: Update to PostgreSQL 9.5+ syntax with ON CONFLICT DO NOTHING
$sql = 'DO $$

View File

@ -3,27 +3,33 @@ declare(strict_types=1);
class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO {
#[\Override]
public static function isCompressed(): bool {
return false;
}
#[\Override]
public static function hasNativeHex(): bool {
return false;
}
#[\Override]
protected static function sqlConcat(string $s1, string $s2): string {
return $s1 . '||' . $s2;
}
#[\Override]
public static function sqlHexDecode(string $x): string {
return $x;
}
#[\Override]
public static function sqlIgnoreConflict(string $sql): string {
return str_replace('INSERT INTO ', 'INSERT OR IGNORE INTO ', $sql);
}
/** @param array<string|int> $errorInfo */
#[\Override]
protected function autoUpdateDb(array $errorInfo): bool {
if ($tableInfo = $this->pdo->query("PRAGMA table_info('entry')")) {
$columns = $tableInfo->fetchAll(PDO::FETCH_COLUMN, 1) ?: [];
@ -36,6 +42,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO {
return false;
}
#[\Override]
public function commitNewEntries(): bool {
$sql = <<<'SQL'
DROP TABLE IF EXISTS `tmp`;
@ -74,6 +81,7 @@ SQL;
* @param bool $is_read
* @return int|false affected rows
*/
#[\Override]
public function markRead($ids, bool $is_read = true) {
FreshRSS_UserDAO::touch();
if (is_array($ids)) { //Many IDs at once (used by API)
@ -119,6 +127,7 @@ SQL;
* @param string $idMax max article ID
* @return int|false affected rows
*/
#[\Override]
public function markReadTag($id = 0, string $idMax = '0', ?FreshRSS_BooleanSearch $filters = null, int $state = 0, bool $is_read = true) {
FreshRSS_UserDAO::touch();
if ($idMax == 0) {

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
class FreshRSS_FeedDAOSQLite extends FreshRSS_FeedDAO {
/** @param array<int|string> $errorInfo */
#[\Override]
protected function autoUpdateDb(array $errorInfo): bool {
if ($tableInfo = $this->pdo->query("PRAGMA table_info('feed')")) {
$columns = $tableInfo->fetchAll(PDO::FETCH_COLUMN, 1);

View File

@ -107,6 +107,7 @@ class FreshRSS_Search {
$this->parseSearch($input);
}
#[\Override]
public function __toString(): string {
return $this->getRawInput();
}

View File

@ -9,6 +9,7 @@ class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO {
* @param int $feed id
* @return array<int,int>
*/
#[\Override]
public function calculateEntryRepartitionPerFeedPerHour(?int $feed = null): array {
return $this->calculateEntryRepartitionPerFeedPerPeriod('hour', $feed);
}
@ -17,6 +18,7 @@ class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO {
* Calculates the number of article per day of week per feed
* @return array<int,int>
*/
#[\Override]
public function calculateEntryRepartitionPerFeedPerDayOfWeek(?int $feed = null): array {
return $this->calculateEntryRepartitionPerFeedPerPeriod('day', $feed);
}
@ -25,6 +27,7 @@ class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO {
* Calculates the number of article per month per feed
* @return array<int,int>
*/
#[\Override]
public function calculateEntryRepartitionPerFeedPerMonth(?int $feed = null): array {
return $this->calculateEntryRepartitionPerFeedPerPeriod('month', $feed);
}
@ -34,6 +37,7 @@ class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO {
* @param string $period format string to use for grouping
* @return array<int,int>
*/
#[\Override]
protected function calculateEntryRepartitionPerFeedPerPeriod(string $period, ?int $feed = null): array {
$restrict = '';
if ($feed) {

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO {
#[\Override]
protected function sqlFloor(string $s): string {
return "CAST(($s) AS INT)";
}
@ -10,6 +11,7 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO {
/**
* @return array<int,int>
*/
#[\Override]
protected function calculateEntryRepartitionPerFeedPerPeriod(string $period, ?int $feed = null): array {
if ($feed) {
$restrict = "WHERE e.id_feed = {$feed}";

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
class FreshRSS_TagDAOPGSQL extends FreshRSS_TagDAO {
#[\Override]
public function sqlIgnore(): string {
return ''; //TODO
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
class FreshRSS_TagDAOSQLite extends FreshRSS_TagDAO {
#[\Override]
public function sqlIgnore(): string {
return 'OR IGNORE';
}

View File

@ -22,6 +22,7 @@ class I18nCompletionValidator implements I18nValidatorInterface {
$this->language = $language;
}
#[\Override]
public function displayReport(): string {
if ($this->passEntries > $this->totalEntries) {
throw new \RuntimeException('The number of translated strings cannot be higher than the number of strings');
@ -32,10 +33,12 @@ class I18nCompletionValidator implements I18nValidatorInterface {
return sprintf('Translation is %5.1f%% complete.', $this->passEntries / $this->totalEntries * 100) . PHP_EOL;
}
#[\Override]
public function displayResult(): string {
return $this->result;
}
#[\Override]
public function validate(): bool {
foreach ($this->reference as $file => $data) {
foreach ($data as $refKey => $refValue) {

View File

@ -22,6 +22,7 @@ class I18nUsageValidator implements I18nValidatorInterface {
$this->reference = $reference;
}
#[\Override]
public function displayReport(): string {
if ($this->failedEntries > $this->totalEntries) {
throw new \RuntimeException('The number of unused strings cannot be higher than the number of strings');
@ -32,10 +33,12 @@ class I18nUsageValidator implements I18nValidatorInterface {
return sprintf('%5.1f%% of translation keys are unused.', $this->failedEntries / $this->totalEntries * 100) . PHP_EOL;
}
#[\Override]
public function displayResult(): string {
return $this->result;
}
#[\Override]
public function validate(): bool {
foreach ($this->reference as $file => $data) {
foreach ($data as $key => $value) {

View File

@ -66,6 +66,7 @@ class I18nValue {
}
}
#[\Override]
public function __toString(): string {
if ($this->state === null) {
return $this->value;

View File

@ -69,7 +69,7 @@
"phpcs": "phpcs . -s",
"phpcbf": "phpcbf . -p -s",
"phpstan": "phpstan analyse --memory-limit 512M .",
"phpstan-next": "phpstan analyse --level 9 --memory-limit 512M $(find . -type d -name 'vendor' -prune -o -name '*.php' -o -name '*.phtml' | grep -Fxvf ./tests/phpstan-next.txt | sort | paste -s -)",
"phpstan-next": "phpstan analyse --memory-limit 512M -c phpstan-next.neon .",
"phpunit": "phpunit --bootstrap ./tests/bootstrap.php --verbose ./tests",
"translations": "cli/manipulate.translation.php -a format",
"test": [

14
composer.lock generated
View File

@ -428,21 +428,21 @@
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "1.5.2",
"version": "1.5.3",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "7a50e9662ee9f3942e4aaaf3d603653f60282542"
"reference": "568210bd301f94a0d4b1e5a0808c374c1b9cf11b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/7a50e9662ee9f3942e4aaaf3d603653f60282542",
"reference": "7a50e9662ee9f3942e4aaaf3d603653f60282542",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/568210bd301f94a0d4b1e5a0808c374c1b9cf11b",
"reference": "568210bd301f94a0d4b1e5a0808c374c1b9cf11b",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.10.34"
"phpstan/phpstan": "^1.10.60"
},
"require-dev": {
"nikic/php-parser": "^4.13.0",
@ -471,9 +471,9 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.2"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.3"
},
"time": "2023-10-30T14:35:06+00:00"
"time": "2024-04-06T07:43:25+00:00"
},
{
"name": "phpunit/php-code-coverage",

View File

@ -132,15 +132,26 @@ The `Minz_Extension` abstract class defines another set of methods that should n
You can register at the FreshRSS event system in an extensions `init()` method, to manipulate data when some of the core functions are executed.
```php
class HelloWorldExtension extends Minz_Extension
final class HelloWorldExtension extends Minz_Extension
{
#[\Override]
public function init(): void {
$this->registerHook('entry_before_display', [$this, 'renderEntry']);
$this->registerHook('check_url_before_add', [self::class, 'checkUrl']);
}
public function renderEntry(FreshRSS_Entry $entry): FreshRSS_Entry {
$entry->_content('<h1>Hello World</h1>' . $entry->content());
$message = $this->getUserConfigurationValue('message');
$entry->_content("<h1>{$message}</h1>" . $entry->content());
return $entry;
}
public static function checkUrlBeforeAdd(string $url): string {
if (str_starts_with($url, 'https://')) {
return $url;
}
return null;
}
}
```

View File

@ -188,15 +188,26 @@ You can register at the FreshRSS event system in an extensions `init()`
method, to manipulate data when some of the core functions are executed.
```php
class HelloWorldExtension extends Minz_Extension
final class HelloWorldExtension extends Minz_Extension
{
#[\Override]
public function init(): void {
$this->registerHook('entry_before_display', [$this, 'renderEntry']);
$this->registerHook('check_url_before_add', [self::class, 'checkUrl']);
}
public function renderEntry(FreshRSS_Entry $entry): FreshRSS_Entry {
$entry->_content('<h1>Hello World</h1>' . $entry->content());
$message = $this->getUserConfigurationValue('message');
$entry->_content("<h1>{$message}</h1>" . $entry->content());
return $entry;
}
public static function checkUrlBeforeAdd(string $url): string {
if (str_starts_with($url, 'https://')) {
return $url;
}
return null;
}
}
```

View File

@ -43,6 +43,7 @@ abstract class Minz_Pdo extends PDO {
* @return string|false
* @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION`
*/
#[\Override]
#[\ReturnTypeWillChange]
public function lastInsertId($name = null) {
if ($name != null) {
@ -59,6 +60,7 @@ abstract class Minz_Pdo extends PDO {
* @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION`
* @phpstan-ignore-next-line
*/
#[\Override]
#[\ReturnTypeWillChange]
public function prepare($query, $options = []) {
$query = $this->preSql($query);
@ -72,6 +74,7 @@ abstract class Minz_Pdo extends PDO {
* @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION`
* @phpstan-ignore-next-line
*/
#[\Override]
#[\ReturnTypeWillChange]
public function exec($statement) {
$statement = $this->preSql($statement);
@ -83,6 +86,7 @@ abstract class Minz_Pdo extends PDO {
* @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION`
* @phpstan-ignore-next-line
*/
#[\Override]
#[\ReturnTypeWillChange]
public function query(string $query, ?int $fetch_mode = null, ...$fetch_mode_args) {
$query = $this->preSql($query);

View File

@ -16,6 +16,7 @@ class Minz_PdoMysql extends Minz_Pdo {
$this->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
}
#[\Override]
public function dbType(): string {
return 'mysql';
}
@ -25,6 +26,7 @@ class Minz_PdoMysql extends Minz_Pdo {
* @return string|false
* @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION`
*/
#[\Override]
#[\ReturnTypeWillChange]
public function lastInsertId($name = null) {
return parent::lastInsertId(); //We discard the name, only used by PostgreSQL

View File

@ -16,10 +16,12 @@ class Minz_PdoPgsql extends Minz_Pdo {
$this->exec("SET NAMES 'UTF8';");
}
#[\Override]
public function dbType(): string {
return 'pgsql';
}
#[\Override]
protected function preSql(string $statement): string {
$statement = parent::preSql($statement);
return str_replace(array('`', ' LIKE '), array('"', ' ILIKE '), $statement);

View File

@ -16,6 +16,7 @@ class Minz_PdoSqlite extends Minz_Pdo {
$this->exec('PRAGMA foreign_keys = ON;');
}
#[\Override]
public function dbType(): string {
return 'sqlite';
}
@ -25,6 +26,7 @@ class Minz_PdoSqlite extends Minz_Pdo {
* @return string|false
* @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION`
*/
#[\Override]
#[\ReturnTypeWillChange]
public function lastInsertId($name = null) {
return parent::lastInsertId(); //We discard the name, only used by PostgreSQL

2
package-lock.json generated
View File

@ -14,7 +14,7 @@
"eslint-plugin-promise": "^6.1.1",
"markdownlint-cli": "^0.39.0",
"rtlcss": "^4.1.1",
"sass": "^1.72.0",
"sass": "^1.74.1",
"stylelint": "^15.11.0",
"stylelint-config-recommended-scss": "^13.1.0",
"stylelint-order": "^6.0.4",

View File

@ -40,7 +40,7 @@
"eslint-plugin-promise": "^6.1.1",
"markdownlint-cli": "^0.39.0",
"rtlcss": "^4.1.1",
"sass": "^1.72.0",
"sass": "^1.74.1",
"stylelint": "^15.11.0",
"stylelint-config-recommended-scss": "^13.1.0",
"stylelint-order": "^6.0.4",

18
phpstan-next.neon Normal file
View File

@ -0,0 +1,18 @@
includes:
- phpstan.neon
parameters:
level: 9
excludePaths:
analyse:
# TODO: Update files below and remove them from this list
- app/Controllers/configureController.php
- app/Controllers/importExportController.php
- app/Models/DatabaseDAO.php
- app/Models/Entry.php
- app/Models/Feed.php
- app/Services/ImportService.php
- app/views/configure/archiving.phtml
- app/views/helpers/feed/update.phtml
- lib/Minz/Helper.php
- lib/Minz/Request.php

View File

@ -35,6 +35,7 @@ parameters:
- STDOUT
- TMP_PATH
- USERS_PATH
checkMissingOverrideMethodAttribute: true
reportMaybesInPropertyPhpDocTypes: false
treatPhpDocTypesAsCertain: false
strictRules:

View File

@ -10,6 +10,7 @@ class LogDAOTest extends TestCase {
private string $logPath;
#[\Override]
protected function setUp(): void {
$this->logDAO = new FreshRSS_LogDAO();
$this->logPath = FreshRSS_LogDAO::logPath(self::LOG_FILE_TEST);
@ -36,6 +37,7 @@ class LogDAOTest extends TestCase {
self::assertStringContainsString('', file_get_contents($this->logPath) ?: '');
}
#[\Override]
protected function tearDown(): void {
unlink($this->logPath);
}

View File

@ -7,6 +7,7 @@ class I18nCompletionValidatorTest extends PHPUnit\Framework\TestCase {
/** @var I18nValue&PHPUnit\Framework\MockObject\MockObject */
private $value;
#[\Override]
public function setUp(): void {
$this->value = $this->getMockBuilder(I18nValue::class)
->disableOriginalConstructor()

View File

@ -9,6 +9,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
/** @var I18nValue&PHPUnit\Framework\MockObject\MockObject */
private $value;
#[\Override]
public function setUp(): void {
$this->value = $this->getMockBuilder(I18nValue::class)
->disableOriginalConstructor()

View File

@ -7,6 +7,7 @@ class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase {
private I18nValue $value;
#[\Override]
public function setUp(): void {
$this->value = $this->getMockBuilder(I18nValue::class)
->disableOriginalConstructor()

View File

@ -1,15 +0,0 @@
# List of files, which are not yet passing PHPStan level 9 https://phpstan.org/user-guide/rule-levels
# Used for automated tests to avoid regressions in files already passing that level.
# Can be regenerated with something like:
# find . -type d -name 'vendor' -prune -o -name '*.php' -exec sh -c 'vendor/bin/phpstan analyse --level 9 --memory-limit 512M {} >/dev/null 2>/dev/null || echo {}' \;
./app/Controllers/configureController.php
./app/Controllers/importExportController.php
./app/Models/DatabaseDAO.php
./app/Models/Entry.php
./app/Models/Feed.php
./app/Services/ImportService.php
./app/views/configure/archiving.phtml
./app/views/helpers/feed/update.phtml
./lib/Minz/Helper.php
./lib/Minz/Request.php