diff --git a/.gitattributes b/.gitattributes index 0a2c694..6a160fa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,7 @@ .editorconfig export-ignore .gitattributes export-ignore .gitignore export-ignore -.php_cs.dist export-ignore +.php-cs-fixer.php export-ignore phpunit.xml export-ignore tests export-ignore git-hooks export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index faa70f9..2b4c087 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,3 +49,25 @@ jobs: - name: Run tests run: composer test + + stan: + name: PHPStan + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.2' + + - name: Check PHP Version + run: php -v + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-suggest + + - name: Run PHPStan + run: composer stan diff --git a/.gitignore b/.gitignore index 191abe8..8278889 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ composer.lock vendor .php_cs.cache +.php-cs-fixer.cache .phpunit.result.cache data/public_suffix_list.dat data/uri-schemes.csv diff --git a/.php_cs.dist b/.php-cs-fixer.php similarity index 53% rename from .php_cs.dist rename to .php-cs-fixer.php index 12e0779..c8462e4 100644 --- a/.php_cs.dist +++ b/.php-cs-fixer.php @@ -1,13 +1,17 @@ in([__DIR__ . '/src', __DIR__ . '/tests', __DIR__ . '/bin']); +$config = new Config(); -return PhpCsFixer\Config::create() +return $config->setFinder($finder) ->setRules([ '@PSR2' => true, 'strict_param' => true, - 'array_syntax' => ['syntax' => 'short'], 'single_class_element_per_statement' => false, ]) - ->setFinder($finder); + ->setRiskyAllowed(true) + ->setUsingCache(true); diff --git a/CHANGELOG.md b/CHANGELOG.md index b45cc7d..bae4889 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.1.0] - 2021-01-10 +### Added +- Static method to create PSR-7 Uri object + (`Url::parsePsr7('https://...')`). + +### Fixed +- Error when resolving something to a url with an empty path. + ## [1.0.2] - 2022-01-05 ### Changed - Run tests also on PHP 8.1 in CI. diff --git a/README.md b/README.md index 2c37119..ac7cc05 100644 --- a/README.md +++ b/README.md @@ -384,10 +384,8 @@ instance of the `Url` class in a private property and thus assures immutability. #### Usage Example ```php -use Crwlr\Url\Psr\Uri; - $url = 'https://user:password@www.example.com:1234/foo/bar?some=query#fragment'; -$uri = new Uri($url); +$uri = Url::parsePsr7($url); // Or instead: new Crwlr\Url\Psr\Uri($url); var_dump($uri->getScheme()); // => 'https' var_dump($uri->getAuthority()); // => 'user:password@www.example.com:1234' diff --git a/composer.json b/composer.json index 0164e11..c521ab0 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,8 @@ }, "require-dev": { "phpunit/phpunit": "^8.0", - "friendsofphp/php-cs-fixer": "^2.15" + "friendsofphp/php-cs-fixer": "^3.4", + "phpstan/phpstan": "^1.3" }, "autoload": { "psr-4": { @@ -46,7 +47,9 @@ }, "scripts": { "test": "@php vendor/bin/phpunit", - "cs": "PHP_CS_FIXER_IGNORE_ENV=1 php vendor/bin/php-cs-fixer fix -v --diff --dry-run --allow-risky=yes", + "cs": "@php vendor/bin/php-cs-fixer fix -v --dry-run", + "cs-fix": "@php vendor/bin/php-cs-fixer fix -v", + "stan": "@php vendor/bin/phpstan analyse -c phpstan.neon", "update-suffixes": "@php bin/update-suffixes", "update-schemes": "@php bin/update-schemes", "update-default-ports": "@php bin/update-default-ports", diff --git a/git-hooks/pre-commit b/git-hooks/pre-commit index 65a1b65..45792b0 100644 --- a/git-hooks/pre-commit +++ b/git-hooks/pre-commit @@ -1,24 +1,80 @@ #!/usr/bin/env php 0) { + $lastLine = array_pop($output); -// Show summary (last line) -echo array_pop($output) . PHP_EOL; + if (trim($lastLine) !== '') { + printLine($lastLine); + return; + } + } +} -exit(0); +function printLine(string $string) +{ + echo $string . PHP_EOL; +} + +function printLines(array $lines) +{ + echo implode(PHP_EOL, $lines) . PHP_EOL; +} + +function printBlankLine() +{ + printLine(''); +} + +function red(string $string): string +{ + return color('0;31', $string); +} + +function green(string $string): string +{ + return color('0;32', $string); +} + +function blue(string $string): string +{ + return color('0;34', $string); +} + +function color(string $colorCode, string $string): string +{ + return "\e[" . $colorCode . "m" . $string . "\e[0m"; +} diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..5049591 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,6 @@ +parameters: + level: 6 + paths: + - src + - tests + treatPhpDocTypesAsCertain: false diff --git a/src/DefaultPorts.php b/src/DefaultPorts.php index 634cd3b..ba00c58 100644 --- a/src/DefaultPorts.php +++ b/src/DefaultPorts.php @@ -14,6 +14,9 @@ class DefaultPorts extends Store { protected $storeFilename = 'default-ports.php'; + /** + * @var int[] + */ protected $fallbackList = [ 'ftp' => 21, 'git' => 9418, diff --git a/src/DefaultPorts/Updater.php b/src/DefaultPorts/Updater.php index 88ae4b4..faa742d 100644 --- a/src/DefaultPorts/Updater.php +++ b/src/DefaultPorts/Updater.php @@ -18,13 +18,17 @@ class Updater extends \Crwlr\Url\Lists\Updater protected $storeValuesAsKeys = false; /** - * @return mixed + * @return int[] */ - protected function getOriginalContent() + protected function getOriginalContent(): array { return include(dirname(__DIR__) . '/../data/schemes.php'); } + /** + * @param int[] $content + * @return int[] + */ protected function parseContent($content = []): array { $defaultPorts = []; diff --git a/src/Exceptions/ListStoreException.php b/src/Exceptions/ListStoreException.php new file mode 100644 index 0000000..65287fe --- /dev/null +++ b/src/Exceptions/ListStoreException.php @@ -0,0 +1,9 @@ + $value) { + foreach ($matches[1] as $value) { if (strpos($value, '.') !== false) { $brokenKeys[str_replace('.', '_', $value)] = $value; } diff --git a/src/Host.php b/src/Host.php index f516c5f..1416726 100644 --- a/src/Host.php +++ b/src/Host.php @@ -22,7 +22,7 @@ class Host private $subdomain; /** - * @var Domain + * @var Domain|null */ private $domain; @@ -121,7 +121,7 @@ public function domainSuffix(?string $domainSuffix = null): ?string */ public function hasIdn(): bool { - return $this->domain instanceof Domain ? $this->domain->isIdn() : false; + return $this->domain instanceof Domain && $this->domain->isIdn(); } /** diff --git a/src/Lists/Store.php b/src/Lists/Store.php index 9b975dc..30669f6 100644 --- a/src/Lists/Store.php +++ b/src/Lists/Store.php @@ -2,6 +2,8 @@ namespace Crwlr\Url\Lists; +use Crwlr\Url\Exceptions\ListStoreException; + /** * Class Store * @@ -23,14 +25,14 @@ abstract class Store * The list as an array, with the values as the keys for fast search * (in_array would be slow with a large number of values). * - * @var array + * @var array|int[] */ - protected $list; + protected $list = []; /** * Fallback list if list file loading fails. * - * @var array + * @var array|int[] */ protected $fallbackList = []; @@ -49,17 +51,23 @@ abstract class Store */ protected $storePath = ''; + /** + * @throws ListStoreException + */ public function __construct() { $this->setStorePath(); } - public function exists($key): bool + public function exists(string $key): bool { return $this->get($key) !== null; } - public function get($key) + /** + * @return string|int|null + */ + public function get(string $key) { if (isset($this->fallbackList[$key])) { return $this->fallbackList[$key]; @@ -87,11 +95,19 @@ public function getStorePath(): string /** * Generates the full store path of the file where the list is stored in the data directory at the root level. * If the child class does not declare a store filename the list will be empty. + * + * @throws ListStoreException */ private function setStorePath(): void { if (is_string($this->storeFilename) && trim($this->storeFilename) !== '') { - $this->storePath = realpath(dirname(__DIR__) . '/../data/' . $this->storeFilename); + $storePath = realpath(dirname(__DIR__) . '/../data/' . $this->storeFilename); + + if ($storePath === false) { + throw new ListStoreException('Looks like store path does not exist.'); + } + + $this->storePath = $storePath; } } @@ -102,7 +118,7 @@ private function setStorePath(): void */ protected function loadFullList(): void { - if (!is_array($this->list) && !empty($this->storePath)) { + if (empty($this->list) && !empty($this->storePath)) { $this->list = include($this->storePath); } elseif (!is_array($this->list)) { $this->list = []; diff --git a/src/Lists/Updater.php b/src/Lists/Updater.php index 4c864f3..8a05055 100644 --- a/src/Lists/Updater.php +++ b/src/Lists/Updater.php @@ -31,14 +31,16 @@ public function update(): void /** * In a child class implement a method that returns the original/source content (may be string, array or whatever). + * + * @return string|array|mixed */ abstract protected function getOriginalContent(); /** * In a child class implement a method that parses the contents to an array representing the list to store. * - * @param mixed $content - * @return array + * @param string|array|mixed $content + * @return array|(string|int)[] */ abstract protected function parseContent($content = ''): array; @@ -50,9 +52,9 @@ abstract protected function parseContent($content = ''): array; abstract protected function getListStorePath(): string; /** - * @param array $parsed + * @param array|(string|int)[] $parsed */ - protected function storeList(array $parsed = []) + protected function storeList(array $parsed = []): void { $content = "url = $url; @@ -44,7 +44,7 @@ public function __construct($url, $resolver = null) throw new InvalidArgumentException('Param url must be either a string or an instance of Crwlr\Url\Url.'); } - $this->resolver = $resolver instanceof Resolver ? $resolver : new Resolver(); + $this->resolver = $resolver ?? new Resolver(); } /** @@ -189,7 +189,7 @@ public function withPath($path): Uri } if (substr($path, 0, 1) !== '/' && trim($path) !== '') { - $path = $this->resolver->resolvePath($path, $this->url->path()); + $path = $this->resolver->resolvePath($path, $this->url->path() ?? ''); } $newUrl->path($path); diff --git a/src/Resolver.php b/src/Resolver.php index 2da56b2..b8258f6 100644 --- a/src/Resolver.php +++ b/src/Resolver.php @@ -38,7 +38,7 @@ public function resolve(string $subject, Url $base): Url return new Url($base->root() . $base->path() . $subject); } - $subject = $this->resolveDots($subject, $base->path()); + $subject = $this->resolveDots($subject, $base->path() ?? ''); if (substr($subject, 0, 2) === '//') { return new Url($base->scheme() . ':' . $subject); @@ -107,11 +107,11 @@ private function resolveDots(string $subject = '', string $basePath = ''): strin /** * Helper method for resolveDots * - * @param array $splitPath + * @param array|string[] $splitPath * @param int $currentKey * @return null|int */ - private function getParentDirFromArray(array $splitPath = [], int $currentKey = 0): ?int + private function getParentDirFromArray(array $splitPath, int $currentKey = 0): ?int { if ($currentKey === 0) { return null; diff --git a/src/Schemes.php b/src/Schemes.php index 5189ed3..520c27e 100644 --- a/src/Schemes.php +++ b/src/Schemes.php @@ -21,7 +21,7 @@ class Schemes extends Store /** * Fallback list if list file loading fails. * - * @var array + * @var int[] */ protected $fallbackList = [ 'cvs' => 0, diff --git a/src/Schemes/Updater.php b/src/Schemes/Updater.php index 7bab804..e3ddc02 100644 --- a/src/Schemes/Updater.php +++ b/src/Schemes/Updater.php @@ -26,7 +26,7 @@ class Updater extends WebUpdater /** * @param string $content - * @return array + * @return array|string[] */ protected function parseContent($content = ''): array { diff --git a/src/Suffixes.php b/src/Suffixes.php index 7e00902..de72dc3 100644 --- a/src/Suffixes.php +++ b/src/Suffixes.php @@ -28,7 +28,7 @@ class Suffixes extends Store * second level (gov, co, com,...) for these suffixes, that account for more than 0.1% of all websites according * to the w3techs.com usage ranking. * - * @var array + * @var int[] */ protected $fallbackList = ['com.ac'=>0,'edu.ac'=>0,'gov.ac'=>0,'net.ac'=>0,'mil.ac'=>0,'org.ac'=>0,'ae'=>0,'co.ae'=>0,'net.ae'=>0,'org.ae'=>0,'ac.ae'=>0,'gov.ae'=>0,'mil.ae'=>0,'gov.af'=>0,'com.af'=>0,'org.af'=>0,'net.af'=>0,'edu.af'=>0,'com.ag'=>0,'org.ag'=>0,'net.ag'=>0,'co.ag'=>0,'com.ai'=>0,'net.ai'=>0,'org.ai'=>0,'com.al'=>0,'edu.al'=>0,'gov.al'=>0,'mil.al'=>0,'net.al'=>0,'org.al'=>0,'co.ao'=>0,'ar'=>0,'com.ar'=>0,'edu.ar'=>0,'gov.ar'=>0,'mil.ar'=>0,'net.ar'=>0,'org.ar'=>0,'gov.as'=>0,'at'=>0,'ac.at'=>0,'co.at'=>0,'au'=>0,'com.au'=>0,'net.au'=>0,'org.au'=>0,'edu.au'=>0,'gov.au'=>0,'com.aw'=>0,'az'=>0,'com.az'=>0,'net.az'=>0,'gov.az'=>0,'org.az'=>0,'edu.az'=>0,'mil.az'=>0,'com.ba'=>0,'edu.ba'=>0,'gov.ba'=>0,'mil.ba'=>0,'net.ba'=>0,'org.ba'=>0,'co.bb'=>0,'com.bb'=>0,'edu.bb'=>0,'gov.bb'=>0,'net.bb'=>0,'org.bb'=>0,'be'=>0,'ac.be'=>0,'gov.bf'=>0,'bg'=>0,'com.bh'=>0,'edu.bh'=>0,'net.bh'=>0,'org.bh'=>0,'gov.bh'=>0,'co.bi'=>0,'com.bi'=>0,'edu.bi'=>0,'org.bi'=>0,'biz'=>0,'com.bm'=>0,'edu.bm'=>0,'gov.bm'=>0,'net.bm'=>0,'org.bm'=>0,'com.bo'=>0,'edu.bo'=>0,'org.bo'=>0,'net.bo'=>0,'mil.bo'=>0,'br'=>0,'com.br'=>0,'edu.br'=>0,'gov.br'=>0,'mil.br'=>0,'net.br'=>0,'org.br'=>0,'com.bs'=>0,'net.bs'=>0,'org.bs'=>0,'edu.bs'=>0,'gov.bs'=>0,'com.bt'=>0,'edu.bt'=>0,'gov.bt'=>0,'net.bt'=>0,'org.bt'=>0,'co.bw'=>0,'org.bw'=>0,'by'=>0,'gov.by'=>0,'mil.by'=>0,'com.by'=>0,'com.bz'=>0,'net.bz'=>0,'org.bz'=>0,'edu.bz'=>0,'gov.bz'=>0,'ca'=>0,'cat'=>0,'cc'=>0,'gov.cd'=>0,'ch'=>0,'org.ci'=>0,'com.ci'=>0,'co.ci'=>0,'edu.ci'=>0,'ac.ci'=>0,'net.ci'=>0,'cl'=>0,'gov.cl'=>0,'co.cl'=>0,'mil.cl'=>0,'co.cm'=>0,'com.cm'=>0,'gov.cm'=>0,'net.cm'=>0,'cn'=>0,'ac.cn'=>0,'com.cn'=>0,'edu.cn'=>0,'gov.cn'=>0,'net.cn'=>0,'org.cn'=>0,'mil.cn'=>0,'com.co'=>0,'edu.co'=>0,'gov.co'=>0,'mil.co'=>0,'net.co'=>0,'org.co'=>0,'com'=>0,'ac.cr'=>0,'co.cr'=>0,'com.cu'=>0,'edu.cu'=>0,'org.cu'=>0,'net.cu'=>0,'gov.cu'=>0,'com.cw'=>0,'edu.cw'=>0,'net.cw'=>0,'org.cw'=>0,'gov.cx'=>0,'ac.cy'=>0,'com.cy'=>0,'gov.cy'=>0,'net.cy'=>0,'org.cy'=>0,'cz'=>0,'de'=>0,'dk'=>0,'com.dm'=>0,'net.dm'=>0,'org.dm'=>0,'edu.dm'=>0,'gov.dm'=>0,'com.do'=>0,'edu.do'=>0,'gov.do'=>0,'mil.do'=>0,'net.do'=>0,'org.do'=>0,'com.dz'=>0,'org.dz'=>0,'net.dz'=>0,'gov.dz'=>0,'edu.dz'=>0,'com.ec'=>0,'net.ec'=>0,'org.ec'=>0,'edu.ec'=>0,'gov.ec'=>0,'mil.ec'=>0,'edu'=>0,'ee'=>0,'edu.ee'=>0,'gov.ee'=>0,'com.ee'=>0,'org.ee'=>0,'com.eg'=>0,'edu.eg'=>0,'gov.eg'=>0,'mil.eg'=>0,'net.eg'=>0,'org.eg'=>0,'es'=>0,'com.es'=>0,'org.es'=>0,'edu.es'=>0,'com.et'=>0,'gov.et'=>0,'org.et'=>0,'edu.et'=>0,'net.et'=>0,'eu'=>0,'fi'=>0,'fr'=>0,'com.fr'=>0,'com.ge'=>0,'edu.ge'=>0,'gov.ge'=>0,'org.ge'=>0,'mil.ge'=>0,'net.ge'=>0,'co.gg'=>0,'net.gg'=>0,'org.gg'=>0,'com.gh'=>0,'edu.gh'=>0,'gov.gh'=>0,'org.gh'=>0,'mil.gh'=>0,'com.gi'=>0,'gov.gi'=>0,'edu.gi'=>0,'org.gi'=>0,'co.gl'=>0,'com.gl'=>0,'edu.gl'=>0,'net.gl'=>0,'org.gl'=>0,'ac.gn'=>0,'com.gn'=>0,'edu.gn'=>0,'gov.gn'=>0,'org.gn'=>0,'net.gn'=>0,'com.gp'=>0,'net.gp'=>0,'edu.gp'=>0,'org.gp'=>0,'gr'=>0,'com.gr'=>0,'edu.gr'=>0,'net.gr'=>0,'org.gr'=>0,'gov.gr'=>0,'com.gt'=>0,'edu.gt'=>0,'mil.gt'=>0,'net.gt'=>0,'org.gt'=>0,'co.gy'=>0,'com.gy'=>0,'edu.gy'=>0,'gov.gy'=>0,'net.gy'=>0,'org.gy'=>0,'hk'=>0,'com.hk'=>0,'edu.hk'=>0,'gov.hk'=>0,'net.hk'=>0,'org.hk'=>0,'com.hn'=>0,'edu.hn'=>0,'org.hn'=>0,'net.hn'=>0,'mil.hn'=>0,'hr'=>0,'com.hr'=>0,'com.ht'=>0,'net.ht'=>0,'org.ht'=>0,'edu.ht'=>0,'hu'=>0,'co.hu'=>0,'org.hu'=>0,'id'=>0,'ac.id'=>0,'co.id'=>0,'mil.id'=>0,'net.id'=>0,'ie'=>0,'gov.ie'=>0,'il'=>0,'ac.il'=>0,'co.il'=>0,'gov.il'=>0,'net.il'=>0,'org.il'=>0,'ac.im'=>0,'co.im'=>0,'com.im'=>0,'net.im'=>0,'org.im'=>0,'in'=>0,'co.in'=>0,'net.in'=>0,'org.in'=>0,'ac.in'=>0,'edu.in'=>0,'gov.in'=>0,'mil.in'=>0,'info'=>0,'io'=>0,'com.io'=>0,'gov.iq'=>0,'edu.iq'=>0,'mil.iq'=>0,'com.iq'=>0,'org.iq'=>0,'net.iq'=>0,'ir'=>0,'ac.ir'=>0,'co.ir'=>0,'gov.ir'=>0,'net.ir'=>0,'org.ir'=>0,'net.is'=>0,'com.is'=>0,'edu.is'=>0,'gov.is'=>0,'org.is'=>0,'it'=>0,'gov.it'=>0,'edu.it'=>0,'co.it'=>0,'co.je'=>0,'net.je'=>0,'org.je'=>0,'com.jo'=>0,'org.jo'=>0,'net.jo'=>0,'edu.jo'=>0,'gov.jo'=>0,'mil.jo'=>0,'jp'=>0,'ac.jp'=>0,'co.jp'=>0,'ac.ke'=>0,'co.ke'=>0,'org.kg'=>0,'net.kg'=>0,'com.kg'=>0,'edu.kg'=>0,'gov.kg'=>0,'mil.kg'=>0,'edu.ki'=>0,'net.ki'=>0,'org.ki'=>0,'gov.ki'=>0,'com.ki'=>0,'org.km'=>0,'gov.km'=>0,'edu.km'=>0,'mil.km'=>0,'com.km'=>0,'net.kn'=>0,'org.kn'=>0,'edu.kn'=>0,'gov.kn'=>0,'com.kp'=>0,'edu.kp'=>0,'gov.kp'=>0,'org.kp'=>0,'kr'=>0,'ac.kr'=>0,'co.kr'=>0,'mil.kr'=>0,'edu.ky'=>0,'gov.ky'=>0,'com.ky'=>0,'org.ky'=>0,'net.ky'=>0,'kz'=>0,'org.kz'=>0,'edu.kz'=>0,'net.kz'=>0,'gov.kz'=>0,'mil.kz'=>0,'com.kz'=>0,'net.la'=>0,'edu.la'=>0,'gov.la'=>0,'com.la'=>0,'org.la'=>0,'com.lb'=>0,'edu.lb'=>0,'gov.lb'=>0,'net.lb'=>0,'org.lb'=>0,'com.lc'=>0,'net.lc'=>0,'co.lc'=>0,'org.lc'=>0,'edu.lc'=>0,'gov.lc'=>0,'gov.lk'=>0,'net.lk'=>0,'com.lk'=>0,'org.lk'=>0,'edu.lk'=>0,'ac.lk'=>0,'com.lr'=>0,'edu.lr'=>0,'gov.lr'=>0,'org.lr'=>0,'net.lr'=>0,'co.ls'=>0,'org.ls'=>0,'lt'=>0,'gov.lt'=>0,'lv'=>0,'com.lv'=>0,'edu.lv'=>0,'gov.lv'=>0,'org.lv'=>0,'mil.lv'=>0,'net.lv'=>0,'com.ly'=>0,'net.ly'=>0,'gov.ly'=>0,'edu.ly'=>0,'org.ly'=>0,'co.ma'=>0,'net.ma'=>0,'gov.ma'=>0,'org.ma'=>0,'ac.ma'=>0,'me'=>0,'co.me'=>0,'net.me'=>0,'org.me'=>0,'edu.me'=>0,'ac.me'=>0,'gov.me'=>0,'org.mg'=>0,'gov.mg'=>0,'edu.mg'=>0,'mil.mg'=>0,'com.mg'=>0,'co.mg'=>0,'com.mk'=>0,'org.mk'=>0,'net.mk'=>0,'edu.mk'=>0,'gov.mk'=>0,'com.ml'=>0,'edu.ml'=>0,'gov.ml'=>0,'net.ml'=>0,'org.ml'=>0,'gov.mn'=>0,'edu.mn'=>0,'org.mn'=>0,'com.mo'=>0,'net.mo'=>0,'org.mo'=>0,'edu.mo'=>0,'gov.mo'=>0,'gov.mr'=>0,'com.ms'=>0,'edu.ms'=>0,'gov.ms'=>0,'net.ms'=>0,'org.ms'=>0,'com.mt'=>0,'edu.mt'=>0,'net.mt'=>0,'org.mt'=>0,'com.mu'=>0,'net.mu'=>0,'org.mu'=>0,'gov.mu'=>0,'ac.mu'=>0,'co.mu'=>0,'com.mv'=>0,'edu.mv'=>0,'gov.mv'=>0,'mil.mv'=>0,'net.mv'=>0,'org.mv'=>0,'ac.mw'=>0,'co.mw'=>0,'com.mw'=>0,'edu.mw'=>0,'gov.mw'=>0,'net.mw'=>0,'org.mw'=>0,'mx'=>0,'com.mx'=>0,'org.mx'=>0,'edu.mx'=>0,'net.mx'=>0,'my'=>0,'com.my'=>0,'net.my'=>0,'org.my'=>0,'gov.my'=>0,'edu.my'=>0,'mil.my'=>0,'ac.mz'=>0,'co.mz'=>0,'edu.mz'=>0,'gov.mz'=>0,'mil.mz'=>0,'net.mz'=>0,'org.mz'=>0,'co.na'=>0,'com.na'=>0,'org.na'=>0,'net'=>0,'com.nf'=>0,'net.nf'=>0,'ng'=>0,'com.ng'=>0,'edu.ng'=>0,'gov.ng'=>0,'mil.ng'=>0,'net.ng'=>0,'org.ng'=>0,'ac.ni'=>0,'co.ni'=>0,'com.ni'=>0,'edu.ni'=>0,'mil.ni'=>0,'net.ni'=>0,'org.ni'=>0,'nl'=>0,'no'=>0,'mil.no'=>0,'gov.nr'=>0,'edu.nr'=>0,'org.nr'=>0,'net.nr'=>0,'com.nr'=>0,'nz'=>0,'ac.nz'=>0,'co.nz'=>0,'mil.nz'=>0,'net.nz'=>0,'org.nz'=>0,'co.om'=>0,'com.om'=>0,'edu.om'=>0,'gov.om'=>0,'net.om'=>0,'org.om'=>0,'org'=>0,'ac.pa'=>0,'com.pa'=>0,'org.pa'=>0,'edu.pa'=>0,'net.pa'=>0,'pe'=>0,'edu.pe'=>0,'mil.pe'=>0,'org.pe'=>0,'com.pe'=>0,'net.pe'=>0,'com.pf'=>0,'org.pf'=>0,'edu.pf'=>0,'ph'=>0,'com.ph'=>0,'net.ph'=>0,'org.ph'=>0,'gov.ph'=>0,'edu.ph'=>0,'mil.ph'=>0,'pk'=>0,'com.pk'=>0,'net.pk'=>0,'edu.pk'=>0,'org.pk'=>0,'gov.pk'=>0,'pl'=>0,'com.pl'=>0,'net.pl'=>0,'org.pl'=>0,'edu.pl'=>0,'mil.pl'=>0,'gov.pl'=>0,'gov.pn'=>0,'co.pn'=>0,'org.pn'=>0,'edu.pn'=>0,'net.pn'=>0,'com.pr'=>0,'net.pr'=>0,'org.pr'=>0,'gov.pr'=>0,'edu.pr'=>0,'ac.pr'=>0,'pro'=>0,'edu.ps'=>0,'gov.ps'=>0,'com.ps'=>0,'org.ps'=>0,'net.ps'=>0,'pt'=>0,'net.pt'=>0,'gov.pt'=>0,'org.pt'=>0,'edu.pt'=>0,'com.pt'=>0,'pw'=>0,'co.pw'=>0,'com.py'=>0,'edu.py'=>0,'gov.py'=>0,'mil.py'=>0,'net.py'=>0,'org.py'=>0,'com.qa'=>0,'edu.qa'=>0,'gov.qa'=>0,'mil.qa'=>0,'net.qa'=>0,'org.qa'=>0,'com.re'=>0,'ro'=>0,'com.ro'=>0,'org.ro'=>0,'rs'=>0,'ac.rs'=>0,'co.rs'=>0,'edu.rs'=>0,'gov.rs'=>0,'org.rs'=>0,'ru'=>0,'ac.ru'=>0,'edu.ru'=>0,'gov.ru'=>0,'mil.ru'=>0,'gov.rw'=>0,'net.rw'=>0,'edu.rw'=>0,'ac.rw'=>0,'com.rw'=>0,'co.rw'=>0,'mil.rw'=>0,'com.sa'=>0,'net.sa'=>0,'org.sa'=>0,'gov.sa'=>0,'edu.sa'=>0,'com.sb'=>0,'edu.sb'=>0,'gov.sb'=>0,'net.sb'=>0,'org.sb'=>0,'com.sc'=>0,'gov.sc'=>0,'net.sc'=>0,'org.sc'=>0,'edu.sc'=>0,'com.sd'=>0,'net.sd'=>0,'org.sd'=>0,'edu.sd'=>0,'gov.sd'=>0,'se'=>0,'ac.se'=>0,'org.se'=>0,'sg'=>0,'com.sg'=>0,'net.sg'=>0,'org.sg'=>0,'gov.sg'=>0,'edu.sg'=>0,'com.sh'=>0,'net.sh'=>0,'gov.sh'=>0,'org.sh'=>0,'mil.sh'=>0,'si'=>0,'sk'=>0,'com.sl'=>0,'net.sl'=>0,'edu.sl'=>0,'gov.sl'=>0,'org.sl'=>0,'com.sn'=>0,'edu.sn'=>0,'org.sn'=>0,'com.so'=>0,'net.so'=>0,'org.so'=>0,'co.st'=>0,'com.st'=>0,'edu.st'=>0,'gov.st'=>0,'mil.st'=>0,'net.st'=>0,'org.st'=>0,'su'=>0,'com.sv'=>0,'edu.sv'=>0,'org.sv'=>0,'gov.sx'=>0,'edu.sy'=>0,'gov.sy'=>0,'net.sy'=>0,'mil.sy'=>0,'com.sy'=>0,'org.sy'=>0,'co.sz'=>0,'ac.sz'=>0,'org.sz'=>0,'th'=>0,'ac.th'=>0,'co.th'=>0,'net.th'=>0,'ac.tj'=>0,'co.tj'=>0,'com.tj'=>0,'edu.tj'=>0,'gov.tj'=>0,'mil.tj'=>0,'net.tj'=>0,'org.tj'=>0,'tk'=>0,'gov.tl'=>0,'com.tm'=>0,'co.tm'=>0,'org.tm'=>0,'net.tm'=>0,'gov.tm'=>0,'mil.tm'=>0,'edu.tm'=>0,'com.tn'=>0,'gov.tn'=>0,'net.tn'=>0,'org.tn'=>0,'com.to'=>0,'gov.to'=>0,'net.to'=>0,'org.to'=>0,'edu.to'=>0,'mil.to'=>0,'tr'=>0,'com.tr'=>0,'net.tr'=>0,'org.tr'=>0,'gov.tr'=>0,'mil.tr'=>0,'edu.tr'=>0,'co.tt'=>0,'com.tt'=>0,'org.tt'=>0,'net.tt'=>0,'gov.tt'=>0,'edu.tt'=>0,'tv'=>0,'tw'=>0,'edu.tw'=>0,'gov.tw'=>0,'mil.tw'=>0,'com.tw'=>0,'net.tw'=>0,'org.tw'=>0,'ac.tz'=>0,'co.tz'=>0,'mil.tz'=>0,'ua'=>0,'com.ua'=>0,'edu.ua'=>0,'gov.ua'=>0,'net.ua'=>0,'org.ua'=>0,'co.ug'=>0,'ac.ug'=>0,'com.ug'=>0,'org.ug'=>0,'uk'=>0,'ac.uk'=>0,'co.uk'=>0,'gov.uk'=>0,'net.uk'=>0,'org.uk'=>0,'us'=>0,'co.us'=>0,'com.uy'=>0,'edu.uy'=>0,'mil.uy'=>0,'net.uy'=>0,'org.uy'=>0,'co.uz'=>0,'com.uz'=>0,'net.uz'=>0,'org.uz'=>0,'com.vc'=>0,'net.vc'=>0,'org.vc'=>0,'gov.vc'=>0,'mil.vc'=>0,'edu.vc'=>0,'co.ve'=>0,'com.ve'=>0,'edu.ve'=>0,'gov.ve'=>0,'mil.ve'=>0,'net.ve'=>0,'org.ve'=>0,'co.vi'=>0,'com.vi'=>0,'net.vi'=>0,'org.vi'=>0,'vn'=>0,'com.vn'=>0,'net.vn'=>0,'org.vn'=>0,'edu.vn'=>0,'gov.vn'=>0,'ac.vn'=>0,'com.vu'=>0,'edu.vu'=>0,'net.vu'=>0,'org.vu'=>0,'com.ws'=>0,'net.ws'=>0,'org.ws'=>0,'gov.ws'=>0,'edu.ws'=>0,'рф'=>0,'ac.za'=>0,'co.za'=>0,'edu.za'=>0,'gov.za'=>0,'mil.za'=>0,'net.za'=>0,'org.za'=>0,'ac.zm'=>0,'co.zm'=>0,'com.zm'=>0,'edu.zm'=>0,'gov.zm'=>0,'mil.zm'=>0,'net.zm'=>0,'org.zm'=>0,'ac.zw'=>0,'co.zw'=>0,'gov.zw'=>0,'mil.zw'=>0,'org.zw'=>0,'club'=>0,'download'=>0,'online'=>0,'site'=>0,'top'=>0,'xyz'=>0,'com.de'=>0,'com.se'=>0,'co.com'=>0,'co.ca'=>0,'co.cz'=>0,'co.nl'=>0,'co.no'=>0,'co.dk'=>0,'com.ru'=>0,'co.krd'=>0,'edu.krd'=>0,'co.pl'=>0,'net.ru'=>0,'org.ru'=>0,'co.ua'=>0]; diff --git a/src/Suffixes/Updater.php b/src/Suffixes/Updater.php index 5d670d6..cc586a9 100644 --- a/src/Suffixes/Updater.php +++ b/src/Suffixes/Updater.php @@ -25,7 +25,7 @@ class Updater extends WebUpdater /** * @param string $content - * @return array + * @return array|string[] */ protected function parseContent($content = ''): array { diff --git a/src/Url.php b/src/Url.php index 5d5a13e..6f91941 100644 --- a/src/Url.php +++ b/src/Url.php @@ -4,6 +4,7 @@ use Crwlr\Url\Exceptions\InvalidUrlComponentException; use Crwlr\Url\Exceptions\InvalidUrlException; +use Crwlr\Url\Psr\Uri; use InvalidArgumentException; /** @@ -23,7 +24,14 @@ class Url * * @var string|null */ - private $url, $scheme, $user, $pass, $host, $path, $query, $fragment; + private $url, $scheme, $user, $pass, $path, $query, $fragment; + + /** + * The host component is parsed to an instance of the Host class. + * + * @var Host|null + */ + private $host; /** * Port url component (int). @@ -61,7 +69,7 @@ class Url ]; /** - * @var Resolver + * @var Resolver|null */ private $resolver; @@ -115,6 +123,17 @@ public static function parse(string $url = ''): Url return new Url($url); } + /** + * Parses $url to a new instance of the PSR-7 UriInterface compatible Uri class. + * + * @param string $url + * @return Uri + */ + public static function parsePsr7(string $url = ''): Uri + { + return new Uri(Url::parse($url)); + } + /** * Get or set the scheme component. * @@ -129,7 +148,7 @@ public function scheme(?string $scheme = null) } elseif ($scheme === '') { $this->scheme = null; } else { - $this->scheme = $this->validateStringComponent('scheme', $scheme); + $this->scheme = $this->validateComponentValue('scheme', $scheme); } return $this->updateFullUrlAndReturnInstance(); @@ -138,7 +157,7 @@ public function scheme(?string $scheme = null) /** * Get or set the url authority (= [userinfo"@"]host[":"port]). * - * @param null|string + * @param null|string $authority * @return string|null|Url * @throws InvalidUrlComponentException */ @@ -183,7 +202,7 @@ public function user(?string $user = null) } elseif ($user === '') { $this->user = $this->pass = null; } else { - $this->user = $this->validateStringComponent('user', $user); + $this->user = $this->validateComponentValue('user', $user); } return $this->updateFullUrlAndReturnInstance(); @@ -203,7 +222,7 @@ public function password(?string $password = null) } elseif ($password === '') { $this->pass = null; } else { - $this->pass = $this->validateStringComponent('password', $password); + $this->pass = $this->validateComponentValue('password', $password); } return $this->updateFullUrlAndReturnInstance(); @@ -263,7 +282,7 @@ public function host(?string $host = null) $this->host = null; } else { $this->validatePathStartsWithSlash(); - $validHost = $this->validateStringComponent('host', $host); + $validHost = $this->validateComponentValue('host', $host); $this->host = new Host($validHost); } @@ -286,7 +305,7 @@ public function domain(?string $domain = null) return $this->host instanceof Host ? $this->host->domain() : null; } - $validDomain = $this->validateStringComponent('domain', $domain); + $validDomain = $this->validateComponentValue('domain', $domain); if ($this->host instanceof Host) { $this->host->domain($validDomain); @@ -320,7 +339,7 @@ public function domainLabel(?string $domainLabel = null) } $this->host->domainLabel( - $this->validateStringComponent('domainLabel', $domainLabel) + $this->validateComponentValue('domainLabel', $domainLabel) ); return $this->updateFullUrlAndReturnInstance(); @@ -349,7 +368,7 @@ public function domainSuffix(?string $domainSuffix = null) } $this->host->domainSuffix( - $this->validateStringComponent('domainSuffix', $domainSuffix) + $this->validateComponentValue('domainSuffix', $domainSuffix) ); return $this->updateFullUrlAndReturnInstance(); @@ -378,7 +397,7 @@ public function subdomain(?string $subdomain = null) } $this->host->subdomain( - $this->validateStringComponent('subdomain', $subdomain) + $this->validateComponentValue('subdomain', $subdomain) ); return $this->updateFullUrlAndReturnInstance(); @@ -401,7 +420,7 @@ public function port(?int $port = null) return ($scheme && $this->port === Helpers::getStandardPortByScheme($scheme)) ? null : $this->port; } - $this->port = $this->validateIntComponent('port', $port); + $this->port = $this->validateComponentValue('port', $port); return $this->updateFullUrlAndReturnInstance(); } @@ -427,7 +446,7 @@ public function path(?string $path = null) return $this->path; } - $this->path = $this->validateStringComponent('path', $path); + $this->path = $this->validateComponentValue('path', $path); return $this->updateFullUrlAndReturnInstance(); } @@ -445,7 +464,7 @@ public function query(?string $query = null) } elseif ($query === '') { $this->query = null; } else { - $this->query = $this->validateStringComponent('query', $query); + $this->query = $this->validateComponentValue('query', $query); } return $this->updateFullUrlAndReturnInstance(); @@ -454,15 +473,15 @@ public function query(?string $query = null) /** * Get or set the query component as array. * - * @param null|array $query - * @return array|Url + * @param null|array|string[] $query + * @return string[]|Url */ public function queryArray(?array $query = null) { if ($query === null) { return $this->query ? Helpers::queryStringToArray($this->query) : []; - } elseif (is_array($query)) { - $this->query = $this->validateStringComponent('query', http_build_query($query)); + } else { + $this->query = $this->validateComponentValue('query', http_build_query($query)); } return $this->updateFullUrlAndReturnInstance(); @@ -481,7 +500,7 @@ public function fragment(?string $fragment = null) } elseif ($fragment === '') { $this->fragment = null; } else { - $this->fragment = $this->validateStringComponent('fragment', $fragment); + $this->fragment = $this->validateComponentValue('fragment', $fragment); } return $this->updateFullUrlAndReturnInstance(); @@ -564,7 +583,7 @@ public function resolve(string $relativeUrl = ''): Url */ public function hasIdn(): bool { - return $this->host instanceof Host ? $this->host->hasIdn() : false; + return $this->host instanceof Host && $this->host->hasIdn(); } /** @@ -595,7 +614,7 @@ public function isComponentEqualIn($url, string $componentName): bool /** * Returns true when the scheme component is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -607,7 +626,7 @@ public function isSchemeEqualIn($url): bool /** * Returns true when the authority is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -619,7 +638,7 @@ public function isAuthorityEqualIn($url): bool /** * Returns true when the user is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -631,7 +650,7 @@ public function isUserEqualIn($url): bool /** * Returns true when the password is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -644,7 +663,7 @@ public function isPasswordEqualIn($url): bool * Returns true when the user information (both user and password) is the same in the current instance and the * url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -656,7 +675,7 @@ public function isUserInfoEqualIn($url): bool /** * Returns true when the host component is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -668,7 +687,7 @@ public function isHostEqualIn($url): bool /** * Returns true when the registrable domain is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -680,7 +699,7 @@ public function isDomainEqualIn($url): bool /** * Returns true when the domain label is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -692,7 +711,7 @@ public function isDomainLabelEqualIn($url): bool /** * Returns true when the domain suffix is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -704,7 +723,7 @@ public function isDomainSuffixEqualIn($url): bool /** * Returns true when the subdomain is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -716,7 +735,7 @@ public function isSubdomainEqualIn($url): bool /** * Returns true when the port component is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -728,7 +747,7 @@ public function isPortEqualIn($url): bool /** * Returns true when the path component is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -740,7 +759,7 @@ public function isPathEqualIn($url): bool /** * Returns true when the query component is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -752,7 +771,7 @@ public function isQueryEqualIn($url): bool /** * Returns true when the fragment component is the same in the current instance and the url you want to compare. * - * @param $url + * @param string|Url $url * @return bool * @throws InvalidArgumentException */ @@ -784,7 +803,7 @@ public function toString(): string * Population from another instance is just like cloning and it's necessary for the PSR-7 UriInterface Adapter * class. * - * @param string[]|Url $components + * @param array|(string|int)[]|Url $components */ private function populate($components): void { @@ -809,7 +828,7 @@ private function populate($components): void * Parse and validate $url in case it's a string, return when it's an instance of Url or throw an Exception. * * @param string|Url $url - * @return array|Url + * @return Url|array|(string|int)[] * @throws InvalidArgumentException * @throws InvalidUrlException */ @@ -847,29 +866,7 @@ private function isValidComponentName(string $componentName): bool /** * @param string $componentName - * @param string $componentValue - * @return string - * @throws InvalidUrlComponentException - */ - private function validateStringComponent(string $componentName, string $componentValue): string - { - return $this->validateComponentValue($componentName, $componentValue); - } - - /** - * @param string $componentName - * @param int $componentValue - * @return int - * @throws InvalidUrlComponentException - */ - private function validateIntComponent(string $componentName, int $componentValue): int - { - return $this->validateComponentValue($componentName, $componentValue); - } - - /** - * @param string $componentName - * @param $componentValue + * @param mixed $componentValue * @return int|string * @throws InvalidUrlComponentException */ @@ -910,7 +907,7 @@ private function updateFullUrlAndReturnInstance(): Url * * @throws InvalidUrlComponentException */ - private function validatePathStartsWithSlash() + private function validatePathStartsWithSlash(): void { if ($this->path() && $this->path() !== '' && !Helpers::startsWith($this->path(), '/', 1)) { throw new InvalidUrlComponentException( @@ -935,7 +932,7 @@ private function resolver(): Resolver /** * Compares the current instance with another url. * - * @param $compareToUrl + * @param string|Url $compareToUrl * @param string|null $componentName Compare either only a certain component of the urls or the whole urls if null. * @return bool * @throws InvalidArgumentException @@ -964,7 +961,7 @@ private function compare($compareToUrl, ?string $componentName = null): bool } /** - * @return array + * @return array|(string|int)[] */ private function authorityComponents(): array { @@ -972,7 +969,7 @@ private function authorityComponents(): array } /** - * @return array + * @return array|string[] */ private function userInfoComponents(): array { diff --git a/src/Validator.php b/src/Validator.php index 2a1b978..8ca6ecf 100644 --- a/src/Validator.php +++ b/src/Validator.php @@ -39,7 +39,7 @@ public static function url(string $url): ?string * Returns an array like ['url' => '...', 'scheme' => '...'] or null for invalid url. * * @param string $url - * @return array|null + * @return null|array|(string|int)[] */ public static function urlAndComponents(string $url): ?array { @@ -79,7 +79,7 @@ public static function absoluteUrl(string $url): ?string * Same as method urlAndComponents() but only an absolute url is valid. Returns null for relative references. * * @param string $url - * @return array|null + * @return null|array|(string|int)[] */ public static function absoluteUrlAndComponents(string $url): ?array { @@ -138,7 +138,7 @@ public static function authority(string $authority): ?string * Returns null if any component is invalid. * * @param string $authority - * @return array|null + * @return null|array|(string|int)[] */ public static function authorityComponents(string $authority): ?array { @@ -176,7 +176,7 @@ public static function userInfo(string $userInfo): ?string * Percent-encodes special characters. Returns null for invalid user information. * * @param string $userInfo - * @return array|null + * @return string[]|null */ public static function userInfoComponents(string $userInfo): ?array { @@ -433,7 +433,7 @@ public static function fragment(string $fragment = ''): string * of method calls for IDEs. * * @param string $componentName - * @param $value + * @param mixed $value * @return string|int|null */ public static function callValidationByComponentName(string $componentName, $value) @@ -478,7 +478,7 @@ public static function callValidationByComponentName(string $componentName, $val * * @param string $url * @param bool $onlyAbsoluteUrl When set to true, it will also return null when the input is a relative reference. - * @return array|null + * @return null|array|(string|int)[] */ private static function getValidUrlComponents(string $url, bool $onlyAbsoluteUrl = false): ?array { @@ -522,11 +522,7 @@ private static function encodeIdnHostInUrl(string $url): string $authority = self::stripUserInfoFromAuthority($authority); $host = self::stripPortFromAuthority($authority); - if (is_string($host) && - $host !== '' && - !self::isIpHost($host) && - !self::containsOnly($host, self::hostCharacters()) - ) { + if ($host !== '' && !self::isIpHost($host) && !self::containsOnly($host, self::hostCharacters())) { $encodedHost = Helpers::idn_to_ascii($host); $url = Helpers::replaceFirstOccurrence($host, $encodedHost, $url); } @@ -679,8 +675,8 @@ private static function getPortFromAuthority(string $authority): ?int * and the returned array contains query and fragment with empty strings as values. * Remove empty string elements for the same outcome in both versions. * - * @param array $components - * @return array + * @param array|(string|int)[] $components + * @return array|(string|int)[] */ private static function filterEmptyStringComponents(array $components = []): array { @@ -698,15 +694,15 @@ private static function filterEmptyStringComponents(array $components = []): arr * * Returns an empty array when one of the components is invalid. * - * @param array $components - * @return array + * @param array|(string|int)[] $components + * @return array|(string|int)[] */ private static function validateUrlComponents(array $components): array { foreach ($components as $componentName => $componentValue) { if (method_exists(self::class, $componentName)) { if ($componentName === 'path') { - $validComponent = self::path($componentValue, isset($components['host']) ? true : false); + $validComponent = self::path($componentValue, isset($components['host'])); } else { $validComponent = self::callValidationByComponentName($componentName, $componentValue); } @@ -727,8 +723,8 @@ private static function validateUrlComponents(array $components): array * * Because it's the same for both methods. * - * @param array|null $validComponents - * @return array|null + * @param null|array|(string|int)[] $validComponents + * @return null|array|(string|int)[] */ private static function returnValidUrlAndComponentsArray(?array $validComponents): ?array { @@ -745,7 +741,7 @@ private static function returnValidUrlAndComponentsArray(?array $validComponents * Get an array of valid authority components (host, userInfo, user, password, port) from an authority string * * @param string $authority - * @return array|null + * @return null|array|(string|int)[] */ private static function getValidAuthorityComponents(string $authority): ?array { @@ -768,7 +764,7 @@ private static function getValidAuthorityComponents(string $authority): ?array * Split an authority string to components (host, userInfo, port) * * @param string $authority - * @return array|null + * @return null|array|(string|int)[] */ private static function splitAuthorityToComponents(string $authority): ?array { @@ -803,7 +799,7 @@ private static function splitAuthorityToComponents(string $authority): ?array * Split user info string : to user and password * * @param string $userInfo - * @return array|null + * @return string[]|null */ private static function splitUserInfoToComponents(string $userInfo): ?array { @@ -827,8 +823,8 @@ private static function splitUserInfoToComponents(string $userInfo): ?array /** * Validate authority components (host, userInfo, port) * - * @param array $components - * @return array|null + * @param array|(string|int)[] $components + * @return null|array|(string|int)[] */ private static function validateAuthorityComponents(array $components): ?array { @@ -853,7 +849,7 @@ private static function validateAuthorityComponents(array $components): ?array * Split user info string to user and password and validate. * * @param string $userInfo - * @return array|null + * @return array|string[]|null */ private static function getValidUserInfoComponents(string $userInfo): ?array { @@ -873,7 +869,7 @@ private static function getValidUserInfoComponents(string $userInfo): ?array } /** - * Validate a user name or password + * Validate a username or password * * Percent encodes characters that aren't allowed within a user information component. * @@ -887,7 +883,7 @@ private static function userOrPassword(string $string): string { $string = self::encodePercentCharacter($string); - return self::urlEncodeExcept($string, "/[^a-zA-Z0-9-._~!$&'() * +,;=%]/"); + return self::urlEncodeExcept($string, "/[^a-zA-Z0-9-._~!$&'()*+,;=%]/"); } /** @@ -950,7 +946,7 @@ private static function encodeIdn(string $string): string */ private static function containsOnly(string $subject, string $regexPattern): bool { - return preg_match('/[^' . $regexPattern . ']/', $subject) ? false : true; + return !preg_match('/[^' . $regexPattern . ']/', $subject); } /** @@ -1034,7 +1030,7 @@ function ($match) { * * https://tools.ietf.org/html/rfc3986#appendix-A * - * @param array $additionalCharacters + * @param string[] $additionalCharacters * @return string */ private static function pcharRegexPattern(array $additionalCharacters = []): string diff --git a/tests/DefaultPortsTest.php b/tests/DefaultPortsTest.php index 7c66be3..357ea94 100644 --- a/tests/DefaultPortsTest.php +++ b/tests/DefaultPortsTest.php @@ -6,7 +6,7 @@ final class DefaultPortsTest extends TestCase { - public function testGetFallbackDefaultPorts() + public function testGetFallbackDefaultPorts(): void { $this->assertEquals(21, (new DefaultPorts())->get('ftp')); $this->assertEquals(9418, (new DefaultPorts())->get('git')); @@ -23,7 +23,7 @@ public function testGetFallbackDefaultPorts() $this->assertEquals(22, (new DefaultPorts())->get('ssh')); } - public function testGetDefaultPortsNotInFallbackList() + public function testGetDefaultPortsNotInFallbackList(): void { $this->assertEquals(2019, (new DefaultPorts())->get('about')); $this->assertEquals(674, (new DefaultPorts())->get('acap')); @@ -36,13 +36,13 @@ public function testGetDefaultPortsNotInFallbackList() $this->assertEquals(516, (new DefaultPorts())->get('videotex')); } - public function testExists() + public function testExists(): void { $this->assertTrue((new DefaultPorts())->exists('http')); $this->assertFalse((new DefaultPorts())->exists('notexistingscheme')); } - public function testGetStorePath() + public function testGetStorePath(): void { $defaultPorts = new DefaultPorts(); $this->assertEquals(realpath(dirname(__DIR__) . '/data/default-ports.php'), $defaultPorts->getStorePath()); diff --git a/tests/DomainTest.php b/tests/DomainTest.php index 094caa5..cb3be7c 100644 --- a/tests/DomainTest.php +++ b/tests/DomainTest.php @@ -10,7 +10,7 @@ final class DomainTest extends TestCase * The domain class is really simple and assumes input validation happens somewhere else, so this test * is rather short ;p */ - public function testDomain() + public function testDomain(): void { $domain = new Domain('example.com'); $this->assertInstanceOf(Domain::class, $domain); @@ -25,7 +25,7 @@ public function testDomain() $this->assertEmpty($domain->__toString()); } - public function testIsIdn() + public function testIsIdn(): void { $domain = new Domain('example.com'); $this->assertFalse($domain->isIdn()); diff --git a/tests/HelpersTest.php b/tests/HelpersTest.php index 1ebcc5c..2682928 100644 --- a/tests/HelpersTest.php +++ b/tests/HelpersTest.php @@ -8,13 +8,13 @@ final class HelpersTest extends TestCase { - public function testGetHelperClassInstancesStatically() + public function testGetHelperClassInstancesStatically(): void { $this->assertInstanceOf(Suffixes::class, Helpers::suffixes()); $this->assertInstanceOf(Schemes::class, Helpers::schemes()); } - public function testBuildUrlFromComponents() + public function testBuildUrlFromComponents(): void { $this->assertEquals( 'https://user:pass@www.example.com:1234/foo/bar?query=string#fragment', @@ -31,7 +31,7 @@ public function testBuildUrlFromComponents() ); } - public function testBuildAuthorityFromComponents() + public function testBuildAuthorityFromComponents(): void { $this->assertEquals( 'user:password@www.example.com:1234', @@ -54,7 +54,7 @@ public function testBuildAuthorityFromComponents() ); } - public function testBuildUserInfoFromComponents() + public function testBuildUserInfoFromComponents(): void { $this->assertEquals( 'user:password', @@ -72,7 +72,7 @@ public function testBuildUserInfoFromComponents() * string to array. The problem is, that dots within keys in the query string are replaced with underscores. * For more information see https://github.com/crwlrsoft/url/issues/2 */ - public function testQueryStringToArray() + public function testQueryStringToArray(): void { $this->assertEquals( [ @@ -86,7 +86,7 @@ public function testQueryStringToArray() ); } - public function testGetStandardPortsByScheme() + public function testGetStandardPortsByScheme(): void { $this->assertEquals(21, Helpers::getStandardPortByScheme('ftp')); $this->assertEquals(9418, Helpers::getStandardPortByScheme('git')); @@ -102,33 +102,33 @@ public function testGetStandardPortsByScheme() $this->assertNull(Helpers::getStandardPortByScheme('unknownscheme')); } - public function testStripFromEnd() + public function testStripFromEnd(): void { $this->assertEquals('example', Helpers::stripFromEnd('examplestring', 'string')); $this->assertEquals('examplestring', Helpers::stripFromEnd('examplestring', 'strong')); $this->assertEquals('examplestring', Helpers::stripFromEnd('examplestring', 'strin')); } - public function testStripFromStart() + public function testStripFromStart(): void { $this->assertEquals('string', Helpers::stripFromStart('examplestring', 'example')); $this->assertEquals('examplestring', Helpers::stripFromStart('examplestring', 'eggsample')); $this->assertEquals('examplestring', Helpers::stripFromStart('examplestring', 'xample')); } - public function testReplaceFirstOccurrence() + public function testReplaceFirstOccurrence(): void { $this->assertEquals('foo bas baz bar', Helpers::replaceFirstOccurrence('bar', 'bas', 'foo bar baz bar')); $this->assertEquals('foo bar bar', Helpers::replaceFirstOccurrence('baz', 'bar', 'foo bar baz')); } - public function testStartsWith() + public function testStartsWith(): void { $this->assertTrue(Helpers::startsWith('Raindrops Keep Fallin\' on My Head', 'Raindrops Keep')); $this->assertFalse(Helpers::startsWith('Raindrops Keep Fallin\' on My Head', 'Braindrops Keep')); } - public function testContainsXBeforeFirstY() + public function testContainsXBeforeFirstY(): void { $this->assertTrue(Helpers::containsXBeforeFirstY('one-two-three-two', '-', 'two')); $this->assertFalse(Helpers::containsXBeforeFirstY('one-two-three-two', 'three', 'two')); diff --git a/tests/HostTest.php b/tests/HostTest.php index f6ddb68..8479bb8 100644 --- a/tests/HostTest.php +++ b/tests/HostTest.php @@ -6,7 +6,7 @@ final class HostTest extends TestCase { - public function testParseHost() + public function testParseHost(): void { $host = new Host('www.example.com'); $this->assertInstanceOf(Host::class, $host); @@ -30,7 +30,7 @@ public function testParseHost() $this->assertEquals('xn--80asehdb', $host->domainSuffix()); } - public function testSubdomain() + public function testSubdomain(): void { $host = new Host('www.example.com'); @@ -47,7 +47,7 @@ public function testSubdomain() $this->assertEquals('foo.bar.yololo.example.com', $host->__toString()); } - public function testDomain() + public function testDomain(): void { $host = new Host('www.example.com'); @@ -64,7 +64,7 @@ public function testDomain() $this->assertEquals('www.crwlr.software', $host->__toString()); } - public function testDomainLabel() + public function testDomainLabel(): void { $host = new Host('www.example.com'); @@ -85,7 +85,7 @@ public function testDomainLabel() $this->assertEquals('www.google.com', $host->__toString()); } - public function testDomainSuffix() + public function testDomainSuffix(): void { $host = new Host('www.example.com'); @@ -106,7 +106,7 @@ public function testDomainSuffix() $this->assertEquals('www.example.software', $host->__toString()); } - public function testHasIdn() + public function testHasIdn(): void { $host = new Host('www.example.com'); $this->assertFalse($host->hasIdn()); diff --git a/tests/Psr/UriTest.php b/tests/Psr/UriTest.php index c66ba3b..80cf8b4 100644 --- a/tests/Psr/UriTest.php +++ b/tests/Psr/UriTest.php @@ -7,7 +7,7 @@ final class UriTest extends TestCase { - public function testScheme() + public function testScheme(): void { $uri = $this->getUri(); $this->assertEquals('http', $uri->getScheme()); @@ -26,7 +26,7 @@ public function testScheme() $this->assertEquals('sftp', $uri->getScheme()); } - public function testAuthority() + public function testAuthority(): void { $uri = $this->getUri(); $this->assertEquals('www.example.com', $uri->getAuthority()); @@ -56,7 +56,7 @@ public function testAuthority() $this->assertEquals('http://example.com/foo/bar?query=string#fragment', $uri->__toString()); } - public function testUserInfo() + public function testUserInfo(): void { $uri = $this->getUri(); $this->assertEquals('', $uri->getUserInfo()); @@ -77,7 +77,7 @@ public function testUserInfo() $this->assertEquals('http://www.example.com/foo/bar?query=string#fragment', $uri->__toString()); } - public function testHost() + public function testHost(): void { $uri = $this->getUri(); $this->assertEquals('www.example.com', $uri->getHost()); @@ -96,7 +96,7 @@ public function testHost() $this->assertEquals('sub.domain.example.com', $uri->getHost()); } - public function testPort() + public function testPort(): void { $uri = $this->getUri(); $this->assertNull($uri->getPort()); @@ -131,21 +131,21 @@ public function testPort() $this->assertEquals('http://www.example.com/foo/bar?query=string#fragment', $uri->__toString()); } - public function testPortAboveRange() + public function testPortAboveRange(): void { $uri = $this->getUri(); $this->expectException(InvalidArgumentException::class); $uri->withPort(65536); } - public function testNegativePort() + public function testNegativePort(): void { $uri = $this->getUri(); $this->expectException(InvalidArgumentException::class); $uri->withPort(-1); } - public function testPath() + public function testPath(): void { $uri = $this->getUri(); $this->assertEquals('/foo/bar', $uri->getPath()); @@ -181,7 +181,7 @@ public function testPath() $this->assertEquals('http://www.example.com/?query=string#fragment', $uri->__toString()); } - public function testQuery() + public function testQuery(): void { $uri = $this->getUri(); $this->assertEquals('query=string', $uri->getQuery()); @@ -196,7 +196,7 @@ public function testQuery() $this->assertEquals('', $uri->getQuery()); } - public function testFragment() + public function testFragment(): void { $uri = $this->getUri(); $this->assertEquals('fragment', $uri->getFragment()); @@ -220,7 +220,7 @@ public function testFragment() $this->assertEquals('fragm%E2%82%ACnt', $uri->getFragment()); } - public function testToString() + public function testToString(): void { $uri = new Uri('/foo/bar?query=string#fragment'); $this->assertEquals('', $uri->getScheme()); @@ -258,7 +258,7 @@ public function testToString() * @return Uri * @throws InvalidUrlException */ - private function getUri() + private function getUri(): Uri { return new Uri('http://www.example.com/foo/bar?query=string#fragment'); } diff --git a/tests/ResolverTest.php b/tests/ResolverTest.php index 4eeaa1d..a3e4c36 100644 --- a/tests/ResolverTest.php +++ b/tests/ResolverTest.php @@ -8,7 +8,7 @@ final class ResolverTest extends TestCase { - public function testResolveRelativeUrls() + public function testResolveRelativeUrls(): void { $baseUrlObject = $this->getBaseUrlObject(); $resolver = new Resolver(); @@ -84,10 +84,18 @@ public function testResolveRelativeUrls() $this->assertEquals('/foo/one/three', $resolved->toString()); } + public function testResolveRelativeUrlAgainstBaseUrlWithEmptyPath(): void + { + $baseUrlObject = Url::parse('https://www.crwlr.software'); + $resolver = new Resolver(); + $resolved = $resolver->resolve('/privacy', $baseUrlObject); + $this->assertEquals('https://www.crwlr.software/privacy', $resolved->toString()); + } + /** * When resolve() is called with an absolute url as subject, it should just return this absolute url. */ - public function testResolveAbsoluteUrl() + public function testResolveAbsoluteUrl(): void { $baseUrlObject = $this->getBaseUrlObject(); $resolver = new Resolver(); @@ -109,7 +117,7 @@ public function testResolveAbsoluteUrl() /** * Resolve a relative path against an absolute path. */ - public function testResolvePaths() + public function testResolvePaths(): void { $resolver = new Resolver(); @@ -128,7 +136,7 @@ public function testResolvePaths() * @return Url * @throws InvalidUrlException */ - private function getBaseUrlObject($url = '') + private function getBaseUrlObject(string $url = ''): Url { if ($url === '') { $url = 'https://www.example.com/foo/bar/baz'; diff --git a/tests/SchemesTest.php b/tests/SchemesTest.php index 0eb1df7..88f79a8 100644 --- a/tests/SchemesTest.php +++ b/tests/SchemesTest.php @@ -6,7 +6,7 @@ final class SchemesTest extends TestCase { - public function testExists() + public function testExists(): void { $schemes = new Schemes(); @@ -21,7 +21,7 @@ public function testExists() $this->assertFalse($schemes->exists('doesnt-exist')); } - public function testGetStorePath() + public function testGetStorePath(): void { $schemes = new Schemes(); $this->assertEquals(realpath(dirname(__DIR__) . '/data/schemes.php'), $schemes->getStorePath()); diff --git a/tests/SuffixesTest.php b/tests/SuffixesTest.php index 605f2f2..0c313ba 100644 --- a/tests/SuffixesTest.php +++ b/tests/SuffixesTest.php @@ -6,7 +6,7 @@ final class SuffixesTest extends TestCase { - public function testExists() + public function testExists(): void { $suffixes = new Suffixes(); @@ -18,7 +18,7 @@ public function testExists() $this->assertFalse($suffixes->exists('does.not.exist')); } - public function testGetStorePath() + public function testGetStorePath(): void { $schemes = new Suffixes(); $this->assertEquals(realpath(dirname(__DIR__) . '/data/suffixes.php'), $schemes->getStorePath()); diff --git a/tests/UrlTest.php b/tests/UrlTest.php index ca1aca3..c5d4cf1 100644 --- a/tests/UrlTest.php +++ b/tests/UrlTest.php @@ -3,12 +3,13 @@ use Crwlr\Url\Exceptions\InvalidUrlComponentException; use Crwlr\Url\Exceptions\InvalidUrlException; +use Crwlr\Url\Psr\Uri; use Crwlr\Url\Url; use PHPUnit\Framework\TestCase; final class UrlTest extends TestCase { - public function testCanBeCreatedFromValidUrl() + public function testCanBeCreatedFromValidUrl(): void { $url = $this->createDefaultUrlObject(); $this->assertInstanceOf(Url::class, $url); @@ -17,31 +18,43 @@ public function testCanBeCreatedFromValidUrl() /** * @throws InvalidUrlException */ - public function testInvalidUrlThrowsException() + public function testInvalidUrlThrowsException(): void { $this->expectException(InvalidUrlException::class); new Url('https://'); } - public function testCanBeCreatedFromRelativeUrl() + public function testCanBeCreatedFromRelativeUrl(): void { $url = new Url('/foo/bar?query=string'); $this->assertInstanceOf(Url::class, $url); } - public function testCantBeCreatedFromRelativePath() + public function testCantBeCreatedFromRelativePath(): void { $url = new Url('yo/lo'); $this->assertInstanceOf(Url::class, $url); } - public function testCanBeCreatedViaFactoryMethod() + public function testCanBeCreatedViaFactoryMethod(): void { $url = Url::parse('http://www.example.com'); $this->assertInstanceOf(Url::class, $url); } - public function testParseUrl() + public function testPsr7FactoryMethodWithAbsoluteUrl(): void + { + $uri = Url::parsePsr7('https://www.crwlr.software/packages/url'); + $this->assertInstanceOf(Uri::class, $uri); + } + + public function testPsr7FactoryMethodWithRelativeReference(): void + { + $uri = Url::parsePsr7('/packages/url'); + $this->assertInstanceOf(Uri::class, $uri); + } + + public function testParseUrl(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('https', $url->scheme()); @@ -64,35 +77,35 @@ public function testParseUrl() $this->assertEquals('/some/path?some=query#fragment', $url->relative()); } - public function testClassPropertyAccess() + public function testClassPropertyAccess(): void { $url = $this->createDefaultUrlObject(); - $this->assertEquals('https', $url->scheme); - $this->assertEquals('user:password@sub.sub.example.com:8080', $url->authority); - $this->assertEquals('user', $url->user); - $this->assertEquals('password', $url->password); - $this->assertEquals('password', $url->pass); - $this->assertEquals('user:password', $url->userInfo); - $this->assertEquals('sub.sub.example.com', $url->host); - $this->assertEquals('example.com', $url->domain); - $this->assertEquals('example', $url->domainLabel); - $this->assertEquals('com', $url->domainSuffix); - $this->assertEquals('sub.sub', $url->subdomain); - $this->assertEquals(8080, $url->port); - $this->assertEquals('/some/path', $url->path); - $this->assertEquals('some=query', $url->query); - $this->assertEquals(['some' => 'query'], $url->queryArray); - $this->assertEquals('fragment', $url->fragment); - $this->assertEquals('https://user:password@sub.sub.example.com:8080', $url->root); - $this->assertEquals('/some/path?some=query#fragment', $url->relative); + $this->assertEquals('https', $url->scheme); // @phpstan-ignore-line + $this->assertEquals('user:password@sub.sub.example.com:8080', $url->authority); // @phpstan-ignore-line + $this->assertEquals('user', $url->user); // @phpstan-ignore-line + $this->assertEquals('password', $url->password); // @phpstan-ignore-line + $this->assertEquals('password', $url->pass); // @phpstan-ignore-line + $this->assertEquals('user:password', $url->userInfo); // @phpstan-ignore-line + $this->assertEquals('sub.sub.example.com', $url->host); // @phpstan-ignore-line + $this->assertEquals('example.com', $url->domain); // @phpstan-ignore-line + $this->assertEquals('example', $url->domainLabel); // @phpstan-ignore-line + $this->assertEquals('com', $url->domainSuffix); // @phpstan-ignore-line + $this->assertEquals('sub.sub', $url->subdomain); // @phpstan-ignore-line + $this->assertEquals(8080, $url->port); // @phpstan-ignore-line + $this->assertEquals('/some/path', $url->path); // @phpstan-ignore-line + $this->assertEquals('some=query', $url->query); // @phpstan-ignore-line + $this->assertEquals(['some' => 'query'], $url->queryArray); // @phpstan-ignore-line + $this->assertEquals('fragment', $url->fragment); // @phpstan-ignore-line + $this->assertEquals('https://user:password@sub.sub.example.com:8080', $url->root); // @phpstan-ignore-line + $this->assertEquals('/some/path?some=query#fragment', $url->relative); // @phpstan-ignore-line // other class properties that aren't components of the parsed url should not be available. - $this->assertNull($url->parser); - $this->assertNull($url->validator); - $this->assertNull($url->resolver); + $this->assertNull($url->parser); // @phpstan-ignore-line + $this->assertNull($url->validator); // @phpstan-ignore-line + $this->assertNull($url->resolver); // @phpstan-ignore-line } - public function testParseIdnUrl() + public function testParseIdnUrl(): void { $url = new Url('https://www.юбилейный.онлайн'); $this->assertEquals('www.xn--90aiifajq6iua.xn--80asehdb', $url->host()); @@ -103,13 +116,13 @@ public function testParseIdnUrl() /** * @throws InvalidUrlException */ - public function testUrlWithInvalidHost() + public function testUrlWithInvalidHost(): void { $this->expectException(InvalidUrlException::class); Url::parse('https://www.exclamation!mark.co'); } - public function testReplaceScheme() + public function testReplaceScheme(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('https', $url->scheme()); @@ -125,32 +138,32 @@ public function testReplaceScheme() /** * @throws InvalidUrlComponentException */ - public function testSetInvalidSchemeThrowsException() + public function testSetInvalidSchemeThrowsException(): void { $url = $this->createDefaultUrlObject(); $this->expectException(InvalidUrlComponentException::class); $url->scheme('1nvalidSch3m3'); } - public function testSchemeContainingPlus() + public function testSchemeContainingPlus(): void { $url = Url::parse('coap+tcp://example.com'); $this->assertEquals('coap+tcp', $url->scheme()); } - public function testSchemeContainingDash() + public function testSchemeContainingDash(): void { $url = Url::parse('chrome-extension://extension-id/page.html'); $this->assertEquals('chrome-extension', $url->scheme()); } - public function testSchemeContainingDot() + public function testSchemeContainingDot(): void { $url = Url::parse('soap.beep://stockquoteserver.example.com/StockQuote'); $this->assertEquals('soap.beep', $url->scheme()); } - public function testParseUrlWithoutScheme() + public function testParseUrlWithoutScheme(): void { $url = Url::parse('//www.example.com/test.html'); $this->assertEquals('//www.example.com/test.html', $url->toString()); @@ -159,7 +172,7 @@ public function testParseUrlWithoutScheme() $this->assertEquals('http://www.example.com/test.html', $url->toString()); } - public function testReplaceAuthority() + public function testReplaceAuthority(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('user:password@sub.sub.example.com:8080', $url->authority()); @@ -203,14 +216,14 @@ public function testReplaceAuthority() /** * @throws InvalidUrlComponentException */ - public function testSetInvalidAuthorityThrowsException() + public function testSetInvalidAuthorityThrowsException(): void { $url = $this->createDefaultUrlObject(); $this->expectException(InvalidUrlComponentException::class); $url->authority('example.com:100000'); } - public function testReplaceUser() + public function testReplaceUser(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('user', $url->user()); @@ -223,7 +236,7 @@ public function testReplaceUser() ); } - public function testReplacePassword() + public function testReplacePassword(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('password', $url->password()); @@ -246,7 +259,7 @@ public function testReplacePassword() ); } - public function testReplaceUserInfo() + public function testReplaceUserInfo(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('user:password', $url->userInfo()); @@ -273,14 +286,14 @@ public function testReplaceUserInfo() $this->assertEquals('https://a:b%3Ac@sub.sub.example.com:8080/some/path?some=query#fragment', $url->toString()); } - public function testUrlWithEmptyUserInfo() + public function testUrlWithEmptyUserInfo(): void { $url = Url::parse('https://@example.com'); $this->assertEquals('https://example.com', $url->toString()); $this->assertEquals('', $url->userInfo()); } - public function testReplaceHost() + public function testReplaceHost(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('sub.sub.example.com', $url->host()); @@ -297,20 +310,20 @@ public function testReplaceHost() /** * @throws InvalidUrlComponentException */ - public function testSetInvalidHostThrowsException() + public function testSetInvalidHostThrowsException(): void { $url = $this->createDefaultUrlObject(); $this->expectException(InvalidUrlComponentException::class); $url->host('crw!r.software'); } - public function testPercentEncodedCharactersInHost() + public function testPercentEncodedCharactersInHost(): void { $url = Url::parse('https://www.m%C3%A4nnersalon.at'); $this->assertEquals('www.xn--mnnersalon-q5a.at', $url->host()); } - public function testIpAddressHost() + public function testIpAddressHost(): void { $url = Url::parse('https://192.168.0.1/foo/bar'); $this->assertEquals('192.168.0.1', $url->host()); @@ -324,7 +337,7 @@ public function testIpAddressHost() /** * Example addresses from https://tools.ietf.org/html/rfc2732#section-2 */ - public function testIpV6AddressHost() + public function testIpV6AddressHost(): void { $url = Url::parse('http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html'); // Host must be lowercased as stated in https://tools.ietf.org/html/rfc3986#section-3.2.2 @@ -357,7 +370,7 @@ public function testIpV6AddressHost() $this->assertEquals('http://[2010:836b:4179::836b:4179]', $url->toString()); } - public function testReplaceSubdomain() + public function testReplaceSubdomain(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('sub.sub', $url->subdomain()); @@ -374,14 +387,14 @@ public function testReplaceSubdomain() /** * @throws InvalidUrlComponentException */ - public function testSetInvalidSubdomainThrowsException() + public function testSetInvalidSubdomainThrowsException(): void { $url = $this->createDefaultUrlObject(); $this->expectException(InvalidUrlComponentException::class); $url->subdomain('crw!r'); } - public function testReplaceDomain() + public function testReplaceDomain(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('example.com', $url->domain()); @@ -409,14 +422,14 @@ public function testReplaceDomain() /** * @throws InvalidUrlComponentException */ - public function testSetInvalidDomainThrowsException() + public function testSetInvalidDomainThrowsException(): void { $url = $this->createDefaultUrlObject(); $this->expectException(InvalidUrlComponentException::class); $url->domain('"example".com'); } - public function testReplaceDomainLabel() + public function testReplaceDomainLabel(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('example', $url->domainLabel()); @@ -430,14 +443,14 @@ public function testReplaceDomainLabel() /** * @throws InvalidUrlComponentException */ - public function testSetInvalidDomainLabelThrowsException() + public function testSetInvalidDomainLabelThrowsException(): void { $url = $this->createDefaultUrlObject(); $this->expectException(InvalidUrlComponentException::class); $url->domainLabel('invalid.label'); } - public function testReplaceDomainSuffix() + public function testReplaceDomainSuffix(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('com', $url->domainSuffix()); @@ -464,14 +477,14 @@ public function testReplaceDomainSuffix() /** * @throws InvalidUrlComponentException */ - public function testSetInvalidDomainSuffixThrowsException() + public function testSetInvalidDomainSuffixThrowsException(): void { $url = $this->createDefaultUrlObject(); $this->expectException(InvalidUrlComponentException::class); $url->domainSuffix('invalid.suffix'); } - public function testReplacePort() + public function testReplacePort(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals(8080, $url->port()); @@ -487,21 +500,21 @@ public function testReplacePort() /** * @throws InvalidUrlComponentException */ - public function testSetInvalidPortThrowsException() + public function testSetInvalidPortThrowsException(): void { $url = $this->createDefaultUrlObject(); $this->expectException(InvalidUrlComponentException::class); $url->port(-3); } - public function testUrlWithEmptyPort() + public function testUrlWithEmptyPort(): void { $url = Url::parse('https://www.example.com:/foo/bar'); $this->assertEquals('https://www.example.com/foo/bar', $url->toString()); $this->assertEquals(null, $url->port()); } - public function testReplacePath() + public function testReplacePath(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('/some/path', $url->path()); @@ -514,7 +527,7 @@ public function testReplacePath() ); } - public function testParseUrlWithEmptyPath() + public function testParseUrlWithEmptyPath(): void { $url = Url::parse('https://www.example.com?foo=bar'); $this->assertEquals('foo=bar', $url->query()); @@ -526,7 +539,7 @@ public function testParseUrlWithEmptyPath() $this->assertEquals('https://www.example.com#foo', $url->toString()); } - public function testReplaceQueryString() + public function testReplaceQueryString(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('some=query', $url->query()); @@ -549,7 +562,7 @@ public function testReplaceQueryString() ); } - public function testParseUrlWithEmptyQuery() + public function testParseUrlWithEmptyQuery(): void { $url = Url::parse('https://www.example.com/path?#fragment'); $this->assertEquals('/path', $url->path()); @@ -569,7 +582,7 @@ public function testParseUrlWithEmptyQuery() $this->assertEquals('https://www.example.com', $url->toString()); } - public function testReplaceFragment() + public function testReplaceFragment(): void { $url = $this->createDefaultUrlObject(); $this->assertEquals('fragment', $url->fragment()); @@ -582,7 +595,7 @@ public function testReplaceFragment() ); } - public function testParseUrlWithEmptyFragment() + public function testParseUrlWithEmptyFragment(): void { $url = Url::parse('https://www.example.com/path?query=string#'); $this->assertEquals('query=string', $url->query()); @@ -599,7 +612,7 @@ public function testParseUrlWithEmptyFragment() $this->assertEquals('https://www.example.com', $url->toString()); } - public function testChainReplacementCalls() + public function testChainReplacementCalls(): void { $url = $this->createDefaultUrlObject(); @@ -618,7 +631,7 @@ public function testChainReplacementCalls() $this->assertEquals('http://john:god@www.crwlr.software:8081/foo/bar?key=value#anchor', $url->toString()); } - public function testParseRelativeReferences() + public function testParseRelativeReferences(): void { $url = Url::parse('/path?query#fragment'); $this->assertEquals('/path', $url->path()); @@ -670,7 +683,7 @@ public function testParseRelativeReferences() $this->assertEquals('https', $url->toString()); } - public function testIsRelativeReference() + public function testIsRelativeReference(): void { $url = Url::parse('/relative/reference?query=string#fragment'); $this->assertTrue($url->isRelativeReference()); @@ -685,7 +698,7 @@ public function testIsRelativeReference() $this->assertFalse($url->isRelativeReference()); } - public function testResolveRelativeReference() + public function testResolveRelativeReference(): void { $url = $this->createDefaultUrlObject(); @@ -697,7 +710,7 @@ public function testResolveRelativeReference() // More tests on resolving relative to absolute urls => see ResolverTest.php } - public function testCompareUrls() + public function testCompareUrls(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -707,7 +720,7 @@ public function testCompareUrls() $this->assertFalse($url->isEqualTo($equalUrl->__toString())); } - public function testCompareScheme() + public function testCompareScheme(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -719,7 +732,7 @@ public function testCompareScheme() $this->assertFalse($url->isSchemeEqualIn($equalUrl)); } - public function testCompareAuthority() + public function testCompareAuthority(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -731,7 +744,7 @@ public function testCompareAuthority() $this->assertFalse($url->isAuthorityEqualIn($equalUrl)); } - public function testCompareUser() + public function testCompareUser(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -743,7 +756,7 @@ public function testCompareUser() $this->assertFalse($url->isUserEqualIn($equalUrl)); } - public function testComparePassword() + public function testComparePassword(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -757,7 +770,7 @@ public function testComparePassword() $this->assertFalse($url->isPasswordEqualIn($equalUrl)); } - public function testCompareUserInfo() + public function testCompareUserInfo(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -769,7 +782,7 @@ public function testCompareUserInfo() $this->assertFalse($url->isUserInfoEqualIn($equalUrl)); } - public function testCompareHost() + public function testCompareHost(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -782,7 +795,7 @@ public function testCompareHost() $equalUrl->host('sub.sub.example.com'); } - public function testCompareDomain() + public function testCompareDomain(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -795,7 +808,7 @@ public function testCompareDomain() $equalUrl->domain('example.com'); } - public function testCompareDomainLabel() + public function testCompareDomainLabel(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -807,7 +820,7 @@ public function testCompareDomainLabel() $this->assertFalse($url->isDomainLabelEqualIn($equalUrl)); } - public function testCompareDomainSuffix() + public function testCompareDomainSuffix(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -819,7 +832,7 @@ public function testCompareDomainSuffix() $this->assertFalse($url->isDomainSuffixEqualIn($equalUrl)); } - public function testCompareSubdomain() + public function testCompareSubdomain(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -831,7 +844,7 @@ public function testCompareSubdomain() $this->assertFalse($url->isSubdomainEqualIn($equalUrl)); } - public function testComparePort() + public function testComparePort(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -843,7 +856,7 @@ public function testComparePort() $this->assertFalse($url->isPortEqualIn($equalUrl)); } - public function testComparePath() + public function testComparePath(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -855,7 +868,7 @@ public function testComparePath() $this->assertFalse($url->isPathEqualIn($equalUrl)); } - public function testCompareQuery() + public function testCompareQuery(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -869,7 +882,7 @@ public function testCompareQuery() $this->assertFalse($url->isQueryEqualIn($equalUrl)); } - public function testCompareFragment() + public function testCompareFragment(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -881,7 +894,7 @@ public function testCompareFragment() $this->assertFalse($url->isFragmentEqualIn($equalUrl)); } - public function testCompareRoot() + public function testCompareRoot(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -891,7 +904,7 @@ public function testCompareRoot() $this->assertFalse($url->isComponentEqualIn($equalUrl, 'root')); } - public function testCompareRelative() + public function testCompareRelative(): void { $url = $this->createDefaultUrlObject(); $equalUrl = $this->createDefaultUrlObject(); @@ -904,7 +917,7 @@ public function testCompareRelative() /** * Special characters in user information will be percent encoded. */ - public function testUrlWithSpecialCharactersInUserInfo() + public function testUrlWithSpecialCharactersInUserInfo(): void { $url = Url::parse('https://u§er:pássword@example.com'); $this->assertEquals('https://u%C2%A7er:p%C3%A1ssword@example.com', $url->toString()); @@ -914,7 +927,7 @@ public function testUrlWithSpecialCharactersInUserInfo() * Parsing urls containing special characters like umlauts in path, query or fragment percent encodes these * characters. */ - public function testParsingUrlsContainingUmlauts() + public function testParsingUrlsContainingUmlauts(): void { $url = Url::parse('https://www.example.com/bürokaufmann'); $this->assertEquals('https://www.example.com/b%C3%BCrokaufmann', $url->toString()); @@ -927,7 +940,7 @@ public function testParsingUrlsContainingUmlauts() /** * Percent characters from percent encoded characters must not be (double) encoded. */ - public function testEncodingPercentEncodedCharacters() + public function testEncodingPercentEncodedCharacters(): void { $url = Url::parse('https://www.example.com/b%C3%BCrokaufmann'); $this->assertEquals('https://www.example.com/b%C3%BCrokaufmann', $url->toString()); @@ -935,7 +948,7 @@ public function testEncodingPercentEncodedCharacters() $this->assertEquals('https://www.example.com/just%25-character', $url->toString()); } - public function testHasIdn() + public function testHasIdn(): void { $url = Url::parse('https://www.example.com'); $this->assertFalse($url->hasIdn()); @@ -959,7 +972,7 @@ public function testHasIdn() /** * @throws InvalidUrlException */ - public function testCreateRelativePathReferenceWithAuthority() + public function testCreateRelativePathReferenceWithAuthority(): void { $url = Url::parse('relative/reference'); $url->scheme('https'); @@ -968,7 +981,7 @@ public function testCreateRelativePathReferenceWithAuthority() $url->authority('www.example.com'); } - public function testParseUrlWithSchemeAndPathButWithoutAuthority() + public function testParseUrlWithSchemeAndPathButWithoutAuthority(): void { $url = Url::parse('http:/foo/bar'); $this->assertEquals('http', $url->scheme()); @@ -982,7 +995,7 @@ public function testParseUrlWithSchemeAndPathButWithoutAuthority() $this->assertEquals('http:path#fragment', $url->toString()); } - public function testParseUrlWithoutSchemeAndPathButPortQueryAndFragment() + public function testParseUrlWithoutSchemeAndPathButPortQueryAndFragment(): void { $url = Url::parse('//www.example.com:80?query=string#fragment'); $this->assertEquals('www.example.com', $url->host()); @@ -992,7 +1005,7 @@ public function testParseUrlWithoutSchemeAndPathButPortQueryAndFragment() $this->assertEquals('//www.example.com:80?query=string#fragment', $url->toString()); } - public function testParseUrlWithEmptyQueryAndFragment() + public function testParseUrlWithEmptyQueryAndFragment(): void { $url = Url::parse('https://www.example.com/?#'); $this->assertEquals('/', $url->path()); @@ -1006,7 +1019,7 @@ public function testParseUrlWithEmptyQueryAndFragment() $this->assertEquals('https://www.example.com', $url->toString()); } - public function testParseUrlWithHostWithTrailingDot() + public function testParseUrlWithHostWithTrailingDot(): void { $url = Url::parse('https://www.example.com./path'); $this->assertEquals('www.example.com.', $url->host()); @@ -1014,14 +1027,14 @@ public function testParseUrlWithHostWithTrailingDot() $this->assertEquals('https://www.example.com./path', $url->toString()); } - public function testParseUrlWithPathInFragment() + public function testParseUrlWithPathInFragment(): void { $url = Url::parse('https://www.example.com#fragment/foo/bar'); $this->assertEquals('fragment/foo/bar', $url->fragment()); $this->assertEquals('https://www.example.com#fragment/foo/bar', $url->toString()); } - public function testParseUrlWithColonInPath() + public function testParseUrlWithColonInPath(): void { $url = Url::parse('https://www.example.com/path:foo/bar'); $this->assertEquals('/path:foo/bar', $url->path()); @@ -1031,7 +1044,7 @@ public function testParseUrlWithColonInPath() /** * @throws InvalidUrlException */ - public function testCreateRelativePathReferenceWithHost() + public function testCreateRelativePathReferenceWithHost(): void { $url = Url::parse('relative/reference'); $url->scheme('https'); @@ -1040,7 +1053,7 @@ public function testCreateRelativePathReferenceWithHost() $url->host('www.example.com'); } - public function testEncodingEdgeCases() + public function testEncodingEdgeCases(): void { $url = Url::parse('https://u§er:pássword@ком.香格里拉.電訊盈科:1234/föô/bár bàz?quär.y=strïng#frägmänt'); $this->assertEquals( @@ -1050,12 +1063,8 @@ public function testEncodingEdgeCases() ); } - /** - * @return Url - */ - private function createDefaultUrlObject() + private function createDefaultUrlObject(): Url { - $url = new Url('https://user:password@sub.sub.example.com:8080/some/path?some=query#fragment'); - return $url; + return new Url('https://user:password@sub.sub.example.com:8080/some/path?some=query#fragment'); } } diff --git a/tests/ValidatorTest.php b/tests/ValidatorTest.php index 55316fe..e447fa1 100644 --- a/tests/ValidatorTest.php +++ b/tests/ValidatorTest.php @@ -6,7 +6,7 @@ final class ValidatorTest extends TestCase { - public function testValidateUrl() + public function testValidateUrl(): void { $this->assertEquals( 'https://www.crwlr.software/packages/url/v0.1.2#installation', @@ -14,7 +14,7 @@ public function testValidateUrl() ); } - public function testValidateUrlWithSpecialCharacters() + public function testValidateUrlWithSpecialCharacters(): void { $this->assertEquals( 'https://u%C2%A7er:p%C3%A1ssword@sub.xn--domin-ira.example.org:345' . @@ -26,7 +26,7 @@ public function testValidateUrlWithSpecialCharacters() /** * Invalid url strings. */ - public function testValidateInvalidUrl() + public function testValidateInvalidUrl(): void { $this->assertNull(Validator::url('1http://example.com/stuff')); $this->assertNull(Validator::url(' https://wwww.example.com ')); @@ -42,7 +42,7 @@ public function testValidateInvalidUrl() $this->assertNull(Validator::url('://')); } - public function testValidateUrlAndComponents() + public function testValidateUrlAndComponents(): void { $this->assertArrayContains( Validator::urlAndComponents('https://www.crwlr.software/packages/url/v0.1.2#installation'), @@ -82,7 +82,7 @@ public function testValidateUrlAndComponents() ); } - public function testValidateIdnUrlAndComponents() + public function testValidateIdnUrlAndComponents(): void { $this->assertArrayContains( Validator::urlAndComponents('http://✪df.ws/123'), @@ -105,7 +105,7 @@ public function testValidateIdnUrlAndComponents() ); } - public function testValidateInvalidUrlAndComponents() + public function testValidateInvalidUrlAndComponents(): void { $this->assertNull(Validator::urlAndComponents('1http://example.com/stuff')); $this->assertNull(Validator::urlAndComponents(' https://wwww.example.com ')); @@ -121,7 +121,7 @@ public function testValidateInvalidUrlAndComponents() $this->assertNull(Validator::urlAndComponents('://')); } - public function testValidateAbsoluteUrl() + public function testValidateAbsoluteUrl(): void { $this->assertEquals( 'https://www.crwlr.software/packages/url/v0.1.2#installation', @@ -131,7 +131,7 @@ public function testValidateAbsoluteUrl() $this->assertNull(Validator::absoluteUrl('/foo/bar?query=string#fragment')); } - public function testValidateAbsoluteUrlAndComponents() + public function testValidateAbsoluteUrlAndComponents(): void { $this->assertArrayContains( Validator::absoluteUrlAndComponents('https://www.crwlr.software/packages/url/v0.1.2#installation'), @@ -147,7 +147,7 @@ public function testValidateAbsoluteUrlAndComponents() $this->assertNull(Validator::absoluteUrlAndComponents('/foo/bar?query=string#fragment')); } - public function testValidateScheme() + public function testValidateScheme(): void { $this->assertEquals('http', Validator::scheme('http')); $this->assertEquals('mailto', Validator::scheme('mailto')); @@ -161,7 +161,7 @@ public function testValidateScheme() $this->assertNull(Validator::scheme('mäilto')); } - public function testValidateAuthority() + public function testValidateAuthority(): void { $this->assertEquals('12.34.56.78', Validator::authority('12.34.56.78')); $this->assertEquals('localhost', Validator::authority('localhost')); @@ -172,13 +172,13 @@ public function testValidateAuthority() ); } - public function testValidateInvalidAuthority() + public function testValidateInvalidAuthority(): void { $this->assertNull(Validator::authority('user:password@:1234')); $this->assertNull(Validator::authority('')); } - public function testValidateAuthorityComponents() + public function testValidateAuthorityComponents(): void { $this->assertArrayContains( Validator::authorityComponents('user:password@www.example.org:1234'), @@ -192,20 +192,20 @@ public function testValidateAuthorityComponents() ); } - public function testValidateInvalidAuthorityComponents() + public function testValidateInvalidAuthorityComponents(): void { $this->assertNull(Validator::authorityComponents('user:password@:1234')); $this->assertNull(Validator::authorityComponents('')); } - public function testValidateUserInfo() + public function testValidateUserInfo(): void { $this->assertEquals('user:password', Validator::userInfo('user:password')); $this->assertEquals('u%C2%A7er:p%C3%A1ssword', Validator::userInfo('u§er:pássword')); $this->assertNull(Validator::userInfoComponents(':password')); } - public function testValidateUserInfoComponents() + public function testValidateUserInfoComponents(): void { $this->assertArrayContains( Validator::userInfoComponents('crwlr:software'), @@ -226,7 +226,7 @@ public function testValidateUserInfoComponents() $this->assertNull(Validator::userInfoComponents(':password')); } - public function testValidateUser() + public function testValidateUser(): void { $this->assertEquals('user', Validator::user('user')); $this->assertEquals('user-123', Validator::user('user-123')); @@ -247,7 +247,7 @@ public function testValidateUser() $this->assertEquals('us%E2%82%ACrname', Validator::user('us€rname')); } - public function testValidatePassword() + public function testValidatePassword(): void { $this->assertEquals('pASS123', Validator::password('pASS123')); $this->assertEquals('P4ss.123', Validator::pass('P4ss.123')); @@ -266,7 +266,7 @@ public function testValidatePassword() $this->assertEquals('pa%C3%9Fword', Validator::pass('paßword')); } - public function testValidateHost() + public function testValidateHost(): void { $this->assertEquals('example.com', Validator::host('example.com')); $this->assertEquals('www.example.com', Validator::host('www.example.com')); @@ -301,7 +301,7 @@ public function testValidateHost() $this->assertNull(Validator::host('www..com')); } - public function testValidateDomainSuffix() + public function testValidateDomainSuffix(): void { $this->assertEquals('com', Validator::domainSuffix('com')); $this->assertEquals('org', Validator::domainSuffix('org')); @@ -324,7 +324,7 @@ public function testValidateDomainSuffix() $this->assertNull(Validator::domainSuffix('idk')); } - public function testValidateDomain() + public function testValidateDomain(): void { $this->assertEquals('google.com', Validator::domain('google.com')); $this->assertEquals('example.xn--80asehdb', Validator::domain('example.xn--80asehdb')); @@ -335,19 +335,19 @@ public function testValidateDomain() $this->assertNull(Validator::domain('subdomain.example.онлайн')); } - public function testValidateDomainLabel() + public function testValidateDomainLabel(): void { $this->assertEquals('yolo', Validator::domainLabel('yolo')); $this->assertEquals('xn--mnnersalon-q5a', Validator::domainLabel('männersalon')); } - public function testValidateInvalidDomainLabel() + public function testValidateInvalidDomainLabel(): void { $this->assertNull(Validator::domainLabel('yo!lo')); $this->assertNull(Validator::domainLabel('')); } - public function testValidateSubdomain() + public function testValidateSubdomain(): void { $this->assertEquals('www', Validator::subdomain('www')); $this->assertEquals('sub.domain', Validator::subdomain('sub.domain')); @@ -356,7 +356,7 @@ public function testValidateSubdomain() $this->assertNull(Validator::subdomain('sub_domain')); } - public function testValidatePort() + public function testValidatePort(): void { $this->assertEquals(0, Validator::port(0)); $this->assertEquals(8080, Validator::port(8080)); @@ -366,7 +366,7 @@ public function testValidatePort() $this->assertNull(Validator::port(65536)); } - public function testValidatePath() + public function testValidatePath(): void { $this->assertEquals('/FoO/bAr', Validator::path('/FoO/bAr')); $this->assertEquals('/foo-123/bar_456', Validator::path('/foo-123/bar_456')); @@ -386,7 +386,7 @@ public function testValidatePath() $this->assertEquals('/foo%25gar', Validator::path('/foo%gar')); } - public function testValidateQuery() + public function testValidateQuery(): void { $this->assertEquals('foo=bar', Validator::query('foo=bar')); $this->assertEquals('foo=bar', Validator::query('?foo=bar')); @@ -404,7 +404,7 @@ public function testValidateQuery() $this->assertEquals('foo%25bar=baz', Validator::query('foo%25bar=baz')); } - public function testValidateFragment() + public function testValidateFragment(): void { $this->assertEquals('fragment', Validator::fragment('fragment')); $this->assertEquals('fragment', Validator::fragment('#fragment')); @@ -424,10 +424,10 @@ public function testValidateFragment() } /** - * @param $validationResult - * @param array $contains + * @param array|mixed $validationResult + * @param array|mixed[] $contains */ - private function assertArrayContains($validationResult, array $contains) + private function assertArrayContains($validationResult, array $contains): void { $this->assertIsArray($validationResult);