From cedde42e9f49727024cf567a22df3a8ec5e52efd Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Mon, 7 Feb 2022 12:05:48 +0100 Subject: [PATCH 1/2] Switch to phpcq 2 and make build green --- .composer-require-checker.json | 18 ++++ .github/workflows/diagnostics.yml | 75 ++++++++++++++++ .gitignore | 4 +- .phpcq.lock | 1 + .phpcq.yaml.dist | 117 +++++++++++++++++++++++++ .travis.yml | 30 ------- README.md | 9 +- build.default.properties | 9 -- build.xml | 11 --- composer.json | 99 +++++++++++---------- phpunit.xml.dist | 46 +++++----- psalm.xml | 14 +++ src/Contao/BackendUrlBuilder.php | 12 +-- src/Contao/CsrfUrlBuilder.php | 4 +- src/UrlBuilder.php | 48 +++++++--- tests/Contao/BackendUrlBuilderTest.php | 6 +- tests/TestCase.php | 1 - tests/UrlBuilderTest.php | 5 ++ 18 files changed, 364 insertions(+), 145 deletions(-) create mode 100644 .composer-require-checker.json create mode 100644 .github/workflows/diagnostics.yml create mode 100644 .phpcq.lock create mode 100644 .phpcq.yaml.dist delete mode 100644 .travis.yml delete mode 100644 build.default.properties delete mode 100644 build.xml create mode 100644 psalm.xml diff --git a/.composer-require-checker.json b/.composer-require-checker.json new file mode 100644 index 0000000..7e58f04 --- /dev/null +++ b/.composer-require-checker.json @@ -0,0 +1,18 @@ +{ + "symbol-whitelist" : [ + "null", "true", "false", + "static", "self", "parent", + "array", "string", "int", "float", "bool", "iterable", "callable", "void", "object", + "REQUEST_TOKEN", + "Symfony\\Component\\Security\\Csrf\\CsrfTokenManagerInterface" + ], + "php-core-extensions" : [ + "Core", + "date", + "pcre", + "Reflection", + "SPL", + "standard" + ], + "scan-files" : [] +} diff --git a/.github/workflows/diagnostics.yml b/.github/workflows/diagnostics.yml new file mode 100644 index 0000000..0e8fda5 --- /dev/null +++ b/.github/workflows/diagnostics.yml @@ -0,0 +1,75 @@ +name: contao-community-alliance/url-builder + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - php: 7.4 + output: '-o github-action -o default' + phpcq_install: 'install' + - php: 8.0 + output: '-o default' + phpcq_install: 'update' + + steps: + - name: PHP ${{ matrix.php }} Pull source + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + # see https://github.com/shivammathur/setup-php + - name: PHP ${{ matrix.php }} Setup PHP. + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + + - name: PHP ${{ matrix.php }} Cache composer cache directory + uses: actions/cache@v1 + env: + cache-name: composer-cache-dir + with: + path: ~/.cache/composer + key: ${{ runner.os }}-${{ matrix.php }}-build-${{ env.cache-name }} + + - name: PHP ${{ matrix.php }} Cache vendor directory + uses: actions/cache@v1 + env: + cache-name: composer-vendor + with: + path: vendor + key: ${{ runner.os }}-${{ matrix.php }}-build-${{ env.cache-name }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.php }}-build-${{ env.cache-name }}- + + - name: PHP ${{ matrix.php }} Cache phpcq directory + uses: actions/cache@v1 + env: + cache-name: phpcq + with: + path: .phpcq + key: ${{ runner.os }}-${{ matrix.php }}-build-${{ env.cache-name }}-${{ hashFiles('**/.phpcq.lock') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.php }}-build-${{ env.cache-name }}- + + - name: PHP ${{ matrix.php }} Install composer dependencies + run: composer install --prefer-dist --no-interaction --no-suggest + + - name: PHP ${{ matrix.php }} Install phpcq toolchain + run: ./vendor/bin/phpcq ${{ matrix.phpcq_install }} -v + + - name: PHP ${{ matrix.php }} Run tests + run: ./vendor/bin/phpcq run -v ${{ matrix.output }} + + - name: PHP ${{ matrix.php }} Upload build directory to artifact + uses: actions/upload-artifact@v2 + if: ${{ success() }} || ${{ failure() }} + with: + name: phpcq-builds-php-${{ matrix.php }} + path: .phpcq/build/ diff --git a/.gitignore b/.gitignore index 39e0181..2bee616 100644 --- a/.gitignore +++ b/.gitignore @@ -16,5 +16,5 @@ vendor/ composer.lock # build -build/ -build.properties +.phpcq/* +.phpunit.result.cache diff --git a/.phpcq.lock b/.phpcq.lock new file mode 100644 index 0000000..7767a80 --- /dev/null +++ b/.phpcq.lock @@ -0,0 +1 @@ +{"plugins":{"phpunit":{"api-version":"1.0.0","version":"1.0.0.0","type":"php-file","url":"https://phpcq.github.io/repository/phpunit-1.0.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0"},"tool":{"phpunit":"^6.0 || ^7.0 || ^8.0 || ^9.0"}},"checksum":{"type":"sha-512","value":"c73f15658e3ba62665f09492ec91c3a6a715760bfaa88473a987538439fff442540148e086e46a6aa18ce55a3ea2fbf76caaa581384cb84a38859fcc609ae7e4"},"tools":{"phpunit":{"version":"9.5.13","url":"https://phar.phpunit.de/phpunit-9.5.13.phar","requirements":{"php":{"php":">=7.3","ext-dom":"*","ext-json":"*","ext-libxml":"*","ext-mbstring":"*","ext-xml":"*","ext-xmlwriter":"*"}},"checksum":{"type":"sha-256","value":"16742686383afac8a7a1e3f905862d77169746b0342f66ab80b0148582e5472a"},"signature":"https://phar.phpunit.de/phpunit-9.5.13.phar.asc"}}},"psalm":{"api-version":"1.0.0","version":"1.0.1.0","type":"php-file","url":"https://phpcq.github.io/repository/psalm-1.0.1.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"psalm":"^3.0 || ^4.0"}},"checksum":{"type":"sha-512","value":"fb591fbea784d65ea1b63ba597616c2dd6346958a61a9129aacf612e0deaa14c0de33d9a37cf81b5ed717f09cc3f1280149a0d46576fc838241070176710675f"},"tools":{"psalm":{"version":"4.20.0","url":"https://github.com/vimeo/psalm/releases/download/4.20.0/psalm.phar","requirements":{"php":{"php":"^7.1|^8","ext-SimpleXML":"*","ext-ctype":"*","ext-dom":"*","ext-json":"*","ext-libxml":"*","ext-mbstring":"*","ext-tokenizer":"*"}},"checksum":null,"signature":"https://github.com/vimeo/psalm/releases/download/4.20.0/psalm.phar.asc"}}},"composer-require-checker":{"api-version":"1.0.0","version":"1.0.1.0","type":"php-file","url":"https://phpcq.github.io/repository/composer-require-checker-1.0.1.0.php","signature":null,"requirements":{"php":{"php":"^7.4 || ^8.0"},"tool":{"composer-require-checker":"^3.8"}},"checksum":{"type":"sha-512","value":"5b0fd8cd5e0f5761c53b9d5375b6f6ba50f148468896248f823cc2a48361adfd872556066764b1b544ff51ffd5de60d6f9a75050db00b257d807976ac761bc3a"},"tools":{"composer-require-checker":{"version":"3.8.0","url":"https://github.com/maglnet/ComposerRequireChecker/releases/download/3.8.0/composer-require-checker.phar","requirements":{"php":{"php":"^7.4 || ^8.0","ext-json":"*","ext-phar":"*"}},"checksum":null,"signature":"https://github.com/maglnet/ComposerRequireChecker/releases/download/3.8.0/composer-require-checker.phar.asc"}}},"phpmd":{"api-version":"1.0.0","version":"1.0.1.0","type":"php-file","url":"https://phpcq.github.io/repository/phpmd-1.0.1.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"phpmd":"^2.6.1"}},"checksum":{"type":"sha-512","value":"88e267b9c36b2edc85e924717606b626e005ac8d97b1f65f5331e2a3b3894dec2cf124f6187541bf759d026477b6d94daacc5d5c81bb09714a68ffabe5698dc5"},"tools":{"phpmd":{"version":"2.11.1","url":"https://github.com/phpmd/phpmd/releases/download/2.11.1/phpmd.phar","requirements":{"php":{"php":">=5.3.9","ext-xml":"*"}},"checksum":null,"signature":null}}},"phpcpd":{"api-version":"1.0.0","version":"1.1.1.0","type":"php-file","url":"https://phpcq.github.io/repository/phpcpd-1.1.1.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"phpcpd":"^6.0"}},"checksum":{"type":"sha-512","value":"1189ce0bf3fade4cb4241f1d96f915ef8fc7651f4450dc79fdf464ee3d6be3009316f0d423ce2d4af9d76ad50807b7fdf4d77bfa6d9ee2c91d6eda32ea214433"},"tools":{"phpcpd":{"version":"6.0.3","url":"https://phar.phpunit.de/phpcpd-6.0.3.phar","requirements":{"php":{"php":">=7.3","ext-dom":"*"}},"checksum":{"type":"sha-256","value":"2cbaea7cfda1bb4299d863eb075e977c3f49055dd16d88529fae5150d48a84cb"},"signature":"https://phar.phpunit.de/phpcpd-6.0.3.phar.asc"}}},"phploc":{"api-version":"1.0.0","version":"1.0.0.0","type":"php-file","url":"https://phpcq.github.io/repository/phploc-1.0.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*","ext-json":"*"},"tool":{"phploc":"^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0"}},"checksum":{"type":"sha-512","value":"f67b02d494796adf553cb3dd13ec06c1cb8e53c799954061749424251379541637538199afb3afa3c7a01cabd1cb6f1c53eb621f015dff9644c6c7cbf10c56d1"},"tools":{"phploc":{"version":"7.0.2","url":"https://phar.phpunit.de/phploc-7.0.2.phar","requirements":{"php":{"php":">=7.3","ext-dom":"*","ext-json":"*"}},"checksum":{"type":"sha-256","value":"3d59778ec86faf25fd00e3a329b2f9ad4a3c751ca91601ea7dab70f887b0bf46"},"signature":"https://phar.phpunit.de/phploc-7.0.2.phar.asc"}}},"phpcs":{"api-version":"1.0.0","version":"1.1.0.0","type":"php-file","url":"https://phpcq.github.io/repository/phpcs-1.1.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"phpcs":"^3.0 || ^2.0","phpcbf":"^3.0 || ^2.0"}},"checksum":{"type":"sha-512","value":"2737022369da1318cc4e0ea194e8a81019f7b079080d869aab878b7486052fdbe68fee3f28131f35573226def1aabd4bd005e038ee7b767c137b1107c1492a83"},"tools":{"phpcs":{"version":"3.6.2","url":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcs.phar","requirements":{"php":{"php":">=5.4.0","ext-tokenizer":"*","ext-xmlwriter":"*","ext-simplexml":"*"}},"checksum":null,"signature":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcs.phar.asc"},"phpcbf":{"version":"3.6.2","url":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcbf.phar","requirements":{"php":{"php":">=5.4.0","ext-tokenizer":"*","ext-xmlwriter":"*","ext-simplexml":"*"}},"checksum":null,"signature":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcbf.phar.asc"}}},"composer-normalize":{"api-version":"1.0.0","version":"1.1.0.0","type":"php-file","url":"https://phpcq.github.io/repository/composer-normalize-1.1.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-json":"*"},"tool":{"composer-normalize":"^2.1"}},"checksum":{"type":"sha-512","value":"d59d3557cb20630734878a9115df5dd32d5aff815e5b15be36f6fb5d6e9d83dd36efd84215ab6529edcc924f600946f739a0d9e67723deff95c88346ab502498"},"tools":{"composer-normalize":{"version":"2.23.1","url":"https://github.com/ergebnis/composer-normalize/releases/download/2.23.1/composer-normalize.phar","requirements":{"php":{"php":"^7.4 || ^8.0"}},"checksum":null,"signature":"https://github.com/ergebnis/composer-normalize/releases/download/2.23.1/composer-normalize.phar.asc"}}}},"tools":[]} \ No newline at end of file diff --git a/.phpcq.yaml.dist b/.phpcq.yaml.dist new file mode 100644 index 0000000..32413b4 --- /dev/null +++ b/.phpcq.yaml.dist @@ -0,0 +1,117 @@ +phpcq: + repositories: + - https://phpcq.github.io/repository/repository.json + directories: + - src + - tests + artifact: .phpcq/build + + plugins: + phpunit: + version: ^1.0 + signed: false + psalm: + version: ^1.0.1 + signed: false + composer-require-checker: + version: ^1.0.1 + signed: false + phpmd: + version: ^1.0.1 + signed: false + requirements: + phpmd: + signed: false + phpcpd: + version: ^1.1.1 + signed: false + requirements: + phpcpd: + version: ^6.0 + phploc: + version: ^1.0 + signed: false + phpcs: + version: ^1.1 + signed: false + composer-normalize: + version: ^1.0 + signed: false + trusted-keys: + # sb@sebastian-bergmann.de + - 4AA394086372C20A + # psalm + - 12CE0F1D262429A5 + # magl@magll.net + - D2CCAC42F6295E7D + # PHP_CodeSniffer + - 31C7E470E2138192 + # Composer normalize + - C00543248C87FB13 + # Composer require checker + - 033E5F8D801A2F8D + # phpmd + - 0F9684B8B16B7AB0 + +tasks: + fix: + - composer-normalize-fix + - phpcbf + + verify: + - composer-require-checker + - composer-normalize + + analyze: + - phploc + - phpcpd + - phpmd + - phpcs + - psalm + - phpunit + + default: + - verify + - analyze + + phpcpd: + plugin: phpcpd + config: + exclude: + - 'src/ApiClient/Shopware/Generated' + + phpmd: + plugin: phpmd + config: + ruleset: + - codesize + - controversial + - naming + - unusedcode + excluded: + - 'src/ApiClient/Shopware/Generated' + + composer-normalize-fix: + plugin: composer-normalize + config: + dry_run: false + + composer-require-checker: + plugin: composer-require-checker + config: + config_file: '.composer-require-checker.json' + + phpcs: + plugin: phpcs + config: &phpcs-config + standard: PSR12 + excluded: + - 'src/ApiClient/Shopware/Generated' + custom_flags: + - '--extensions=php' + + phpcbf: + plugin: phpcs + config: + <<: *phpcs-config + fix: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7199199..0000000 --- a/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -dist: xenial - -addons: - apt: - packages: - - ant-optional - -language: php - -php: - - "7.3" - - "7.2" - - "7.1" - - "7.0" - - "5.6" - -install: - - echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - - travis_retry composer self-update && composer --version - - travis_retry composer update --prefer-dist --no-interaction - -script: ant -keep-going - -# Hack to make things work again - we can not use a shallow repository. -git: - depth: 2147483647 - -cache: - directories: - - vendor diff --git a/README.md b/README.md index c806c2d..37f9c06 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ Url Builder =========== -[![Version](http://img.shields.io/packagist/v/contao-community-alliance/url-builder.svg?style=flat-square)](https://packagist.org/packages/contao-community-alliance/url-builder) -[![Stable Build Status](http://img.shields.io/travis/contao-community-alliance/url-builder/master.svg?style=flat-square&label=stable%20build)](https://travis-ci.org/contao-community-alliance/url-builder) -[![Develop Build Status](http://img.shields.io/travis/contao-community-alliance/url-builder/develop.svg?style=flat-square&label=dev%20build)](https://travis-ci.org/contao-community-alliance/url-builder) -[![License](http://img.shields.io/packagist/l/contao-community-alliance/url-builder.svg?style=flat-square)](https://github.com/contao-community-alliance/url-builder/blob/master/LICENSE) -[![Downloads](http://img.shields.io/packagist/dt/contao-community-alliance/url-builder.svg?style=flat-square)](https://packagist.org/packages/contao-community-alliance/url-builder) +[![Version](https://img.shields.io/packagist/v/contao-community-alliance/url-builder.svg?style=flat-square)](https://packagist.org/packages/contao-community-alliance/url-builder) +[![Code Quality Diagnostics](https://github.com/contao-community-alliance/url-builder/actions/workflows/diagnostics.yml/badge.svg)](https://github.com/contao-community-alliance/url-builder/actions/workflows/diagnostics.yml) +[![License](https://img.shields.io/packagist/l/contao-community-alliance/url-builder.svg?style=flat-square)](https://github.com/contao-community-alliance/url-builder/blob/master/LICENSE) +[![Downloads](https://img.shields.io/packagist/dt/contao-community-alliance/url-builder.svg?style=flat-square)](https://packagist.org/packages/contao-community-alliance/url-builder) General purpose URL builder and manipulator. diff --git a/build.default.properties b/build.default.properties deleted file mode 100644 index e3fa8ea..0000000 --- a/build.default.properties +++ /dev/null @@ -1,9 +0,0 @@ -##################################################### -## This project is using the ## -## PHP code quality project (phpcq) ## -## ## -## https://github.com/phpcq/phpcq ## -##################################################### - -phpcs.standard=${basedir}/vendor/phpcq/coding-standard/phpcs/PhpCodeQuality/ruleset.xml -phpmd.ruleset=${basedir}/vendor/phpcq/coding-standard/phpmd/ruleset.xml diff --git a/build.xml b/build.xml deleted file mode 100644 index 3883bc0..0000000 --- a/build.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/composer.json b/composer.json index 8c4081f..b878777 100644 --- a/composer.json +++ b/composer.json @@ -1,48 +1,59 @@ { - "name": "contao-community-alliance/url-builder", - "description": "General purpose URL builder and manipulator.", - "license": "LGPL-3.0-or-later", - "authors": [ - { - "name": "Christian Schiffler", - "email": "c.schiffler@cyberspectrum.de", - "homepage": "http://www.cyberspectrum.de", - "role": "Developer" - }, - { - "name": "Stefan Heimes", - "email": "stefan_heimes@hotmail.com", - "role": "Developer" - } - ], - "support": { - "email": "info@contao-community-alliance.de", - "issues": "https://github.com/contao-community-alliance/url-builder/issues", - "irc": "irc://irc.freenode.org/contao.cca", - "source": "https://github.com/contao-community-alliance/url-builder" + "name": "contao-community-alliance/url-builder", + "description": "General purpose URL builder and manipulator.", + "license": "LGPL-3.0-or-later", + "authors": [ + { + "name": "Christian Schiffler", + "email": "c.schiffler@cyberspectrum.de", + "homepage": "https://www.cyberspectrum.de", + "role": "Developer" }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpcq/all-tasks": "^1.2", - "contao/core-bundle": "^4.4", - "php-http/guzzle6-adapter": "^1.1" - }, - "autoload": { - "psr-4": { - "ContaoCommunityAlliance\\UrlBuilder\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "ContaoCommunityAlliance\\UrlBuilder\\Test\\": "tests/" - } - }, - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev", - "dev-develop": "1.4.x-dev" - } + { + "name": "Stefan Heimes", + "email": "stefan_heimes@hotmail.com", + "role": "Developer" + } + ], + "support": { + "email": "info@contao-community-alliance.de", + "issues": "https://github.com/contao-community-alliance/url-builder/issues", + "irc": "irc://irc.freenode.org/contao.cca", + "source": "https://github.com/contao-community-alliance/url-builder" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "contao/core-bundle": "^4.4", + "php-http/guzzle6-adapter": "^1.1", + "phpcq/runner-bootstrap": "^1.0@dev", + "symfony/security-csrf": "^4.4 || ^5.2" + }, + "conflict": { + "contao/core-bundle": "<4.4 || >=5.0", + "symfony/security-csrf": "<4.4 || >=6.0" + }, + "autoload": { + "psr-4": { + "ContaoCommunityAlliance\\UrlBuilder\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "ContaoCommunityAlliance\\UrlBuilder\\Test\\": "tests/" + } + }, + "config": { + "allow-plugins": { + "composer/package-versions-deprecated": true, + "contao-components/installer": false + } + }, + "extra": { + "branch-alias": { + "dev-develop": "1.4.x-dev", + "dev-master": "1.3.x-dev" } + } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a268e17..3514ea9 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,28 +1,28 @@ - - - ./tests/ - - + backupStaticAttributes="false" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false" + syntaxCheck="false" + bootstrap="vendor/autoload.php" +> + + + ./tests/ + + - - - ./src/ - - - - - + + + ./src/ + + + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..cb225ee --- /dev/null +++ b/psalm.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/Contao/BackendUrlBuilder.php b/src/Contao/BackendUrlBuilder.php index 1a871de..3b8d20d 100644 --- a/src/Contao/BackendUrlBuilder.php +++ b/src/Contao/BackendUrlBuilder.php @@ -21,6 +21,7 @@ namespace ContaoCommunityAlliance\UrlBuilder\Contao; use ContaoCommunityAlliance\UrlBuilder\UrlBuilder; +use RuntimeException; /** * URL builder for the Contao Backend. @@ -37,20 +38,21 @@ class BackendUrlBuilder extends UrlBuilder * * @return string * - * @throws \RuntimeException If no REQUEST_TOKEN constant exists. + * @throws RuntimeException If no REQUEST_TOKEN constant exists. */ public function getQueryString() { - $query = parent::getQueryString(); - if ($query) { + $query = (string) parent::getQueryString(); + if (!empty($query)) { $query .= '&'; } if (!defined('REQUEST_TOKEN')) { - throw new \RuntimeException('Request token not defined - can not append to query string.'); + throw new RuntimeException('Request token not defined - can not append to query string.'); } + $token = (string) REQUEST_TOKEN; - $query .= 'rt=' . REQUEST_TOKEN; + $query .= 'rt=' . $token; return $query; } diff --git a/src/Contao/CsrfUrlBuilder.php b/src/Contao/CsrfUrlBuilder.php index d632ed8..c0afced 100644 --- a/src/Contao/CsrfUrlBuilder.php +++ b/src/Contao/CsrfUrlBuilder.php @@ -66,8 +66,8 @@ public function __construct(CsrfTokenManagerInterface $tokenManager, $tokenName, */ public function getQueryString() { - $query = parent::getQueryString(); - if ($query) { + $query = (string) parent::getQueryString(); + if (!empty($query)) { $query .= '&'; } diff --git a/src/UrlBuilder.php b/src/UrlBuilder.php index eee0f41..b639da6 100644 --- a/src/UrlBuilder.php +++ b/src/UrlBuilder.php @@ -25,6 +25,8 @@ * General purpose URL builder class. * * @package ContaoCommunityAlliance\UrlBuilder + * + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ class UrlBuilder { @@ -80,7 +82,7 @@ class UrlBuilder /** * The part after the hash. * - * @var string + * @var string|null */ protected $fragment; @@ -141,7 +143,7 @@ public function __construct($url = '') */ public static function fromUrl($url) { - return new static($url); + return new self($url); } /** @@ -283,6 +285,11 @@ public function getPath() */ public function setPath($path) { + if (null === $path) { + $this->path = null; + + return $this; + } // Replace 2 or more slashes together. $this->path = preg_replace('@/{2,}@', '/', $path); @@ -324,7 +331,7 @@ public function setFragment($fragment) */ public function setQueryParameter($name, $value) { - $this->query[(string) $name] = (string) $value; + $this->query[$name] = $value; return $this; } @@ -344,7 +351,7 @@ public function insertQueryParameter($name, $value, $position) { $this->query = array_merge( array_slice($this->query, 0, $position), - array((string) $name => (string) $value), + [$name => $value], array_slice($this->query, $position) ); @@ -367,9 +374,9 @@ public function insertQueryParameterBefore($name, $value, $before) $index = array_search($before, array_keys($this->query)); if ($index !== false) { - $this->insertQueryParameter((string) $name, (string) $value, $index); + $this->insertQueryParameter($name, $value, $index); } else { - $this->setQueryParameter((string) $name, (string) $value); + $this->setQueryParameter($name, $value); } return $this; @@ -454,7 +461,9 @@ public function addQueryParameters($queryString) */ public function addQueryParametersFromUrl($url) { - $this->addQueryParameters(static::fromUrl($url)->getQueryString()); + if (null !== ($parameters = static::fromUrl($url)->getQueryString())) { + $this->addQueryParameters($parameters); + } return $this; } @@ -491,7 +500,9 @@ public function getQueryString() * * The base URL is the url without query part and fragment. * - * @return string|null + * @return string + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function getBaseUrl() { @@ -513,7 +524,9 @@ public function getBaseUrl() $url .= '@'; } - $url .= $this->host; + if (isset($this->host)) { + $url .= $this->host; + } if (isset($this->port)) { $url .= ':' . $this->port; @@ -562,13 +575,26 @@ public function getUrl() * * @param string $url The url to parse. * - * @return array + * @return array{ + * fragment?: string, + * host?: string, + * pass?: string, + * path?: string, + * port?: int, + * query?: string, + * scheme?: string, + * user?: string + * } */ private function parseUrl($url) { $parsed = parse_url($url); + if (!is_array($parsed)) { + return []; + } - if ((count($parsed) === 1) + if ( + (count($parsed) === 1) && isset($parsed['path']) && (0 === strpos($parsed['path'], '?') || false !== strpos($parsed['path'], '&')) ) { diff --git a/tests/Contao/BackendUrlBuilderTest.php b/tests/Contao/BackendUrlBuilderTest.php index e6fe00d..618a2af 100644 --- a/tests/Contao/BackendUrlBuilderTest.php +++ b/tests/Contao/BackendUrlBuilderTest.php @@ -34,12 +34,14 @@ class BackendUrlBuilderTest extends TestCase * @return void * * @runInSeparateProcess - * @expectedException \RuntimeException - * @expectedExceptionMessage Request token not defined */ public function testThrowsExceptionWithoutConstant() { $test = new BackendUrlBuilder('http://secure.c-c-a.org'); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Request token not defined'); + $test->getUrl(); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 1fc7210..30bff3b 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -25,5 +25,4 @@ */ abstract class TestCase extends \PHPUnit\Framework\TestCase { - } diff --git a/tests/UrlBuilderTest.php b/tests/UrlBuilderTest.php index c1197ac..40e65d0 100644 --- a/tests/UrlBuilderTest.php +++ b/tests/UrlBuilderTest.php @@ -24,6 +24,8 @@ /** * Main test class for UrlBuilder class. + * + * @SuppressWarnings(PHPMD.TooManyPublicMethods) */ class UrlBuilderTest extends TestCase { @@ -64,6 +66,7 @@ public function testFullUrl() * Prepare URLs for testPartialUrls test. * * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function prepareUrls() { @@ -192,6 +195,8 @@ function ($url) { * @return void * * @dataProvider prepareUrls + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function testPartialUrls($url, $expected, $user, $pass, $scheme, $host, $port, $path, $fragment, $query) { From 28ab354b17a2c939f17cb58d8e5a844acab792c7 Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Mon, 7 Feb 2022 14:06:54 +0100 Subject: [PATCH 2/2] Draft a fix for issue #3 --- src/UrlBuilder.php | 23 ++++++++++++++++++++--- tests/UrlBuilderTest.php | 2 +- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/UrlBuilder.php b/src/UrlBuilder.php index b639da6..aab1564 100644 --- a/src/UrlBuilder.php +++ b/src/UrlBuilder.php @@ -86,6 +86,15 @@ class UrlBuilder */ protected $fragment; + /** + * Flag to determine if the query string is to be prefixed with a question mark. + * + * See issue #3 + * + * @var bool + */ + private $queryWasPrefixed = false; + /** * Create a new instance. * @@ -558,6 +567,8 @@ public function getUrl() $url .= '/'; } $url .= '?'; + } elseif ($this->queryWasPrefixed) { + $url .= '?'; } $url .= $query; @@ -593,17 +604,23 @@ private function parseUrl($url) return []; } + if (count($parsed) !== 1) { + $this->queryWasPrefixed = false; + return $parsed; + } if ( - (count($parsed) === 1) - && isset($parsed['path']) - && (0 === strpos($parsed['path'], '?') || false !== strpos($parsed['path'], '&')) + isset($parsed['path']) + && (($queryWasPrefixed = (0 === strpos($parsed['path'], '?'))) || false !== strpos($parsed['path'], '&')) ) { $parsed = array( 'query' => $parsed['path'] ); + $this->queryWasPrefixed = $queryWasPrefixed; + return $parsed; } + $this->queryWasPrefixed = isset($parsed['query']); return $parsed; } diff --git a/tests/UrlBuilderTest.php b/tests/UrlBuilderTest.php index 40e65d0..4d900ea 100644 --- a/tests/UrlBuilderTest.php +++ b/tests/UrlBuilderTest.php @@ -120,7 +120,7 @@ public function prepareUrls() ), array( 'input' => '?authenticated=1&token=123&perform', - 'expected' => 'authenticated=1&token=123&perform', + 'expected' => '?authenticated=1&token=123&perform', 'query' => 'authenticated=1&token=123&perform', ), array(