From c9ef60553efb71a55e1dbe3dd90a2f3698c256ec Mon Sep 17 00:00:00 2001 From: Lode Claassen Date: Tue, 25 Nov 2025 22:47:14 +0100 Subject: [PATCH 1/8] setup linting scripts, although reviewdog doesn't work yet :( --- .gitignore | 1 + composer.json | 15 +- composer.lock | 437 ++++++++++++++++++++++++++++++++++++++++++++- phpcs.bonus.xml | 32 ++++ phpcs.xml | 44 +++++ phpstan.bonus.neon | 12 ++ phpstan.neon | 23 +++ rector.php | 27 +++ script/README.md | 2 + script/fix | 101 +++++++++++ script/lint | 183 +++++++++++++++++++ 11 files changed, 875 insertions(+), 2 deletions(-) create mode 100644 phpcs.bonus.xml create mode 100644 phpcs.xml create mode 100644 phpstan.bonus.neon create mode 100644 phpstan.neon create mode 100644 rector.php create mode 100755 script/fix create mode 100755 script/lint diff --git a/.gitignore b/.gitignore index f219c391..faae2eeb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ vendor/ examples/test-coverage/ +.phpcs-cache .phpunit.cache .phpunit.result.cache diff --git a/composer.json b/composer.json index aff3a3f6..d244643f 100644 --- a/composer.json +++ b/composer.json @@ -24,9 +24,22 @@ }, "require-dev": { "phpunit/phpunit": "^12.4", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0", + "phpstan/phpstan": "^2.1", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "rector/rector": "^2.2", + "rector/swiss-knife": "^2.3", + "squizlabs/php_codesniffer": "^4.0" }, "suggest": { "psr/http-message": "Allows constructing requests from Psr RequestInterface" + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true + } } } diff --git a/composer.lock b/composer.lock index 683b0515..141fbc6b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "74b269f7150166e49e186c501e276db7", + "content-hash": "263d00c16803c650bac943c2a0287fcf", "packages": [], "packages-dev": [ { @@ -243,6 +243,255 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "time": "2024-09-04T20:21:43+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.1.32", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e126cad1e30a99b137b8ed75a85a676450ebb227", + "reference": "e126cad1e30a99b137b8ed75a85a676450ebb227", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-11-11T15:18:17+00:00" + }, + { + "name": "phpstan/phpstan-deprecation-rules", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", + "reference": "468e02c9176891cc901143da118f09dc9505fc2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/468e02c9176891cc901143da118f09dc9505fc2f", + "reference": "468e02c9176891cc901143da118f09dc9505fc2f", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.15" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", + "support": { + "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", + "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.3" + }, + "time": "2025-05-14T10:56:57+00:00" + }, + { + "name": "phpstan/phpstan-phpunit", + "version": "2.0.8", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-phpunit.git", + "reference": "2fe9fbeceaf76dd1ebaa7bbbb25e2fb5e59db2fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/2fe9fbeceaf76dd1ebaa7bbbb25e2fb5e59db2fe", + "reference": "2fe9fbeceaf76dd1ebaa7bbbb25e2fb5e59db2fe", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.32" + }, + "conflict": { + "phpunit/phpunit": "<7.0" + }, + "require-dev": { + "nikic/php-parser": "^5", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPUnit extensions and rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-phpunit/issues", + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.8" + }, + "time": "2025-11-11T07:55:22+00:00" + }, + { + "name": "phpstan/phpstan-strict-rules", + "version": "2.0.7", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-strict-rules.git", + "reference": "d6211c46213d4181054b3d77b10a5c5cb0d59538" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/d6211c46213d4181054b3d77b10a5c5cb0d59538", + "reference": "d6211c46213d4181054b3d77b10a5c5cb0d59538", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.29" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Extra strict and opinionated rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.7" + }, + "time": "2025-09-26T11:19:08+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "12.4.0", @@ -735,6 +984,113 @@ }, "time": "2023-04-04T09:50:52+00:00" }, + { + "name": "rector/rector", + "version": "2.2.8", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "303aa811649ccd1d32e51e62d5c85949d01b5f1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/303aa811649ccd1d32e51e62d5c85949d01b5f1b", + "reference": "303aa811649ccd1d32e51e62d5c85949d01b5f1b", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.32" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "homepage": "https://getrector.com/", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/2.2.8" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2025-11-12T18:38:00+00:00" + }, + { + "name": "rector/swiss-knife", + "version": "2.3.3", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/swiss-knife.git", + "reference": "4e19741422511b7b26d64dcf272fab6dc155f873" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/swiss-knife/zipball/4e19741422511b7b26d64dcf272fab6dc155f873", + "reference": "4e19741422511b7b26d64dcf272fab6dc155f873", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "bin": [ + "bin/swiss-knife" + ], + "type": "library", + "autoload": { + "psr-4": { + "Rector\\SwissKnife\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Swiss knife in pocket of every upgrade architect", + "support": { + "issues": "https://github.com/rectorphp/swiss-knife/issues", + "source": "https://github.com/rectorphp/swiss-knife/tree/2.3.3" + }, + "funding": [ + { + "url": "https://www.paypal.me/rectorphp", + "type": "custom" + }, + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2025-08-15T14:49:18+00:00" + }, { "name": "sebastian/cli-parser", "version": "4.2.0", @@ -1632,6 +1988,85 @@ ], "time": "2025-02-07T05:00:38+00:00" }, + { + "name": "squizlabs/php_codesniffer", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "0525c73950de35ded110cffafb9892946d7771b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0525c73950de35ded110cffafb9892946d7771b5", + "reference": "0525c73950de35ded110cffafb9892946d7771b5", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=7.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.4.0 || ^9.3.4 || ^10.5.32 || 11.3.3 - 11.5.28 || ^11.5.31" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-10T16:43:36+00:00" + }, { "name": "staabm/side-effects-detector", "version": "1.0.5", diff --git a/phpcs.bonus.xml b/phpcs.bonus.xml new file mode 100644 index 00000000..be72666a --- /dev/null +++ b/phpcs.bonus.xml @@ -0,0 +1,32 @@ + + + . + + ./.ddev/* + ./vendor/* + ./src/base.php + ./src/collection.php + ./src/error.php + ./src/errors.php + ./src/exception.php + ./src/resource.php + ./src/response.php + + + + + + + + + + + + + + + diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 00000000..dfe3e690 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,44 @@ + + + . + + ./.ddev/* + ./vendor/* + ./src/base.php + ./src/collection.php + ./src/error.php + ./src/errors.php + ./src/exception.php + ./src/resource.php + ./src/response.php + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phpstan.bonus.neon b/phpstan.bonus.neon new file mode 100644 index 00000000..7a702e5e --- /dev/null +++ b/phpstan.bonus.neon @@ -0,0 +1,12 @@ +includes: + - phpstan.neon + - vendor/phpstan/phpstan/conf/bleedingEdge.neon + +parameters: + level: 9 + + treatPhpDocTypesAsCertain: true + + # @see https://github.com/phpstan/phpstan-strict-rules + strictRules: + allRules: true diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..57de3457 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,23 @@ +parameters: + # slowly increase + level: 0 + paths: + - src/ + - tests/ + - examples/ + excludePaths: + - src/base.php + - src/collection.php + - src/error.php + - src/errors.php + - src/exception.php + - src/resource.php + - src/response.php + + strictRules: + allRules: false + + reportUnmatchedIgnoredErrors: true + ignoreErrors: + # add cases to ignore because they are too much work for now + # @see https://phpstan.org/user-guide/ignoring-errors#ignoring-in-configuration-file diff --git a/rector.php b/rector.php new file mode 100644 index 00000000..d0ae665f --- /dev/null +++ b/rector.php @@ -0,0 +1,27 @@ +withPaths([ + __DIR__ . '/src', + __DIR__ . '/tests', + __DIR__ . '/examples', + ]) + + // tab-based indenting + ->withIndent(indentChar: "\t", indentSize: 1) + + // slowly increase php version + ->withPhpSets(php53: true) + + // slowly increase levels + ->withTypeCoverageLevel(1) + ->withDeadCodeLevel(1) + + // @todo add `->withPreparedSets()` once on a higher level with other rules +; diff --git a/script/README.md b/script/README.md index 8ba3c414..c836c116 100644 --- a/script/README.md +++ b/script/README.md @@ -25,6 +25,8 @@ This will updates composer packages. ## Lint / fix / test +- `./script/lint`: run all linters (reviewdog is broken, see `--help` to run for specific types) +- `./script/fix`: auto fix from linters (reviewdog is broken, see `--help` to run for specific types) - `./script/test`: run all tests diff --git a/script/fix b/script/fix new file mode 100755 index 00000000..3d072270 --- /dev/null +++ b/script/fix @@ -0,0 +1,101 @@ +#!/usr/bin/env bash + +set -e +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cd $SCRIPT_DIR/.. + +# docker configured and not inside docker +CONSOLE_PREFIX="" +if test ! -f /.dockerenv; then + CONSOLE_PREFIX="./script/console" +fi + +# colors and fonts, only loaded on interactive terminals +if [ -t 0 ]; then + T_ERROR=$(tput setaf 7; tput setab 1) + T_INFO=$(tput setaf 7; tput setab 4) + T_WARNING=$(tput setaf 0; tput setab 3) + T_SUCCESS=$(tput setaf 0; tput setab 2) + T_BOLD=$(tput bold) + T_RESET=$(tput sgr0) +fi + +if test "$1" = "--help"; then + echo "${T_INFO}./script/fix [] [--everything] [extra arguments]${T_RESET}" + echo 'Lets linters fix code, defaults to phpcbf (phpcs) and rector on the *git-diff* between the base and the head branch' + echo '' + echo "${T_BOLD}${T_RESET}" + echo 'Optional, if set it runs on the *changed files* (not only git-diff) between the base and the head branch' + echo '- phpcbf (or phpcs)' + echo '- rector' + echo '' + echo "${T_BOLD}--everything${T_RESET}" + echo 'Optional, if set it runs on the *whole codebase* instead of the diff/changed-files (ignored when no type is given)' + echo '' + echo "${T_BOLD}extra arguments${T_RESET}" + echo 'Optional, passed to the linter of the specified type (ignored when no type is given)' + echo '' + echo "${T_INFO}./script/fix --help${T_RESET}" + echo 'Shows this help' + exit 0 +fi + +# check arguments +test "$2" = "--everything" && HAS_EVERYTHING=1 || HAS_EVERYTHING=0 +test "$#" -gt 0 && HAS_TYPE=1 || HAS_TYPE=0 + +# store type and its extra arguments +TYPE="" +EXTRA_ARGUMENTS="" +if test "$HAS_TYPE" = 1; then + TYPE="$1" + EXTRA_ARGUMENTS="${@:2}" + + if test "$HAS_EVERYTHING" = 1; then + EXTRA_ARGUMENTS="${@:3}" + fi + + if test -n "$EXTRA_ARGUMENTS"; then + echo "${T_INFO}Running $TYPE with extra arguments: $EXTRA_ARGUMENTS${T_RESET}" + fi +fi + +# gather files to test +GIT_MERGE_BASE=$(git merge-base main @) +if test "$HAS_EVERYTHING" = 1; then + FILE_FILTER="" +else + # get names of files changed in this branch + DIFF_FILE_NAMES=`git diff $GIT_MERGE_BASE --name-only --diff-filter=d` + if test -z "$DIFF_FILE_NAMES"; then + echo "${T_WARNING}No files changed${T_RESET}" + exit 0 + fi + + # convert filenames with newlines to filenames with spaces + FILE_FILTER="${DIFF_FILE_NAMES//$'\n'/ }" +fi + +if test "$HAS_TYPE" = 1; then + if test "$TYPE" = "phpcbf" || test "$TYPE" = "phpcs"; then + $CONSOLE_PREFIX ./vendor/bin/phpcbf $EXTRA_ARGUMENTS $FILE_FILTER + + elif test "$TYPE" = "rector"; then + echo "${T_WARNING}Rector might not produce correct results until phpstan is on level 4 on the main branch${T_RESET}" + $CONSOLE_PREFIX ./vendor/bin/rector process $EXTRA_ARGUMENTS $FILE_FILTER + + else + echo "${T_ERROR}Unknown type specified: $TYPE${T_RESET}" + exit 1 + + fi +else + echo -e "${T_BOLD}Running fixes on the changed files (not only git-diff) between the base and the head branch${T_RESET}\n" + + echo "${T_INFO}Fixing refactors (rector)${T_RESET}" + echo "${T_WARNING}Rector might not produce correct results until phpstan is on level 4 on the main branch${T_RESET}" + $CONSOLE_PREFIX ./vendor/bin/rector process $FILE_FILTER || true + + echo "${T_INFO}Fixing coding standards (phpcs)${T_RESET}" + $CONSOLE_PREFIX ./vendor/bin/phpcbf $FILE_FILTER || true +fi diff --git a/script/lint b/script/lint new file mode 100755 index 00000000..18fa5ae1 --- /dev/null +++ b/script/lint @@ -0,0 +1,183 @@ +#!/usr/bin/env bash + +set -e +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cd $SCRIPT_DIR/.. + +# whether to run bonus levels by default, or only when requested +BONUS_DEFAULT=0 + +# docker configured and not inside docker +CONSOLE_PREFIX="" +if test ! -f /.dockerenv; then + CONSOLE_PREFIX="./script/console" +fi + +# colors and fonts, only loaded on interactive terminals +if [ -t 0 ]; then + T_ERROR=$(tput setaf 7; tput setab 1) + T_INFO=$(tput setaf 7; tput setab 4) + T_WARNING=$(tput setaf 0; tput setab 3) + T_SUCCESS=$(tput setaf 0; tput setab 2) + T_BOLD=$(tput bold) + T_RESET=$(tput sgr0) +fi + +if test "$1" = "--help"; then + echo "${T_INFO}./script/lint [] [--bonus] [--no-bonus] [--everything] [extra arguments]${T_RESET}" + echo 'Runs linters, defaults to phpcs and phpstan on the *git-diff* between the base and the head branch' + echo '' + echo "${T_BOLD}${T_RESET}" + echo 'Optional, if set it runs on the *changed files* (not only git-diff) between the base and the head branch' + echo '- phpcs' + echo '- phpstan' + echo '- rector' + echo '- commented (assumes --everything)' + echo '' + echo "${T_BOLD}--bonus${T_RESET}" + echo "${T_BOLD}--no-bonus${T_RESET}" + echo 'Optional, if set it includes/excludes linters on more strict levels (can be used with or without specific type)' + echo 'Default behavior can be changed with `BONUS_DEFAULT` variable in `script/lint` file' + echo '' + echo "${T_BOLD}--everything${T_RESET}" + echo 'Optional, if set it runs on the *whole codebase* instead of the diff/changed-files (ignored when no type is given)' + echo '' + echo "${T_BOLD}extra arguments${T_RESET}" + echo 'Optional, passed to the linter of the specified type (ignored when no type is given)' + echo '' + echo "${T_INFO}./script/lint --list-files${T_RESET}" + echo 'Shows the files it will run the linter on' + echo '' + echo "${T_INFO}./script/lint --help${T_RESET}" + echo 'Shows this help' + exit 0 +fi + +# check arguments +(test "$1" = "--list-files") && HAS_LIST_FILES=1 || HAS_LIST_FILES=0 +(test "$2" = "--everything" || test "$3" = "--everything") && HAS_EVERYTHING=1 || HAS_EVERYTHING=0 +(test "$1" = "--bonus" || test "$2" = "--bonus" || test "$3" = "--bonus") && BONUS_REQUESTED=1 || BONUS_REQUESTED=0 +(test "$1" = "--no-bonus" || test "$2" = "--no-bonus" || test "$3" = "--no-bonus") && BONUS_REJECTED=1 || BONUS_REJECTED=0 +(test "$#" -gt 0 && test "$1" != "--bonus" && test "$1" != "--no-bonus" && test "$1" != "--list-files" && test "$1" != "--everything") && HAS_TYPE=1 || HAS_TYPE=0 +(test "$BONUS_REJECTED" = 0 && (test "$BONUS_REQUESTED" = 1 || test "$BONUS_DEFAULT" = 1)) && HAS_BONUS=1 || HAS_BONUS=0 + +# store type and its extra arguments +TYPE="" +EXTRA_ARGUMENTS="" +if test "$HAS_TYPE" = 1; then + TYPE="$1" + EXTRA_ARGUMENTS="${@:2}" + + if (test "$BONUS_REQUESTED" = 1 || test "$BONUS_REJECTED" = 1) && test "$HAS_EVERYTHING" = 1; then + EXTRA_ARGUMENTS="${@:4}" + elif test "$BONUS_REQUESTED" = 1 || test "$BONUS_REJECTED" = 1 || test "$HAS_EVERYTHING" = 1; then + EXTRA_ARGUMENTS="${@:3}" + fi + + if test -n "$EXTRA_ARGUMENTS"; then + echo "${T_INFO}Running $TYPE with extra arguments: $EXTRA_ARGUMENTS${T_RESET}" + fi +fi + +# gather files to test +GIT_MERGE_BASE=$(git merge-base main @) +if test "$HAS_EVERYTHING" = 1; then + FILE_FILTER="" +else + # get names of files changed in this branch + DIFF_FILE_NAMES=`git diff $GIT_MERGE_BASE --name-only --diff-filter=d -- '*.php'` + if test -z "$DIFF_FILE_NAMES"; then + echo "${T_WARNING}No files changed${T_RESET}" + exit 0 + fi + + # convert filenames with newlines to filenames with spaces + FILE_FILTER="${DIFF_FILE_NAMES//$'\n'/ }" + + if test "$HAS_LIST_FILES" = 1; then + echo "$DIFF_FILE_NAMES" + exit 0 + fi +fi + +if test "$HAS_TYPE" = 1; then + if test "$TYPE" = "commented"; then + # can only work on file _paths_, thus we assume `--everything` + $CONSOLE_PREFIX ./vendor/bin/swiss-knife check-commented-code . $EXTRA_ARGUMENTS + + elif test "$TYPE" = "phpcs"; then + if test "$HAS_BONUS" = 1; then + $CONSOLE_PREFIX ./vendor/bin/phpcs --standard=phpcs.bonus.xml -p $EXTRA_ARGUMENTS $FILE_FILTER + else + $CONSOLE_PREFIX ./vendor/bin/phpcs --standard=phpcs.xml -p $EXTRA_ARGUMENTS $FILE_FILTER + fi + + elif test "$TYPE" = "phpstan"; then + if test "$HAS_BONUS" = 1; then + $CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.bonus.neon -v $EXTRA_ARGUMENTS $FILE_FILTER 2> /dev/null + else + $CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.neon -v $EXTRA_ARGUMENTS $FILE_FILTER 2> /dev/null + fi + + elif test "$TYPE" = "rector"; then + echo "${T_WARNING}Rector might not produce correct results until phpstan is on level 4 on the main branch${T_RESET}" + $CONSOLE_PREFIX ./vendor/bin/rector process --dry-run $EXTRA_ARGUMENTS $FILE_FILTER + + else + echo "${T_ERROR}Unknown type specified: $TYPE${T_RESET}" + exit 1 + fi +else + echo -e "${T_BOLD}Running checks on the git changed lines between the base and the head branch${T_RESET}\n" + + echo "${T_INFO}Checking syntax errors (php -l)${T_RESET}" + $CONSOLE_PREFIX php -l $FILE_FILTER 1> /dev/null \ + || exit 1 \ + && echo "${T_SUCCESS}Success${T_RESET}" + echo -e '\n' + + echo -e "${T_BOLD}Running checks on the git-diff between the base and the head branch${T_RESET}\n" + + if test ! -f ./vendor/bin/reviewdog; then + echo -e "${T_INFO}Installing reviewdog (in /vendor/bin/reviewdog) to lint changes only, this is one-time only${T_RESET}\n" + curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh | sh -s -- -b ./vendor/bin + echo -e '\n' + fi + + echo "${T_INFO}Checking coding standards (phpcs)${T_RESET}" + echo -e "${T_WARNING}Reviewdog is currently broken${T_RESET}\n" + $CONSOLE_PREFIX ./vendor/bin/phpcs --standard=phpcs.xml --report=checkstyle $FILE_FILTER 2> /dev/null \ + | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + && echo "${T_SUCCESS}Success${T_RESET}" + echo -e '\n' + + echo "${T_INFO}Checking static analysis (phpstan)${T_RESET}" + echo -e "${T_WARNING}Reviewdog is currently broken${T_RESET}\n" + $CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.neon --no-progress --error-format=checkstyle 2> /dev/null $FILE_FILTER \ + | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + && echo "${T_SUCCESS}Success${T_RESET}" + echo -e '\n' + + echo "${T_INFO}Checking refactors (rector)${T_RESET}" + echo "${T_WARNING}Rector might not produce correct results until phpstan is on level 4 on the main branch${T_RESET}" + $CONSOLE_PREFIX ./vendor/bin/rector process --memory-limit=4g --dry-run $FILE_FILTER 2> /dev/null \ + && echo "${T_SUCCESS}Success${T_RESET}" + + if test "$HAS_BONUS" = 1; then + echo -e '\n' + echo -e "${T_BOLD}Running bonus checks${T_RESET}\n" + + echo "${T_INFO}Checking coding standards (phpcs --bonus)${T_RESET}" + echo -e "${T_WARNING}Reviewdog is currently broken${T_RESET}\n" + $CONSOLE_PREFIX ./vendor/bin/phpcs --report=checkstyle --standard=phpcs.bonus.xml $FILE_FILTER 2> /dev/null \ + | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + && echo "${T_SUCCESS}Success${T_RESET}" + echo -e '\n' + + echo "${T_INFO}Checking static analysis (phpstan --bonus)${T_RESET}" + echo -e "${T_WARNING}Reviewdog is currently broken${T_RESET}\n" + $CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.bonus.neon --no-progress --error-format=checkstyle $FILE_FILTER 2> /dev/null \ + | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + && echo "${T_SUCCESS}Success${T_RESET}" + fi +fi From 0e3835da52b9433813595f2d89e813a354530206 Mon Sep 17 00:00:00 2001 From: Lode Claassen Date: Wed, 26 Nov 2025 08:29:18 +0100 Subject: [PATCH 2/8] small CS improvements --- examples/bootstrap_examples.php | 1 + src/exceptions/DuplicateException.php | 2 +- src/exceptions/InputException.php | 2 +- tests/ConverterTest.php | 3 +- tests/DocumentTest.php | 10 +-- .../ExampleTimestampsProfile.php | 2 +- tests/helpers/LinksManagerTest.php | 8 +- tests/helpers/RequestParserTest.php | 22 +++--- .../TestableNonInterfaceRequestInterface.php | 74 +++++++++++++++---- ...ableNonInterfaceServerRequestInterface.php | 54 +++++++++++--- .../TestableNonInterfaceStreamInterface.php | 49 +++++++++--- .../TestableNonInterfaceUriInterface.php | 69 +++++++++++++---- tests/objects/LinksObjectTest.php | 18 ++--- tests/objects/RelationshipObjectTest.php | 2 +- .../profiles/CursorPaginationProfileTest.php | 4 +- 15 files changed, 235 insertions(+), 85 deletions(-) diff --git a/examples/bootstrap_examples.php b/examples/bootstrap_examples.php index e266cb58..36a7c369 100644 --- a/examples/bootstrap_examples.php +++ b/examples/bootstrap_examples.php @@ -5,6 +5,7 @@ use alsvanzelf\jsonapi\interfaces\ExtensionInterface; use alsvanzelf\jsonapi\interfaces\ProfileInterface; use alsvanzelf\jsonapi\interfaces\ResourceInterface; +use alsvanzelf\jsonapi\objects\ResourceIdentifierObject; ini_set('display_errors', 1); error_reporting(-1); diff --git a/src/exceptions/DuplicateException.php b/src/exceptions/DuplicateException.php index 528e534e..c2a2d6fe 100644 --- a/src/exceptions/DuplicateException.php +++ b/src/exceptions/DuplicateException.php @@ -6,6 +6,6 @@ class DuplicateException extends Exception { public function __construct($message='', $code=409, $previous=null) { - return parent::__construct($message, $code, $previous); + parent::__construct($message, $code, $previous); } } diff --git a/src/exceptions/InputException.php b/src/exceptions/InputException.php index 0046f204..8f4d9295 100644 --- a/src/exceptions/InputException.php +++ b/src/exceptions/InputException.php @@ -6,6 +6,6 @@ class InputException extends Exception { public function __construct($message='', $code=400, $previous=null) { - return parent::__construct($message, $code, $previous); + parent::__construct($message, $code, $previous); } } diff --git a/tests/ConverterTest.php b/tests/ConverterTest.php index c564c6ea..0f4f35e0 100644 --- a/tests/ConverterTest.php +++ b/tests/ConverterTest.php @@ -119,7 +119,8 @@ public function testMergeProfilesInContentType_HappyPath() { $profile = new TestProfile(); $profile->setOfficialLink('bar'); - $this->assertSame('foo; profile="bar"', Converter::mergeProfilesInContentType('foo', [$profile])); + $contentType = Converter::mergeProfilesInContentType('foo', [$profile]); // @phpstan-ignore staticMethod.deprecated + $this->assertSame('foo; profile="bar"', $contentType); } } diff --git a/tests/DocumentTest.php b/tests/DocumentTest.php index 020a70ac..8a262049 100644 --- a/tests/DocumentTest.php +++ b/tests/DocumentTest.php @@ -45,7 +45,7 @@ public function testAddLink_HappyPath() { $this->assertIsString($array['links']['foo']); } else { - $this->assertInternalType('string', $array['links']['foo']); + $this->assertIsString($array['links']['foo']); } $this->assertSame('https://jsonapi.org', $array['links']['foo']); } @@ -61,7 +61,7 @@ public function testAddLink_WithMeta() { $this->assertIsArray($array['links']['foo']); } else { - $this->assertInternalType('array', $array['links']['foo']); + $this->assertIsArray($array['links']['foo']); } $this->assertCount(2, $array['links']['foo']); $this->assertArrayHasKey('href', $array['links']['foo']); @@ -125,7 +125,7 @@ public function testSetDescribedByLink_HappyPath() { $this->assertIsArray($array['links']['describedby']); } else { - $this->assertInternalType('array', $array['links']['describedby']); + $this->assertIsArray($array['links']['describedby']); } $this->assertCount(2, $array['links']['describedby']); $this->assertArrayHasKey('href', $array['links']['describedby']); @@ -168,7 +168,7 @@ public function testAddMeta_HappyPath() { $this->assertIsString($array['meta']['foo']); } else { - $this->assertInternalType('string', $array['meta']['foo']); + $this->assertIsString($array['meta']['foo']); } $this->assertSame('bar', $array['meta']['foo']); } @@ -192,7 +192,7 @@ public function testAddMeta_AtJsonapiLevel() { $this->assertIsString($array['jsonapi']['meta']['foo']); } else { - $this->assertInternalType('string', $array['jsonapi']['meta']['foo']); + $this->assertIsString($array['jsonapi']['meta']['foo']); } $this->assertSame('bar', $array['jsonapi']['meta']['foo']); } diff --git a/tests/example_output/ExampleTimestampsProfile.php b/tests/example_output/ExampleTimestampsProfile.php index 4426643f..ad485bcf 100644 --- a/tests/example_output/ExampleTimestampsProfile.php +++ b/tests/example_output/ExampleTimestampsProfile.php @@ -13,7 +13,7 @@ public function getOfficialLink() { public function setTimestamps(ResourceInterface $resource, ?\DateTimeInterface $created=null, ?\DateTimeInterface $updated=null) { if ($resource instanceof ResourceIdentifierObject) { - throw new Exception('cannot add attributes to identifier objects'); + throw new \Exception('cannot add attributes to identifier objects'); } $timestamps = []; diff --git a/tests/helpers/LinksManagerTest.php b/tests/helpers/LinksManagerTest.php index be87fa2c..d3fa114e 100644 --- a/tests/helpers/LinksManagerTest.php +++ b/tests/helpers/LinksManagerTest.php @@ -22,7 +22,7 @@ public function testAddLink_HappyPath() { public function testAppendLink_HappyPath() { $linksManager = new LinksManager(); - $linksManager->appendLink('foo', 'https://jsonapi.org'); + $linksManager->appendLink('foo', 'https://jsonapi.org'); // @phpstan-ignore method.deprecated $array = $linksManager->toArray(); @@ -35,7 +35,7 @@ public function testAppendLink_HappyPath() { public function testAppendLink_WithMeta() { $linksManager = new LinksManager(); - $linksManager->appendLink('foo', 'https://jsonapi.org', ['bar' => 'baz']); + $linksManager->appendLink('foo', 'https://jsonapi.org', ['bar' => 'baz']); // @phpstan-ignore method.deprecated $array = $linksManager->toArray(); @@ -52,8 +52,8 @@ public function testAppendLink_WithMeta() { public function testAppendLink_MultipleLinks() { $linksManager = new LinksManager(); - $linksManager->appendLink('foo', 'https://jsonapi.org', ['bar' => 'baz']); - $linksManager->appendLink('foo', 'https://jsonapi.org/2'); + $linksManager->appendLink('foo', 'https://jsonapi.org', ['bar' => 'baz']); // @phpstan-ignore method.deprecated + $linksManager->appendLink('foo', 'https://jsonapi.org/2'); // @phpstan-ignore method.deprecated $array = $linksManager->toArray(); diff --git a/tests/helpers/RequestParserTest.php b/tests/helpers/RequestParserTest.php index e1a586dd..e3d63115 100644 --- a/tests/helpers/RequestParserTest.php +++ b/tests/helpers/RequestParserTest.php @@ -71,7 +71,7 @@ public function testFromSuperglobals_HappyPath() { $this->assertSame('Foo', $requestParser->getAttribute('name')); $this->assertSame(['data' => ['type' => 'ship', 'id' => '42']], $requestParser->getRelationship('ship')); - $this->assertSame(true, $requestParser->getMeta('lock')); + $this->assertTrue($requestParser->getMeta('lock')); $this->assertSame($_POST, $requestParser->getDocument()); } @@ -162,7 +162,7 @@ public function testFromPsrRequest_WithRequestInterface() { $this->assertSame('Foo', $requestParser->getAttribute('name')); $this->assertSame(['data' => ['type' => 'ship', 'id' => '42']], $requestParser->getRelationship('ship')); - $this->assertSame(true, $requestParser->getMeta('lock')); + $this->assertTrue($requestParser->getMeta('lock')); $this->assertSame($document, $requestParser->getDocument()); } @@ -358,7 +358,7 @@ public function testHasLocalId() { 'id' => 'foo', ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertArrayHasKey('data', $requestParser->getDocument()); $this->assertArrayHasKey('id', $requestParser->getDocument()['data']); @@ -369,7 +369,7 @@ public function testHasLocalId() { 'lid' => 'foo', ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertArrayHasKey('data', $requestParser->getDocument()); $this->assertArrayNotHasKey('id', $requestParser->getDocument()['data']); @@ -390,7 +390,7 @@ public function testHasAttribute() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertTrue($requestParser->hasAttribute('foo')); $this->assertFalse($requestParser->hasAttribute('bar')); } @@ -404,7 +404,7 @@ public function testGetAttribute() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertSame('bar', $requestParser->getAttribute('foo')); } @@ -426,7 +426,7 @@ public function testHasRelationship() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertTrue($requestParser->hasRelationship('foo')); $this->assertFalse($requestParser->hasRelationship('bar')); } @@ -445,7 +445,7 @@ public function testGetRelationship() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertSame(['data' => ['type' => 'bar', 'id' => '42']], $requestParser->getRelationship('foo')); } @@ -460,7 +460,7 @@ public function testHasMeta() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertTrue($requestParser->hasMeta('foo')); $this->assertFalse($requestParser->hasMeta('bar')); } @@ -472,7 +472,7 @@ public function testGetMeta() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertSame('bar', $requestParser->getMeta('foo')); } @@ -497,7 +497,7 @@ public function testGetDocument() { 'foo' => 'bar', ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertSame($document, $requestParser->getDocument()); } } diff --git a/tests/helpers/TestableNonInterfaceRequestInterface.php b/tests/helpers/TestableNonInterfaceRequestInterface.php index 97a332f7..9bfbd07c 100644 --- a/tests/helpers/TestableNonInterfaceRequestInterface.php +++ b/tests/helpers/TestableNonInterfaceRequestInterface.php @@ -28,11 +28,26 @@ public function getUri() { } // not used in current implementation - public function getRequestTarget() {} - public function withRequestTarget($requestTarget) {} - public function getMethod() {} - public function withMethod($method) {} - public function withUri(UriInterface $uri, $preserveHost = false) {} + public function getRequestTarget() { + return ''; + } + + public function withRequestTarget($requestTarget) { + return $this; + } + + public function getMethod() { + return ''; + } + + public function withMethod($method) { + return $this; + } + + public function withUri(UriInterface $uri, $preserveHost = false) { + return $this; + } + /** * MessageInterface @@ -43,14 +58,43 @@ public function getBody() { } // not used in current implementation - public function getProtocolVersion() {} - public function withProtocolVersion($version) {} - public function getHeaders() {} - public function hasHeader($name) {} - public function getHeader($name) {} - public function getHeaderLine($name) {} - public function withHeader($name, $value) {} - public function withAddedHeader($name, $value) {} - public function withoutHeader($name) {} - public function withBody(StreamInterface $body) {} + public function getProtocolVersion() { + return ''; + } + + public function withProtocolVersion($version) { + return $this; + } + + public function getHeaders() { + return [['']]; + } + + public function hasHeader($name) { + return false; + } + + public function getHeader($name) { + return ['']; + } + + public function getHeaderLine($name) { + return ''; + } + + public function withHeader($name, $value) { + return $this; + } + + public function withAddedHeader($name, $value) { + return $this; + } + + public function withoutHeader($name) { + return $this; + } + + public function withBody(StreamInterface $body) { + return $this; + } } diff --git a/tests/helpers/TestableNonInterfaceServerRequestInterface.php b/tests/helpers/TestableNonInterfaceServerRequestInterface.php index 017a12fe..944861bf 100644 --- a/tests/helpers/TestableNonInterfaceServerRequestInterface.php +++ b/tests/helpers/TestableNonInterfaceServerRequestInterface.php @@ -15,16 +15,48 @@ public function getQueryParams() { } // not used in current implementation - public function getServerParams() {} - public function getCookieParams() {} - public function withCookieParams(array $cookies) {} - public function withQueryParams(array $query) {} - public function getUploadedFiles() {} - public function withUploadedFiles(array $uploadedFiles) {} + public function getServerParams() { + return []; + } + + public function getCookieParams() { + return []; + } + + public function withCookieParams(array $cookies) { + return $this; + } + + public function withQueryParams(array $query) { + return $this; + } + + public function getUploadedFiles() { + return []; + } + + public function withUploadedFiles(array $uploadedFiles) { + return $this; + } + public function getParsedBody() {} - public function withParsedBody($data) {} - public function getAttributes() {} - public function getAttribute($name, $default = null) {} - public function withAttribute($name, $value) {} - public function withoutAttribute($name) {} + public function withParsedBody($data) { + return $this; + } + + public function getAttributes() { + return []; + } + + public function getAttribute($name, $default = null) { + return null; + } + + public function withAttribute($name, $value) { + return $this; + } + + public function withoutAttribute($name) { + return $this; + } } diff --git a/tests/helpers/TestableNonInterfaceStreamInterface.php b/tests/helpers/TestableNonInterfaceStreamInterface.php index d5739880..1590964c 100644 --- a/tests/helpers/TestableNonInterfaceStreamInterface.php +++ b/tests/helpers/TestableNonInterfaceStreamInterface.php @@ -24,18 +24,49 @@ public function getContents() { } // not used in current implementation - public function __toString() {} + public function __toString() { + return ''; + } + public function close() {} + public function detach() {} + public function getSize() {} - public function tell() {} - public function eof() {} - public function isSeekable() {} + + public function tell() { + return 0; + } + + public function eof() { + return false; + } + + public function isSeekable() { + return false; + } + public function seek($offset, $whence = SEEK_SET) {} + public function rewind() {} - public function isWritable() {} - public function write($string) {} - public function isReadable() {} - public function read($length) {} - public function getMetadata($key = null) {} + + public function isWritable() { + return false; + } + + public function write($string) { + return 0; + } + + public function isReadable() { + return false; + } + + public function read($length) { + return ''; + } + + public function getMetadata($key = null) { + return null; + } } diff --git a/tests/helpers/TestableNonInterfaceUriInterface.php b/tests/helpers/TestableNonInterfaceUriInterface.php index 5a1dd894..e6f6ad01 100644 --- a/tests/helpers/TestableNonInterfaceUriInterface.php +++ b/tests/helpers/TestableNonInterfaceUriInterface.php @@ -26,18 +26,59 @@ public function __toString() { } // not used in current implementation - public function getScheme() {} - public function getAuthority() {} - public function getUserInfo() {} - public function getHost() {} - public function getPort() {} - public function getPath() {} - public function getFragment() {} - public function withScheme($scheme) {} - public function withUserInfo($user, $password = null) {} - public function withHost($host) {} - public function withPort($port) {} - public function withPath($path) {} - public function withQuery($query) {} - public function withFragment($fragment) {} + public function getScheme() { + return ''; + } + + public function getAuthority() { + return ''; + } + + public function getUserInfo() { + return ''; + } + + public function getHost() { + return ''; + } + + public function getPort() { + return ''; + } + + public function getPath() { + return ''; + } + + public function getFragment() { + return ''; + } + + public function withScheme($scheme) { + return $this; + } + + public function withUserInfo($user, $password = null) { + return $this; + } + + public function withHost($host) { + return $this; + } + + public function withPort($port) { + return $this; + } + + public function withPath($path) { + return $this; + } + + public function withQuery($query) { + return $this; + } + + public function withFragment($fragment) { + return $this; + } } diff --git a/tests/objects/LinksObjectTest.php b/tests/objects/LinksObjectTest.php index ac2995f0..351a0cd7 100644 --- a/tests/objects/LinksObjectTest.php +++ b/tests/objects/LinksObjectTest.php @@ -25,7 +25,7 @@ public function testFromObject_HappyPath() { public function testAppend_HappyPath() { $linksObject = new LinksObject(); - $linksObject->append('foo', 'https://jsonapi.org'); + $linksObject->append('foo', 'https://jsonapi.org'); // @phpstan-ignore method.deprecated $array = $linksObject->toArray(); @@ -39,10 +39,10 @@ public function testAppend_HappyPath() { public function testAppend_BlocksReusingNonArray() { $linksObject = new LinksObject(); $linksObject->add('foo', 'https://jsonapi.org'); - + $this->expectException(DuplicateException::class); - - $linksObject->append('foo', 'https://jsonapi.org/2'); + + $linksObject->append('foo', 'https://jsonapi.org/2'); // @phpstan-ignore method.deprecated } public function testAddLinkString_HappyPath() { @@ -139,8 +139,8 @@ public function testAddLinksArray_BlocksReusingNonArray() { public function testAppendLinkObject_HappyPath() { $linksObject = new LinksObject(); - $linksObject->appendLinkObject('foo', new LinkObject('https://jsonapi.org/1')); - $linksObject->appendLinkObject('foo', new LinkObject('https://jsonapi.org/2')); + $linksObject->appendLinkObject('foo', new LinkObject('https://jsonapi.org/1')); // @phpstan-ignore method.deprecated + $linksObject->appendLinkObject('foo', new LinkObject('https://jsonapi.org/2')); // @phpstan-ignore method.deprecated $array = $linksObject->toArray(); @@ -158,10 +158,10 @@ public function testAppendLinkObject_HappyPath() { public function testAppendLinkObject_BlocksReusingNonArray() { $linksObject = new LinksObject(); $linksObject->add('foo', 'https://jsonapi.org'); - + $this->expectException(DuplicateException::class); - - $linksObject->appendLinkObject('foo', new LinkObject('https://jsonapi.org/2')); + + $linksObject->appendLinkObject('foo', new LinkObject('https://jsonapi.org/2')); // @phpstan-ignore method.deprecated } public function testToArray_ExplicitlyEmpty() { diff --git a/tests/objects/RelationshipObjectTest.php b/tests/objects/RelationshipObjectTest.php index e5a99fbf..9861ac60 100644 --- a/tests/objects/RelationshipObjectTest.php +++ b/tests/objects/RelationshipObjectTest.php @@ -302,7 +302,7 @@ public function testToArray_EmptyResources() { $this->assertIsArray($array['data']); } else { - $this->assertInternalType('array', $array['data']); + $this->assertIsArray($array['data']); } } diff --git a/tests/profiles/CursorPaginationProfileTest.php b/tests/profiles/CursorPaginationProfileTest.php index 97704d34..82ab1106 100644 --- a/tests/profiles/CursorPaginationProfileTest.php +++ b/tests/profiles/CursorPaginationProfileTest.php @@ -209,7 +209,7 @@ public function testSetPaginationMeta() { $this->assertArrayHasKey('rangeTruncated', $array['meta']['page']); $this->assertSame(42, $array['meta']['page']['total']); $this->assertSame(100, $array['meta']['page']['estimatedTotal']['bestGuess']); - $this->assertSame(true, $array['meta']['page']['rangeTruncated']); + $this->assertTrue($array['meta']['page']['rangeTruncated']); } public function testGetUnsupportedSortErrorObject_HappyPath() { @@ -350,7 +350,7 @@ public function testSetQueryParameter_EncodedUrl() { public function testGetKeyword_HappyPath() { $profile = new CursorPaginationProfile(); - $keyword = $profile->getKeyword('page'); + $keyword = $profile->getKeyword('page'); // @phpstan-ignore method.deprecated $this->assertSame('page', $keyword); } From 7efe175c53759801c1080d8f4c3d7c9f7577b48c Mon Sep 17 00:00:00 2001 From: Lode Claassen Date: Wed, 26 Nov 2025 08:29:35 +0100 Subject: [PATCH 3/8] try out linting in github action --- .github/workflows/lint.yml | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..3de729ec --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,48 @@ +name: lint +on: + pull_request: + paths: + - "**.php" + +jobs: + lint: + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + + - name: Setup Composer + uses: ramsey/composer-install@v3 + with: + composer-options: "--no-scripts" + + - name: Setup Reviewdog + uses: reviewdog/action-setup@v1 + with: + reviewdog_version: latest + + - name: Collect changed files + id: changed-files + uses: tj-actions/changed-files@v46 + with: + files: | + **.php + files_ignore: | + vendor/* + + - name: Run phpcs and filter through reviewdog + if: steps.changed-files.outputs.any_changed == 'true' + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: ./vendor/bin/phpcs --report=checkstyle ${{ steps.changed-files.outputs.all_changed_files }} | reviewdog -f=checkstyle -reporter=github-pr-annotations -filter-mode=added -name=phpcs + + - name: Run phpstan and filter through reviewdog + if: steps.changed-files.outputs.any_changed == 'true' && (success() || failure()) + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: ./vendor/bin/phpstan analyse --no-progress --configuration=phpstan.neon --error-format=checkstyle ${{ steps.changed-files.outputs.all_changed_files }} | reviewdog -f=checkstyle -reporter=github-pr-annotations -filter-mode=added -name=phpstan From b5770f9874dcc7aba0e7af375c03789161849487 Mon Sep 17 00:00:00 2001 From: Lode Claassen Date: Wed, 26 Nov 2025 17:55:11 +0100 Subject: [PATCH 4/8] easier to run linting until we fixed reviewdog --- script/lint | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/script/lint b/script/lint index 18fa5ae1..d6fe5778 100755 --- a/script/lint +++ b/script/lint @@ -145,16 +145,18 @@ else fi echo "${T_INFO}Checking coding standards (phpcs)${T_RESET}" - echo -e "${T_WARNING}Reviewdog is currently broken${T_RESET}\n" - $CONSOLE_PREFIX ./vendor/bin/phpcs --standard=phpcs.xml --report=checkstyle $FILE_FILTER 2> /dev/null \ - | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + echo -e "${T_WARNING}Running without reviewdog${T_RESET}\n" + #$CONSOLE_PREFIX ./vendor/bin/phpcs --standard=phpcs.xml --report=checkstyle $FILE_FILTER 2> /dev/null \ + # | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + $CONSOLE_PREFIX ./vendor/bin/phpcs --standard=phpcs.xml $FILE_FILTER 2> /dev/null \ && echo "${T_SUCCESS}Success${T_RESET}" echo -e '\n' echo "${T_INFO}Checking static analysis (phpstan)${T_RESET}" - echo -e "${T_WARNING}Reviewdog is currently broken${T_RESET}\n" - $CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.neon --no-progress --error-format=checkstyle 2> /dev/null $FILE_FILTER \ - | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + echo -e "${T_WARNING}Running without reviewdog${T_RESET}\n" + #$CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.neon --no-progress --error-format=checkstyle 2> /dev/null $FILE_FILTER \ + # | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + $CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.neon $FILE_FILTER 2> /dev/null \ && echo "${T_SUCCESS}Success${T_RESET}" echo -e '\n' @@ -168,16 +170,18 @@ else echo -e "${T_BOLD}Running bonus checks${T_RESET}\n" echo "${T_INFO}Checking coding standards (phpcs --bonus)${T_RESET}" - echo -e "${T_WARNING}Reviewdog is currently broken${T_RESET}\n" - $CONSOLE_PREFIX ./vendor/bin/phpcs --report=checkstyle --standard=phpcs.bonus.xml $FILE_FILTER 2> /dev/null \ - | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + echo -e "${T_WARNING}Running without reviewdog${T_RESET}\n" + #$CONSOLE_PREFIX ./vendor/bin/phpcs --report=checkstyle --standard=phpcs.bonus.xml $FILE_FILTER 2> /dev/null \ + # | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + $CONSOLE_PREFIX ./vendor/bin/phpcs --standard=phpcs.bonus.xml $FILE_FILTER 2> /dev/null \ && echo "${T_SUCCESS}Success${T_RESET}" echo -e '\n' echo "${T_INFO}Checking static analysis (phpstan --bonus)${T_RESET}" - echo -e "${T_WARNING}Reviewdog is currently broken${T_RESET}\n" - $CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.bonus.neon --no-progress --error-format=checkstyle $FILE_FILTER 2> /dev/null \ - | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + echo -e "${T_WARNING}Running without reviewdog${T_RESET}\n" + #$CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.bonus.neon --no-progress --error-format=checkstyle $FILE_FILTER 2> /dev/null \ + # | $CONSOLE_PREFIX ./vendor/bin/reviewdog -f=checkstyle -reporter=local -diff="git diff $GIT_MERGE_BASE" -fail-level=any 2> /dev/null \ + $CONSOLE_PREFIX ./vendor/bin/phpstan analyse --configuration=phpstan.bonus.neon $FILE_FILTER 2> /dev/null \ && echo "${T_SUCCESS}Success${T_RESET}" fi fi From 35f0e9d7c96ca5d917f81ac26d38d477544b8c06 Mon Sep 17 00:00:00 2001 From: Lode Claassen Date: Wed, 26 Nov 2025 17:55:29 +0100 Subject: [PATCH 5/8] small fixes for phpstan lvl 1 --- examples/relationships.php | 1 + phpstan.neon | 2 +- tests/ErrorsDocumentTest.php | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/relationships.php b/examples/relationships.php index df92dfb3..483ab1b5 100644 --- a/examples/relationships.php +++ b/examples/relationships.php @@ -74,6 +74,7 @@ /** * custom */ +$jsonapi = new ResourceDocument('user', 1); $custom_relation = [ 'data' => ['cus' => 'tom'], ]; diff --git a/phpstan.neon b/phpstan.neon index 57de3457..d1b333dc 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,6 +1,6 @@ parameters: # slowly increase - level: 0 + level: 1 paths: - src/ - tests/ diff --git a/tests/ErrorsDocumentTest.php b/tests/ErrorsDocumentTest.php index 369d04cd..89dac18b 100644 --- a/tests/ErrorsDocumentTest.php +++ b/tests/ErrorsDocumentTest.php @@ -124,13 +124,17 @@ public function testToArray_EmptyErrorObject() { $this->assertSame('foo', $array['errors'][0]['code']); } + /** + * @param non-empty-array $allErrorCodes + */ #[DataProvider('dataProviderDetermineHttpStatusCode_HappyPath')] - public function testDetermineHttpStatusCode_HappyPath($expectedAdvisedErrorCode, $allErrorCodes) { + public function testDetermineHttpStatusCode_HappyPath(int $expectedAdvisedErrorCode, array $allErrorCodes) { $document = new ErrorsDocument(); $method = new \ReflectionMethod($document, 'determineHttpStatusCode'); $method->setAccessible(true); + $advisedErrorCode = null; foreach ($allErrorCodes as $errorCode) { $advisedErrorCode = $method->invoke($document, $errorCode); } From ed37622af555d2b84bdc55effd319ace4040b57c Mon Sep 17 00:00:00 2001 From: Lode Claassen Date: Wed, 26 Nov 2025 17:56:57 +0100 Subject: [PATCH 6/8] rector php54 --- rector.php | 2 +- src/collection.php | 6 +++--- src/error.php | 16 ++++++++-------- src/errors.php | 2 +- src/resource.php | 24 ++++++++++++------------ src/response.php | 24 ++++++++++++------------ 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/rector.php b/rector.php index d0ae665f..e93ebef9 100644 --- a/rector.php +++ b/rector.php @@ -17,7 +17,7 @@ ->withIndent(indentChar: "\t", indentSize: 1) // slowly increase php version - ->withPhpSets(php53: true) + ->withPhpSets(php54: true) // slowly increase levels ->withTypeCoverageLevel(1) diff --git a/src/collection.php b/src/collection.php index b3e4d984..c32a968d 100644 --- a/src/collection.php +++ b/src/collection.php @@ -22,8 +22,8 @@ class collection extends response { * internal data containers */ protected $primary_type = null; -protected $primary_collection = array(); -protected $primary_resource_objects = array(); +protected $primary_collection = []; +protected $primary_resource_objects = []; /** * creates a new collection @@ -58,7 +58,7 @@ public function get_type() { * - meta */ public function get_array() { - $response = array(); + $response = []; // links if ($this->links) { diff --git a/src/error.php b/src/error.php index 301d5962..985c8fe8 100644 --- a/src/error.php +++ b/src/error.php @@ -28,7 +28,7 @@ class error extends base { /** * http status messages used for string output */ -private static $http_status_messages = array( +private static $http_status_messages = [ 200 => 'OK', 201 => 'Created', 204 => 'No Content', @@ -43,7 +43,7 @@ class error extends base { 422 => 'Unprocessable Entity', 500 => 'Internal Server Error', 503 => 'Service Unavailable', -); +]; /** * creates a new error for inclusion in the errors collection @@ -89,7 +89,7 @@ public function __construct($error_message, $friendly_message=null, $about_link= * - meta */ public function get_array() { - $response_part = array(); + $response_part = []; // the basics $response_part['status'] = $this->http_status; @@ -107,7 +107,7 @@ public function get_array() { // the source of the problem if ($this->post_body_pointer || $this->get_parameter_name) { - $response_part['source'] = array(); + $response_part['source'] = []; if ($this->post_body_pointer) { $response_part['source']['pointer'] = $this->post_body_pointer; @@ -119,9 +119,9 @@ public function get_array() { // technical guidance if ($this->about_link) { - $response_part['links'] = array( + $response_part['links'] = [ 'about' => $this->about_link, - ); + ]; } if ($this->identifier) { $response_part['id'] = $this->identifier; @@ -239,10 +239,10 @@ public function set_about_link($about_link, $meta_data=null) { $meta_data = parent::convert_object_to_array($meta_data); } - $about_link = array( + $about_link = [ 'href' => $about_link, 'meta' => $meta_data, - ); + ]; } $this->about_link = $about_link; diff --git a/src/errors.php b/src/errors.php index bde8d392..4b6bc673 100644 --- a/src/errors.php +++ b/src/errors.php @@ -79,7 +79,7 @@ public function __construct($error_message=null, $friendly_message=null, $about_ * - meta */ public function get_array() { - $response = array(); + $response = []; // links if ($this->links) { diff --git a/src/resource.php b/src/resource.php index 7bba329a..7d346043 100644 --- a/src/resource.php +++ b/src/resource.php @@ -69,10 +69,10 @@ class resource extends response { */ protected $primary_type = null; protected $primary_id = null; -protected $primary_attributes = array(); -protected $primary_relationships = array(); -protected $primary_links = array(); -protected $primary_meta_data = array(); +protected $primary_attributes = []; +protected $primary_relationships = []; +protected $primary_links = []; +protected $primary_meta_data = []; /** * creates a new resource @@ -134,7 +134,7 @@ public function has_data() { * - meta */ public function get_array() { - $response = array(); + $response = []; // links if ($this->links) { @@ -142,9 +142,9 @@ public function get_array() { } // primary data - $response['data'] = array( + $response['data'] = [ 'type' => $this->primary_type, - ); + ]; if ($this->primary_id) { $response['data']['id'] = $this->primary_id; } @@ -249,7 +249,7 @@ public function fill_data($values) { * @todo allow to add collections as well */ public function add_relation($key, $relation, $skip_include=false, $type=null) { - if ($type && in_array($type, array(self::RELATION_TO_ONE, self::RELATION_TO_MANY)) == false) { + if ($type && in_array($type, [self::RELATION_TO_ONE, self::RELATION_TO_MANY]) == false) { throw new \Exception('unknown relation type'); } if (isset($this->primary_relationships[$key]) && $relation instanceof \alsvanzelf\jsonapi\resource == false) { @@ -291,7 +291,7 @@ public function add_relation($key, $relation, $skip_include=false, $type=null) { return; } if ($type == self::RELATION_TO_MANY) { - $relation_data = array($relation_data); + $relation_data = [$relation_data]; } } elseif ($relation instanceof \alsvanzelf\jsonapi\collection) { @@ -303,7 +303,7 @@ public function add_relation($key, $relation, $skip_include=false, $type=null) { } $base_url = (isset($this->primary_links['self']['href'])) ? $this->primary_links['self']['href'] : $this->primary_links['self']; - $relation_data = array(); + $relation_data = []; foreach ($relation_resources as $relation_resource) { $relation_data[] = [ 'type' => $relation_resource->get_type(), @@ -312,9 +312,9 @@ public function add_relation($key, $relation, $skip_include=false, $type=null) { } } - $this->primary_relationships[$key] = array( + $this->primary_relationships[$key] = [ 'data' => $relation_data, - ); + ]; $relation_links = []; if (self::$relation_links == self::RELATION_LINKS_RELATIONSHIP || self::$relation_links == self::RELATION_LINKS_BOTH) { diff --git a/src/response.php b/src/response.php index fa8c359c..d41361db 100644 --- a/src/response.php +++ b/src/response.php @@ -54,10 +54,10 @@ class response extends base { /** * internal data containers */ -protected $links = array(); -protected $meta_data = array(); -protected $included_data = array(); -protected $included_resources = array(); +protected $links = []; +protected $meta_data = []; +protected $included_data = []; +protected $included_resources = []; protected $http_status = self::STATUS_OK; protected $redirect_location = null; @@ -102,7 +102,7 @@ public function __toString() { * - meta */ public function get_array() { - $response = array(); + $response = []; // links if ($this->links) { @@ -260,10 +260,10 @@ public function add_link($key, $link, $meta_data=null) { $meta_data = parent::convert_object_to_array($meta_data); } - $link = array( + $link = [ 'href' => $link, 'meta' => $meta_data, - ); + ]; } $this->links[$key] = $link; @@ -309,10 +309,10 @@ public function set_self_link($link, $meta_data=null) { $meta_data = parent::convert_object_to_array($meta_data); } - $link = array( + $link = [ 'href' => $link, 'meta' => $meta_data, - ); + ]; } $this->links['self'] = $link; @@ -335,10 +335,10 @@ public function add_self_link_meta($key, $meta_data) { // converts string-type link if (is_string($this->links['self'])) { - $this->links['self'] = array( + $this->links['self'] = [ 'href' => $this->links['self'], - 'meta' => array(), - ); + 'meta' => [], + ]; } $this->links['self']['meta'][$key] = $meta_data; From 51ad05d06125e64ec463f114a33c4877b20ca441 Mon Sep 17 00:00:00 2001 From: Lode Claassen Date: Wed, 26 Nov 2025 17:57:18 +0100 Subject: [PATCH 7/8] rector php55 --- rector.php | 2 +- tests/ErrorsDocumentTest.php | 4 ++-- tests/objects/ErrorObjectTest.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rector.php b/rector.php index e93ebef9..60e34534 100644 --- a/rector.php +++ b/rector.php @@ -17,7 +17,7 @@ ->withIndent(indentChar: "\t", indentSize: 1) // slowly increase php version - ->withPhpSets(php54: true) + ->withPhpSets(php55: true) // slowly increase levels ->withTypeCoverageLevel(1) diff --git a/tests/ErrorsDocumentTest.php b/tests/ErrorsDocumentTest.php index 89dac18b..d3add169 100644 --- a/tests/ErrorsDocumentTest.php +++ b/tests/ErrorsDocumentTest.php @@ -29,7 +29,7 @@ public function testFromException_HappyPath() { $this->assertArrayHasKey('function', $array['errors'][0]['meta']['trace'][0]); $this->assertArrayHasKey('class', $array['errors'][0]['meta']['trace'][0]); $this->assertSame(__FUNCTION__, $array['errors'][0]['meta']['trace'][0]['function']); - $this->assertSame(__CLASS__, $array['errors'][0]['meta']['trace'][0]['class']); + $this->assertSame(self::class, $array['errors'][0]['meta']['trace'][0]['class']); } /** @@ -60,7 +60,7 @@ public function testFromException_AllowsThrowable() { $this->assertArrayHasKey('function', $array['errors'][0]['meta']['trace'][0]); $this->assertArrayHasKey('class', $array['errors'][0]['meta']['trace'][0]); $this->assertSame(__FUNCTION__, $array['errors'][0]['meta']['trace'][0]['function']); - $this->assertSame(__CLASS__, $array['errors'][0]['meta']['trace'][0]['class']); + $this->assertSame(self::class, $array['errors'][0]['meta']['trace'][0]['class']); } public function testFromException_BlocksNonException() { diff --git a/tests/objects/ErrorObjectTest.php b/tests/objects/ErrorObjectTest.php index 95e67244..bf43f572 100644 --- a/tests/objects/ErrorObjectTest.php +++ b/tests/objects/ErrorObjectTest.php @@ -35,7 +35,7 @@ public function testFromException_HappyPath() { $this->assertArrayHasKey('function', $array['meta']['trace'][0]); $this->assertArrayHasKey('class', $array['meta']['trace'][0]); $this->assertSame(__FUNCTION__, $array['meta']['trace'][0]['function']); - $this->assertSame(__CLASS__, $array['meta']['trace'][0]['class']); + $this->assertSame(self::class, $array['meta']['trace'][0]['class']); } public function testFromException_DoNotExposeTrace() { From 782d1cc2e34b36db7fbb0df2d18220db93aa5d72 Mon Sep 17 00:00:00 2001 From: Lode Claassen Date: Wed, 26 Nov 2025 18:00:33 +0100 Subject: [PATCH 8/8] skip v1 paths for rector as well --- rector.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rector.php b/rector.php index 60e34534..03c18b24 100644 --- a/rector.php +++ b/rector.php @@ -12,12 +12,21 @@ __DIR__ . '/tests', __DIR__ . '/examples', ]) + ->withSkip([ + __DIR__ . '/src/base.php', + __DIR__ . '/src/collection.php', + __DIR__ . '/src/error.php', + __DIR__ . '/src/errors.php', + __DIR__ . '/src/exception.php', + __DIR__ . '/src/resource.php', + __DIR__ . '/src/response.php', + ]) // tab-based indenting ->withIndent(indentChar: "\t", indentSize: 1) // slowly increase php version - ->withPhpSets(php55: true) + ->withPhpSets(php56: true) // slowly increase levels ->withTypeCoverageLevel(1)