Skip to content

Commit

Permalink
New static parse method, bugfix and code quality
Browse files Browse the repository at this point in the history
New feature:
- Add static method to create PSR-7 Uri object: Url::parsePsr7().

Bugfix:
- Fix error when resolving something to a url with an empty path.

Code quality:
- Update php cs fixer to ^v3.4.
- Add phpstan at level 6.
- Add `composer cs-fix` command that automatically fixes code style.
- Improve pre-commit hook and add running phpstan.
  • Loading branch information
otsch committed Jan 9, 2022
1 parent c8c33ff commit 7582e1a
Show file tree
Hide file tree
Showing 35 changed files with 479 additions and 329 deletions.
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -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
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
12 changes: 8 additions & 4 deletions .php_cs.dist → .php-cs-fixer.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
<?php

$finder = PhpCsFixer\Finder::create()
use PhpCsFixer\Config;
use PhpCsFixer\Finder;

$finder = Finder::create()
->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);
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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",
Expand Down
82 changes: 69 additions & 13 deletions git-hooks/pre-commit
Original file line number Diff line number Diff line change
@@ -1,24 +1,80 @@
#!/usr/bin/env php
<?php

function handleFail($output, $returnCode) {
run('composer test', 'Unit tests');
run('composer cs', 'PHP Coding Standards Fixer');
run('composer stan', 'PHPStan');
exit(0);

function run(string $command, ?string $descriptiveName = null)
{
printLine(blue('RUN ' . ($descriptiveName ?? $command) . '...'));
exec($command, $output, $returnCode);
handleFail($output, $returnCode);
showSummary($output);
}

function handleFail($output, $returnCode)
{
if ($returnCode !== 0) {
// Show full output
echo PHP_EOL . implode($output, PHP_EOL) . PHP_EOL;
echo "Aborting commit.." . PHP_EOL;
printLine(red('Failed:'));
printLines($output);
printLine(red('Aborting commit...'));
exit(1);
}
}

echo "Running tests.. ";
exec('composer test', $output, $returnCode);
handleFail($output, $returnCode);
function showSummary(array $output)
{
printBlankLine();
printLine(green('Summary:'));
outputLastNotEmptyLine($output);
printBlankLine();
}

echo "Running php-cs-fixer.. ";
exec('composer cs', $output, $returnCode);
handleFail($output, $returnCode);
function outputLastNotEmptyLine(array $output)
{
while (count($output) > 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";
}
6 changes: 6 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
parameters:
level: 6
paths:
- src
- tests
treatPhpDocTypesAsCertain: false
3 changes: 3 additions & 0 deletions src/DefaultPorts.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ class DefaultPorts extends Store
{
protected $storeFilename = 'default-ports.php';

/**
* @var int[]
*/
protected $fallbackList = [
'ftp' => 21,
'git' => 9418,
Expand Down
8 changes: 6 additions & 2 deletions src/DefaultPorts/Updater.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [];
Expand Down
9 changes: 9 additions & 0 deletions src/Exceptions/ListStoreException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Crwlr\Url\Exceptions;

use Exception;

class ListStoreException extends Exception
{
}
30 changes: 19 additions & 11 deletions src/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static function defaultPorts(): DefaultPorts
*
* It doesn't do any validation and assumes the provided component values are valid!
*
* @param array $components
* @param array|(int|string)[] $components
* @return string
*/
public static function buildUrlFromComponents(array $components): string
Expand Down Expand Up @@ -108,7 +108,7 @@ public static function buildUrlFromComponents(array $components): string
*
* It doesn't do any validation and assumes the provided component values are valid!
*
* @param array $components
* @param array|(int|string)[] $components
* @return string
*/
public static function buildAuthorityFromComponents(array $components): string
Expand Down Expand Up @@ -137,7 +137,7 @@ public static function buildAuthorityFromComponents(array $components): string
*
* It doesn't do any validation and assumes the provided component values are valid!
*
* @param array $components
* @param array|(int|string)[] $components
* @return string
*/
public static function buildUserInfoFromComponents(array $components): string
Expand All @@ -161,7 +161,7 @@ public static function buildUserInfoFromComponents(array $components): string
* Converts a url query string to array.
*
* @param string $query
* @return array
* @return string[]
*/
public static function queryStringToArray(string $query = ''): array
{
Expand Down Expand Up @@ -200,13 +200,13 @@ public static function getStandardPortByScheme(string $scheme): ?int
$standardPortTcp = getservbyname($scheme, 'tcp');

if ($standardPortTcp) {
return (int) $standardPortTcp;
return $standardPortTcp;
}

$standardPortUdp = getservbyname($scheme, 'udp');

if ($standardPortUdp) {
return (int) $standardPortUdp;
return $standardPortUdp;
}

return null;
Expand Down Expand Up @@ -304,6 +304,10 @@ public static function startsWith(string $string, string $startsWith, ?int $leng
*/
public static function containsXBeforeFirstY(string $string, string $x, string $y): bool
{
if ($y === '') {
return strpos($string, $x) !== false;
}

$untilFirstY = explode($y, $string)[0];

return strpos($untilFirstY, $x) !== false;
Expand All @@ -320,7 +324,9 @@ public static function containsXBeforeFirstY(string $string, string $x, string $
*/
public static function idn_to_ascii(string $string): string
{
return idn_to_ascii($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
$converted = idn_to_ascii($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);

return $converted !== false ? $converted : $string;
}

/**
Expand All @@ -334,7 +340,9 @@ public static function idn_to_ascii(string $string): string
*/
public static function idn_to_utf8(string $string): string
{
return idn_to_utf8($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
$converted = idn_to_utf8($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);

return $converted !== false ? $converted : $string;
}

/**
Expand All @@ -344,8 +352,8 @@ public static function idn_to_utf8(string $string): string
* method works around this issue so the requested query array returns the proper keys with dots.
*
* @param string $query
* @param array $array
* @return array
* @param string[] $array
* @return string[]
*/
private static function replaceKeysContainingDots(string $query, array $array): array
{
Expand All @@ -354,7 +362,7 @@ private static function replaceKeysContainingDots(string $query, array $array):
$brokenKeys = $fixedArray = [];

// Create mapping of broken keys to original proper keys.
foreach ($matches[1] as $key => $value) {
foreach ($matches[1] as $value) {
if (strpos($value, '.') !== false) {
$brokenKeys[str_replace('.', '_', $value)] = $value;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Host.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Host
private $subdomain;

/**
* @var Domain
* @var Domain|null
*/
private $domain;

Expand Down Expand Up @@ -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();
}

/**
Expand Down
Loading

0 comments on commit 7582e1a

Please sign in to comment.