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
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/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/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/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..d1b333dc
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,23 @@
+parameters:
+ # slowly increase
+ level: 1
+ 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..03c18b24
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,36 @@
+withPaths([
+ __DIR__ . '/src',
+ __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(php56: 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..d6fe5778
--- /dev/null
+++ b/script/lint
@@ -0,0 +1,187 @@
+#!/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}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}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'
+
+ 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}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}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
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/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/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;
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/ErrorsDocumentTest.php b/tests/ErrorsDocumentTest.php
index 369d04cd..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() {
@@ -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);
}
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/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() {
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);
}