diff options
75 files changed, 596 insertions, 958 deletions
diff --git a/Docker/Dockerfile-Oldest b/Docker/Dockerfile-Oldest index ee478c2cd..9227e53f4 100644 --- a/Docker/Dockerfile-Oldest +++ b/Docker/Dockerfile-Oldest @@ -1,14 +1,14 @@ -FROM alpine:3.13 +FROM alpine:3.16 ENV TZ UTC SHELL ["/bin/ash", "-eo", "pipefail", "-c"] RUN apk add --no-cache \ tzdata \ - apache2 php7-apache2 \ - php7 php7-curl php7-gmp php7-intl php7-mbstring php7-xml php7-zip \ - php7-ctype php7-dom php7-fileinfo php7-iconv php7-json php7-opcache php7-openssl php7-phar php7-session php7-simplexml php7-xmlreader php7-xmlwriter php7-xml php7-tokenizer php7-zlib \ - php7-pdo_sqlite php7-pdo_mysql php7-pdo_pgsql + apache2 php81-apache2 \ + php81 php81-curl php81-gmp php81-intl php81-mbstring php81-xml php81-zip \ + php81-ctype php81-dom php81-fileinfo php81-iconv php81-json php81-opcache php81-openssl php81-phar php81-session php81-simplexml php81-xmlreader php81-xmlwriter php81-xml php81-tokenizer php81-zlib \ + php81-pdo_sqlite php81-pdo_mysql php81-pdo_pgsql RUN mkdir -p /var/www/FreshRSS /run/apache2/ WORKDIR /var/www/FreshRSS @@ -39,8 +39,8 @@ RUN rm -f /etc/apache2/conf.d/languages.conf /etc/apache2/conf.d/info.conf \ /etc/apache2/httpd.conf && \ sed -r -i "/^\s*(CustomLog|ErrorLog|Listen) /s/^/#/" \ /etc/apache2/httpd.conf && \ - if [ ! -f /usr/bin/php ]; then ln -s /usr/bin/php7 /usr/bin/php; else true; fi && \ - echo 'memory_limit = 256M' > /etc/php7/conf.d/10_memory.ini && \ + if [ ! -f /usr/bin/php ]; then ln -s /usr/bin/php81 /usr/bin/php; else true; fi && \ + echo 'memory_limit = 256M' > /etc/php81/conf.d/10_memory.ini && \ # Disable built-in updates when using Docker, as the full image is supposed to be updated instead. sed -r -i "\\#disable_update#s#^.*#\t'disable_update' => true,#" ./config.default.php && \ touch /var/www/FreshRSS/Docker/env.txt && \ diff --git a/README.fr.md b/README.fr.md index ca9b6bc06..ad592227e 100644 --- a/README.fr.md +++ b/README.fr.md @@ -62,7 +62,7 @@ FreshRSS n’est fourni avec aucune garantie. * Serveur modeste, par exemple sous Linux ou Windows * Fonctionne même sur un Raspberry Pi 1 avec des temps de réponse < 1s (testé sur 150 flux, 22k articles) * Serveur Web Apache2.4+ (recommandé), ou nginx, lighttpd (non testé sur les autres) -* PHP 7.4+ +* PHP 8.1+ * Extensions requises : [cURL](https://www.php.net/curl), [DOM](https://www.php.net/dom), [JSON](https://www.php.net/json), [XML](https://www.php.net/xml), [session](https://www.php.net/session), [ctype](https://www.php.net/ctype) * Extensions recommandées : [PDO_SQLite](https://www.php.net/pdo-sqlite) (pour l’export/import), [GMP](https://www.php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](https://www.php.net/intl.idn) (pour les noms de domaines internationalisés), [mbstring](https://www.php.net/mbstring) (pour le texte Unicode), [iconv](https://www.php.net/iconv) (pour conversion d’encodages), [ZIP](https://www.php.net/zip) (pour import/export), [zlib](https://www.php.net/zlib) (pour les flux compressés) * Extension pour base de données : [PDO_PGSQL](https://www.php.net/pdo-pgsql) ou [PDO_SQLite](https://www.php.net/pdo-sqlite) ou [PDO_MySQL](https://www.php.net/pdo-mysql) @@ -62,7 +62,7 @@ FreshRSS comes with absolutely no warranty. * Light server running Linux or Windows * It even works on Raspberry Pi 1 with response time under a second (tested with 150 feeds, 22k articles) * A web server: Apache2.4+ (recommended), nginx, lighttpd (not tested on others) -* PHP 7.4+ +* PHP 8.1+ * Required extensions: [cURL](https://www.php.net/curl), [DOM](https://www.php.net/dom), [JSON](https://www.php.net/json), [XML](https://www.php.net/xml), [session](https://www.php.net/session), [ctype](https://www.php.net/ctype) * Recommended extensions: [PDO_SQLite](https://www.php.net/pdo-sqlite) (for export/import), [GMP](https://www.php.net/gmp) (for API access on 32-bit platforms), [IDN](https://www.php.net/intl.idn) (for Internationalized Domain Names), [mbstring](https://www.php.net/mbstring) (for Unicode strings), [iconv](https://www.php.net/iconv) (for charset conversion), [ZIP](https://www.php.net/zip) (for import/export), [zlib](https://www.php.net/zlib) (for compressed feeds) * Extension for database: [PDO_PGSQL](https://www.php.net/pdo-pgsql) or [PDO_SQLite](https://www.php.net/pdo-sqlite) or [PDO_MySQL](https://www.php.net/pdo-mysql) diff --git a/app/Controllers/apiController.php b/app/Controllers/apiController.php index 7c20b630b..585a7a9bb 100644 --- a/app/Controllers/apiController.php +++ b/app/Controllers/apiController.php @@ -9,9 +9,8 @@ class FreshRSS_api_Controller extends FreshRSS_ActionController { /** * Update the user API password. * Return an error message, or `false` if no error. - * @return false|string */ - public static function updatePassword(string $apiPasswordPlain) { + public static function updatePassword(string $apiPasswordPlain): string|false { $username = Minz_User::name(); if ($username == null) { return _t('feedback.api.password.failed'); diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 385bd1e2e..a9304376f 100644 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -479,8 +479,6 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController { * - user category limit (default: 16384) * - user feed limit (default: 16384) * - user login duration for form auth (default: FreshRSS_Auth::DEFAULT_COOKIE_DURATION) - * - * The `force-email-validation` is ignored with PHP < 5.5 */ public function systemAction(): void { if (!FreshRSS_Auth::hasAccess('admin')) { diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index dbdf858a7..42639f5e1 100644 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -755,7 +755,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { * @param int $nbNewEntries The number of top recent entries to process. * @return int|false The number of new labels added, or false in case of error. */ - private static function applyLabelActions(int $nbNewEntries) { + private static function applyLabelActions(int $nbNewEntries): int|false { $tagDAO = FreshRSS_Factory::createTagDao(); $labels = FreshRSS_Context::labels(); $labels = array_filter($labels, static function (FreshRSS_Tag $label) { diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 2dc25fa2f..c4f64337b 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -33,10 +33,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { FreshRSS_View::prependTitle(_t('sub.import_export.title') . ' · '); } - /** - * @return float|int|string - */ - private static function megabytes(string $size_str) { + private static function megabytes(string $size_str): float|int|string { switch (substr($size_str, -1)) { case 'M': case 'm': @@ -51,10 +48,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { return $size_str; } - /** - * @param string|int $mb - */ - private static function minimumMemory($mb): void { + private static function minimumMemory(int|string $mb): void { $mb = (int)$mb; $ini = self::megabytes(ini_get('memory_limit') ?: '0'); if ($ini < $mb) { @@ -240,11 +234,8 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { return 'unknown'; } - /** - * @return false|string - */ - private function ttrssXmlToJson(string $xml) { - $table = (array)simplexml_load_string($xml, null, LIBXML_NOBLANKS | LIBXML_NOCDATA); + private function ttrssXmlToJson(string $xml): string|false { + $table = (array)simplexml_load_string($xml, options: LIBXML_NOBLANKS | LIBXML_NOCDATA); $table['items'] = $table['article'] ?? []; unset($table['article']); for ($i = count($table['items']) - 1; $i >= 0; $i--) { diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index f07ed338b..e5bf276cd 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -93,7 +93,7 @@ class FreshRSS_update_Controller extends FreshRSS_ActionController { } /** @return string|true */ - public static function gitPull() { + public static function gitPull(): string|bool { Minz_Log::notice(_t('admin.update.viaGit')); $cwd = getcwd(); if ($cwd === false) { diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index da770ade7..b101f0b3f 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -100,9 +100,8 @@ 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 - * @return int|false */ - public function addCategory(array $valuesTmp) { + public function addCategory(array $valuesTmp): int|false { // TRIM() to provide a type hint as text // No tag of the same name $sql = <<<'SQL' @@ -136,8 +135,7 @@ SQL; } } - /** @return int|false */ - public function addCategoryObject(FreshRSS_Category $category) { + public function addCategoryObject(FreshRSS_Category $category): int|false { $cat = $this->searchByName($category->name()); if (!$cat) { $values = [ @@ -153,9 +151,8 @@ SQL; /** * @param array{'name':string,'kind':int,'attributes'?:array<string,mixed>|mixed|null} $valuesTmp - * @return int|false */ - public function updateCategory(int $id, array $valuesTmp) { + public function updateCategory(int $id, array $valuesTmp): int|false { // No tag of the same name $sql = <<<'SQL' UPDATE `_category` SET name=?, kind=?, attributes=? WHERE id=? @@ -187,8 +184,7 @@ SQL; } } - /** @return int|false */ - public function updateLastUpdate(int $id, bool $inError = false, int $mtime = 0) { + public function updateLastUpdate(int $id, bool $inError = false, int $mtime = 0): int|false { $sql = 'UPDATE `_category` SET `lastUpdate`=?, error=? WHERE id=?'; $values = [ $mtime <= 0 ? time() : $mtime, @@ -206,8 +202,7 @@ SQL; } } - /** @return int|false */ - public function deleteCategory(int $id) { + public function deleteCategory(int $id): int|false { if ($id <= self::DEFAULTCATEGORYID) { return false; } @@ -345,8 +340,7 @@ SQL; } } - /** @return int|bool */ - public function checkDefault() { + public function checkDefault(): int|bool { $def_cat = $this->searchById(self::DEFAULTCATEGORYID); if ($def_cat == null) { diff --git a/app/Models/Context.php b/app/Models/Context.php index 988eedc71..8634b5e71 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -274,7 +274,7 @@ final class FreshRSS_Context { * @phpstan-return ($asArray is true ? array{'a'|'c'|'f'|'i'|'s'|'t'|'T',bool|int} : string) * @return string|array{string,bool|int} */ - public static function currentGet(bool $asArray = false) { + public static function currentGet(bool $asArray = false): string|array { if (self::$current_get['all']) { return $asArray ? ['a', true] : 'a'; } elseif (self::$current_get['important']) { diff --git a/app/Models/Entry.php b/app/Models/Entry.php index f2701fb68..4b331419b 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -32,13 +32,10 @@ class FreshRSS_Entry extends Minz_Model { private array $tags = []; /** - * @param int|string $pubdate - * @param bool|int|null $is_read - * @param bool|int|null $is_favorite * @param string|array<string> $tags */ public function __construct(int $feedId = 0, string $guid = '', string $title = '', string $authors = '', string $content = '', - string $link = '', $pubdate = 0, $is_read = false, $is_favorite = false, $tags = '') { + string $link = '', int|string $pubdate = 0, bool|int|null $is_read = false, bool|int|null $is_favorite = false, $tags = '') { $this->_title($title); $this->_authors($authors); $this->_content($content); @@ -149,7 +146,7 @@ class FreshRSS_Entry extends Minz_Model { * @phpstan-return ($asString is true ? string : array<string>) * @return string|array<string> */ - public function authors(bool $asString = false) { + public function authors(bool $asString = false): string|array { if ($asString) { return $this->authors == null ? '' : ';' . implode('; ', $this->authors); } else { @@ -384,9 +381,8 @@ HTML; } /** * @phpstan-return ($raw is false ? string : int) - * @return string|int */ - public function date(bool $raw = false) { + public function date(bool $raw = false): int|string { if ($raw) { return $this->date; } @@ -402,9 +398,8 @@ HTML; /** * @phpstan-return ($raw is false ? string : ($microsecond is true ? string : int)) - * @return int|string */ - public function dateAdded(bool $raw = false, bool $microsecond = false) { + public function dateAdded(bool $raw = false, bool $microsecond = false): int|string { if ($raw) { if ($microsecond) { return $this->date_added; @@ -451,7 +446,7 @@ HTML; * @phpstan-return ($asString is true ? string : array<string>) * @return string|array<string> */ - public function tags(bool $asString = false) { + public function tags(bool $asString = false): array|string { if ($asString) { return $this->tags == null ? '' : '#' . implode(' #', $this->tags); } else { @@ -719,9 +714,7 @@ HTML; } } FreshRSS_Context::userConf()->applyFilterActions($this); - if ($feed->category() !== null) { - $feed->category()->applyFilterActions($this); - } + $feed->category()?->applyFilterActions($this); $feed->applyFilterActions($this); } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index a90b98a60..175df15c3 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -291,9 +291,8 @@ SQL; * there is an other way to do that. * * @param numeric-string|array<numeric-string> $ids - * @return int|false */ - public function markFavorite($ids, bool $is_favorite = true) { + public function markFavorite($ids, bool $is_favorite = true): int|false { if (!is_array($ids)) { $ids = [$ids]; } @@ -369,10 +368,9 @@ SQL; * Then the cache is updated. * * @param numeric-string|array<numeric-string> $ids - * @param bool $is_read * @return int|false affected rows */ - public function markRead($ids, bool $is_read = true) { + public function markRead(array|string $ids, bool $is_read = true): int|false { if (is_array($ids)) { //Many IDs at once if (count($ids) < 6) { //Speed heuristics $affected = 0; @@ -438,7 +436,7 @@ SQL; * @param numeric-string $idMax fail safe article ID * @return int|false affected rows */ - public function markReadEntries(string $idMax = '0', bool $onlyFavorites = false, ?int $priorityMin = null, ?int $prioritMax = null, + public function markReadEntries(string $idMax = '0', bool $onlyFavorites = false, ?int $priorityMin = null, ?int $priorityMax = null, ?FreshRSS_BooleanSearch $filters = null, int $state = 0, bool $is_read = true) { FreshRSS_UserDAO::touch(); if ($idMax == '0') { @@ -451,15 +449,15 @@ SQL; if ($onlyFavorites) { $sql .= ' AND is_favorite=1'; } - if ($priorityMin !== null || $prioritMax !== null) { + if ($priorityMin !== null || $priorityMax !== null) { $sql .= ' AND id_feed IN (SELECT f.id FROM `_feed` f WHERE 1=1'; if ($priorityMin !== null) { $sql .= ' AND f.priority >= ?'; $values[] = $priorityMin; } - if ($prioritMax !== null) { + if ($priorityMax !== null) { $sql .= ' AND f.priority < ?'; - $values[] = $prioritMax; + $values[] = $priorityMax; } $sql .= ')'; } @@ -490,7 +488,7 @@ SQL; * @param numeric-string $idMax fail safe article ID * @return int|false affected rows */ - public function markReadCat(int $id, string $idMax = '0', ?FreshRSS_BooleanSearch $filters = null, int $state = 0, bool $is_read = true) { + public function markReadCat(int $id, string $idMax = '0', ?FreshRSS_BooleanSearch $filters = null, int $state = 0, bool $is_read = true): int|false { FreshRSS_UserDAO::touch(); if ($idMax == '0') { $idMax = time() . '000000'; @@ -531,7 +529,7 @@ SQL; * @param numeric-string $idMax fail safe article ID * @return int|false affected rows */ - public function markReadFeed(int $id_feed, string $idMax = '0', ?FreshRSS_BooleanSearch $filters = null, int $state = 0, bool $is_read = true) { + public function markReadFeed(int $id_feed, string $idMax = '0', ?FreshRSS_BooleanSearch $filters = null, int $state = 0, bool $is_read = true): int|false { FreshRSS_UserDAO::touch(); if ($idMax == '0') { $idMax = time() . '000000'; @@ -623,9 +621,8 @@ SQL; /** * Remember to call updateCachedValues($id_feed) or updateCachedValues() just after. * @param array<string,bool|int|string> $options - * @return int|false */ - public function cleanOldEntries(int $id_feed, array $options = []) { + public function cleanOldEntries(int $id_feed, array $options = []): int|false { $sql = 'DELETE FROM `_entry` WHERE id_feed = :id_feed1'; //No alias for MySQL / MariaDB $params = []; $params[':id_feed1'] = $id_feed; @@ -1121,12 +1118,11 @@ SQL; * @phpstan-param 'a'|'A'|'s'|'S'|'i'|'c'|'f'|'t'|'T'|'ST' $type * @param 'ASC'|'DESC' $order * @param int $id category/feed/tag ID - * @return PDOStatement|false * @throws FreshRSS_EntriesGetter_Exception */ private function listWhereRaw(string $type = 'a', int $id = 0, int $state = FreshRSS_Entry::STATE_ALL, string $order = 'DESC', int $limit = 1, int $offset = 0, string $firstId = '', ?FreshRSS_BooleanSearch $filters = null, - int $date_min = 0) { + int $date_min = 0): PDOStatement|false { [$values, $sql] = $this->sqlListWhere($type, $id, $state, $order, $limit, $offset, $firstId, $filters, $date_min); if ($order !== 'DESC' && $order !== 'ASC') { @@ -1244,7 +1240,7 @@ SQL; * @param array<string> $guids * @return array<string>|false */ - public function listHashForFeedGuids(int $id_feed, array $guids) { + public function listHashForFeedGuids(int $id_feed, array $guids): array|false { $result = []; if (count($guids) < 1) { return $result; @@ -1283,7 +1279,7 @@ SQL; * @param array<string> $guids * @return int|false The number of affected entries, or false if error */ - public function updateLastSeen(int $id_feed, array $guids, int $mtime = 0) { + public function updateLastSeen(int $id_feed, array $guids, int $mtime = 0): int|false { if (count($guids) < 1) { return 0; } elseif (count($guids) > FreshRSS_DatabaseDAO::MAX_VARIABLE_NUMBER) { @@ -1321,7 +1317,7 @@ SQL; * To be performed just before {@see FreshRSS_FeedDAO::updateLastUpdate()} * @return int|false The number of affected entries, or false in case of error */ - public function updateLastSeenUnchanged(int $id_feed, int $mtime = 0) { + public function updateLastSeenUnchanged(int $id_feed, int $mtime = 0): int|false { $sql = <<<'SQL' UPDATE `_entry` SET `lastSeen` = :mtime WHERE id_feed = :id_feed1 AND `lastSeen` = ( diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index d6364fec9..9c2b37623 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -77,12 +77,11 @@ SQL; * Toggle the read marker on one or more article. * Then the cache is updated. * - * @param string|array<string> $ids - * @param bool $is_read + * @param numeric-string|array<numeric-string> $ids * @return int|false affected rows */ #[\Override] - public function markRead($ids, bool $is_read = true) { + public function markRead(array|string $ids, bool $is_read = true): int|false { if (is_array($ids)) { //Many IDs at once (used by API) //if (true) { //Speed heuristics //TODO: Not implemented yet for SQLite (so always call IDs one by one) $affected = 0; @@ -128,7 +127,7 @@ SQL; * @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) { + public function markReadTag($id = 0, string $idMax = '0', ?FreshRSS_BooleanSearch $filters = null, int $state = 0, bool $is_read = true): int|false { FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 36cc58cfd..6e468e33f 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -116,10 +116,7 @@ class FreshRSS_Feed extends Minz_Model { } public function categoryId(): int { - if ($this->category !== null) { - return $this->category->id() ?: $this->categoryId; - } - return $this->categoryId; + return $this->category?->id() ?: $this->categoryId; } /** @@ -155,7 +152,7 @@ class FreshRSS_Feed extends Minz_Model { * @phpstan-return ($raw is true ? string : array{'username':string,'password':string}) * @return array{'username':string,'password':string}|string */ - public function httpAuth(bool $raw = true) { + public function httpAuth(bool $raw = true): array|string { if ($raw) { return $this->httpAuth; } else { @@ -816,7 +813,7 @@ class FreshRSS_Feed extends Minz_Model { /** * @return int|null The max number of unread articles to keep, or null if disabled. */ - public function keepMaxUnread() { + public function keepMaxUnread(): ?int { $keepMaxUnread = $this->attributeInt('keep_max_n_unread'); if ($keepMaxUnread === null) { $keepMaxUnread = FreshRSS_Context::userConf()->mark_when['max_n_unread']; @@ -827,7 +824,7 @@ class FreshRSS_Feed extends Minz_Model { /** * @return int|false The number of articles marked as read, of false if error */ - public function markAsReadMaxUnread() { + public function markAsReadMaxUnread(): int|false { $keepMaxUnread = $this->keepMaxUnread(); if ($keepMaxUnread === null) { return false; @@ -842,7 +839,7 @@ class FreshRSS_Feed extends Minz_Model { * Remember to call `updateCachedValues($id_feed)` or `updateCachedValues()` just after. * @return int|false the number of lines affected, or false if not applicable */ - public function markAsReadUponGone(bool $upstreamIsEmpty, int $minLastSeen = 0) { + public function markAsReadUponGone(bool $upstreamIsEmpty, int $minLastSeen = 0): int|false { $readUponGone = $this->attributeBoolean('read_upon_gone'); if ($readUponGone === null) { $readUponGone = FreshRSS_Context::userConf()->mark_when['gone']; @@ -868,9 +865,8 @@ class FreshRSS_Feed extends Minz_Model { /** * Remember to call `updateCachedValues($id_feed)` or `updateCachedValues()` just after - * @return int|false */ - public function cleanOldEntries() { + public function cleanOldEntries(): int|false { /** @var array<string,bool|int|string>|null $archiving */ $archiving = $this->attributeArray('archiving'); if ($archiving === null) { @@ -926,7 +922,7 @@ class FreshRSS_Feed extends Minz_Model { } /** @return int|false */ - public function cacheModifiedTime() { + public function cacheModifiedTime(): int|false { $filename = $this->cacheFilename(); clearstatcache(true, $filename); return @filemtime($filename); @@ -977,10 +973,7 @@ class FreshRSS_Feed extends Minz_Model { return false; } - /** - * @return string|false - */ - public function pubSubHubbubPrepare() { + public function pubSubHubbubPrepare(): string|false { $key = ''; if (Minz_Request::serverIsPublic(FreshRSS_Context::systemConf()->base_url) && $this->hubUrl && $this->selfUrl && @is_dir(PSHB_PATH)) { diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 11eef4e90..96a8fc3c5 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -36,9 +36,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { /** * @param array{'url':string,'kind':int,'category':int,'name':string,'website':string,'description':string,'lastUpdate':int,'priority'?:int, * 'pathEntries'?:string,'httpAuth':string,'error':int|bool,'ttl'?:int,'attributes'?:string|array<string|mixed>} $valuesTmp - * @return int|false */ - public function addFeed(array $valuesTmp) { + public function addFeed(array $valuesTmp): int|false { $sql = 'INSERT INTO `_feed` (url, kind, category, name, website, description, `lastUpdate`, priority, `pathEntries`, `httpAuth`, error, ttl, attributes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; $stm = $this->pdo->prepare($sql); @@ -81,8 +80,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { } } - /** @return int|false */ - public function addFeedObject(FreshRSS_Feed $feed) { + public function addFeedObject(FreshRSS_Feed $feed): int|false { // Add feed only if we don’t find it in DB $feed_search = $this->searchByUrl($feed->url()); if (!$feed_search) { @@ -141,9 +139,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { /** * @param array{'url'?:string,'kind'?:int,'category'?:int,'name'?:string,'website'?:string,'description'?:string,'lastUpdate'?:int,'priority'?:int, * 'pathEntries'?:string,'httpAuth'?:string,'error'?:int,'ttl'?:int,'attributes'?:string|array<string,mixed>} $valuesTmp $valuesTmp - * @return int|false */ - public function updateFeed(int $id, array $valuesTmp) { + public function updateFeed(int $id, array $valuesTmp): int|false { $values = []; $originalValues = $valuesTmp; if (isset($valuesTmp['name'])) { @@ -191,9 +188,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { /** * @param non-empty-string $key * @param string|array<mixed>|bool|int|null $value - * @return int|false */ - public function updateFeedAttribute(FreshRSS_Feed $feed, string $key, $value) { + public function updateFeedAttribute(FreshRSS_Feed $feed, string $key, $value): int|false { $feed->_attribute($key, $value); return $this->updateFeed( $feed->id(), @@ -202,10 +198,9 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { } /** - * @return int|false * @see updateCachedValues() */ - public function updateLastUpdate(int $id, bool $inError = false, int $mtime = 0) { + public function updateLastUpdate(int $id, bool $inError = false, int $mtime = 0): int|false { $sql = 'UPDATE `_feed` SET `lastUpdate`=?, error=? WHERE id=?'; $values = [ $mtime <= 0 ? time() : $mtime, @@ -223,14 +218,12 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { } } - /** @return int|false */ - public function mute(int $id, bool $value = true) { + public function mute(int $id, bool $value = true): int|false { $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) { + public function changeCategory(int $idOldCat, int $idNewCat): int|false { $catDAO = FreshRSS_Factory::createCategoryDao(); $newCat = $catDAO->searchById($idNewCat); if ($newCat === null) { @@ -257,8 +250,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { } } - /** @return int|false */ - public function deleteFeed(int $id) { + public function deleteFeed(int $id): int|false { $sql = 'DELETE FROM `_feed` WHERE id=?'; $stm = $this->pdo->prepare($sql); @@ -275,9 +267,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { /** * @param bool|null $muted to include only muted feeds - * @return int|false */ - public function deleteFeedByCategory(int $id, ?bool $muted = null) { + public function deleteFeedByCategory(int $id, ?bool $muted = null): int|false { $sql = 'DELETE FROM `_feed` WHERE category=?'; if ($muted) { $sql .= ' AND ttl < 0'; @@ -454,9 +445,8 @@ SQL; /** * Update cached values for selected feeds, or all feeds if no feed ID is provided. - * @return int|false */ - public function updateCachedValues(int ...$feedIds) { + public function updateCachedValues(int ...$feedIds): int|false { //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE $sql = <<<SQL UPDATE `_feed` @@ -480,7 +470,7 @@ SQL; * Remember to call updateCachedValues() after calling this function * @return int|false number of lines affected or false in case of error */ - public function markAsReadMaxUnread(int $id, int $n) { + public function markAsReadMaxUnread(int $id, int $n): int|false { //Double SELECT for MySQL workaround ERROR 1093 (HY000) $sql = <<<'SQL' UPDATE `_entry` SET is_read=1 @@ -509,7 +499,7 @@ SQL; * Remember to call updateCachedValues() after calling this function * @return int|false number of lines affected or false in case of error */ - public function markAsReadNotSeen(int $id, int $minLastSeen) { + public function markAsReadNotSeen(int $id, int $minLastSeen): int|false { $sql = <<<'SQL' UPDATE `_entry` SET is_read=1 WHERE id_feed=:id_feed AND is_read=0 AND (`lastSeen` + 10 < :min_last_seen) @@ -527,10 +517,7 @@ SQL; } } - /** - * @return int|false - */ - public function truncate(int $id) { + public function truncate(int $id): int|false { $sql = 'DELETE FROM `_entry` WHERE id_feed=:id'; $stm = $this->pdo->prepare($sql); $this->pdo->beginTransaction(); diff --git a/app/Models/FormAuth.php b/app/Models/FormAuth.php index a8b4dab8a..5bd6d97bc 100644 --- a/app/Models/FormAuth.php +++ b/app/Models/FormAuth.php @@ -38,8 +38,7 @@ class FreshRSS_FormAuth { return []; } - /** @return string|false */ - private static function renewCookie(string $token) { + private static function renewCookie(string $token): string|false { $token_file = DATA_PATH . '/tokens/' . $token . '.txt'; if (touch($token_file)) { $limits = FreshRSS_Context::systemConf()->limits; @@ -51,8 +50,7 @@ class FreshRSS_FormAuth { return false; } - /** @return string|false */ - public static function makeCookie(string $username, string $password_hash) { + public static function makeCookie(string $username, string $password_hash): string|false { do { $token = sha1(FreshRSS_Context::systemConf()->salt . $username . uniqid('' . mt_rand(), true)); $token_file = DATA_PATH . '/tokens/' . $token . '.txt'; diff --git a/app/Models/Search.php b/app/Models/Search.php index 31b3d8d5a..7eaf741c3 100644 --- a/app/Models/Search.php +++ b/app/Models/Search.php @@ -135,11 +135,11 @@ class FreshRSS_Search { } /** @return array<int>|'*'|null */ - public function getLabelIds() { + public function getLabelIds(): array|string|null { return $this->label_ids; } /** @return array<int>|'*'|null */ - public function getNotLabelIds() { + public function getNotLabelIds(): array|string|null { return $this->not_label_ids; } /** @return array<string>|null */ @@ -242,7 +242,7 @@ class FreshRSS_Search { * @param array<string>|string $value * @return ($value is array ? array<string> : string) */ - private static function decodeSpaces($value) { + private static function decodeSpaces($value): array|string { if (is_array($value)) { for ($i = count($value) - 1; $i >= 0; $i--) { $value[$i] = self::decodeSpaces($value[$i]); diff --git a/app/Models/Share.php b/app/Models/Share.php index 9c8f2084e..2df9dd4d9 100644 --- a/app/Models/Share.php +++ b/app/Models/Share.php @@ -106,9 +106,7 @@ class FreshRSS_Share { * decentralized ones. * @param string $help_url is an optional url to give help on this option. * @param 'GET'|'POST' $method defines the sharing method (GET or POST) - * @param string|null $field * @param 'button'|null $HTMLtag - * @param bool $isDeprecated */ private function __construct(string $type, string $url_transform, array $transforms, string $form_type, string $help_url, string $method, ?string $field, ?string $HTMLtag, bool $isDeprecated = false) { diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 6331e24f2..c9753cf2c 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -31,7 +31,7 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { * * @return array{'total':int,'count_unreads':int,'count_reads':int,'count_favorites':int}|false */ - public function calculateEntryRepartitionPerFeed(?int $feed = null, bool $only_main = false) { + public function calculateEntryRepartitionPerFeed(?int $feed = null, bool $only_main = false): array|false { $filter = ''; if ($only_main) { $filter .= 'AND f.priority = 10'; diff --git a/app/Models/Tag.php b/app/Models/Tag.php index 0ed7c462c..9a3baffcd 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -17,10 +17,7 @@ class FreshRSS_Tag extends Minz_Model { return $this->id; } - /** - * @param int|string $value - */ - public function _id($value): void { + public function _id(int|string $value): void { $this->id = (int)$value; } @@ -40,10 +37,7 @@ class FreshRSS_Tag extends Minz_Model { return $this->nbEntries; } - /** - * @param string|int $value - */ - public function _nbEntries($value): void { + public function _nbEntries(int|string $value): void { $this->nbEntries = (int)$value; } @@ -55,10 +49,7 @@ class FreshRSS_Tag extends Minz_Model { return $this->nbUnread; } - /** - * @param string|int $value - */ - public function _nbUnread($value): void { + public function _nbUnread(int|string $value): void { $this->nbUnread = (int)$value; } } diff --git a/app/Models/TagDAO.php b/app/Models/TagDAO.php index 1feba263e..920a09c2c 100644 --- a/app/Models/TagDAO.php +++ b/app/Models/TagDAO.php @@ -9,9 +9,8 @@ class FreshRSS_TagDAO extends Minz_ModelPdo { /** * @param array{'id'?:int,'name':string,'attributes'?:array<string,mixed>} $valuesTmp - * @return int|false */ - public function addTag(array $valuesTmp) { + public function addTag(array $valuesTmp): int|false { // TRIM() gives a text type hint to PostgreSQL // No category of the same name $sql = <<<'SQL' @@ -41,8 +40,7 @@ SQL; } } - /** @return int|false */ - public function addTagObject(FreshRSS_Tag $tag) { + public function addTagObject(FreshRSS_Tag $tag): int|false { $tag0 = $this->searchByName($tag->name()); if (!$tag0) { $values = [ @@ -54,8 +52,7 @@ SQL; return $tag->id(); } - /** @return int|false */ - public function updateTagName(int $id, string $name) { + public function updateTagName(int $id, string $name): int|false { // No category of the same name $sql = <<<'SQL' UPDATE `_tag` SET name = :name1 WHERE id = :id @@ -79,9 +76,8 @@ SQL; /** * @param array<string,mixed> $attributes - * @return int|false */ - public function updateTagAttributes(int $id, array $attributes) { + public function updateTagAttributes(int $id, array $attributes): int|false { $sql = 'UPDATE `_tag` SET attributes=:attributes WHERE id=:id'; $stm = $this->pdo->prepare($sql); if ($stm !== false && @@ -97,18 +93,13 @@ SQL; /** * @param non-empty-string $key - * @param mixed $value - * @return int|false */ - public function updateTagAttribute(FreshRSS_Tag $tag, string $key, $value) { + public function updateTagAttribute(FreshRSS_Tag $tag, string $key, mixed $value): int|false { $tag->_attribute($key, $value); return $this->updateTagAttributes($tag->id(), $tag->attributes()); } - /** - * @return int|false - */ - public function deleteTag(int $id) { + public function deleteTag(int $id): int|false { if ($id <= 0) { return false; } @@ -155,8 +146,7 @@ SQL; } } - /** @return int|false */ - public function updateEntryTag(int $oldTagId, int $newTagId) { + public function updateEntryTag(int $oldTagId, int $newTagId): int|false { $sql = <<<'SQL' DELETE FROM `_entrytag` WHERE EXISTS ( SELECT 1 FROM `_entrytag` AS e @@ -194,7 +184,7 @@ SQL; } /** @return array<int,FreshRSS_Tag>|false */ - public function listTags(bool $precounts = false) { + public function listTags(bool $precounts = false): array|false { if ($precounts) { $sql = <<<'SQL' SELECT t.id, t.name, count(e.id) AS unreads @@ -304,7 +294,7 @@ SQL; * @param array<array{id_tag:int,id_entry:string}> $addLabels Labels to insert as batch * @return int|false Number of new entries or false in case of error */ - public function tagEntries(array $addLabels) { + public function tagEntries(array $addLabels): int|false { $hasValues = false; $sql = 'INSERT ' . $this->sqlIgnore() . ' INTO `_entrytag`(id_tag, id_entry) VALUES '; foreach ($addLabels as $addLabel) { @@ -332,7 +322,7 @@ SQL; /** * @return array<int,array{'id':int,'name':string,'id_entry':string,'checked':bool}>|false */ - public function getTagsForEntry(string $id_entry) { + public function getTagsForEntry(string $id_entry): array|false { $sql = <<<'SQL' SELECT t.id, t.name, et.id_entry IS NOT NULL as checked FROM `_tag` t @@ -360,7 +350,7 @@ SQL; * @param array<FreshRSS_Entry|numeric-string|array<string,string>> $entries * @return array<array{'id_entry':string,'id_tag':int,'name':string}>|false */ - public function getTagsForEntries(array $entries) { + public function getTagsForEntries(array $entries): array|false { $sql = <<<'SQL' SELECT et.id_entry, et.id_tag, t.name FROM `_tag` t diff --git a/app/Models/Themes.php b/app/Models/Themes.php index 04ce0a36d..055db42e5 100644 --- a/app/Models/Themes.php +++ b/app/Models/Themes.php @@ -31,7 +31,7 @@ class FreshRSS_Themes extends Minz_Model { /** * @return false|array{'id':string,'name':string,'author':string,'description':string,'version':float|string,'files':array<string>,'theme-color'?:string|array{'dark'?:string,'light'?:string,'default'?:string}} */ - public static function get_infos(string $theme_id) { + public static function get_infos(string $theme_id): array|false { $theme_dir = PUBLIC_PATH . self::$themesUrl . $theme_id; if (is_dir($theme_dir)) { $json_filename = $theme_dir . '/metadata.json'; @@ -58,7 +58,7 @@ class FreshRSS_Themes extends Minz_Model { /** * @return false|array{'id':string,'name':string,'author':string,'description':string,'version':float|string,'files':array<string>,'theme-color'?:string|array{'dark'?:string,'light'?:string,'default'?:string}} */ - public static function load(string $theme_id) { + public static function load(string $theme_id): array|false { $infos = self::get_infos($theme_id); if (!$infos) { if ($theme_id !== self::$defaultTheme) { //Fall-back to default theme diff --git a/app/Services/ExportService.php b/app/Services/ExportService.php index 91c8c91e3..ba4042d21 100644 --- a/app/Services/ExportService.php +++ b/app/Services/ExportService.php @@ -16,13 +16,13 @@ class FreshRSS_Export_Service { private FreshRSS_TagDAO $tag_dao; - public const FRSS_NAMESPACE = 'https://freshrss.org/opml'; - public const TYPE_HTML_XPATH = 'HTML+XPath'; - public const TYPE_XML_XPATH = 'XML+XPath'; - public const TYPE_RSS_ATOM = 'rss'; - public const TYPE_JSON_DOTPATH = 'JSON+DotPath'; // Legacy 1.24.0-dev - public const TYPE_JSON_DOTNOTATION = 'JSON+DotNotation'; - public const TYPE_JSONFEED = 'JSONFeed'; + final public const FRSS_NAMESPACE = 'https://freshrss.org/opml'; + final public const TYPE_HTML_XPATH = 'HTML+XPath'; + final public const TYPE_XML_XPATH = 'XML+XPath'; + final public const TYPE_RSS_ATOM = 'rss'; + final public const TYPE_JSON_DOTPATH = 'JSON+DotPath'; // Legacy 1.24.0-dev + final public const TYPE_JSON_DOTNOTATION = 'JSON+DotNotation'; + final public const TYPE_JSONFEED = 'JSONFeed'; /** * Initialize the service for the given user. @@ -87,8 +87,6 @@ class FreshRSS_Export_Service { /** * Generate the entries file content for the given feed. - * @param int $feed_id - * @param int $max_number_entries * @return array{0:string,1:string}|null First item is the filename, second item is the content. * It also can return null if the feed doesn’t exist. */ @@ -124,7 +122,6 @@ class FreshRSS_Export_Service { /** * Generate the entries file content for all the feeds. - * @param int $max_number_entries * @return array<string,string> Keys are filenames and values are contents. */ public function generateAllFeedEntries(int $max_number_entries): array { diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index 11da49217..8060e4d51 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -362,10 +362,8 @@ class FreshRSS_Import_Service { * This method is applied to a list of outlines. It merges the different * list of feeds from several outlines into one array. * - * @param array<array<mixed>> $outlines - * The outlines from which to extract the outlines. - * @param string $parent_category_name - * The name of the parent category of the current outlines. + * @param array<array<mixed>> $outlines The outlines from which to extract the outlines. + * @param string $parent_category_name The name of the parent category of the current outlines. * @return array{0:array<string,array<string,string>>,1:array<string,array<array<string,string>>>} */ private function loadFromOutlines(array $outlines, string $parent_category_name): array { @@ -405,10 +403,8 @@ class FreshRSS_Import_Service { * exists), it will add the outline to an array accessible by its category * name. * - * @param array<mixed> $outline - * The outline from which to extract the categories and feeds outlines. - * @param string $parent_category_name - * The name of the parent category of the current outline. + * @param array<mixed> $outline The outline from which to extract the categories and feeds outlines. + * @param string $parent_category_name The name of the parent category of the current outline. * * @return array{0:array<string,array<string,string>>,1:array<array<string,array<string,string>>>} */ diff --git a/app/Utils/dotNotationUtil.php b/app/Utils/dotNotationUtil.php index 9c44e5312..73addbe74 100644 --- a/app/Utils/dotNotationUtil.php +++ b/app/Utils/dotNotationUtil.php @@ -12,11 +12,8 @@ final class FreshRSS_dotNotation_Util * https://github.com/laravel/framework/blob/10.x/src/Illuminate/Collections/Arr.php#L302-L337 * * @param \ArrayAccess<string,mixed>|array<string,mixed>|mixed $array - * @param string|null $key - * @param mixed $default - * @return mixed */ - public static function get($array, ?string $key, mixed $default = null) { + public static function get($array, ?string $key, mixed $default = null): mixed { if (!static::accessible($array)) { return static::value($default); } @@ -51,7 +48,6 @@ final class FreshRSS_dotNotation_Util * Get a string from an array using "dot" notation. * * @param \ArrayAccess<string,mixed>|array<string,mixed>|mixed $array - * @param string|null $key */ public static function getString($array, ?string $key): ?string { $result = self::get($array, $key, null); @@ -60,11 +56,8 @@ final class FreshRSS_dotNotation_Util /** * Determine whether the given value is array accessible. - * - * @param mixed $value - * @return bool */ - private static function accessible($value): bool { + private static function accessible(mixed $value): bool { return is_array($value) || $value instanceof \ArrayAccess; } @@ -72,8 +65,6 @@ final class FreshRSS_dotNotation_Util * Determine if the given key exists in the provided array. * * @param \ArrayAccess<string,mixed>|array<string,mixed>|mixed $array - * @param string $key - * @return bool */ private static function exists($array, string $key): bool { if ($array instanceof \ArrayAccess) { @@ -85,8 +76,7 @@ final class FreshRSS_dotNotation_Util return false; } - /** @param mixed $value */ - private static function value($value): mixed { + private static function value(mixed $value): mixed { return $value instanceof Closure ? $value() : $value; } diff --git a/app/Utils/feverUtil.php b/app/Utils/feverUtil.php index 571c2bc00..8b06568dd 100644 --- a/app/Utils/feverUtil.php +++ b/app/Utils/feverUtil.php @@ -38,7 +38,7 @@ class FreshRSS_fever_Util { * @return string|false the Fever key, or false if the update failed * @throws FreshRSS_Context_Exception */ - public static function updateKey(string $username, string $passwordPlain) { + public static function updateKey(string $username, string $passwordPlain): string|false { if (!self::checkFeverPath()) { return false; } diff --git a/cli/_cli.php b/cli/_cli.php index 9d9d9c32d..9486405aa 100755 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -20,8 +20,7 @@ Minz_Translate::init('en'); FreshRSS_Context::$isCli = true; -/** @return never */ -function fail(string $message, int $exitCode = 1) { +function fail(string $message, int $exitCode = 1): never { fwrite(STDERR, $message . "\n"); die($exitCode); } @@ -51,8 +50,7 @@ function accessRights(): void { "\t", 'sudo cli/access-permissions.sh', "\n"; } -/** @return never */ -function done(bool $ok = true) { +function done(bool $ok = true): never { if (!$ok) { fwrite(STDERR, (empty($_SERVER['argv'][0]) ? 'Process' : basename($_SERVER['argv'][0])) . ' failed!' . "\n"); } diff --git a/cli/check.translation.php b/cli/check.translation.php index 0da415d85..b452054ed 100755 --- a/cli/check.translation.php +++ b/cli/check.translation.php @@ -102,9 +102,8 @@ function findUsedTranslations(): array { /** * Output help message. - * @return never */ -function checkHelp() { +function checkHelp(): never { $file = str_replace(__DIR__ . '/', '', __FILE__); echo <<<HELP diff --git a/cli/i18n/I18nFile.php b/cli/i18n/I18nFile.php index 8085164c5..5d310d6bf 100644 --- a/cli/i18n/I18nFile.php +++ b/cli/i18n/I18nFile.php @@ -82,7 +82,6 @@ class I18nFile { * Flatten an array of translation * * @param array<string,I18nValue|array<string,I18nValue>> $translation - * @param string $prefix * @return array<string,I18nValue> */ private function flatten(array $translation, string $prefix = ''): array { diff --git a/cli/i18n/I18nValue.php b/cli/i18n/I18nValue.php index 03e7676ae..aa2a670e1 100644 --- a/cli/i18n/I18nValue.php +++ b/cli/i18n/I18nValue.php @@ -32,7 +32,7 @@ class I18nValue { } } - public function __clone() { + public function __clone(): void { $this->markAsTodo(); } diff --git a/composer.json b/composer.json index c654e4db5..f2d27bb1a 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "WebSub" ], "require": { - "php": ">=7.4", + "php": ">=8.1", "ext-ctype": "*", "ext-curl": "*", "ext-dom": "*", @@ -49,18 +49,18 @@ "phpstan/extension-installer": false }, "platform": { - "php": "7.4" + "php": "8.1" } }, "require-dev": { - "php": ">=7.4", + "php": ">=8.1", "ext-phar": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", "phpstan/phpstan": "^1.11", "phpstan/phpstan-phpunit": "^1.4", "phpstan/phpstan-strict-rules": "^1.6", - "phpunit/phpunit": "^9", + "phpunit/phpunit": "^10", "squizlabs/php_codesniffer": "^3.9" }, "scripts": { @@ -70,7 +70,7 @@ "phpcbf": "phpcbf . -p -s", "phpstan": "phpstan analyse --memory-limit 512M .", "phpstan-next": "phpstan analyse --memory-limit 512M -c phpstan-next.neon .", - "phpunit": "phpunit --bootstrap ./tests/bootstrap.php --verbose ./tests", + "phpunit": "phpunit --bootstrap ./tests/bootstrap.php --display-notices ./tests", "translations": "cli/manipulate.translation.php -a format", "test": [ "@php-lint", diff --git a/composer.lock b/composer.lock index 67502ba9b..6d5f7e045 100644 --- a/composer.lock +++ b/composer.lock @@ -4,80 +4,10 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2dcd52d3495f0c8bbca900f58e469323", + "content-hash": "2857227089a97e428fe66e5f6c207e8d", "packages": [], "packages-dev": [ { - "name": "doctrine/instantiator", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.30 || ^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.5.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:15:36+00:00" - }, - { "name": "myclabs/deep-copy", "version": "1.12.0", "source": { @@ -315,16 +245,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "384af967d35b2162f69526c7276acadce534d0e1" + "reference": "d8ed7fffa66de1db0d2972267d8ed1d8fa0fe5a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/384af967d35b2162f69526c7276acadce534d0e1", - "reference": "384af967d35b2162f69526c7276acadce534d0e1", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d8ed7fffa66de1db0d2972267d8ed1d8fa0fe5a2", + "reference": "d8ed7fffa66de1db0d2972267d8ed1d8fa0fe5a2", "shasum": "" }, "require": { @@ -369,7 +299,7 @@ "type": "github" } ], - "time": "2024-08-27T09:18:05+00:00" + "time": "2024-09-03T19:55:22+00:00" }, { "name": "phpstan/phpstan-phpunit", @@ -474,16 +404,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.32", + "version": "10.1.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" + "reference": "7e308268858ed6baedc8704a304727d20bc07c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", - "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77", "shasum": "" }, "require": { @@ -491,18 +421,18 @@ "ext-libxml": "*", "ext-xmlwriter": "*", "nikic/php-parser": "^4.19.1 || ^5.1.0", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.6", - "phpunit/php-text-template": "^2.0.4", - "sebastian/code-unit-reverse-lookup": "^2.0.3", - "sebastian/complexity": "^2.0.3", - "sebastian/environment": "^5.1.5", - "sebastian/lines-of-code": "^1.0.4", - "sebastian/version": "^3.0.2", + "php": ">=8.1", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-text-template": "^3.0.1", + "sebastian/code-unit-reverse-lookup": "^3.0.0", + "sebastian/complexity": "^3.2.0", + "sebastian/environment": "^6.1.0", + "sebastian/lines-of-code": "^2.0.2", + "sebastian/version": "^4.0.1", "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.6" + "phpunit/phpunit": "^10.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -511,7 +441,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "9.2.x-dev" + "dev-main": "10.1.x-dev" } }, "autoload": { @@ -540,7 +470,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" }, "funding": [ { @@ -548,32 +478,32 @@ "type": "github" } ], - "time": "2024-08-22T04:23:01+00:00" + "time": "2024-08-22T04:31:57+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.6", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -600,7 +530,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" }, "funding": [ { @@ -608,28 +539,28 @@ "type": "github" } ], - "time": "2021-12-02T12:48:52+00:00" + "time": "2023-08-31T06:24:48+00:00" }, { "name": "phpunit/php-invoker", - "version": "3.1.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-pcntl": "*" @@ -637,7 +568,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -663,7 +594,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" }, "funding": [ { @@ -671,32 +602,32 @@ "type": "github" } ], - "time": "2020-09-28T05:58:55+00:00" + "time": "2023-02-03T06:56:09+00:00" }, { "name": "phpunit/php-text-template", - "version": "2.0.4", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -722,7 +653,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" }, "funding": [ { @@ -730,32 +662,32 @@ "type": "github" } ], - "time": "2020-10-26T05:33:50+00:00" + "time": "2023-08-31T14:07:24+00:00" }, { "name": "phpunit/php-timer", - "version": "5.0.3", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -781,7 +713,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" }, "funding": [ { @@ -789,24 +721,23 @@ "type": "github" } ], - "time": "2020-10-26T13:16:10+00:00" + "time": "2023-02-03T06:57:52+00:00" }, { "name": "phpunit/phpunit", - "version": "9.6.20", + "version": "10.5.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "49d7820565836236411f5dc002d16dd689cde42f" + "reference": "f069f46840445d37a4e6f0de8c5879598f9c4327" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", - "reference": "49d7820565836236411f5dc002d16dd689cde42f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f069f46840445d37a4e6f0de8c5879598f9c4327", + "reference": "f069f46840445d37a4e6f0de8c5879598f9c4327", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -816,27 +747,26 @@ "myclabs/deep-copy": "^1.12.0", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.31", - "phpunit/php-file-iterator": "^3.0.6", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.4", - "phpunit/php-timer": "^5.0.3", - "sebastian/cli-parser": "^1.0.2", - "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.6", - "sebastian/environment": "^5.1.5", - "sebastian/exporter": "^4.0.6", - "sebastian/global-state": "^5.0.7", - "sebastian/object-enumerator": "^4.0.4", - "sebastian/resource-operations": "^3.0.4", - "sebastian/type": "^3.2.1", - "sebastian/version": "^3.0.2" + "php": ">=8.1", + "phpunit/php-code-coverage": "^10.1.16", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-invoker": "^4.0.0", + "phpunit/php-text-template": "^3.0.1", + "phpunit/php-timer": "^6.0.0", + "sebastian/cli-parser": "^2.0.1", + "sebastian/code-unit": "^2.0.0", + "sebastian/comparator": "^5.0.2", + "sebastian/diff": "^5.1.1", + "sebastian/environment": "^6.1.0", + "sebastian/exporter": "^5.1.2", + "sebastian/global-state": "^6.0.2", + "sebastian/object-enumerator": "^5.0.0", + "sebastian/recursion-context": "^5.0.0", + "sebastian/type": "^4.0.0", + "sebastian/version": "^4.0.1" }, "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + "ext-soap": "To be able to generate mocks based on WSDL files" }, "bin": [ "phpunit" @@ -844,7 +774,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.6-dev" + "dev-main": "10.5-dev" } }, "autoload": { @@ -876,7 +806,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.32" }, "funding": [ { @@ -892,32 +822,32 @@ "type": "tidelift" } ], - "time": "2024-07-10T11:45:39+00:00" + "time": "2024-09-04T13:33:39+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -940,7 +870,8 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" }, "funding": [ { @@ -948,32 +879,32 @@ "type": "github" } ], - "time": "2024-03-02T06:27:43+00:00" + "time": "2024-03-02T07:12:49+00:00" }, { "name": "sebastian/code-unit", - "version": "1.0.8", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -996,7 +927,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" }, "funding": [ { @@ -1004,32 +935,32 @@ "type": "github" } ], - "time": "2020-10-26T13:08:54+00:00" + "time": "2023-02-03T06:58:43+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1051,7 +982,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" }, "funding": [ { @@ -1059,34 +990,36 @@ "type": "github" } ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2023-02-03T06:59:15+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.8", + "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", + "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/diff": "^5.0", + "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -1125,7 +1058,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.2" }, "funding": [ { @@ -1133,33 +1067,33 @@ "type": "github" } ], - "time": "2022-09-14T12:41:17+00:00" + "time": "2024-08-12T06:03:08+00:00" }, { "name": "sebastian/complexity", - "version": "2.0.3", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" + "reference": "68ff824baeae169ec9f2137158ee529584553799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", "shasum": "" }, "require": { "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.2-dev" } }, "autoload": { @@ -1182,7 +1116,8 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" }, "funding": [ { @@ -1190,33 +1125,33 @@ "type": "github" } ], - "time": "2023-12-22T06:19:30+00:00" + "time": "2023-12-21T08:37:17+00:00" }, { "name": "sebastian/diff", - "version": "4.0.6", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^10.0", + "symfony/process": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -1248,7 +1183,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" }, "funding": [ { @@ -1256,27 +1192,27 @@ "type": "github" } ], - "time": "2024-03-02T06:30:58+00:00" + "time": "2024-03-02T07:15:17+00:00" }, { "name": "sebastian/environment", - "version": "5.1.5", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-posix": "*" @@ -1284,7 +1220,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-main": "6.1-dev" } }, "autoload": { @@ -1303,7 +1239,7 @@ } ], "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "homepage": "https://github.com/sebastianbergmann/environment", "keywords": [ "Xdebug", "environment", @@ -1311,7 +1247,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" }, "funding": [ { @@ -1319,34 +1256,34 @@ "type": "github" } ], - "time": "2023-02-03T06:03:51+00:00" + "time": "2024-03-23T08:47:14+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.6", + "version": "5.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" + "reference": "955288482d97c19a372d3f31006ab3f37da47adf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", + "reference": "955288482d97c19a372d3f31006ab3f37da47adf", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -1388,7 +1325,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2" }, "funding": [ { @@ -1396,38 +1334,35 @@ "type": "github" } ], - "time": "2024-03-02T06:33:00+00:00" + "time": "2024-03-02T07:17:12+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.7", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1446,13 +1381,14 @@ } ], "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", "keywords": [ "global state" ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" }, "funding": [ { @@ -1460,33 +1396,33 @@ "type": "github" } ], - "time": "2024-03-02T06:35:11+00:00" + "time": "2024-03-02T07:19:19+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.4", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", "shasum": "" }, "require": { "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -1509,7 +1445,8 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" }, "funding": [ { @@ -1517,34 +1454,34 @@ "type": "github" } ], - "time": "2023-12-22T06:20:34+00:00" + "time": "2023-12-21T08:38:20+00:00" }, { "name": "sebastian/object-enumerator", - "version": "4.0.4", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -1566,7 +1503,7 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" }, "funding": [ { @@ -1574,32 +1511,32 @@ "type": "github" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2023-02-03T07:08:32+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1621,7 +1558,7 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" }, "funding": [ { @@ -1629,32 +1566,32 @@ "type": "github" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2023-02-03T07:06:18+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.5", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + "reference": "05909fb5bc7df4c52992396d0116aed689f93712" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -1684,7 +1621,7 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" }, "funding": [ { @@ -1692,86 +1629,32 @@ "type": "github" } ], - "time": "2023-02-03T06:07:39+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-14T16:00:52+00:00" + "time": "2023-02-03T07:05:40+00:00" }, { "name": "sebastian/type", - "version": "3.2.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1794,7 +1677,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" }, "funding": [ { @@ -1802,29 +1685,29 @@ "type": "github" } ], - "time": "2023-02-03T06:13:03+00:00" + "time": "2023-02-03T07:10:45+00:00" }, { "name": "sebastian/version", - "version": "3.0.2", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1847,7 +1730,7 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" }, "funding": [ { @@ -1855,7 +1738,7 @@ "type": "github" } ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2023-02-07T11:34:05+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -1994,7 +1877,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.4", + "php": ">=8.1", "ext-ctype": "*", "ext-curl": "*", "ext-dom": "*", @@ -2017,13 +1900,13 @@ "ext-zlib": "*" }, "platform-dev": { - "php": ">=7.4", + "php": ">=8.1", "ext-phar": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*" }, "platform-overrides": { - "php": "7.4" + "php": "8.1" }, "plugin-api-version": "2.6.0" } diff --git a/config.default.php b/config.default.php index 80c2f257c..af9f45511 100644 --- a/config.default.php +++ b/config.default.php @@ -42,8 +42,6 @@ return array( # Force users to validate their email address. If `true`, an email with a # validation URL is sent during registration, and users cannot access their # feed if they didn’t access this URL. - # Note: it is recommended to not enable it with PHP < 5.5 (emails cannot be - # sent). 'force_email_validation' => false, # Allow or not visitors without login to see the articles @@ -173,7 +171,7 @@ return array( ], - # Configuration to send emails. Be aware that PHP < 5.5 are not supported. + # Configuration to send emails. # These options are basically a mapping of the PHPMailer class attributes # from the PHPMailer library. # diff --git a/constants.php b/constants.php index bf52b8daf..c7765cb12 100644 --- a/constants.php +++ b/constants.php @@ -3,7 +3,7 @@ declare(strict_types=1); //NB: Do not edit; use ./constants.local.php instead. //<Not customisable> -const FRESHRSS_MIN_PHP_VERSION = '7.4.0'; +const FRESHRSS_MIN_PHP_VERSION = '8.1.0'; const FRESHRSS_VERSION = '1.25.0-dev'; const FRESHRSS_WEBSITE = 'https://freshrss.org'; const FRESHRSS_WIKI = 'https://freshrss.github.io/FreshRSS/'; diff --git a/docs/en/admins/02_Prerequisites.md b/docs/en/admins/02_Prerequisites.md index f048d8534..c54a7fd56 100644 --- a/docs/en/admins/02_Prerequisites.md +++ b/docs/en/admins/02_Prerequisites.md @@ -7,7 +7,7 @@ You need to verify that your server can run FreshRSS before installing it. If yo | Software | Recommended | Also Works With | | ------------- | ----------------------- | ----------------------- | | Web server | **Apache 2.4** | nginx, lighttpd<br />minimal compatibility with Apache 2.2 | -| PHP | **PHP 7.4+** | FreshRSS 1.21/1.22: PHP 7.2+; FreshRSS 1.23/1.24: PHP 7.4+ | +| PHP | **PHP 8.1+** | FreshRSS 1.21/1.22: PHP 7.2+; FreshRSS 1.23/1.24: PHP 7.4+ | | PHP modules | Required: libxml, cURL, JSON, PDO_MySQL, PCRE and ctype.<br />Required (32-bit only): GMP <br />Recommended: Zlib, mbstring, iconv, ZipArchive<br />*For the whole modules list see [Dockerfile](https://github.com/FreshRSS/FreshRSS/blob/edge/Docker/Dockerfile-Alpine#L7-L9)* | | | Database | **PostgreSQL 10+** | SQLite, MySQL 5.5.3+, MariaDB 5.5+ | | Browser | **Firefox** | Chrome, Opera, Safari, or Edge | diff --git a/docs/en/admins/10_ServerConfig.md b/docs/en/admins/10_ServerConfig.md index 2db12883e..b7f57e61a 100644 --- a/docs/en/admins/10_ServerConfig.md +++ b/docs/en/admins/10_ServerConfig.md @@ -95,7 +95,7 @@ server { # php files handling # this regex is mandatory because of the API location ~ ^.+?\.php(/.*)?$ { - fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; + fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; # By default, the variable PATH_INFO is not set under PHP-FPM # But FreshRSS API greader.php need it. If you have a “Bad Request” error, double check this var! diff --git a/docs/fr/users/01_Installation.md b/docs/fr/users/01_Installation.md index 7e331776c..390052ec5 100644 --- a/docs/fr/users/01_Installation.md +++ b/docs/fr/users/01_Installation.md @@ -7,7 +7,7 @@ Il est toutefois de votre responsabilité de vérifier que votre hébergement pe | Logiciel | Recommandé | Fonctionne aussi avec | | -------- | ----------- | --------------------- | | Serveur web | **Apache 2.4+** | nginx, lighttpd | -| PHP | **PHP 7.4+** | | +| PHP | **PHP 8.1+** | | | Modules PHP | Requis : libxml, cURL, JSON, PDO_MySQL, PCRE et ctype<br />Requis (32 bits seulement) : GMP<br />Recommandé : Zlib, mbstring et iconv, ZipArchive<br />*Pour une liste complète des modules nécessaires voir le [Dockerfile](https://github.com/FreshRSS/FreshRSS/blob/edge/Docker/Dockerfile-Alpine#L7-L9)* | | | Base de données | **PostgreSQL 10+** | SQLite, MySQL 5.5.3+, MariaDB 5.5+ | | Navigateur | **Firefox** | Chrome, Opera, Safari, or Edge | @@ -115,7 +115,7 @@ server { # gestion des fichiers php # il est nécessaire d’utiliser cette expression régulière pour le bon fonctionnement de l’API location ~ ^.+?\.php(/.*)?$ { - fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; + fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; # Par défaut la variable PATH_INFO n’est pas définie sous PHP-FPM # or l’API FreshRSS greader.php en a besoin. Si vous avez un “Bad Request”, vérifiez bien cette dernière ! diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 7205f3009..89aea4fae 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -56,10 +56,9 @@ class Minz_Configuration { * Return the configuration related to a given namespace. * * @param string $namespace the name of the configuration to get. - * @return static object * @throws Minz_ConfigurationNamespaceException if the namespace does not exist. */ - public static function get(string $namespace) { + public static function get(string $namespace): static { if (!isset(self::$config_list[$namespace])) { throw new Minz_ConfigurationNamespaceException( $namespace . ' namespace does not exist' @@ -156,7 +155,7 @@ class Minz_Configuration { * @param mixed $default default value to return if key does not exist. * @return array|mixed value corresponding to the key. */ - public function param(string $key, $default = null) { + public function param(string $key, mixed $default = null): mixed { if (isset($this->data[$key])) { return $this->data[$key]; } elseif (!is_null($default)) { @@ -171,7 +170,7 @@ class Minz_Configuration { * A wrapper for param(). * @return array|mixed */ - public function __get(string $key) { + public function __get(string $key): mixed { return $this->param($key); } @@ -181,7 +180,7 @@ class Minz_Configuration { * @param string $key the param name to set. * @param mixed $value the value to set. If null, the key is removed from the configuration. */ - public function _param(string $key, $value = null): void { + public function _param(string $key, mixed $value = null): void { if ($this->configuration_setter !== null && $this->configuration_setter->support($key)) { $this->configuration_setter->handle($this->data, $key, $value); } elseif (isset($this->data[$key]) && is_null($value)) { @@ -193,9 +192,8 @@ class Minz_Configuration { /** * A wrapper for _param(). - * @param mixed $value */ - public function __set(string $key, $value): void { + public function __set(string $key, mixed $value): void { $this->_param($key, $value); } diff --git a/lib/Minz/ConfigurationSetterInterface.php b/lib/Minz/ConfigurationSetterInterface.php index f141a1a6f..451d4cb0e 100644 --- a/lib/Minz/ConfigurationSetterInterface.php +++ b/lib/Minz/ConfigurationSetterInterface.php @@ -16,5 +16,5 @@ interface Minz_ConfigurationSetterInterface { * @param string $key the key to update. * @param mixed $value the value to set. */ - public function handle(&$data, string $key, $value): void; + public function handle(array &$data, string $key, mixed $value): void; } diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index 95d28af8a..69b9c569c 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -105,7 +105,7 @@ abstract class Minz_Extension { * * @return string|false html content from ext_dir/configure.phtml, false if it does not exist. */ - final public function getConfigureView() { + final public function getConfigureView(): string|false { $filename = $this->path . '/configure.phtml'; if (!file_exists($filename)) { return false; @@ -146,7 +146,7 @@ abstract class Minz_Extension { return $this->version; } /** @return 'system'|'user' */ - final public function getType() { + final public function getType(): string { return $this->type; } @@ -296,11 +296,7 @@ abstract class Minz_Extension { return []; } - /** - * @param mixed $default - * @return mixed - */ - final public function getSystemConfigurationValue(string $key, $default = null) { + final public function getSystemConfigurationValue(string $key, mixed $default = null): mixed { if (!is_array($this->system_configuration)) { $this->system_configuration = $this->getSystemConfiguration(); } @@ -311,11 +307,7 @@ abstract class Minz_Extension { return $default; } - /** - * @param mixed $default - * @return mixed - */ - final public function getUserConfigurationValue(string $key, $default = null) { + final public function getUserConfigurationValue(string $key, mixed $default = null): mixed { if (!is_array($this->user_configuration)) { $this->user_configuration = $this->getUserConfiguration(); } diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index d9e38955b..2d7c92d6b 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -369,7 +369,7 @@ final class Minz_ExtensionManager { * @return mixed|null final chained result of the hooks. If nothing is changed, * the initial argument is returned. */ - private static function callOneToOne(string $hook_name, $arg) { + private static function callOneToOne(string $hook_name, mixed $arg): mixed { $result = $arg; foreach (self::$hook_list[$hook_name]['list'] as $function) { $result = call_user_func($function, $arg); diff --git a/lib/Minz/FrontController.php b/lib/Minz/FrontController.php index e57fb69c6..3a86d2d6d 100644 --- a/lib/Minz/FrontController.php +++ b/lib/Minz/FrontController.php @@ -79,9 +79,8 @@ class Minz_FrontController { /** * Kills the programme - * @return never */ - public static function killApp(string $txt = '') { + public static function killApp(string $txt = ''): never { header('HTTP/1.1 500 Internal Server Error', true, 500); if (function_exists('errorMessageInfo')) { //If the application has defined a custom error message function diff --git a/lib/Minz/Helper.php b/lib/Minz/Helper.php index 50243ded0..91c1bdc00 100644 --- a/lib/Minz/Helper.php +++ b/lib/Minz/Helper.php @@ -18,11 +18,8 @@ final class Minz_Helper { * @phpstan-template T of mixed * @phpstan-param T $var * @phpstan-return T - * - * @param mixed $var - * @return mixed */ - public static function htmlspecialchars_utf8($var) { + public static function htmlspecialchars_utf8(mixed $var): mixed { if (is_array($var)) { // @phpstan-ignore argument.type, return.type return array_map([self::class, 'htmlspecialchars_utf8'], $var); diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php index 648c2c663..8bf193ffe 100644 --- a/lib/Minz/Log.php +++ b/lib/Minz/Log.php @@ -76,7 +76,6 @@ class Minz_Log { * This method can be called multiple times for one script execution, but its result will not change unless * you call clearstatcache() in between. We won’t do do that for performance reasons. * - * @param string $file_name * @throws Minz_PermissionDeniedException */ protected static function ensureMaxLogSize(string $file_name): void { diff --git a/lib/Minz/Mailer.php b/lib/Minz/Mailer.php index 8e1211807..c657bd486 100644 --- a/lib/Minz/Mailer.php +++ b/lib/Minz/Mailer.php @@ -18,10 +18,6 @@ use PHPMailer\PHPMailer\Exception; * $this->view->_path('user_mailer/email_need_validation.txt.php') * ``` * - * Minz_Mailer uses the PHPMailer library under the hood. The latter requires - * PHP >= 5.5 to work. If you instantiate a Minz_Mailer with PHP < 5.5, a - * warning will be logged. - * * The email is sent by calling the `mail` method. */ class Minz_Mailer { diff --git a/lib/Minz/Migrator.php b/lib/Minz/Migrator.php index c1978dc69..39c834765 100644 --- a/lib/Minz/Migrator.php +++ b/lib/Minz/Migrator.php @@ -19,9 +19,6 @@ class Minz_Migrator /** * Execute a list of migrations, skipping versions indicated in a file * - * @param string $migrations_path - * @param string $applied_migrations_path - * * @return true|string Returns true if execute succeeds to apply * migrations, or a string if it fails. * @throws DomainException if there is no migrations corresponding to the @@ -31,7 +28,7 @@ class Minz_Migrator * * @throws BadFunctionCallException if a callback isn’t callable. */ - public static function execute(string $migrations_path, string $applied_migrations_path) { + public static function execute(string $migrations_path, string $applied_migrations_path): string|bool { $applied_migrations = @file_get_contents($applied_migrations_path); if ($applied_migrations === false) { return "Cannot open the {$applied_migrations_path} file"; diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index b39ae2f81..f27ae5dc7 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -86,8 +86,6 @@ class Minz_ModelPdo { /** * Create the connection to the database using the variables * HOST, BASE, USER and PASS variables defined in the configuration file - * @param string|null $currentUser - * @param Minz_Pdo|null $currentPdo * @throws Minz_ConfigurationException * @throws Minz_PDOConnectionException */ diff --git a/lib/Minz/Paginator.php b/lib/Minz/Paginator.php index 3b3c0961e..727fe42d3 100644 --- a/lib/Minz/Paginator.php +++ b/lib/Minz/Paginator.php @@ -64,7 +64,7 @@ class Minz_Paginator { * @param Minz_Model $item l'élément à retrouver * @return int|false la page à laquelle se trouve l’élément, false si non trouvé */ - public function pageByItem($item) { + public function pageByItem($item): int|false { $i = 0; do { @@ -82,7 +82,7 @@ class Minz_Paginator { * @param Minz_Model $item the element to search * @return int|false the position of the element, or false if not found */ - public function positionByItem($item) { + public function positionByItem($item): int|false { $i = 0; do { diff --git a/lib/Minz/Pdo.php b/lib/Minz/Pdo.php index 33d84eb45..705c2d58c 100644 --- a/lib/Minz/Pdo.php +++ b/lib/Minz/Pdo.php @@ -37,58 +37,44 @@ abstract class Minz_Pdo extends PDO { return $this->autoPrefix($statement); } - // PHP8+: PDO::lastInsertId(?string $name = null): string|false /** - * @param string|null $name - * @return string|false * @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION` */ #[\Override] - #[\ReturnTypeWillChange] - public function lastInsertId($name = null) { + public function lastInsertId(?string $name = null): string|false { if ($name != null) { $name = $this->preSql($name); } return parent::lastInsertId($name); } - // PHP8+: PDO::prepare(string $query, array $options = []): PDOStatement|false /** - * @param string $query * @param array<int,string> $options - * @return PDOStatement|false * @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION` * @phpstan-ignore method.childParameterType, throws.unusedType */ #[\Override] - #[\ReturnTypeWillChange] - public function prepare($query, $options = []) { + public function prepare(string $query, array $options = []): PDOStatement|false { $query = $this->preSql($query); return parent::prepare($query, $options); } - // PHP8+: PDO::exec(string $statement): int|false /** - * @param string $statement - * @return int|false * @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION` * @phpstan-ignore throws.unusedType */ #[\Override] - #[\ReturnTypeWillChange] - public function exec($statement) { + public function exec(string $statement): int|false { $statement = $this->preSql($statement); return parent::exec($statement); } /** - * @return PDOStatement|false * @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION` * @phpstan-ignore throws.unusedType */ #[\Override] - #[\ReturnTypeWillChange] - public function query(string $query, ?int $fetch_mode = null, ...$fetch_mode_args) { + public function query(string $query, ?int $fetch_mode = null, ...$fetch_mode_args): PDOStatement|false { $query = $this->preSql($query); return $fetch_mode === null ? parent::query($query) : parent::query($query, $fetch_mode, ...$fetch_mode_args); } diff --git a/lib/Minz/PdoMysql.php b/lib/Minz/PdoMysql.php index 3f7a804a3..d7fca0168 100644 --- a/lib/Minz/PdoMysql.php +++ b/lib/Minz/PdoMysql.php @@ -22,13 +22,10 @@ class Minz_PdoMysql extends Minz_Pdo { } /** - * @param string|null $name - * @return string|false * @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION` */ #[\Override] - #[\ReturnTypeWillChange] - public function lastInsertId($name = null) { + public function lastInsertId(?string $name = null): string|false { return parent::lastInsertId(); //We discard the name, only used by PostgreSQL } } diff --git a/lib/Minz/PdoSqlite.php b/lib/Minz/PdoSqlite.php index 537b6cdc6..6aa83690c 100644 --- a/lib/Minz/PdoSqlite.php +++ b/lib/Minz/PdoSqlite.php @@ -22,13 +22,10 @@ class Minz_PdoSqlite extends Minz_Pdo { } /** - * @param string|null $name - * @return string|false * @throws PDOException if the attribute `PDO::ATTR_ERRMODE` is set to `PDO::ERRMODE_EXCEPTION` */ #[\Override] - #[\ReturnTypeWillChange] - public function lastInsertId($name = null) { + public function lastInsertId(?string $name = null): string|false { return parent::lastInsertId(); //We discard the name, only used by PostgreSQL } } diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php index 1f15730fb..fcece464b 100644 --- a/lib/Minz/Request.php +++ b/lib/Minz/Request.php @@ -44,7 +44,7 @@ class Minz_Request { * @return mixed value of the parameter * @deprecated use typed versions instead */ - public static function param(string $key, $default = false, bool $specialchars = false) { + public static function param(string $key, mixed $default = false, bool $specialchars = false): mixed { if (isset(self::$params[$key])) { $p = self::$params[$key]; if (is_string($p) || is_array($p)) { @@ -156,7 +156,7 @@ class Minz_Request { } /** @return array{c?:string,a?:string,params?:array<string,mixed>} */ - public static function originalRequest() { + public static function originalRequest(): array { return self::$originalRequest; } diff --git a/lib/Minz/Session.php b/lib/Minz/Session.php index 99b7fef45..c08ad688b 100644 --- a/lib/Minz/Session.php +++ b/lib/Minz/Session.php @@ -63,7 +63,7 @@ class Minz_Session { * @return mixed|false the value of the session variable, false if doesn’t exist * @deprecated Use typed versions instead */ - public static function param(string $p, $default = false) { + public static function param(string $p, $default = false): mixed { return $_SESSION[$p] ?? $default; } diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index 183fa48ca..a8dc889ee 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -255,9 +255,7 @@ class Minz_Translate { /** * Alias for Minz_Translate::t() - * @param string $key - * @param bool|float|int|string ...$args */ -function _t(string $key, ...$args): string { +function _t(string $key, bool|float|int|string ...$args): string { return Minz_Translate::t($key, ...$args); } diff --git a/lib/Minz/Url.php b/lib/Minz/Url.php index 310067382..3948414d8 100644 --- a/lib/Minz/Url.php +++ b/lib/Minz/Url.php @@ -13,11 +13,10 @@ class Minz_Url { * $url['params'] = array of additional parameters * or as a string * @param string $encoding how to encode & (& ou & pour html) - * @param bool|string $absolute * @return string Formatted URL * @throws Minz_ConfigurationException */ - public static function display($url = [], string $encoding = 'html', $absolute = false): string { + public static function display($url = [], string $encoding = 'html', bool|string $absolute = false): string { $isArray = is_array($url); if ($isArray) { @@ -160,13 +159,7 @@ class Minz_Url { } } -/** - * @param string $controller - * @param string $action - * @param string|int ...$args - * @return string|false - */ -function _url(string $controller, string $action, ...$args) { +function _url(string $controller, string $action, int|string ...$args): string|false { $nb_args = count($args); if ($nb_args % 2 !== 0) { diff --git a/lib/Minz/View.php b/lib/Minz/View.php index 44b7378b6..f7dceef0a 100644 --- a/lib/Minz/View.php +++ b/lib/Minz/View.php @@ -232,8 +232,6 @@ class Minz_View { /** * Append a `<link>` element referencing stylesheet. - * @param string $url - * @param string $media * @param bool $cond Conditional comment for IE, now deprecated and ignored @deprecated */ public static function appendStyle(string $url, string $media = 'all', bool $cond = false): void { @@ -298,7 +296,6 @@ class Minz_View { } /** * Prepend a `<script>` element. - * @param string $url * @param bool $cond Conditional comment for IE, now deprecated and ignored @deprecated * @param bool $defer Use `defer` flag * @param bool $async Use `async` flag @@ -318,7 +315,6 @@ class Minz_View { /** * Append a `<script>` element. - * @param string $url * @param bool $cond Conditional comment for IE, now deprecated and ignored @deprecated * @param bool $defer Use `defer` flag * @param bool $async Use `async` flag @@ -338,9 +334,8 @@ class Minz_View { /** * Management of parameters added to the view - * @param mixed $value */ - public static function _param(string $key, $value): void { + public static function _param(string $key, mixed $value): void { self::$params[$key] = $value; } diff --git a/lib/lib_date.php b/lib/lib_date.php index ee8bf92f6..201d548ad 100644 --- a/lib/lib_date.php +++ b/lib/lib_date.php @@ -36,7 +36,7 @@ example('PT6M/'); example('PT7S/'); example('P1DT1H/'); -function example(string $dateInterval) { +function example(string $dateInterval): void { $dateIntervalArray = parseDateInterval($dateInterval); echo $dateInterval, "\t=>\t", $dateIntervalArray[0] == null ? 'null' : @date('c', $dateIntervalArray[0]), '/', diff --git a/lib/lib_rss.php b/lib/lib_rss.php index d066bd254..61055153c 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -5,37 +5,12 @@ if (version_compare(PHP_VERSION, FRESHRSS_MIN_PHP_VERSION, '<')) { die(sprintf('FreshRSS error: FreshRSS requires PHP %s+!', FRESHRSS_MIN_PHP_VERSION)); } -if (!function_exists('array_is_list')) { - /** - * Polyfill for PHP <8.1 - * https://php.net/array-is-list#127044 - * @param array<mixed> $array - */ - function array_is_list(array $array): bool { - $i = -1; - foreach ($array as $k => $v) { - ++$i; - if ($k !== $i) { - return false; - } - } - return true; - } -} - if (!function_exists('mb_strcut')) { function mb_strcut(string $str, int $start, ?int $length = null, string $encoding = 'UTF-8'): string { return substr($str, $start, $length) ?: ''; } } -if (!function_exists('str_starts_with')) { - /** Polyfill for PHP <8.0 */ - function str_starts_with(string $haystack, string $needle): bool { - return strncmp($haystack, $needle, strlen($needle)) === 0; - } -} - if (!function_exists('syslog')) { if (COPY_SYSLOG_TO_STDERR && !defined('STDERR')) { define('STDERR', fopen('php://stderr', 'w')); @@ -149,14 +124,7 @@ function idn_to_puny(string $url): string { if (function_exists('idn_to_ascii')) { $idn = parse_url($url, PHP_URL_HOST); if (is_string($idn) && $idn != '') { - // https://wiki.php.net/rfc/deprecate-and-remove-intl_idna_variant_2003 - if (defined('INTL_IDNA_VARIANT_UTS46')) { - $puny = idn_to_ascii($idn, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46); - } elseif (defined('INTL_IDNA_VARIANT_2003')) { - $puny = idn_to_ascii($idn, IDNA_DEFAULT, INTL_IDNA_VARIANT_2003); - } else { - $puny = idn_to_ascii($idn); - } + $puny = idn_to_ascii($idn); $pos = strpos($url, $idn); if ($puny != false && $pos !== false) { $url = substr_replace($url, $puny, $pos, strlen($idn)); @@ -166,10 +134,7 @@ function idn_to_puny(string $url): string { return $url; } -/** - * @return string|false - */ -function checkUrl(string $url, bool $fixScheme = true) { +function checkUrl(string $url, bool $fixScheme = true): string|false { $url = trim($url); if ($url == '') { return ''; @@ -178,7 +143,7 @@ function checkUrl(string $url, bool $fixScheme = true) { $url = 'https://' . ltrim($url, '/'); } - $url = idn_to_puny($url); //PHP bug #53474 IDN + $url = idn_to_puny($url); // https://bugs.php.net/bug.php?id=53474 $urlRelaxed = str_replace('_', 'z', $url); //PHP discussion #64948 Underscore if (is_string(filter_var($urlRelaxed, FILTER_VALIDATE_URL))) { @@ -279,7 +244,7 @@ function html_only_entity_decode(?string $text): string { * @param array<string,mixed>|string $log * @return array<string,mixed>|string */ -function sensitive_log($log) { +function sensitive_log($log): array|string { if (is_array($log)) { foreach ($log as $k => $v) { if (in_array($k, ['api_key', 'Passwd', 'T'], true)) { diff --git a/p/api/fever.php b/p/api/fever.php index 77d778305..5ddfba269 100644 --- a/p/api/fever.php +++ b/p/api/fever.php @@ -426,33 +426,29 @@ final class FeverAPI /** * @param numeric-string $id - * @return int|false */ - private function setItemAsRead(string $id) { + private function setItemAsRead(string $id): int|false { return $this->entryDAO->markRead($id, true); } /** * @param numeric-string $id - * @return int|false */ - private function setItemAsUnread(string $id) { + private function setItemAsUnread(string $id): int|false { return $this->entryDAO->markRead($id, false); } /** * @param numeric-string $id - * @return int|false */ - private function setItemAsSaved(string $id) { + private function setItemAsSaved(string $id): int|false { return $this->entryDAO->markFavorite($id, true); } /** * @param numeric-string $id - * @return int|false */ - private function setItemAsUnsaved(string $id) { + private function setItemAsUnsaved(string $id): int|false { return $this->entryDAO->markFavorite($id, false); } @@ -538,18 +534,12 @@ final class FeverAPI return $beforeTimestamp == 0 ? '0' : $beforeTimestamp . '000000'; } - /** - * @return int|false - */ - private function setFeedAsRead(int $id, int $before) { + private function setFeedAsRead(int $id, int $before): int|false { $before = $this->convertBeforeToId($before); return $this->entryDAO->markReadFeed($id, $before); } - /** - * @return int|false - */ - private function setGroupAsRead(int $id, int $before) { + private function setGroupAsRead(int $id, int $before): int|false { $before = $this->convertBeforeToId($before); // special case to mark all items as read diff --git a/p/api/greader.php b/p/api/greader.php index 8a492a213..1fd821307 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -112,14 +112,12 @@ function debugInfo(): string { final class GReaderAPI { - /** @return never */ - private static function noContent() { + private static function noContent(): never { header('HTTP/1.1 204 No Content'); exit(); } - /** @return never */ - private static function badRequest() { + private static function badRequest(): never { Minz_Log::warning(__METHOD__, API_LOG); Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); header('HTTP/1.1 400 Bad Request'); @@ -127,8 +125,7 @@ final class GReaderAPI { die('Bad Request!'); } - /** @return never */ - private static function unauthorized() { + private static function unauthorized(): never { Minz_Log::warning(__METHOD__, API_LOG); Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); header('HTTP/1.1 401 Unauthorized'); @@ -137,8 +134,7 @@ final class GReaderAPI { die('Unauthorized!'); } - /** @return never */ - private static function internalServerError() { + private static function internalServerError(): never { Minz_Log::warning(__METHOD__, API_LOG); Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); header('HTTP/1.1 500 Internal Server Error'); @@ -146,8 +142,7 @@ final class GReaderAPI { die('Internal Server Error!'); } - /** @return never */ - private static function notImplemented() { + private static function notImplemented(): never { Minz_Log::warning(__METHOD__, API_LOG); Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); header('HTTP/1.1 501 Not Implemented'); @@ -155,8 +150,7 @@ final class GReaderAPI { die('Not Implemented!'); } - /** @return never */ - private static function serviceUnavailable() { + private static function serviceUnavailable(): never { Minz_Log::warning(__METHOD__, API_LOG); Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); header('HTTP/1.1 503 Service Unavailable'); @@ -164,8 +158,7 @@ final class GReaderAPI { die('Service Unavailable!'); } - /** @return never */ - private static function checkCompatibility() { + private static function checkCompatibility(): never { Minz_Log::warning(__METHOD__, API_LOG); Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); header('Content-Type: text/plain; charset=UTF-8'); @@ -211,8 +204,7 @@ final class GReaderAPI { return ''; } - /** @return never */ - private static function clientLogin(string $email, string $pass) { + private static function clientLogin(string $email, string $pass): never { //https://web.archive.org/web/20130604091042/http://undoc.in/clientLogin.html if (FreshRSS_user_Controller::checkUsername($email)) { FreshRSS_Context::initUser($email); @@ -237,10 +229,7 @@ final class GReaderAPI { } } - /** - * @return never - */ - private static function token(?FreshRSS_UserConfiguration $conf) { + private static function token(?FreshRSS_UserConfiguration $conf): never { //http://blog.martindoms.com/2009/08/15/using-the-google-reader-api-part-1/ //https://github.com/ericmann/gReader-Library/blob/master/greader.class.php $user = Minz_User::name(); @@ -271,8 +260,7 @@ final class GReaderAPI { self::unauthorized(); } - /** @return never */ - private static function userInfo() { + private static function userInfo(): never { //https://github.com/theoldreader/api#user-info if (!FreshRSS_Context::hasUserConf()) { self::unauthorized(); @@ -286,8 +274,7 @@ final class GReaderAPI { ), JSON_OPTIONS)); } - /** @return never */ - private static function tagList() { + private static function tagList(): never { header('Content-Type: application/json; charset=UTF-8'); $tags = array( @@ -320,8 +307,7 @@ final class GReaderAPI { exit(); } - /** @return never */ - private static function subscriptionExport() { + private static function subscriptionExport(): never { $user = Minz_User::name() ?? Minz_User::INTERNAL_USER; $export_service = new FreshRSS_Export_Service($user); [$filename, $content] = $export_service->generateOpml(); @@ -331,8 +317,7 @@ final class GReaderAPI { exit(); } - /** @return never */ - private static function subscriptionImport(string $opml) { + private static function subscriptionImport(string $opml): never { $user = Minz_User::name() ?? Minz_User::INTERNAL_USER; $importService = new FreshRSS_Import_Service($user); $importService->importOpml($opml); @@ -345,8 +330,7 @@ final class GReaderAPI { } } - /** @return never */ - private static function subscriptionList() { + private static function subscriptionList(): never { if (!FreshRSS_Context::hasSystemConf()) { self::internalServerError(); } @@ -384,9 +368,8 @@ final class GReaderAPI { /** * @param array<string> $streamNames * @param array<string> $titles - * @return never */ - private static function subscriptionEdit(array $streamNames, array $titles, string $action, string $add = '', string $remove = '') { + private static function subscriptionEdit(array $streamNames, array $titles, string $action, string $add = '', string $remove = ''): never { //https://github.com/mihaip/google-reader-api/blob/master/wiki/ApiSubscriptionEdit.wiki switch ($action) { case 'subscribe': @@ -474,8 +457,7 @@ final class GReaderAPI { exit('OK'); } - /** @return never */ - private static function quickadd(string $url) { + private static function quickadd(string $url): never { try { $url = htmlspecialchars($url, ENT_COMPAT, 'UTF-8'); if (str_starts_with($url, 'feed/')) { @@ -497,8 +479,7 @@ final class GReaderAPI { } } - /** @return never */ - private static function unreadCount() { + private static function unreadCount(): never { //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#unread-count header('Content-Type: application/json; charset=UTF-8'); @@ -592,10 +573,9 @@ final class GReaderAPI { /** * @param 'A'|'c'|'f'|'s' $type - * @param string|int $streamId * @phpstan-return array{'A'|'c'|'f'|'s'|'t',int,int,FreshRSS_BooleanSearch} */ - private static function streamContentsFilters(string $type, $streamId, + private static function streamContentsFilters(string $type, int|string $streamId, string $filter_target, string $exclude_target, int $start_time, int $stop_time): array { switch ($type) { case 'f': //feed @@ -670,9 +650,8 @@ final class GReaderAPI { return array($type, $streamId, $state, $searches); } - /** @return never */ private static function streamContents(string $path, string $include_target, int $start_time, int $stop_time, int $count, - string $order, string $filter_target, string $exclude_target, string $continuation) { + string $order, string $filter_target, string $exclude_target, string $continuation): never { //http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed header('Content-Type: application/json; charset=UTF-8'); @@ -728,9 +707,8 @@ final class GReaderAPI { exit(); } - /** @return never */ private static function streamContentsItemsIds(string $streamId, int $start_time, int $stop_time, int $count, - string $order, string $filter_target, string $exclude_target, string $continuation) { + string $order, string $filter_target, string $exclude_target, string $continuation): never { //http://code.google.com/p/google-reader-api/wiki/ApiStreamItemsIds //http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed @@ -790,9 +768,8 @@ final class GReaderAPI { /** * @param array<string> $e_ids - * @return never */ - private static function streamContentsItems(array $e_ids, string $order) { + private static function streamContentsItems(array $e_ids, string $order): never { header('Content-Type: application/json; charset=UTF-8'); foreach ($e_ids as $i => $e_id) { @@ -822,9 +799,8 @@ final class GReaderAPI { /** * @param array<string> $e_ids - * @return never */ - private static function editTag(array $e_ids, string $a, string $r): void { + private static function editTag(array $e_ids, string $a, string $r): never { foreach ($e_ids as $i => $e_id) { if (!ctype_digit($e_id) || $e_id[0] === '0') { $e_ids[$i] = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' @@ -898,8 +874,7 @@ final class GReaderAPI { exit('OK'); } - /** @return never */ - private static function renameTag(string $s, string $dest) { + private static function renameTag(string $s, string $dest): never { if ($s != '' && strpos($s, 'user/-/label/') === 0 && $dest != '' && strpos($dest, 'user/-/label/') === 0) { $s = substr($s, 13); @@ -926,8 +901,7 @@ final class GReaderAPI { self::badRequest(); } - /** @return never */ - private static function disableTag(string $s) { + private static function disableTag(string $s): never { if ($s != '' && strpos($s, 'user/-/label/') === 0) { $s = substr($s, 13); $s = htmlspecialchars($s, ENT_COMPAT, 'UTF-8'); @@ -954,9 +928,8 @@ final class GReaderAPI { /** * @param numeric-string $olderThanId - * @return never */ - private static function markAllAsRead(string $streamId, string $olderThanId) { + private static function markAllAsRead(string $streamId, string $olderThanId): never { $entryDAO = FreshRSS_Factory::createEntryDao(); if (strpos($streamId, 'feed/') === 0) { $f_id = basename($streamId); @@ -989,8 +962,7 @@ final class GReaderAPI { exit('OK'); } - /** @return never */ - public static function parse() { + public static function parse(): never { global $ORIGINAL_INPUT; header('Access-Control-Allow-Headers: Authorization'); @@ -83,14 +83,12 @@ function is_valid_path(string $path): bool { || is_valid_path_extension($path, USERS_PATH, false); } -/** @return never */ -function sendBadRequestResponse(string $message = null) { +function sendBadRequestResponse(string $message = null): never { header('HTTP/1.1 400 Bad Request'); die($message); } -/** @return never */ -function sendNotFoundResponse() { +function sendNotFoundResponse(): never { header('HTTP/1.1 404 Not Found'); die(); } diff --git a/phpstan.neon b/phpstan.neon index 640e4d9f9..1b75235b4 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,6 +1,5 @@ parameters: level: 9 # https://phpstan.org/user-guide/rule-levels - phpVersion: 80399 # TODO: Remove line when moving composer.json to PHP 8+ fileExtensions: - php - phtml diff --git a/tests/README.md b/tests/README.md index 311461d0c..59035a775 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,8 +1,23 @@ # FreshRSS tests +See our [documentation about running tests](https://freshrss.github.io/FreshRSS/en/developers/03_Running_tests.html). + +```sh +make test-all +``` + +See [`test.yml`](../.github/workflows/tests.yml) for the GitHub Actions automated tests. + +See [`composer.json`](../composer.json) for the different tests and versions, to be run locally. + +## Details about this *tests* folder + +Unit tests are based on [PHPUnit](https://phpunit.de/). +Here is an example of manual install: + ```sh cd ./tests/ -wget -O phpunit.phar https://phar.phpunit.de/phpunit-9.phar +wget -O phpunit.phar https://phar.phpunit.de/phpunit-10.phar php phpunit.phar --bootstrap bootstrap.php ``` diff --git a/tests/app/Models/CategoryTest.php b/tests/app/Models/CategoryTest.php index c9e88a32d..f9aa1a280 100644 --- a/tests/app/Models/CategoryTest.php +++ b/tests/app/Models/CategoryTest.php @@ -1,24 +1,24 @@ <?php declare(strict_types=1); +use PHPUnit\Framework\Attributes\DataProvider; + class CategoryTest extends PHPUnit\Framework\TestCase { - public function test__construct_whenNoParameters_createsObjectWithDefaultValues(): void { + public static function test__construct_whenNoParameters_createsObjectWithDefaultValues(): void { $category = new FreshRSS_Category(); self::assertEquals(0, $category->id()); self::assertEquals('', $category->name()); } - /** - * @dataProvider provideValidNames - */ - public function test_name_whenValidValue_storesModifiedValue(string $input, string $expected): void { + #[DataProvider('provideValidNames')] + public static function test_name_whenValidValue_storesModifiedValue(string $input, string $expected): void { $category = new FreshRSS_Category($input); self::assertEquals($expected, $category->name()); } /** @return array<array{string,string}> */ - public function provideValidNames(): array { + public static function provideValidNames(): array { return [ ['', ''], ['this string does not need trimming', 'this string does not need trimming'], diff --git a/tests/app/Models/FeedDAOTest.php b/tests/app/Models/FeedDAOTest.php index cd197bf9e..31cfc57f9 100644 --- a/tests/app/Models/FeedDAOTest.php +++ b/tests/app/Models/FeedDAOTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); class FeedDAOTest extends PHPUnit\Framework\TestCase { - public function test_ttl_min(): void { + public static function test_ttl_min(): void { $feed = new FreshRSS_Feed('https://example.net/', false); $feed->_ttl(-5); self::assertEquals(-5, $feed->ttl(true)); diff --git a/tests/app/Models/SearchTest.php b/tests/app/Models/SearchTest.php index e01830314..27943cdb2 100644 --- a/tests/app/Models/SearchTest.php +++ b/tests/app/Models/SearchTest.php @@ -1,13 +1,14 @@ <?php declare(strict_types=1); + +use PHPUnit\Framework\Attributes\DataProvider; + require_once(LIB_PATH . '/lib_date.php'); class SearchTest extends PHPUnit\Framework\TestCase { - /** - * @dataProvider provideEmptyInput - */ - public function test__construct_whenInputIsEmpty_getsOnlyNullValues(string $input): void { + #[DataProvider('provideEmptyInput')] + public static function test__construct_whenInputIsEmpty_getsOnlyNullValues(string $input): void { $search = new FreshRSS_Search($input); self::assertEquals('', $search->getRawInput()); self::assertNull($search->getIntitle()); @@ -25,7 +26,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { * Here is the description of the values * @return array{array{''},array{' '}} */ - public function provideEmptyInput(): array { + public static function provideEmptyInput(): array { return [ [''], [' '], @@ -33,11 +34,11 @@ class SearchTest extends PHPUnit\Framework\TestCase { } /** - * @dataProvider provideIntitleSearch * @param array<string>|null $intitle_value * @param array<string>|null $search_value */ - public function test__construct_whenInputContainsIntitle_setsIntitleProperty(string $input, ?array $intitle_value, ?array $search_value): void { + #[DataProvider('provideIntitleSearch')] + public static function test__construct_whenInputContainsIntitle_setsIntitleProperty(string $input, ?array $intitle_value, ?array $search_value): void { $search = new FreshRSS_Search($input); self::assertEquals($intitle_value, $search->getIntitle()); self::assertEquals($search_value, $search->getSearch()); @@ -46,7 +47,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { /** * @return array<array<mixed>> */ - public function provideIntitleSearch(): array { + public static function provideIntitleSearch(): array { return [ ['intitle:word1', ['word1'], null], ['intitle:word1-word2', ['word1-word2'], null], @@ -70,11 +71,11 @@ class SearchTest extends PHPUnit\Framework\TestCase { } /** - * @dataProvider provideAuthorSearch * @param array<string>|null $author_value * @param array<string>|null $search_value */ - public function test__construct_whenInputContainsAuthor_setsAuthorValue(string $input, ?array $author_value, ?array $search_value): void { + #[DataProvider('provideAuthorSearch')] + public static function test__construct_whenInputContainsAuthor_setsAuthorValue(string $input, ?array $author_value, ?array $search_value): void { $search = new FreshRSS_Search($input); self::assertEquals($author_value, $search->getAuthor()); self::assertEquals($search_value, $search->getSearch()); @@ -83,7 +84,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { /** * @return array<array<mixed>> */ - public function provideAuthorSearch(): array { + public static function provideAuthorSearch(): array { return [ ['author:word1', ['word1'], null], ['author:word1-word2', ['word1-word2'], null], @@ -107,11 +108,11 @@ class SearchTest extends PHPUnit\Framework\TestCase { } /** - * @dataProvider provideInurlSearch * @param array<string>|null $inurl_value * @param array<string>|null $search_value */ - public function test__construct_whenInputContainsInurl_setsInurlValue(string $input, ?array $inurl_value, ?array $search_value): void { + #[DataProvider('provideInurlSearch')] + public static function test__construct_whenInputContainsInurl_setsInurlValue(string $input, ?array $inurl_value, ?array $search_value): void { $search = new FreshRSS_Search($input); self::assertEquals($inurl_value, $search->getInurl()); self::assertEquals($search_value, $search->getSearch()); @@ -120,7 +121,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { /** * @return array<array<mixed>> */ - public function provideInurlSearch(): array { + public static function provideInurlSearch(): array { return [ ['inurl:word1', ['word1'], null], ['inurl: word1', [], ['word1']], @@ -133,10 +134,8 @@ class SearchTest extends PHPUnit\Framework\TestCase { ]; } - /** - * @dataProvider provideDateSearch - */ - public function test__construct_whenInputContainsDate_setsDateValues(string $input, ?int $min_date_value, ?int $max_date_value): void { + #[DataProvider('provideDateSearch')] + public static function test__construct_whenInputContainsDate_setsDateValues(string $input, ?int $min_date_value, ?int $max_date_value): void { $search = new FreshRSS_Search($input); self::assertEquals($min_date_value, $search->getMinDate()); self::assertEquals($max_date_value, $search->getMaxDate()); @@ -145,7 +144,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { /** * @return array<array<mixed>> */ - public function provideDateSearch(): array { + public static function provideDateSearch(): array { return array( array('date:2007-03-01T13:00:00Z/2008-05-11T15:30:00Z', 1172754000, 1210519800), array('date:2007-03-01T13:00:00Z/P1Y2M10DT2H30M', 1172754000, 1210519799), @@ -156,10 +155,8 @@ class SearchTest extends PHPUnit\Framework\TestCase { ); } - /** - * @dataProvider providePubdateSearch - */ - public function test__construct_whenInputContainsPubdate_setsPubdateValues(string $input, ?int $min_pubdate_value, ?int $max_pubdate_value): void { + #[DataProvider('providePubdateSearch')] + public static function test__construct_whenInputContainsPubdate_setsPubdateValues(string $input, ?int $min_pubdate_value, ?int $max_pubdate_value): void { $search = new FreshRSS_Search($input); self::assertEquals($min_pubdate_value, $search->getMinPubdate()); self::assertEquals($max_pubdate_value, $search->getMaxPubdate()); @@ -168,7 +165,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { /** * @return array<array<mixed>> */ - public function providePubdateSearch(): array { + public static function providePubdateSearch(): array { return array( array('pubdate:2007-03-01T13:00:00Z/2008-05-11T15:30:00Z', 1172754000, 1210519800), array('pubdate:2007-03-01T13:00:00Z/P1Y2M10DT2H30M', 1172754000, 1210519799), @@ -180,11 +177,11 @@ class SearchTest extends PHPUnit\Framework\TestCase { } /** - * @dataProvider provideTagsSearch * @param array<string>|null $tags_value * @param array<string>|null $search_value */ - public function test__construct_whenInputContainsTags_setsTagsValue(string $input, ?array $tags_value, ?array $search_value): void { + #[DataProvider('provideTagsSearch')] + public static function test__construct_whenInputContainsTags_setsTagsValue(string $input, ?array $tags_value, ?array $search_value): void { $search = new FreshRSS_Search($input); self::assertEquals($tags_value, $search->getTags()); self::assertEquals($search_value, $search->getSearch()); @@ -193,7 +190,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { /** * @return array<array<string|array<string>|null>> */ - public function provideTagsSearch(): array { + public static function provideTagsSearch(): array { return [ ['#word1', ['word1'], null], ['# word1', null, ['#', 'word1']], @@ -207,14 +204,14 @@ class SearchTest extends PHPUnit\Framework\TestCase { } /** - * @dataProvider provideMultipleSearch * @param array<string>|null $author_value * @param array<string> $intitle_value * @param array<string>|null $inurl_value * @param array<string>|null $tags_value * @param array<string>|null $search_value */ - public function test__construct_whenInputContainsMultipleKeywords_setsValues(string $input, ?array $author_value, ?int $min_date_value, + #[DataProvider('provideMultipleSearch')] + public static function test__construct_whenInputContainsMultipleKeywords_setsValues(string $input, ?array $author_value, ?int $min_date_value, ?int $max_date_value, ?array $intitle_value, ?array $inurl_value, ?int $min_pubdate_value, ?int $max_pubdate_value, ?array $tags_value, ?array $search_value): void { $search = new FreshRSS_Search($input); @@ -231,7 +228,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { } /** @return array<array<mixed>> */ - public function provideMultipleSearch(): array { + public static function provideMultipleSearch(): array { return array( array( 'author:word1 date:2007-03-01/2008-05-11 intitle:word2 inurl:word3 pubdate:2007-03-01/2008-05-11 #word4 #word5', @@ -284,15 +281,13 @@ class SearchTest extends PHPUnit\Framework\TestCase { ); } - /** - * @dataProvider provideAddOrParentheses - */ - public function test__addOrParentheses(string $input, string $output): void { + #[DataProvider('provideAddOrParentheses')] + public static function test__addOrParentheses(string $input, string $output): void { self::assertEquals($output, FreshRSS_BooleanSearch::addOrParentheses($input)); } /** @return array<array{string,string}> */ - public function provideAddOrParentheses(): array { + public static function provideAddOrParentheses(): array { return [ ['ab', 'ab'], ['ab cd', 'ab cd'], @@ -304,15 +299,13 @@ class SearchTest extends PHPUnit\Framework\TestCase { ]; } - /** - * @dataProvider provideconsistentOrParentheses - */ - public function test__consistentOrParentheses(string $input, string $output): void { + #[DataProvider('provideconsistentOrParentheses')] + public static function test__consistentOrParentheses(string $input, string $output): void { self::assertEquals($output, FreshRSS_BooleanSearch::consistentOrParentheses($input)); } /** @return array<array{string,string}> */ - public function provideconsistentOrParentheses(): array { + public static function provideconsistentOrParentheses(): array { return [ ['ab cd ef', 'ab cd ef'], ['(ab cd ef)', '(ab cd ef)'], @@ -332,9 +325,9 @@ class SearchTest extends PHPUnit\Framework\TestCase { } /** - * @dataProvider provideParentheses * @param array<string> $values */ + #[DataProvider('provideParentheses')] public function test__parentheses(string $input, string $sql, array $values): void { [$filterValues, $filterSearch] = FreshRSS_EntryDAOPGSQL::sqlBooleanSearch('e.', new FreshRSS_BooleanSearch($input)); self::assertEquals(trim($sql), trim($filterSearch)); @@ -342,7 +335,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { } /** @return array<array<mixed>> */ - public function provideParentheses(): array { + public static function provideParentheses(): array { return [ [ 'f:1 (f:2 OR f:3 OR f:4) (f:5 OR (f:6 OR f:7))', diff --git a/tests/app/Models/UserQueryTest.php b/tests/app/Models/UserQueryTest.php index 828bd4276..f9577e49b 100644 --- a/tests/app/Models/UserQueryTest.php +++ b/tests/app/Models/UserQueryTest.php @@ -6,13 +6,13 @@ declare(strict_types=1); */ class UserQueryTest extends PHPUnit\Framework\TestCase { - public function test__construct_whenAllQuery_storesAllParameters(): void { + public static function test__construct_whenAllQuery_storesAllParameters(): void { $query = array('get' => 'a'); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertEquals('all', $user_query->getGetType()); } - public function test__construct_whenFavoriteQuery_storesFavoriteParameters(): void { + public static function test__construct_whenFavoriteQuery_storesFavoriteParameters(): void { $query = array('get' => 's'); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertEquals('favorite', $user_query->getGetType()); @@ -56,47 +56,47 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { self::assertEquals('feed', $user_query->getGetType()); } - public function test__construct_whenUnknownQuery_doesStoreParameters(): void { + public static function test__construct_whenUnknownQuery_doesStoreParameters(): void { $query = array('get' => 'q'); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertEmpty($user_query->getGetName()); self::assertEmpty($user_query->getGetType()); } - public function test__construct_whenName_storesName(): void { + public static function test__construct_whenName_storesName(): void { $name = 'some name'; $query = array('name' => $name); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertEquals($name, $user_query->getName()); } - public function test__construct_whenOrder_storesOrder(): void { + public static function test__construct_whenOrder_storesOrder(): void { $order = 'some order'; $query = array('order' => $order); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertEquals($order, $user_query->getOrder()); } - public function test__construct_whenState_storesState(): void { + public static function test__construct_whenState_storesState(): void { $state = FreshRSS_Entry::STATE_NOT_READ | FreshRSS_Entry::STATE_FAVORITE; $query = array('state' => $state); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertEquals($state, $user_query->getState()); } - public function test__construct_whenUrl_storesUrl(): void { + public static function test__construct_whenUrl_storesUrl(): void { $url = 'some url'; $query = array('url' => $url); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertEquals($url, $user_query->getUrl()); } - public function testToArray_whenNoData_returnsEmptyArray(): void { + public static function testToArray_whenNoData_returnsEmptyArray(): void { $user_query = new FreshRSS_UserQuery([], [], []); self::assertCount(0, $user_query->toArray()); } - public function testToArray_whenData_returnsArray(): void { + public static function testToArray_whenData_returnsArray(): void { $query = array( 'get' => 's', 'name' => 'some name', @@ -110,7 +110,7 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { self::assertEquals($query, $user_query->toArray()); } - public function testHasSearch_whenSearch_returnsTrue(): void { + public static function testHasSearch_whenSearch_returnsTrue(): void { $query = array( 'search' => 'some search', ); @@ -118,24 +118,24 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { self::assertTrue($user_query->hasSearch()); } - public function testHasSearch_whenNoSearch_returnsFalse(): void { + public static function testHasSearch_whenNoSearch_returnsFalse(): void { $user_query = new FreshRSS_UserQuery([], [], []); self::assertFalse($user_query->hasSearch()); } - public function testHasParameters_whenAllQuery_returnsFalse(): void { + public static function testHasParameters_whenAllQuery_returnsFalse(): void { $query = array('get' => 'a'); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertFalse($user_query->hasParameters()); } - public function testHasParameters_whenNoParameter_returnsFalse(): void { + public static function testHasParameters_whenNoParameter_returnsFalse(): void { $query = array(); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertFalse($user_query->hasParameters()); } - public function testHasParameters_whenParameter_returnTrue(): void { + public static function testHasParameters_whenParameter_returnTrue(): void { $query = array('get' => 's'); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertTrue($user_query->hasParameters()); @@ -153,7 +153,7 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { self::assertFalse($user_query->isDeprecated()); } - public function testIsDeprecated_whenCategoryDoesNotExist_returnTrue(): void { + public static function testIsDeprecated_whenCategoryDoesNotExist_returnTrue(): void { $query = array('get' => 'c_1'); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertTrue($user_query->isDeprecated()); @@ -193,19 +193,19 @@ class UserQueryTest extends PHPUnit\Framework\TestCase { self::assertTrue($user_query->isDeprecated()); } - public function testIsDeprecated_whenAllQuery_returnFalse(): void { + public static function testIsDeprecated_whenAllQuery_returnFalse(): void { $query = array('get' => 'a'); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertFalse($user_query->isDeprecated()); } - public function testIsDeprecated_whenFavoriteQuery_returnFalse(): void { + public static function testIsDeprecated_whenFavoriteQuery_returnFalse(): void { $query = array('get' => 's'); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertFalse($user_query->isDeprecated()); } - public function testIsDeprecated_whenUnknownQuery_returnFalse(): void { + public static function testIsDeprecated_whenUnknownQuery_returnFalse(): void { $query = array('get' => 'q'); $user_query = new FreshRSS_UserQuery($query, [], []); self::assertFalse($user_query->isDeprecated()); diff --git a/tests/app/Utils/dotNotationUtilTest.php b/tests/app/Utils/dotNotationUtilTest.php index a04ddba4f..e49220d30 100644 --- a/tests/app/Utils/dotNotationUtilTest.php +++ b/tests/app/Utils/dotNotationUtilTest.php @@ -1,12 +1,14 @@ <?php declare(strict_types=1); +use PHPUnit\Framework\Attributes\DataProvider; + class dotNotationUtilTest extends PHPUnit\Framework\TestCase { /** * @return Traversable<array{array<string,mixed>,string,string}> */ - public function provideJsonDots(): Traversable { + public static function provideJsonDots(): Traversable { $json = <<<json { "hello": "world", @@ -34,10 +36,10 @@ class dotNotationUtilTest extends PHPUnit\Framework\TestCase { } /** - * @dataProvider provideJsonDots * @param array<string,mixed> $array */ - public function testJsonDots(array $array, string $key, string $expected): void { + #[DataProvider('provideJsonDots')] + public static function testJsonDots(array $array, string $key, string $expected): void { $value = FreshRSS_dotNotation_Util::get($array, $key); self::assertEquals($expected, $value); } diff --git a/tests/cli/CliOptionsParserTest.php b/tests/cli/CliOptionsParserTest.php index facb5dbc5..046617721 100644 --- a/tests/cli/CliOptionsParserTest.php +++ b/tests/cli/CliOptionsParserTest.php @@ -52,163 +52,138 @@ final class CliOptionsOptionalAndRequiredTest extends CliOptionsParser { class CliOptionsParserTest extends TestCase { - public function testInvalidOptionSetWithValueReturnsError(): void { - $result = $this->runOptionalOptions('--invalid=invalid'); - + public static function testInvalidOptionSetWithValueReturnsError(): void { + $result = self::runOptionalOptions('--invalid=invalid'); self::assertEquals(['invalid' => 'unknown option: invalid'], $result->errors); } - public function testInvalidOptionSetWithoutValueReturnsError(): void { - $result = $this->runOptionalOptions('--invalid'); - + public static function testInvalidOptionSetWithoutValueReturnsError(): void { + $result = self::runOptionalOptions('--invalid'); self::assertEquals(['invalid' => 'unknown option: invalid'], $result->errors); } - public function testValidOptionSetWithValidValueAndInvalidOptionSetWithValueReturnsValueForValidOptionAndErrorForInvalidOption(): void { - $result = $this->runOptionalOptions('--string=string --invalid=invalid'); - + public static function testValidOptionSetWithValidValueAndInvalidOptionSetWithValueReturnsValueForValidOptionAndErrorForInvalidOption(): void { + $result = self::runOptionalOptions('--string=string --invalid=invalid'); self::assertEquals('string', $result->string); self::assertEquals(['invalid' => 'unknown option: invalid'], $result->errors); } - public function testOptionWithValueTypeOfStringSetOnceWithValidValueReturnsValueAsString(): void { - $result = $this->runOptionalOptions('--string=string'); - + public static function testOptionWithValueTypeOfStringSetOnceWithValidValueReturnsValueAsString(): void { + $result = self::runOptionalOptions('--string=string'); self::assertEquals('string', $result->string); } - public function testOptionWithRequiredValueTypeOfIntSetOnceWithValidValueReturnsValueAsInt(): void { - $result = $this->runOptionalOptions('--int=111'); - + public static function testOptionWithRequiredValueTypeOfIntSetOnceWithValidValueReturnsValueAsInt(): void { + $result = self::runOptionalOptions('--int=111'); self::assertEquals(111, $result->int); } - public function testOptionWithRequiredValueTypeOfBoolSetOnceWithValidValueReturnsValueAsBool(): void { - $result = $this->runOptionalOptions('--bool=on'); - + public static function testOptionWithRequiredValueTypeOfBoolSetOnceWithValidValueReturnsValueAsBool(): void { + $result = self::runOptionalOptions('--bool=on'); self::assertEquals(true, $result->bool); } - public function testOptionWithValueTypeOfArrayOfStringSetOnceWithValidValueReturnsValueAsArrayOfString(): void { - $result = $this->runOptionalOptions('--array-of-string=string'); - + public static function testOptionWithValueTypeOfArrayOfStringSetOnceWithValidValueReturnsValueAsArrayOfString(): void { + $result = self::runOptionalOptions('--array-of-string=string'); self::assertEquals(['string'], $result->arrayOfString); } - public function testOptionWithValueTypeOfStringSetMultipleTimesWithValidValueReturnsLastValueSetAsString(): void { - $result = $this->runOptionalOptions('--string=first --string=second'); - + public static function testOptionWithValueTypeOfStringSetMultipleTimesWithValidValueReturnsLastValueSetAsString(): void { + $result = self::runOptionalOptions('--string=first --string=second'); self::assertEquals('second', $result->string); } - public function testOptionWithValueTypeOfIntSetMultipleTimesWithValidValueReturnsLastValueSetAsInt(): void { - $result = $this->runOptionalOptions('--int=111 --int=222'); - + public static function testOptionWithValueTypeOfIntSetMultipleTimesWithValidValueReturnsLastValueSetAsInt(): void { + $result = self::runOptionalOptions('--int=111 --int=222'); self::assertEquals(222, $result->int); } - public function testOptionWithValueTypeOfBoolSetMultipleTimesWithValidValueReturnsLastValueSetAsBool(): void { - $result = $this->runOptionalOptions('--bool=on --bool=off'); - + public static function testOptionWithValueTypeOfBoolSetMultipleTimesWithValidValueReturnsLastValueSetAsBool(): void { + $result = self::runOptionalOptions('--bool=on --bool=off'); self::assertEquals(false, $result->bool); } - public function testOptionWithValueTypeOfArrayOfStringSetMultipleTimesWithValidValueReturnsAllSetValuesAsArrayOfString(): void { - $result = $this->runOptionalOptions('--array-of-string=first --array-of-string=second'); - + public static function testOptionWithValueTypeOfArrayOfStringSetMultipleTimesWithValidValueReturnsAllSetValuesAsArrayOfString(): void { + $result = self::runOptionalOptions('--array-of-string=first --array-of-string=second'); self::assertEquals(['first', 'second'], $result->arrayOfString); } - public function testOptionWithValueTypeOfIntSetWithInvalidValueReturnsAnError(): void { - $result = $this->runOptionalOptions('--int=one'); - + public static function testOptionWithValueTypeOfIntSetWithInvalidValueReturnsAnError(): void { + $result = self::runOptionalOptions('--int=one'); self::assertEquals(['int' => 'invalid input: int must be an integer'], $result->errors); } - public function testOptionWithValueTypeOfBoolSetWithInvalidValuesReturnsAnError(): void { - $result = $this->runOptionalOptions('--bool=bad'); - + public static function testOptionWithValueTypeOfBoolSetWithInvalidValuesReturnsAnError(): void { + $result = self::runOptionalOptions('--bool=bad'); self::assertEquals(['bool' => 'invalid input: bool must be a boolean'], $result->errors); } - public function testOptionWithValueTypeOfIntSetMultipleTimesWithValidAndInvalidValuesReturnsLastValidValueSetAsIntAndError(): void { - $result = $this->runOptionalOptions('--int=111 --int=one --int=222 --int=two'); - + public static function testOptionWithValueTypeOfIntSetMultipleTimesWithValidAndInvalidValuesReturnsLastValidValueSetAsIntAndError(): void { + $result = self::runOptionalOptions('--int=111 --int=one --int=222 --int=two'); self::assertEquals(222, $result->int); self::assertEquals(['int' => 'invalid input: int must be an integer'], $result->errors); } - public function testOptionWithValueTypeOfBoolSetMultipleTimesWithWithValidAndInvalidValuesReturnsLastValidValueSetAsBoolAndError(): void { - $result = $this->runOptionalOptions('--bool=on --bool=good --bool=off --bool=bad'); - + public static function testOptionWithValueTypeOfBoolSetMultipleTimesWithWithValidAndInvalidValuesReturnsLastValidValueSetAsBoolAndError(): void { + $result = self::runOptionalOptions('--bool=on --bool=good --bool=off --bool=bad'); self::assertEquals(false, $result->bool); self::assertEquals(['bool' => 'invalid input: bool must be a boolean'], $result->errors); } - public function testNotSetOptionWithDefaultInputReturnsDefaultInput(): void { - $result = $this->runOptionalOptions(''); - + public static function testNotSetOptionWithDefaultInputReturnsDefaultInput(): void { + $result = self::runOptionalOptions(''); self::assertEquals('default', $result->defaultInput); } - public function testOptionWithDefaultInputSetWithValidValueReturnsCorrectlyTypedValue(): void { - $result = $this->runOptionalOptions('--default-input=input'); - + public static function testOptionWithDefaultInputSetWithValidValueReturnsCorrectlyTypedValue(): void { + $result = self::runOptionalOptions('--default-input=input'); self::assertEquals('input', $result->defaultInput); } - public function testOptionWithOptionalValueSetWithoutValueReturnsEmptyString(): void { - $result = $this->runOptionalOptions('--optional-value'); - + public static function testOptionWithOptionalValueSetWithoutValueReturnsEmptyString(): void { + $result = self::runOptionalOptions('--optional-value'); self::assertEquals('', $result->optionalValue); } - public function testOptionWithOptionalValueDefaultSetWithoutValueReturnsOptionalValueDefault(): void { - $result = $this->runOptionalOptions('--optional-value-with-default'); - + public static function testOptionWithOptionalValueDefaultSetWithoutValueReturnsOptionalValueDefault(): void { + $result = self::runOptionalOptions('--optional-value-with-default'); self::assertEquals(true, $result->optionalValueWithDefault); } - public function testNotSetOptionWithOptionalValueDefaultAndDefaultInputReturnsDefaultInput(): void { - $result = $this->runOptionalOptions(''); - + public static function testNotSetOptionWithOptionalValueDefaultAndDefaultInputReturnsDefaultInput(): void { + $result = self::runOptionalOptions(''); self::assertEquals('default', $result->defaultInputAndOptionalValueWithDefault); } - public function testOptionWithOptionalValueDefaultAndDefaultInputSetWithoutValueReturnsOptionalValueDefault(): void { - $result = $this->runOptionalOptions('--default-input-and-optional-value-with-default'); - + public static function testOptionWithOptionalValueDefaultAndDefaultInputSetWithoutValueReturnsOptionalValueDefault(): void { + $result = self::runOptionalOptions('--default-input-and-optional-value-with-default'); self::assertEquals('optional', $result->defaultInputAndOptionalValueWithDefault); } - public function testRequiredOptionNotSetReturnsError(): void { - $result = $this->runOptionalAndRequiredOptions(''); - + public static function testRequiredOptionNotSetReturnsError(): void { + $result = self::runOptionalAndRequiredOptions(''); self::assertEquals(['required' => 'invalid input: required cannot be empty'], $result->errors); } - public function testOptionSetWithDeprecatedAliasGeneratesDeprecationWarningAndReturnsValue(): void { - $result = $this->runCommandReadingStandardError('--deprecated-string=string'); - + public static function testOptionSetWithDeprecatedAliasGeneratesDeprecationWarningAndReturnsValue(): void { + $result = self::runCommandReadingStandardError('--deprecated-string=string'); self::assertEquals('FreshRSS deprecation warning: the CLI option(s): deprecated-string are deprecated ' . 'and will be removed in a future release. Use: string instead', $result ); - $result = $this->runOptionalOptions('--deprecated-string=string'); - + $result = self::runOptionalOptions('--deprecated-string=string'); self::assertEquals('string', $result->string); } - public function testAlwaysReturnUsageMessageWithUsageInfoForAllOptions(): void { - $result = $this->runOptionalAndRequiredOptions(''); - + public static function testAlwaysReturnUsageMessageWithUsageInfoForAllOptions(): void { + $result = self::runOptionalAndRequiredOptions(''); self::assertEquals('Usage: cli-parser-test.php --required=<required> [-s --string=<string>] [-i --int=<int>] [-b --bool=<bool>] [-f --flag]', $result->usage, ); } - private function runOptionalOptions(string $cliOptions = ''): CliOptionsOptionalTest { + private static function runOptionalOptions(string $cliOptions = ''): CliOptionsOptionalTest { $command = __DIR__ . '/cli-parser-test.php'; $className = CliOptionsOptionalTest::class; @@ -219,7 +194,7 @@ class CliOptionsParserTest extends TestCase { return $result; } - private function runOptionalAndRequiredOptions(string $cliOptions = ''): CliOptionsOptionalAndRequiredTest { + private static function runOptionalAndRequiredOptions(string $cliOptions = ''): CliOptionsOptionalAndRequiredTest { $command = __DIR__ . '/cli-parser-test.php'; $className = CliOptionsOptionalAndRequiredTest::class; @@ -230,7 +205,7 @@ class CliOptionsParserTest extends TestCase { return $result; } - private function runCommandReadingStandardError(string $cliOptions = ''): string { + private static function runCommandReadingStandardError(string $cliOptions = ''): string { $command = __DIR__ . '/cli-parser-test.php'; $className = CliOptionsOptionalTest::class; diff --git a/tests/cli/i18n/I18nCompletionValidatorTest.php b/tests/cli/i18n/I18nCompletionValidatorTest.php index bc992edbe..f16285005 100644 --- a/tests/cli/i18n/I18nCompletionValidatorTest.php +++ b/tests/cli/i18n/I18nCompletionValidatorTest.php @@ -42,7 +42,7 @@ class I18nCompletionValidatorTest extends PHPUnit\Framework\TestCase { $validator->displayReport(); } - public function testValidateWhenNoData(): void { + public static function testValidateWhenNoData(): void { $validator = new I18nCompletionValidator([], []); self::assertTrue($validator->validate()); self::assertEquals('', $validator->displayResult()); diff --git a/tests/cli/i18n/I18nUsageValidatorTest.php b/tests/cli/i18n/I18nUsageValidatorTest.php index 3135cef22..1c604390f 100644 --- a/tests/cli/i18n/I18nUsageValidatorTest.php +++ b/tests/cli/i18n/I18nUsageValidatorTest.php @@ -42,7 +42,7 @@ class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase { $validator->displayReport(); } - public function testValidateWhenNoData(): void { + public static function testValidateWhenNoData(): void { $validator = new I18nUsageValidator([], []); self::assertTrue($validator->validate()); self::assertEquals('', $validator->displayResult()); diff --git a/tests/cli/i18n/I18nValueTest.php b/tests/cli/i18n/I18nValueTest.php index 06d57eb08..44984d7b2 100644 --- a/tests/cli/i18n/I18nValueTest.php +++ b/tests/cli/i18n/I18nValueTest.php @@ -3,35 +3,35 @@ declare(strict_types=1); require_once __DIR__ . '/../../../cli/i18n/I18nValue.php'; class I18nValueTest extends PHPUnit\Framework\TestCase { - public function testConstructorWithoutState(): void { + public static function testConstructorWithoutState(): void { $value = new I18nValue('some value'); self::assertEquals('some value', $value->getValue()); self::assertFalse($value->isIgnore()); self::assertFalse($value->isTodo()); } - public function testConstructorWithUnknownState(): void { + public static function testConstructorWithUnknownState(): void { $value = new I18nValue('some value -> unknown'); self::assertEquals('some value', $value->getValue()); self::assertFalse($value->isIgnore()); self::assertFalse($value->isTodo()); } - public function testConstructorWithTodoState(): void { + public static function testConstructorWithTodoState(): void { $value = new I18nValue('some value -> todo'); self::assertEquals('some value', $value->getValue()); self::assertFalse($value->isIgnore()); self::assertTrue($value->isTodo()); } - public function testConstructorWithIgnoreState(): void { + public static function testConstructorWithIgnoreState(): void { $value = new I18nValue('some value -> ignore'); self::assertEquals('some value', $value->getValue()); self::assertTrue($value->isIgnore()); self::assertFalse($value->isTodo()); } - public function testClone(): void { + public static function testClone(): void { $value = new I18nValue('some value'); $clonedValue = clone $value; self::assertEquals('some value', $value->getValue()); @@ -42,21 +42,21 @@ class I18nValueTest extends PHPUnit\Framework\TestCase { self::assertTrue($clonedValue->isTodo()); } - public function testEqualWhenValueIsIdentical(): void { + public static function testEqualWhenValueIsIdentical(): void { $value = new I18nValue('some value'); $clonedValue = clone $value; self::assertTrue($value->equal($clonedValue)); self::assertTrue($clonedValue->equal($value)); } - public function testEqualWhenValueIsDifferent(): void { + public static function testEqualWhenValueIsDifferent(): void { $value = new I18nValue('some value'); $otherValue = new I18nValue('some other value'); self::assertFalse($value->equal($otherValue)); self::assertFalse($otherValue->equal($value)); } - public function testStates(): void { + public static function testStates(): void { $reflectionProperty = new ReflectionProperty(I18nValue::class, 'state'); $reflectionProperty->setAccessible(true); @@ -74,7 +74,7 @@ class I18nValueTest extends PHPUnit\Framework\TestCase { self::assertEquals('todo', $reflectionProperty->getValue($value)); } - public function testToString(): void { + public static function testToString(): void { $value = new I18nValue('some value'); self::assertEquals('some value', $value->__toString()); $value->markAsTodo(); diff --git a/tests/lib/CssXPath/CssXPathTest.php b/tests/lib/CssXPath/CssXPathTest.php index ed92ece16..8197f5b87 100644 --- a/tests/lib/CssXPath/CssXPathTest.php +++ b/tests/lib/CssXPath/CssXPathTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); class CssXPathTest extends PHPUnit\Framework\TestCase { - public function testCssXPathTranslatorClassExists(): void { + public static function testCssXPathTranslatorClassExists(): void { self::assertTrue(class_exists('Gt\\CssXPath\\Translator')); } } diff --git a/tests/lib/Minz/MigratorTest.php b/tests/lib/Minz/MigratorTest.php index 6560715da..75c6eee23 100644 --- a/tests/lib/Minz/MigratorTest.php +++ b/tests/lib/Minz/MigratorTest.php @@ -4,7 +4,7 @@ use PHPUnit\Framework\TestCase; class MigratorTest extends TestCase { - public function testAddMigration(): void { + public static function testAddMigration(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('foo', fn() => true); @@ -15,7 +15,7 @@ class MigratorTest extends TestCase self::assertTrue($result); } - public function testMigrationsIsSorted(): void { + public static function testMigrationsIsSorted(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('2_foo', fn() => true); $migrator->addMigration('10_foo', fn() => true); @@ -27,7 +27,7 @@ class MigratorTest extends TestCase self::assertSame($expected_versions, array_keys($migrations)); } - public function testSetAppliedVersions(): void { + public static function testSetAppliedVersions(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('foo', fn() => true); @@ -36,7 +36,7 @@ class MigratorTest extends TestCase self::assertSame(['foo'], $migrator->appliedVersions()); } - public function testSetAppliedVersionsTrimArgument(): void { + public static function testSetAppliedVersionsTrimArgument(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('foo', fn() => true); @@ -54,7 +54,7 @@ class MigratorTest extends TestCase $migrator->setAppliedVersions(['foo']); } - public function testVersions(): void { + public static function testVersions(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('foo', fn() => true); $migrator->addMigration('bar', fn() => true); @@ -64,7 +64,7 @@ class MigratorTest extends TestCase self::assertSame(['bar', 'foo'], $versions); } - public function testMigrate(): void { + public static function testMigrate(): void { $migrator = new Minz_Migrator(); $spy = false; $migrator->addMigration('foo', function () use (&$spy) { @@ -82,7 +82,7 @@ class MigratorTest extends TestCase ], $result); } - public function testMigrateCallsMigrationsInSortedOrder(): void { + public static function testMigrateCallsMigrationsInSortedOrder(): void { $migrator = new Minz_Migrator(); $spy_foo_1_is_called = false; $migrator->addMigration('2_foo', function () use (&$spy_foo_1_is_called) { @@ -102,7 +102,7 @@ class MigratorTest extends TestCase ], $result); } - public function testMigrateDoesNotCallAppliedMigrations(): void { + public static function testMigrateDoesNotCallAppliedMigrations(): void { $migrator = new Minz_Migrator(); $spy = false; $migrator->addMigration('1_foo', function () use (&$spy) { @@ -117,7 +117,7 @@ class MigratorTest extends TestCase self::assertSame([], $result); } - public function testMigrateCallNonAppliedBetweenTwoApplied(): void { + public static function testMigrateCallNonAppliedBetweenTwoApplied(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('1_foo', fn() => true); $migrator->addMigration('2_foo', fn() => true); @@ -132,7 +132,7 @@ class MigratorTest extends TestCase ], $result); } - public function testMigrateWithMigrationReturningFalseDoesNotApplyVersion(): void { + public static function testMigrateWithMigrationReturningFalseDoesNotApplyVersion(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('1_foo', fn() => true); $migrator->addMigration('2_foo', fn() => false); @@ -146,7 +146,7 @@ class MigratorTest extends TestCase ], $result); } - public function testMigrateWithMigrationReturningFalseDoesNotExecuteNextMigrations(): void { + public static function testMigrateWithMigrationReturningFalseDoesNotExecuteNextMigrations(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('1_foo', fn() => false); $spy = false; @@ -164,7 +164,7 @@ class MigratorTest extends TestCase ], $result); } - public function testMigrateWithFailingMigration(): void { + public static function testMigrateWithFailingMigration(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('foo', function () { throw new \Exception('Oops, it failed.'); @@ -178,7 +178,7 @@ class MigratorTest extends TestCase ], $result); } - public function testUpToDate(): void { + public static function testUpToDate(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('foo', fn() => true); $migrator->setAppliedVersions(['foo']); @@ -188,7 +188,7 @@ class MigratorTest extends TestCase self::assertTrue($upToDate); } - public function testUpToDateIfRemainingMigration(): void { + public static function testUpToDateIfRemainingMigration(): void { $migrator = new Minz_Migrator(); $migrator->addMigration('1_foo', fn() => true); $migrator->addMigration('2_foo', fn() => true); @@ -199,7 +199,7 @@ class MigratorTest extends TestCase self::assertFalse($upToDate); } - public function testUpToDateIfNoMigrations(): void { + public static function testUpToDateIfNoMigrations(): void { $migrator = new Minz_Migrator(); $upToDate = $migrator->upToDate(); @@ -207,7 +207,7 @@ class MigratorTest extends TestCase self::assertTrue($upToDate); } - public function testConstructorLoadsDirectory(): void { + public static function testConstructorLoadsDirectory(): void { $migrations_path = TESTS_PATH . '/fixtures/migrations/'; $migrator = new Minz_Migrator($migrations_path); $expected_versions = ['2019_12_22_FooBar', '2019_12_23_Baz']; @@ -217,7 +217,7 @@ class MigratorTest extends TestCase self::assertSame($expected_versions, array_keys($migrations)); } - public function testExecute(): void { + public static function testExecute(): void { $migrations_path = TESTS_PATH . '/fixtures/migrations/'; $applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt'); self::assertIsString($applied_migrations_path); @@ -229,7 +229,7 @@ class MigratorTest extends TestCase @unlink($applied_migrations_path); } - public function testExecuteWithAlreadyAppliedMigration(): void { + public static function testExecuteWithAlreadyAppliedMigration(): void { $migrations_path = TESTS_PATH . '/fixtures/migrations/'; $applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt'); self::assertIsString($applied_migrations_path); @@ -243,7 +243,7 @@ class MigratorTest extends TestCase @unlink($applied_migrations_path); } - public function testExecuteWithAppliedMigrationInDifferentOrder(): void { + public static function testExecuteWithAppliedMigrationInDifferentOrder(): void { $migrations_path = TESTS_PATH . '/fixtures/migrations/'; $applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt'); self::assertIsString($applied_migrations_path); @@ -258,7 +258,7 @@ class MigratorTest extends TestCase @unlink($applied_migrations_path); } - public function testExecuteFailsIfVersionPathDoesNotExist(): void { + public static function testExecuteFailsIfVersionPathDoesNotExist(): void { $migrations_path = TESTS_PATH . '/fixtures/migrations/'; $applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt'); $expected_result = "Cannot open the {$applied_migrations_path} file"; @@ -270,7 +270,7 @@ class MigratorTest extends TestCase @unlink($applied_migrations_path); } - public function testExecuteFailsIfAMigrationIsFailing(): void { + public static function testExecuteFailsIfAMigrationIsFailing(): void { $migrations_path = TESTS_PATH . '/fixtures/migrations_with_failing/'; $applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt'); $expected_result = 'A migration failed to be applied, please see previous logs.'; diff --git a/tests/lib/PHPMailer/PHPMailerTest.php b/tests/lib/PHPMailer/PHPMailerTest.php index bb08deaa8..8bc8378b6 100644 --- a/tests/lib/PHPMailer/PHPMailerTest.php +++ b/tests/lib/PHPMailer/PHPMailerTest.php @@ -5,7 +5,7 @@ use PHPMailer\PHPMailer\PHPMailer; class PHPMailerTest extends PHPUnit\Framework\TestCase { - public function testPHPMailerClassExists(): void { + public static function testPHPMailerClassExists(): void { self::assertTrue(class_exists(PHPMailer::class)); } } |
