mirror of
https://github.com/standardebooks/web.git
synced 2025-07-12 09:32:24 -04:00
Update composer packages
This commit is contained in:
parent
58cc098058
commit
415aed8b31
59 changed files with 3352 additions and 2347 deletions
58
composer.lock
generated
58
composer.lock
generated
|
@ -382,33 +382,33 @@
|
|||
},
|
||||
{
|
||||
"name": "nette/finder",
|
||||
"version": "v2.4.2",
|
||||
"version": "v2.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/finder.git",
|
||||
"reference": "ee951a656cb8ac622e5dd33474a01fd2470505a0"
|
||||
"reference": "6be1b83ea68ac558aff189d640abe242e0306fe2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/finder/zipball/ee951a656cb8ac622e5dd33474a01fd2470505a0",
|
||||
"reference": "ee951a656cb8ac622e5dd33474a01fd2470505a0",
|
||||
"url": "https://api.github.com/repos/nette/finder/zipball/6be1b83ea68ac558aff189d640abe242e0306fe2",
|
||||
"reference": "6be1b83ea68ac558aff189d640abe242e0306fe2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nette/utils": "~2.4",
|
||||
"php": ">=5.6.0"
|
||||
"nette/utils": "^2.4 || ~3.0.0",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "~2.0",
|
||||
"nette/tester": "^2.0",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
"dev-master": "2.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -440,7 +440,7 @@
|
|||
"iterator",
|
||||
"nette"
|
||||
],
|
||||
"time": "2018-06-28T11:49:23+00:00"
|
||||
"time": "2019-02-28T18:13:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/neon",
|
||||
|
@ -567,16 +567,16 @@
|
|||
},
|
||||
{
|
||||
"name": "nette/robot-loader",
|
||||
"version": "v3.1.0",
|
||||
"version": "v3.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/robot-loader.git",
|
||||
"reference": "fc76c70e740b10f091e502b2e393d0be912f38d4"
|
||||
"reference": "3e8d75d6d976e191bdf46752ca40a286671219d2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/robot-loader/zipball/fc76c70e740b10f091e502b2e393d0be912f38d4",
|
||||
"reference": "fc76c70e740b10f091e502b2e393d0be912f38d4",
|
||||
"url": "https://api.github.com/repos/nette/robot-loader/zipball/3e8d75d6d976e191bdf46752ca40a286671219d2",
|
||||
"reference": "3e8d75d6d976e191bdf46752ca40a286671219d2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -628,7 +628,7 @@
|
|||
"nette",
|
||||
"trait"
|
||||
],
|
||||
"time": "2018-08-13T14:19:06+00:00"
|
||||
"time": "2019-03-01T20:23:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
|
@ -861,16 +861,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "8e185a74004920419ee97bf9dc62e6a175e8dca5"
|
||||
"reference": "e4644b4a8fd393c346f1137305fb2f76a7dc20a7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8e185a74004920419ee97bf9dc62e6a175e8dca5",
|
||||
"reference": "8e185a74004920419ee97bf9dc62e6a175e8dca5",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e4644b4a8fd393c346f1137305fb2f76a7dc20a7",
|
||||
"reference": "e4644b4a8fd393c346f1137305fb2f76a7dc20a7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -930,7 +930,7 @@
|
|||
"MIT"
|
||||
],
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"time": "2019-02-12T14:54:38+00:00"
|
||||
"time": "2019-03-10T16:25:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
|
@ -981,16 +981,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.2.3",
|
||||
"version": "v4.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4"
|
||||
"reference": "9dc2299a016497f9ee620be94524e6c0af0280a9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4",
|
||||
"reference": "1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/9dc2299a016497f9ee620be94524e6c0af0280a9",
|
||||
"reference": "9dc2299a016497f9ee620be94524e6c0af0280a9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1049,7 +1049,7 @@
|
|||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-01-25T14:35:16+00:00"
|
||||
"time": "2019-02-23T15:17:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/contracts",
|
||||
|
@ -1121,16 +1121,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v4.2.3",
|
||||
"version": "v4.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "ef71816cbb264988bb57fe6a73f610888b9aa70c"
|
||||
"reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/ef71816cbb264988bb57fe6a73f610888b9aa70c",
|
||||
"reference": "ef71816cbb264988bb57fe6a73f610888b9aa70c",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/267b7002c1b70ea80db0833c3afe05f0fbde580a",
|
||||
"reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1166,7 +1166,7 @@
|
|||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-01-16T20:35:37+00:00"
|
||||
"time": "2019-02-23T15:42:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
|
|
68
vendor/composer/installed.json
vendored
68
vendor/composer/installed.json
vendored
|
@ -249,35 +249,35 @@
|
|||
},
|
||||
{
|
||||
"name": "nette/finder",
|
||||
"version": "v2.4.2",
|
||||
"version_normalized": "2.4.2.0",
|
||||
"version": "v2.5.0",
|
||||
"version_normalized": "2.5.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/finder.git",
|
||||
"reference": "ee951a656cb8ac622e5dd33474a01fd2470505a0"
|
||||
"reference": "6be1b83ea68ac558aff189d640abe242e0306fe2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/finder/zipball/ee951a656cb8ac622e5dd33474a01fd2470505a0",
|
||||
"reference": "ee951a656cb8ac622e5dd33474a01fd2470505a0",
|
||||
"url": "https://api.github.com/repos/nette/finder/zipball/6be1b83ea68ac558aff189d640abe242e0306fe2",
|
||||
"reference": "6be1b83ea68ac558aff189d640abe242e0306fe2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nette/utils": "~2.4",
|
||||
"php": ">=5.6.0"
|
||||
"nette/utils": "^2.4 || ~3.0.0",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "~2.0",
|
||||
"nette/tester": "^2.0",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"time": "2018-06-28T11:49:23+00:00",
|
||||
"time": "2019-02-28T18:13:25+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
"dev-master": "2.5-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
|
@ -440,17 +440,17 @@
|
|||
},
|
||||
{
|
||||
"name": "nette/robot-loader",
|
||||
"version": "v3.1.0",
|
||||
"version_normalized": "3.1.0.0",
|
||||
"version": "v3.1.1",
|
||||
"version_normalized": "3.1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/robot-loader.git",
|
||||
"reference": "fc76c70e740b10f091e502b2e393d0be912f38d4"
|
||||
"reference": "3e8d75d6d976e191bdf46752ca40a286671219d2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/robot-loader/zipball/fc76c70e740b10f091e502b2e393d0be912f38d4",
|
||||
"reference": "fc76c70e740b10f091e502b2e393d0be912f38d4",
|
||||
"url": "https://api.github.com/repos/nette/robot-loader/zipball/3e8d75d6d976e191bdf46752ca40a286671219d2",
|
||||
"reference": "3e8d75d6d976e191bdf46752ca40a286671219d2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -466,7 +466,7 @@
|
|||
"nette/tester": "^2.0",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"time": "2018-08-13T14:19:06+00:00",
|
||||
"time": "2019-03-01T20:23:02+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -744,17 +744,17 @@
|
|||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "0.11.2",
|
||||
"version_normalized": "0.11.2.0",
|
||||
"version": "0.11.3",
|
||||
"version_normalized": "0.11.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "8e185a74004920419ee97bf9dc62e6a175e8dca5"
|
||||
"reference": "e4644b4a8fd393c346f1137305fb2f76a7dc20a7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8e185a74004920419ee97bf9dc62e6a175e8dca5",
|
||||
"reference": "8e185a74004920419ee97bf9dc62e6a175e8dca5",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e4644b4a8fd393c346f1137305fb2f76a7dc20a7",
|
||||
"reference": "e4644b4a8fd393c346f1137305fb2f76a7dc20a7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -792,7 +792,7 @@
|
|||
"slevomat/coding-standard": "^4.7.2",
|
||||
"squizlabs/php_codesniffer": "^3.3.2"
|
||||
},
|
||||
"time": "2019-02-12T14:54:38+00:00",
|
||||
"time": "2019-03-10T16:25:30+00:00",
|
||||
"bin": [
|
||||
"bin/phpstan"
|
||||
],
|
||||
|
@ -868,17 +868,17 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.2.3",
|
||||
"version_normalized": "4.2.3.0",
|
||||
"version": "v4.2.4",
|
||||
"version_normalized": "4.2.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4"
|
||||
"reference": "9dc2299a016497f9ee620be94524e6c0af0280a9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4",
|
||||
"reference": "1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/9dc2299a016497f9ee620be94524e6c0af0280a9",
|
||||
"reference": "9dc2299a016497f9ee620be94524e6c0af0280a9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -907,7 +907,7 @@
|
|||
"symfony/lock": "",
|
||||
"symfony/process": ""
|
||||
},
|
||||
"time": "2019-01-25T14:35:16+00:00",
|
||||
"time": "2019-02-23T15:17:42+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1012,23 +1012,23 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v4.2.3",
|
||||
"version_normalized": "4.2.3.0",
|
||||
"version": "v4.2.4",
|
||||
"version_normalized": "4.2.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "ef71816cbb264988bb57fe6a73f610888b9aa70c"
|
||||
"reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/ef71816cbb264988bb57fe6a73f610888b9aa70c",
|
||||
"reference": "ef71816cbb264988bb57fe6a73f610888b9aa70c",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/267b7002c1b70ea80db0833c3afe05f0fbde580a",
|
||||
"reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"time": "2019-01-16T20:35:37+00:00",
|
||||
"time": "2019-02-23T15:42:05+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
|
8
vendor/nette/finder/composer.json
vendored
8
vendor/nette/finder/composer.json
vendored
|
@ -15,11 +15,11 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"nette/utils": "~2.4"
|
||||
"php": ">=7.1",
|
||||
"nette/utils": "^2.4 || ~3.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "~2.0",
|
||||
"nette/tester": "^2.0",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"conflict": {
|
||||
|
@ -31,7 +31,7 @@
|
|||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
"dev-master": "2.5-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
31
vendor/nette/finder/readme.md
vendored
31
vendor/nette/finder/readme.md
vendored
|
@ -7,18 +7,31 @@ Nette Finder: Files Searching
|
|||
[](https://github.com/nette/finder/releases)
|
||||
[](https://github.com/nette/finder/blob/master/license.md)
|
||||
|
||||
Class `Nette\Utils\Finder` makes browsing the directory structure really easy.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Nette Finder makes browsing the directory structure really easy.
|
||||
|
||||
Documentation can be found on the [website](https://doc.nette.org/finder).
|
||||
|
||||
If you like Nette, **[please make a donation now](https://nette.org/donate)**. Thank you!
|
||||
|
||||
|
||||
All examples assume the following class alias is defined:
|
||||
Installation
|
||||
------------
|
||||
|
||||
```php
|
||||
use Nette\Utils\Finder;
|
||||
The recommended way to install is via Composer:
|
||||
|
||||
```
|
||||
composer require nette/finder
|
||||
```
|
||||
|
||||
It requires PHP version 5.6 and supports PHP up to 7.3. The dev-master version requires PHP 7.1.
|
||||
|
||||
Searching for Files
|
||||
-------------------
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
How to find all `*.txt` files in `$dir` directory without recursing subdirectories?
|
||||
|
||||
|
@ -104,13 +117,13 @@ Depth of search can be limited using the `limitDepth()` method.
|
|||
|
||||
|
||||
Searching for directories
|
||||
----------------
|
||||
-------------------------
|
||||
|
||||
In addition to files, it is possible to search for directories using `Finder::findDirectories('subdir*')`, or to search for files and directories: `Finder::find('file.txt')`.
|
||||
|
||||
|
||||
Filtering
|
||||
----------
|
||||
---------
|
||||
|
||||
You can also filter results. For example by size. This way we will traverse the files of size between 100B and 200B:
|
||||
|
||||
|
@ -151,7 +164,7 @@ foreach (Finder::findFiles('*')
|
|||
|
||||
|
||||
Connection to Amazon S3
|
||||
----------------------
|
||||
-----------------------
|
||||
|
||||
It's possible to use custom streams, for example Zend_Service_Amazon_S3:
|
||||
|
||||
|
|
119
vendor/nette/finder/src/Utils/Finder.php
vendored
119
vendor/nette/finder/src/Utils/Finder.php
vendored
|
@ -5,6 +5,8 @@
|
|||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Utils;
|
||||
|
||||
use Nette;
|
||||
|
@ -26,6 +28,9 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
/** @var callable extension methods */
|
||||
private static $extMethods = [];
|
||||
|
||||
/** @var array */
|
||||
private $paths = [];
|
||||
|
||||
|
@ -47,10 +52,10 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Begins search for files matching mask and all directories.
|
||||
* @param mixed
|
||||
* @param string|string[] $masks
|
||||
* @return static
|
||||
*/
|
||||
public static function find(...$masks)
|
||||
public static function find(...$masks): self
|
||||
{
|
||||
$masks = $masks && is_array($masks[0]) ? $masks[0] : $masks;
|
||||
return (new static)->select($masks, 'isDir')->select($masks, 'isFile');
|
||||
|
@ -59,10 +64,10 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Begins search for files matching mask.
|
||||
* @param mixed
|
||||
* @param string|string[] $masks
|
||||
* @return static
|
||||
*/
|
||||
public static function findFiles(...$masks)
|
||||
public static function findFiles(...$masks): self
|
||||
{
|
||||
$masks = $masks && is_array($masks[0]) ? $masks[0] : $masks;
|
||||
return (new static)->select($masks, 'isFile');
|
||||
|
@ -71,10 +76,10 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Begins search for directories matching mask.
|
||||
* @param mixed
|
||||
* @param string|string[] $masks
|
||||
* @return static
|
||||
*/
|
||||
public static function findDirectories(...$masks)
|
||||
public static function findDirectories(...$masks): self
|
||||
{
|
||||
$masks = $masks && is_array($masks[0]) ? $masks[0] : $masks;
|
||||
return (new static)->select($masks, 'isDir');
|
||||
|
@ -83,31 +88,27 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Creates filtering group by mask & type selector.
|
||||
* @param array
|
||||
* @param string
|
||||
* @return static
|
||||
*/
|
||||
private function select($masks, $type)
|
||||
private function select(array $masks, string $type): self
|
||||
{
|
||||
$this->cursor = &$this->groups[];
|
||||
$pattern = self::buildPattern($masks);
|
||||
if ($type || $pattern) {
|
||||
$this->filter(function (RecursiveDirectoryIterator $file) use ($type, $pattern) {
|
||||
$this->filter(function (RecursiveDirectoryIterator $file) use ($type, $pattern): bool {
|
||||
return !$file->isDot()
|
||||
&& (!$type || $file->$type())
|
||||
&& $file->$type()
|
||||
&& (!$pattern || preg_match($pattern, '/' . strtr($file->getSubPathName(), '\\', '/')));
|
||||
});
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Searchs in the given folder(s).
|
||||
* @param string|array
|
||||
* Searches in the given folder(s).
|
||||
* @param string|string[] $paths
|
||||
* @return static
|
||||
*/
|
||||
public function in(...$paths)
|
||||
public function in(...$paths): self
|
||||
{
|
||||
$this->maxDepth = 0;
|
||||
return $this->from(...$paths);
|
||||
|
@ -115,11 +116,11 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
|
||||
/**
|
||||
* Searchs recursively from the given folder(s).
|
||||
* @param string|array
|
||||
* Searches recursively from the given folder(s).
|
||||
* @param string|string[] $paths
|
||||
* @return static
|
||||
*/
|
||||
public function from(...$paths)
|
||||
public function from(...$paths): self
|
||||
{
|
||||
if ($this->paths) {
|
||||
throw new Nette\InvalidStateException('Directory to search has already been specified.');
|
||||
|
@ -134,7 +135,7 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
* Shows folder content prior to the folder.
|
||||
* @return static
|
||||
*/
|
||||
public function childFirst()
|
||||
public function childFirst(): self
|
||||
{
|
||||
$this->order = RecursiveIteratorIterator::CHILD_FIRST;
|
||||
return $this;
|
||||
|
@ -143,10 +144,8 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Converts Finder pattern to regular expression.
|
||||
* @param array
|
||||
* @return string|null
|
||||
*/
|
||||
private static function buildPattern($masks)
|
||||
private static function buildPattern(array $masks): ?string
|
||||
{
|
||||
$pattern = [];
|
||||
foreach ($masks as $mask) {
|
||||
|
@ -174,9 +173,8 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Get the number of found files and/or directories.
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
public function count(): int
|
||||
{
|
||||
return iterator_count($this->getIterator());
|
||||
}
|
||||
|
@ -184,23 +182,20 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Returns iterator.
|
||||
* @return \Iterator
|
||||
*/
|
||||
public function getIterator()
|
||||
public function getIterator(): \Iterator
|
||||
{
|
||||
if (!$this->paths) {
|
||||
throw new Nette\InvalidStateException('Call in() or from() to specify directory to search.');
|
||||
|
||||
} elseif (count($this->paths) === 1) {
|
||||
return $this->buildIterator($this->paths[0]);
|
||||
return $this->buildIterator((string) $this->paths[0]);
|
||||
|
||||
} else {
|
||||
$iterator = new \AppendIterator();
|
||||
$iterator->append($workaround = new \ArrayIterator(['workaround PHP bugs #49104, #63077']));
|
||||
foreach ($this->paths as $path) {
|
||||
$iterator->append($this->buildIterator($path));
|
||||
$iterator->append($this->buildIterator((string) $path));
|
||||
}
|
||||
unset($workaround[0]);
|
||||
return $iterator;
|
||||
}
|
||||
}
|
||||
|
@ -208,18 +203,16 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Returns per-path iterator.
|
||||
* @param string
|
||||
* @return \Iterator
|
||||
*/
|
||||
private function buildIterator($path)
|
||||
private function buildIterator(string $path): \Iterator
|
||||
{
|
||||
$iterator = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::FOLLOW_SYMLINKS);
|
||||
|
||||
if ($this->exclude) {
|
||||
$iterator = new \RecursiveCallbackFilterIterator($iterator, function ($foo, $bar, RecursiveDirectoryIterator $file) {
|
||||
$iterator = new \RecursiveCallbackFilterIterator($iterator, function ($foo, $bar, RecursiveDirectoryIterator $file): bool {
|
||||
if (!$file->isDot() && !$file->isFile()) {
|
||||
foreach ($this->exclude as $filter) {
|
||||
if (!call_user_func($filter, $file)) {
|
||||
if (!$filter($file)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -233,14 +226,14 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
$iterator->setMaxDepth($this->maxDepth);
|
||||
}
|
||||
|
||||
$iterator = new \CallbackFilterIterator($iterator, function ($foo, $bar, \Iterator $file) {
|
||||
$iterator = new \CallbackFilterIterator($iterator, function ($foo, $bar, \Iterator $file): bool {
|
||||
while ($file instanceof \OuterIterator) {
|
||||
$file = $file->getInnerIterator();
|
||||
}
|
||||
|
||||
foreach ($this->groups as $filters) {
|
||||
foreach ($filters as $filter) {
|
||||
if (!call_user_func($filter, $file)) {
|
||||
if (!$filter($file)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
@ -259,15 +252,15 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
/**
|
||||
* Restricts the search using mask.
|
||||
* Excludes directories from recursive traversing.
|
||||
* @param mixed
|
||||
* @param string|string[] $masks
|
||||
* @return static
|
||||
*/
|
||||
public function exclude(...$masks)
|
||||
public function exclude(...$masks): self
|
||||
{
|
||||
$masks = $masks && is_array($masks[0]) ? $masks[0] : $masks;
|
||||
$pattern = self::buildPattern($masks);
|
||||
if ($pattern) {
|
||||
$this->filter(function (RecursiveDirectoryIterator $file) use ($pattern) {
|
||||
$this->filter(function (RecursiveDirectoryIterator $file) use ($pattern): bool {
|
||||
return !preg_match($pattern, '/' . strtr($file->getSubPathName(), '\\', '/'));
|
||||
});
|
||||
}
|
||||
|
@ -277,10 +270,10 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Restricts the search using callback.
|
||||
* @param callable function (RecursiveDirectoryIterator $file)
|
||||
* @param callable $callback function (RecursiveDirectoryIterator $file): bool
|
||||
* @return static
|
||||
*/
|
||||
public function filter($callback)
|
||||
public function filter(callable $callback): self
|
||||
{
|
||||
$this->cursor[] = $callback;
|
||||
return $this;
|
||||
|
@ -289,10 +282,9 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Limits recursion level.
|
||||
* @param int
|
||||
* @return static
|
||||
*/
|
||||
public function limitDepth($depth)
|
||||
public function limitDepth(int $depth): self
|
||||
{
|
||||
$this->maxDepth = $depth;
|
||||
return $this;
|
||||
|
@ -301,22 +293,21 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Restricts the search by size.
|
||||
* @param string "[operator] [size] [unit]" example: >=10kB
|
||||
* @param int
|
||||
* @param string $operator "[operator] [size] [unit]" example: >=10kB
|
||||
* @return static
|
||||
*/
|
||||
public function size($operator, $size = null)
|
||||
public function size(string $operator, int $size = null): self
|
||||
{
|
||||
if (func_num_args() === 1) { // in $operator is predicate
|
||||
if (!preg_match('#^(?:([=<>!]=?|<>)\s*)?((?:\d*\.)?\d+)\s*(K|M|G|)B?\z#i', $operator, $matches)) {
|
||||
throw new Nette\InvalidArgumentException('Invalid size predicate format.');
|
||||
}
|
||||
list(, $operator, $size, $unit) = $matches;
|
||||
[, $operator, $size, $unit] = $matches;
|
||||
static $units = ['' => 1, 'k' => 1e3, 'm' => 1e6, 'g' => 1e9];
|
||||
$size *= $units[strtolower($unit)];
|
||||
$operator = $operator ?: '=';
|
||||
}
|
||||
return $this->filter(function (RecursiveDirectoryIterator $file) use ($operator, $size) {
|
||||
return $this->filter(function (RecursiveDirectoryIterator $file) use ($operator, $size): bool {
|
||||
return self::compare($file->getSize(), $operator, $size);
|
||||
});
|
||||
}
|
||||
|
@ -324,21 +315,21 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Restricts the search by modified time.
|
||||
* @param string "[operator] [date]" example: >1978-01-23
|
||||
* @param mixed
|
||||
* @param string $operator "[operator] [date]" example: >1978-01-23
|
||||
* @param string|int|\DateTimeInterface $date
|
||||
* @return static
|
||||
*/
|
||||
public function date($operator, $date = null)
|
||||
public function date(string $operator, $date = null): self
|
||||
{
|
||||
if (func_num_args() === 1) { // in $operator is predicate
|
||||
if (!preg_match('#^(?:([=<>!]=?|<>)\s*)?(.+)\z#i', $operator, $matches)) {
|
||||
throw new Nette\InvalidArgumentException('Invalid date predicate format.');
|
||||
}
|
||||
list(, $operator, $date) = $matches;
|
||||
[, $operator, $date] = $matches;
|
||||
$operator = $operator ?: '=';
|
||||
}
|
||||
$date = DateTime::from($date)->format('U');
|
||||
return $this->filter(function (RecursiveDirectoryIterator $file) use ($operator, $date) {
|
||||
return $this->filter(function (RecursiveDirectoryIterator $file) use ($operator, $date): bool {
|
||||
return self::compare($file->getMTime(), $operator, $date);
|
||||
});
|
||||
}
|
||||
|
@ -346,11 +337,8 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
/**
|
||||
* Compares two values.
|
||||
* @param mixed
|
||||
* @param mixed
|
||||
* @return bool
|
||||
*/
|
||||
public static function compare($l, $operator, $r)
|
||||
public static function compare($l, string $operator, $r): bool
|
||||
{
|
||||
switch ($operator) {
|
||||
case '>':
|
||||
|
@ -377,17 +365,16 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
/********************* extension methods ****************d*g**/
|
||||
|
||||
|
||||
public function __call($name, $args)
|
||||
public function __call(string $name, array $args)
|
||||
{
|
||||
if ($callback = Nette\Utils\ObjectMixin::getExtensionMethod(__CLASS__, $name)) {
|
||||
return $callback($this, ...$args);
|
||||
}
|
||||
Nette\Utils\ObjectMixin::strictCall(__CLASS__, $name);
|
||||
return isset(self::$extMethods[$name])
|
||||
? (self::$extMethods[$name])($this, ...$args)
|
||||
: parent::__call($name, $args);
|
||||
}
|
||||
|
||||
|
||||
public static function extensionMethod($name, $callback)
|
||||
public static function extensionMethod(string $name, callable $callback): void
|
||||
{
|
||||
Nette\Utils\ObjectMixin::setExtensionMethod(__CLASS__, $name, $callback);
|
||||
self::$extMethods[$name] = $callback;
|
||||
}
|
||||
}
|
||||
|
|
41
vendor/nette/robot-loader/readme.md
vendored
41
vendor/nette/robot-loader/readme.md
vendored
|
@ -14,11 +14,13 @@ Introduction
|
|||
RobotLoader is a tool that gives you comfort of automated class loading for your entire application including third-party libraries.
|
||||
|
||||
- get rid of all `require`
|
||||
- only necessary scripts are loaded
|
||||
- requires no strict file naming conventions
|
||||
- allows more classes in single file
|
||||
- extremely fast
|
||||
- no manual cache updates, everything runs automatically
|
||||
- highly mature, stable and widely used library
|
||||
|
||||
RobotLoader is extremely comfortable and addictive!
|
||||
RobotLoader is incredibly comfortable and addictive!
|
||||
|
||||
If you like Nette, **[please make a donation now](https://nette.org/donate)**. Thank you!
|
||||
|
||||
|
@ -46,7 +48,7 @@ The recommended way to install is via Composer:
|
|||
composer require nette/robot-loader
|
||||
```
|
||||
|
||||
It requires PHP version 5.6 and supports PHP up to 7.2.
|
||||
It requires PHP version 5.6 and supports PHP up to 7.3.
|
||||
|
||||
|
||||
Usage
|
||||
|
@ -76,3 +78,36 @@ This feature should be disabled on production server.
|
|||
If you want RobotLoader to skip some directory, use `$loader->excludeDirectory('temp')`.
|
||||
|
||||
By default, RobotLoader reports errors in PHP files by throwing exception `ParseError` (since PHP 7.0). It can be disabled via `$loader->reportParseErrors(false)`.
|
||||
|
||||
|
||||
PHP files analyzer
|
||||
------------------
|
||||
|
||||
RobotLoader can also be used to find classes, interfaces, and trait in PHP files without using the autoloading feature:
|
||||
|
||||
```php
|
||||
$loader = new Nette\Loaders\RobotLoader;
|
||||
$loader->addDirectory(__DIR__ . '/app');
|
||||
|
||||
// Scans directories for classes / intefaces / traits
|
||||
$loader->rebuild();
|
||||
|
||||
// Returns array of class => filename pairs
|
||||
$res = $loader->getIndexedClasses();
|
||||
```
|
||||
|
||||
When scanning files again, we can use the cache and unmodified files will not be analyzed repeatedly:
|
||||
|
||||
```php
|
||||
$loader = new Nette\Loaders\RobotLoader;
|
||||
$loader->addDirectory(__DIR__ . '/app');
|
||||
$loader->setTempDirectory(__DIR__ . '/temp');
|
||||
|
||||
// Scans directories using a cache
|
||||
$loader->refresh();
|
||||
|
||||
// Returns array of class => filename pairs
|
||||
$res = $loader->getIndexedClasses();
|
||||
```
|
||||
|
||||
Enjoy RobotLoader!
|
||||
|
|
|
@ -28,10 +28,10 @@ class RobotLoader
|
|||
|
||||
const RETRY_LIMIT = 3;
|
||||
|
||||
/** @var array comma separated wildcards */
|
||||
/** @var array */
|
||||
public $ignoreDirs = ['.*', '*.old', '*.bak', '*.tmp', 'temp'];
|
||||
|
||||
/** @var array comma separated wildcards */
|
||||
/** @var array */
|
||||
public $acceptFiles = ['*.php'];
|
||||
|
||||
/** @var bool */
|
||||
|
@ -95,7 +95,7 @@ class RobotLoader
|
|||
$missing = &$this->missing[$type];
|
||||
$missing++;
|
||||
if (!$this->refreshed && $missing <= self::RETRY_LIMIT) {
|
||||
$this->refresh();
|
||||
$this->refreshClasses();
|
||||
$this->saveCache();
|
||||
} elseif ($info) {
|
||||
unset($this->classes[$type]);
|
||||
|
@ -171,7 +171,8 @@ class RobotLoader
|
|||
*/
|
||||
public function rebuild()
|
||||
{
|
||||
$this->refresh();
|
||||
$this->classes = $this->missing = [];
|
||||
$this->refreshClasses();
|
||||
if ($this->tempDirectory) {
|
||||
$this->saveCache();
|
||||
}
|
||||
|
@ -179,12 +180,26 @@ class RobotLoader
|
|||
|
||||
|
||||
/**
|
||||
* Refreshes class list.
|
||||
* Refreshes class list cache.
|
||||
* @return void
|
||||
*/
|
||||
private function refresh()
|
||||
public function refresh()
|
||||
{
|
||||
$this->refreshed = true; // prevents calling refresh() or updateFile() in tryLoad()
|
||||
$this->loadCache();
|
||||
if (!$this->refreshed) {
|
||||
$this->refreshClasses();
|
||||
$this->saveCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refreshes $classes.
|
||||
* @return void
|
||||
*/
|
||||
private function refreshClasses()
|
||||
{
|
||||
$this->refreshed = true; // prevents calling refreshClasses() or updateFile() in tryLoad()
|
||||
$files = [];
|
||||
foreach ($this->classes as $class => $info) {
|
||||
$files[$info['file']]['time'] = $info['time'];
|
||||
|
@ -193,7 +208,8 @@ class RobotLoader
|
|||
|
||||
$this->classes = [];
|
||||
foreach ($this->scanPaths as $path) {
|
||||
foreach (is_file($path) ? [new SplFileInfo($path)] : $this->createFileIterator($path) as $file) {
|
||||
$iterator = is_file($path) ? [new SplFileInfo($path)] : $this->createFileIterator($path);
|
||||
foreach ($iterator as $file) {
|
||||
$file = $file->getPathname();
|
||||
if (isset($files[$file]) && $files[$file]['time'] == filemtime($file)) {
|
||||
$classes = $files[$file]['classes'];
|
||||
|
@ -234,7 +250,8 @@ class RobotLoader
|
|||
}
|
||||
}
|
||||
|
||||
$iterator = Nette\Utils\Finder::findFiles(is_array($this->acceptFiles) ? $this->acceptFiles : preg_split('#[,\s]+#', $this->acceptFiles))
|
||||
$acceptFiles = is_array($this->acceptFiles) ? $this->acceptFiles : preg_split('#[,\s]+#', $this->acceptFiles);
|
||||
$iterator = Nette\Utils\Finder::findFiles($acceptFiles)
|
||||
->filter(function (SplFileInfo $file) use (&$disallow) {
|
||||
return !isset($disallow[str_replace('\\', '/', $file->getRealPath())]);
|
||||
})
|
||||
|
@ -419,9 +436,7 @@ class RobotLoader
|
|||
|
||||
list($this->classes, $this->missing) = @include $file; // @ file may not exist
|
||||
if (!is_array($this->classes)) {
|
||||
$this->classes = [];
|
||||
$this->refresh();
|
||||
$this->saveCache();
|
||||
$this->rebuild();
|
||||
}
|
||||
|
||||
flock($handle, LOCK_UN);
|
||||
|
|
|
@ -19,22 +19,22 @@ final class Versions
|
|||
'jean85/pretty-package-versions' => '1.2@75c7effcf3f77501d0e0caa75111aff4daa0dd48',
|
||||
'nette/bootstrap' => 'v2.4.6@268816e3f1bb7426c3a4ceec2bd38a036b532543',
|
||||
'nette/di' => 'v2.4.15@d0561b8f77e8ef2ed6d83328860e16c81a5a8649',
|
||||
'nette/finder' => 'v2.4.2@ee951a656cb8ac622e5dd33474a01fd2470505a0',
|
||||
'nette/finder' => 'v2.5.0@6be1b83ea68ac558aff189d640abe242e0306fe2',
|
||||
'nette/neon' => 'v3.0.0@cbff32059cbdd8720deccf9e9eace6ee516f02eb',
|
||||
'nette/php-generator' => 'v3.2.1@9de4e093a130f7a1bd175198799ebc0efbac6924',
|
||||
'nette/robot-loader' => 'v3.1.0@fc76c70e740b10f091e502b2e393d0be912f38d4',
|
||||
'nette/robot-loader' => 'v3.1.1@3e8d75d6d976e191bdf46752ca40a286671219d2',
|
||||
'nette/utils' => 'v2.5.3@17b9f76f2abd0c943adfb556e56f2165460b15ce',
|
||||
'nikic/php-parser' => 'v4.2.1@5221f49a608808c1e4d436df32884cbc1b821ac0',
|
||||
'ocramius/package-versions' => '1.4.0@a4d4b60d0e60da2487bd21a2c6ac089f85570dbb',
|
||||
'phpstan/phpdoc-parser' => '0.3.1@2cc49f47c69b023eaf05b48e6529389893b13d74',
|
||||
'phpstan/phpstan' => '0.11.2@8e185a74004920419ee97bf9dc62e6a175e8dca5',
|
||||
'phpstan/phpstan' => '0.11.3@e4644b4a8fd393c346f1137305fb2f76a7dc20a7',
|
||||
'psr/log' => '1.1.0@6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd',
|
||||
'symfony/console' => 'v4.2.3@1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4',
|
||||
'symfony/console' => 'v4.2.4@9dc2299a016497f9ee620be94524e6c0af0280a9',
|
||||
'symfony/contracts' => 'v1.0.2@1aa7ab2429c3d594dd70689604b5cf7421254cdf',
|
||||
'symfony/finder' => 'v4.2.3@ef71816cbb264988bb57fe6a73f610888b9aa70c',
|
||||
'symfony/finder' => 'v4.2.4@267b7002c1b70ea80db0833c3afe05f0fbde580a',
|
||||
'symfony/polyfill-mbstring' => 'v1.10.0@c79c051f5b3a46be09205c73b80b346e4153e494',
|
||||
'thecodingmachine/phpstan-safe-rule' => 'v0.1.3@00f4845905feb5240ca62fb799e3c51ba85c9230',
|
||||
'__root__' => 'dev-master@04a956886ab327ddbe5eec546b911b9e55a0e5ef',
|
||||
'__root__' => 'dev-master@58cc098058143344a846f01a5d2252a45e2be9ba',
|
||||
);
|
||||
|
||||
private function __construct()
|
||||
|
|
8
vendor/phpstan/phpstan/README.md
vendored
8
vendor/phpstan/phpstan/README.md
vendored
|
@ -27,11 +27,12 @@ can be checked before you run the actual line.
|
|||
<a href="https://mike-pretzlaw.de/"><img src="https://i.imgur.com/TW2US6H.png" alt="Mike Pretzlaw" width="247" height="64"></a>
|
||||
|
||||
<a href="https://coders.thecodingmachine.com/phpstan"><img src="https://i.imgur.com/kQhNOTP.png" alt="TheCodingMachine" width="247" height="64"></a>
|
||||
|
||||
<a href="https://www.wispay.io/t/JdL" target="_blank"><img src="https://assets.wispay.io/wgt2_d_o.png" width="247" height="78"></a>
|
||||
|
||||
Check out [PHPStan's Patreon](https://www.patreon.com/phpstan) for sponsoring options. One-time donations [through PayPal](https://paypal.me/phpstan) are also accepted. To request an invoice, [contact me](mailto:ondrej@mirtes.cz) through e-mail.
|
||||
|
||||
BTC: bc1qd5s06wjtf8rzag08mk3s264aekn52jze9zeapt
|
||||
<br>LTC: LSU5xLsWEfrVx1P9yJwmhziHAXikiE8xtC
|
||||
|
||||
## Prerequisites
|
||||
|
||||
PHPStan requires PHP >= 7.1. You have to run it in environment with PHP 7.x but the actual code does not have to use
|
||||
|
@ -119,6 +120,7 @@ Unofficial extensions for other frameworks and libraries are also available:
|
|||
* [Yii2](https://github.com/proget-hq/phpstan-yii2)
|
||||
* [PhpSpec](https://github.com/proget-hq/phpstan-phpspec)
|
||||
* [TYPO3](https://github.com/sascha-egerer/phpstan-typo3)
|
||||
* [moneyphp/money](https://github.com/JohnstonCode/phpstan-moneyphp)
|
||||
|
||||
New extensions are becoming available on a regular basis!
|
||||
|
||||
|
@ -406,6 +408,8 @@ You can pass the following keywords to the `--error-format=X` parameter in order
|
|||
- `table`: Default. Grouped errors by file, colorized. For human consumption.
|
||||
- `raw`: Contains one error per line, with path to file, line number, and error description
|
||||
- `checkstyle`: Creates a checkstyle.xml compatible output. Note that you'd have to redirect output into a file in order to capture the results for later processing.
|
||||
- `json`: Creates minified .json output without whitespaces. Note that you'd have to redirect output into a file in order to capture the results for later processing.
|
||||
- `prettyJson`: Creates human readable .json output with whitespaces and indentations. Note that you'd have to redirect output into a file in order to capture the results for later processing.
|
||||
|
||||
## Class reflection extensions
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ rules:
|
|||
- PHPStan\Rules\Functions\PrintfParametersRule
|
||||
- PHPStan\Rules\Functions\UnusedClosureUsesRule
|
||||
- PHPStan\Rules\Methods\ExistingClassesInTypehintsRule
|
||||
- PHPStan\Rules\Properties\AccessStaticPropertiesRule
|
||||
- PHPStan\Rules\Properties\AccessPropertiesInAssignRule
|
||||
- PHPStan\Rules\Properties\AccessStaticPropertiesInAssignRule
|
||||
- PHPStan\Rules\Variables\ThisVariableRule
|
||||
|
||||
services:
|
||||
|
@ -90,6 +91,11 @@ services:
|
|||
arguments:
|
||||
reportMagicProperties: %reportMagicProperties%
|
||||
|
||||
-
|
||||
class: PHPStan\Rules\Properties\AccessStaticPropertiesRule
|
||||
tags:
|
||||
- phpstan.rules.rule
|
||||
|
||||
-
|
||||
class: PHPStan\Rules\Properties\ExistingClassesInPropertiesRule
|
||||
tags:
|
||||
|
|
5
vendor/phpstan/phpstan/conf/config.neon
vendored
5
vendor/phpstan/phpstan/conf/config.neon
vendored
|
@ -379,6 +379,11 @@ services:
|
|||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: PHPStan\Type\Php\FilterVarDynamicReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: PHPStan\Type\Php\GetParentClassDynamicFunctionReturnTypeExtension
|
||||
tags:
|
||||
|
|
37
vendor/phpstan/phpstan/src/Analyser/EnsuredNonNullabilityResult.php
vendored
Normal file
37
vendor/phpstan/phpstan/src/Analyser/EnsuredNonNullabilityResult.php
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Analyser;
|
||||
|
||||
class EnsuredNonNullabilityResult
|
||||
{
|
||||
|
||||
/** @var Scope */
|
||||
private $scope;
|
||||
|
||||
/** @var EnsuredNonNullabilityResultExpression[] */
|
||||
private $specifiedExpressions;
|
||||
|
||||
/**
|
||||
* @param Scope $scope
|
||||
* @param EnsuredNonNullabilityResultExpression[] $specifiedExpressions
|
||||
*/
|
||||
public function __construct(Scope $scope, array $specifiedExpressions)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
$this->specifiedExpressions = $specifiedExpressions;
|
||||
}
|
||||
|
||||
public function getScope(): Scope
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EnsuredNonNullabilityResultExpression[]
|
||||
*/
|
||||
public function getSpecifiedExpressions(): array
|
||||
{
|
||||
return $this->specifiedExpressions;
|
||||
}
|
||||
|
||||
}
|
33
vendor/phpstan/phpstan/src/Analyser/EnsuredNonNullabilityResultExpression.php
vendored
Normal file
33
vendor/phpstan/phpstan/src/Analyser/EnsuredNonNullabilityResultExpression.php
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Analyser;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PHPStan\Type\Type;
|
||||
|
||||
class EnsuredNonNullabilityResultExpression
|
||||
{
|
||||
|
||||
/** @var Expr */
|
||||
private $expression;
|
||||
|
||||
/** @var Type */
|
||||
private $originalType;
|
||||
|
||||
public function __construct(Expr $expression, Type $originalType)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->originalType = $originalType;
|
||||
}
|
||||
|
||||
public function getExpression(): Expr
|
||||
{
|
||||
return $this->expression;
|
||||
}
|
||||
|
||||
public function getOriginalType(): Type
|
||||
{
|
||||
return $this->originalType;
|
||||
}
|
||||
|
||||
}
|
69
vendor/phpstan/phpstan/src/Analyser/ExpressionContext.php
vendored
Normal file
69
vendor/phpstan/phpstan/src/Analyser/ExpressionContext.php
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Analyser;
|
||||
|
||||
use PHPStan\Type\Type;
|
||||
|
||||
class ExpressionContext
|
||||
{
|
||||
|
||||
/** @var bool */
|
||||
private $isDeep;
|
||||
|
||||
/** @var string|null */
|
||||
private $inAssignRightSideVariableName;
|
||||
|
||||
/** @var Type|null */
|
||||
private $inAssignRightSideType;
|
||||
|
||||
private function __construct(
|
||||
bool $isDeep,
|
||||
?string $inAssignRightSideVariableName,
|
||||
?Type $inAssignRightSideType
|
||||
)
|
||||
{
|
||||
$this->isDeep = $isDeep;
|
||||
$this->inAssignRightSideVariableName = $inAssignRightSideVariableName;
|
||||
$this->inAssignRightSideType = $inAssignRightSideType;
|
||||
}
|
||||
|
||||
public static function createTopLevel(): self
|
||||
{
|
||||
return new self(false, null, null);
|
||||
}
|
||||
|
||||
public static function createDeep(): self
|
||||
{
|
||||
return new self(true, null, null);
|
||||
}
|
||||
|
||||
public function enterDeep(): self
|
||||
{
|
||||
if ($this->isDeep) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return new self(true, $this->inAssignRightSideVariableName, $this->inAssignRightSideType);
|
||||
}
|
||||
|
||||
public function isDeep(): bool
|
||||
{
|
||||
return $this->isDeep;
|
||||
}
|
||||
|
||||
public function enterRightSideAssign(string $variableName, Type $type): self
|
||||
{
|
||||
return new self($this->isDeep, $variableName, $type);
|
||||
}
|
||||
|
||||
public function getInAssignRightSideVariableName(): ?string
|
||||
{
|
||||
return $this->inAssignRightSideVariableName;
|
||||
}
|
||||
|
||||
public function getInAssignRightSideType(): ?Type
|
||||
{
|
||||
return $this->inAssignRightSideType;
|
||||
}
|
||||
|
||||
}
|
74
vendor/phpstan/phpstan/src/Analyser/ExpressionResult.php
vendored
Normal file
74
vendor/phpstan/phpstan/src/Analyser/ExpressionResult.php
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Analyser;
|
||||
|
||||
class ExpressionResult
|
||||
{
|
||||
|
||||
/** @var Scope */
|
||||
private $scope;
|
||||
|
||||
/** @var (callable(): Scope)|null */
|
||||
private $truthyScopeCallback;
|
||||
|
||||
/** @var Scope|null */
|
||||
private $truthyScope;
|
||||
|
||||
/** @var (callable(): Scope)|null */
|
||||
private $falseyScopeCallback;
|
||||
|
||||
/** @var Scope|null */
|
||||
private $falseyScope;
|
||||
|
||||
/**
|
||||
* @param Scope $scope
|
||||
* @param (callable(): Scope)|null $truthyScopeCallback
|
||||
* @param (callable(): Scope)|null $falseyScopeCallback
|
||||
*/
|
||||
public function __construct(
|
||||
Scope $scope,
|
||||
?callable $truthyScopeCallback = null,
|
||||
?callable $falseyScopeCallback = null
|
||||
)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
$this->truthyScopeCallback = $truthyScopeCallback;
|
||||
$this->falseyScopeCallback = $falseyScopeCallback;
|
||||
}
|
||||
|
||||
public function getScope(): Scope
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
public function getTruthyScope(): Scope
|
||||
{
|
||||
if ($this->truthyScopeCallback === null) {
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
if ($this->truthyScope !== null) {
|
||||
return $this->truthyScope;
|
||||
}
|
||||
|
||||
$callback = $this->truthyScopeCallback;
|
||||
$this->truthyScope = $callback();
|
||||
return $this->truthyScope;
|
||||
}
|
||||
|
||||
public function getFalseyScope(): Scope
|
||||
{
|
||||
if ($this->falseyScopeCallback === null) {
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
if ($this->falseyScope !== null) {
|
||||
return $this->falseyScope;
|
||||
}
|
||||
|
||||
$callback = $this->falseyScopeCallback;
|
||||
$this->falseyScope = $callback();
|
||||
return $this->falseyScope;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Analyser;
|
||||
|
||||
use PhpParser\Node\Stmt\Break_;
|
||||
use PhpParser\Node\Stmt\Continue_;
|
||||
|
||||
class LookForAssignsSettings
|
||||
{
|
||||
|
||||
private const EARLY_TERMINATION_CONTINUE = 1;
|
||||
private const EARLY_TERMINATION_BREAK = 2;
|
||||
private const EARLY_TERMINATION_STOP = 4;
|
||||
private const EARLY_TERMINATION_ALL = self::EARLY_TERMINATION_CONTINUE
|
||||
+ self::EARLY_TERMINATION_BREAK
|
||||
+ self::EARLY_TERMINATION_STOP;
|
||||
private const EARLY_TERMINATION_CLOSURE = 8;
|
||||
private const REPEAT_ANALYSIS = 16;
|
||||
|
||||
/** @var int */
|
||||
private $respectEarlyTermination;
|
||||
|
||||
/** @var self[] */
|
||||
private static $registry = [];
|
||||
|
||||
private function __construct(
|
||||
int $respectEarlyTermination
|
||||
)
|
||||
{
|
||||
$this->respectEarlyTermination = $respectEarlyTermination;
|
||||
}
|
||||
|
||||
public static function default(): self
|
||||
{
|
||||
return self::create(self::EARLY_TERMINATION_ALL);
|
||||
}
|
||||
|
||||
public static function insideLoop(): self
|
||||
{
|
||||
return self::create(self::EARLY_TERMINATION_STOP + self::EARLY_TERMINATION_BREAK + self::REPEAT_ANALYSIS);
|
||||
}
|
||||
|
||||
public static function afterLoop(): self
|
||||
{
|
||||
return self::create(self::EARLY_TERMINATION_STOP + self::REPEAT_ANALYSIS);
|
||||
}
|
||||
|
||||
public static function afterSwitch(): self
|
||||
{
|
||||
return self::create(self::EARLY_TERMINATION_STOP);
|
||||
}
|
||||
|
||||
public static function insideFinally(): self
|
||||
{
|
||||
return self::create(0);
|
||||
}
|
||||
|
||||
public static function insideClosure(): self
|
||||
{
|
||||
return self::create(self::EARLY_TERMINATION_CLOSURE);
|
||||
}
|
||||
|
||||
private static function create(int $value): self
|
||||
{
|
||||
self::$registry[$value] = self::$registry[$value] ?? new self($value);
|
||||
return self::$registry[$value];
|
||||
}
|
||||
|
||||
public function shouldRepeatAnalysis(): bool
|
||||
{
|
||||
return ($this->respectEarlyTermination & self::REPEAT_ANALYSIS) === self::REPEAT_ANALYSIS;
|
||||
}
|
||||
|
||||
public function shouldSkipBranch(\PhpParser\Node $earlyTerminationStatement): bool
|
||||
{
|
||||
return $this->isRespected($earlyTerminationStatement);
|
||||
}
|
||||
|
||||
private function isRespected(\PhpParser\Node $earlyTerminationStatement): bool
|
||||
{
|
||||
if (
|
||||
$earlyTerminationStatement instanceof Break_
|
||||
) {
|
||||
return ($this->respectEarlyTermination & self::EARLY_TERMINATION_BREAK) === self::EARLY_TERMINATION_BREAK;
|
||||
}
|
||||
|
||||
if (
|
||||
$earlyTerminationStatement instanceof Continue_
|
||||
) {
|
||||
return ($this->respectEarlyTermination & self::EARLY_TERMINATION_CONTINUE) === self::EARLY_TERMINATION_CONTINUE;
|
||||
}
|
||||
|
||||
return ($this->respectEarlyTermination & self::EARLY_TERMINATION_STOP) === self::EARLY_TERMINATION_STOP;
|
||||
}
|
||||
|
||||
public function shouldIntersectVariables(?\PhpParser\Node $earlyTerminationStatement): bool
|
||||
{
|
||||
if ($earlyTerminationStatement === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->shouldSkipBranch($earlyTerminationStatement)) {
|
||||
throw new \PHPStan\ShouldNotHappenException();
|
||||
}
|
||||
|
||||
return $earlyTerminationStatement instanceof Break_
|
||||
|| $earlyTerminationStatement instanceof Continue_
|
||||
|| ($this->respectEarlyTermination & self::EARLY_TERMINATION_STOP) === 0;
|
||||
}
|
||||
|
||||
public function shouldGeneralizeConstantTypesOfNonIdempotentOperations(): bool
|
||||
{
|
||||
return (
|
||||
($this->respectEarlyTermination & self::EARLY_TERMINATION_STOP) === self::EARLY_TERMINATION_STOP
|
||||
&& $this->respectEarlyTermination !== self::EARLY_TERMINATION_ALL
|
||||
) || $this->respectEarlyTermination === self::EARLY_TERMINATION_CLOSURE;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
910
vendor/phpstan/phpstan/src/Analyser/Scope.php
vendored
910
vendor/phpstan/phpstan/src/Analyser/Scope.php
vendored
File diff suppressed because it is too large
Load diff
|
@ -60,6 +60,31 @@ class ScopeContext
|
|||
return new self($this->file, $this->classReflection, $traitReflection);
|
||||
}
|
||||
|
||||
public function equals(self $otherContext): bool
|
||||
{
|
||||
if ($this->file !== $otherContext->file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getClassReflection() === null) {
|
||||
return $otherContext->getClassReflection() === null;
|
||||
} elseif ($otherContext->getClassReflection() === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$isSameClass = $this->getClassReflection()->getName() === $otherContext->getClassReflection()->getName();
|
||||
|
||||
if ($this->getTraitReflection() === null) {
|
||||
return $otherContext->getTraitReflection() === null && $isSameClass;
|
||||
} elseif ($otherContext->getTraitReflection() === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$isSameTrait = $this->getTraitReflection()->getName() === $otherContext->getTraitReflection()->getName();
|
||||
|
||||
return $isSameClass && $isSameTrait;
|
||||
}
|
||||
|
||||
public function getFile(): string
|
||||
{
|
||||
return $this->file;
|
||||
|
|
|
@ -51,7 +51,7 @@ class ScopeFactory
|
|||
* @param \PhpParser\Node\Expr\FuncCall|\PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall|null $inFunctionCall
|
||||
* @param bool $negated
|
||||
* @param bool $inFirstLevelStatement
|
||||
* @param string[] $currentlyAssignedExpressions
|
||||
* @param array<string, true> $currentlyAssignedExpressions
|
||||
*
|
||||
* @return Scope
|
||||
*/
|
||||
|
|
32
vendor/phpstan/phpstan/src/Analyser/StatementExitPoint.php
vendored
Normal file
32
vendor/phpstan/phpstan/src/Analyser/StatementExitPoint.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Analyser;
|
||||
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class StatementExitPoint
|
||||
{
|
||||
|
||||
/** @var Stmt */
|
||||
private $statement;
|
||||
|
||||
/** @var Scope */
|
||||
private $scope;
|
||||
|
||||
public function __construct(Stmt $statement, Scope $scope)
|
||||
{
|
||||
$this->statement = $statement;
|
||||
$this->scope = $scope;
|
||||
}
|
||||
|
||||
public function getStatement(): Stmt
|
||||
{
|
||||
return $this->statement;
|
||||
}
|
||||
|
||||
public function getScope(): Scope
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Analyser;
|
||||
|
||||
class StatementList
|
||||
{
|
||||
|
||||
/** @var \PHPStan\Analyser\Scope */
|
||||
private $scope;
|
||||
|
||||
/** @var \PhpParser\Node[] */
|
||||
private $statements;
|
||||
|
||||
/** @var bool */
|
||||
private $filterByTruthyValue;
|
||||
|
||||
/** @var callable(Scope $scope): Scope|null */
|
||||
private $processScope;
|
||||
|
||||
/**
|
||||
* @param Scope $scope
|
||||
* @param \PhpParser\Node[] $statements
|
||||
* @param bool $filterByTruthyValue
|
||||
* @param callable(Scope $scope): Scope|null $processScope
|
||||
*/
|
||||
public function __construct(
|
||||
Scope $scope,
|
||||
array $statements,
|
||||
bool $filterByTruthyValue = false,
|
||||
?callable $processScope = null
|
||||
)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
$this->statements = $statements;
|
||||
$this->filterByTruthyValue = $filterByTruthyValue;
|
||||
$this->processScope = $processScope;
|
||||
}
|
||||
|
||||
public static function fromList(Scope $scope, self $list): self
|
||||
{
|
||||
return new self(
|
||||
$scope,
|
||||
$list->statements,
|
||||
$list->filterByTruthyValue,
|
||||
$list->processScope
|
||||
);
|
||||
}
|
||||
|
||||
public function getScope(): Scope
|
||||
{
|
||||
$scope = $this->scope;
|
||||
if ($this->processScope !== null) {
|
||||
$callback = $this->processScope;
|
||||
$scope = $callback($scope);
|
||||
}
|
||||
|
||||
return $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \PhpParser\Node[]
|
||||
*/
|
||||
public function getStatements(): array
|
||||
{
|
||||
return $this->statements;
|
||||
}
|
||||
|
||||
public function shouldFilterByTruthyValue(): bool
|
||||
{
|
||||
return $this->filterByTruthyValue;
|
||||
}
|
||||
|
||||
}
|
110
vendor/phpstan/phpstan/src/Analyser/StatementResult.php
vendored
Normal file
110
vendor/phpstan/phpstan/src/Analyser/StatementResult.php
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Analyser;
|
||||
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class StatementResult
|
||||
{
|
||||
|
||||
/** @var Scope */
|
||||
private $scope;
|
||||
|
||||
/** @var Stmt[] */
|
||||
private $alwaysTerminatingStatements;
|
||||
|
||||
/** @var StatementExitPoint[] */
|
||||
private $exitPoints;
|
||||
|
||||
/**
|
||||
* @param Scope $scope
|
||||
* @param Stmt[] $alwaysTerminatingStatements
|
||||
* @param StatementExitPoint[] $exitPoints
|
||||
*/
|
||||
public function __construct(
|
||||
Scope $scope,
|
||||
array $alwaysTerminatingStatements,
|
||||
array $exitPoints
|
||||
)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
$this->alwaysTerminatingStatements = $alwaysTerminatingStatements;
|
||||
$this->exitPoints = $exitPoints;
|
||||
}
|
||||
|
||||
public function getScope(): Scope
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Stmt[]
|
||||
*/
|
||||
public function getAlwaysTerminatingStatements(): array
|
||||
{
|
||||
return $this->alwaysTerminatingStatements;
|
||||
}
|
||||
|
||||
public function areAllAlwaysTerminatingStatementsLoopTerminationStatements(): bool
|
||||
{
|
||||
if (count($this->alwaysTerminatingStatements) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->alwaysTerminatingStatements as $statement) {
|
||||
if ($statement instanceof Stmt\Break_) {
|
||||
continue;
|
||||
}
|
||||
if ($statement instanceof Stmt\Continue_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isAlwaysTerminating(): bool
|
||||
{
|
||||
return count($this->alwaysTerminatingStatements) > 0;
|
||||
}
|
||||
|
||||
public function filterOutLoopTerminationStatements(): self
|
||||
{
|
||||
foreach ($this->alwaysTerminatingStatements as $statement) {
|
||||
if ($statement instanceof Stmt\Break_ || $statement instanceof Stmt\Continue_) {
|
||||
return new self($this->scope, [], $this->exitPoints);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StatementExitPoint[]
|
||||
*/
|
||||
public function getExitPoints(): array
|
||||
{
|
||||
return $this->exitPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $stmtClass
|
||||
* @return StatementExitPoint[]
|
||||
*/
|
||||
public function getExitPointsByType(string $stmtClass): array
|
||||
{
|
||||
$exitPoints = [];
|
||||
foreach ($this->exitPoints as $exitPoint) {
|
||||
if (!$exitPoint->getStatement() instanceof $stmtClass) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$exitPoints[] = $exitPoint;
|
||||
}
|
||||
|
||||
return $exitPoints;
|
||||
}
|
||||
|
||||
}
|
|
@ -20,13 +20,16 @@ use PhpParser\Node\Expr\StaticPropertyFetch;
|
|||
use PhpParser\Node\Name;
|
||||
use PHPStan\Broker\Broker;
|
||||
use PHPStan\Type\Accessory\HasOffsetType;
|
||||
use PHPStan\Type\Accessory\HasPropertyType;
|
||||
use PHPStan\Type\Accessory\NonEmptyArrayType;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\BooleanType;
|
||||
use PHPStan\Type\Constant\ConstantArrayType;
|
||||
use PHPStan\Type\Constant\ConstantBooleanType;
|
||||
use PHPStan\Type\Constant\ConstantFloatType;
|
||||
use PHPStan\Type\Constant\ConstantIntegerType;
|
||||
use PHPStan\Type\Constant\ConstantStringType;
|
||||
use PHPStan\Type\IntersectionType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\NeverType;
|
||||
use PHPStan\Type\NonexistentParentClassType;
|
||||
|
@ -102,6 +105,10 @@ class TypeSpecifier
|
|||
): SpecifiedTypes
|
||||
{
|
||||
if ($expr instanceof Instanceof_) {
|
||||
$exprNode = $expr->expr;
|
||||
if ($exprNode instanceof Expr\Assign) {
|
||||
$exprNode = $exprNode->var;
|
||||
}
|
||||
if ($expr->class instanceof Name) {
|
||||
$className = (string) $expr->class;
|
||||
$lowercasedClassName = strtolower($className);
|
||||
|
@ -121,17 +128,20 @@ class TypeSpecifier
|
|||
} else {
|
||||
$type = new ObjectType($className);
|
||||
}
|
||||
return $this->create($expr->expr, $type, $context);
|
||||
return $this->create($exprNode, $type, $context);
|
||||
}
|
||||
|
||||
if ($context->true()) {
|
||||
return $this->create($expr->expr, new ObjectWithoutClassType(), $context);
|
||||
return $this->create($exprNode, new ObjectWithoutClassType(), $context);
|
||||
}
|
||||
} elseif ($expr instanceof Node\Expr\BinaryOp\Identical) {
|
||||
$expressions = $this->findTypeExpressionsFromBinaryOperation($scope, $expr);
|
||||
if ($expressions !== null) {
|
||||
/** @var Expr $exprNode */
|
||||
$exprNode = $expressions[0];
|
||||
if ($exprNode instanceof Expr\Assign) {
|
||||
$exprNode = $exprNode->var;
|
||||
}
|
||||
/** @var \PHPStan\Type\ConstantScalarType $constantType */
|
||||
$constantType = $expressions[1];
|
||||
if ($constantType->getValue() === false) {
|
||||
|
@ -250,6 +260,66 @@ class TypeSpecifier
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
$leftType = $scope->getType($expr->left);
|
||||
$leftBooleanType = $leftType->toBoolean();
|
||||
$rightType = $scope->getType($expr->right);
|
||||
if ($leftBooleanType instanceof ConstantBooleanType && $rightType instanceof BooleanType) {
|
||||
return $this->specifyTypesInCondition(
|
||||
$scope,
|
||||
new Expr\BinaryOp\Identical(
|
||||
new ConstFetch(new Name($leftBooleanType->getValue() ? 'true' : 'false')),
|
||||
$expr->right
|
||||
),
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
$rightBooleanType = $rightType->toBoolean();
|
||||
if ($rightBooleanType instanceof ConstantBooleanType && $leftType instanceof BooleanType) {
|
||||
return $this->specifyTypesInCondition(
|
||||
$scope,
|
||||
new Expr\BinaryOp\Identical(
|
||||
$expr->left,
|
||||
new ConstFetch(new Name($rightBooleanType->getValue() ? 'true' : 'false'))
|
||||
),
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
$expr->left instanceof FuncCall
|
||||
&& $expr->left->name instanceof Name
|
||||
&& strtolower($expr->left->name->toString()) === 'get_class'
|
||||
&& isset($expr->left->args[0])
|
||||
&& $rightType instanceof ConstantStringType
|
||||
) {
|
||||
return $this->specifyTypesInCondition(
|
||||
$scope,
|
||||
new Instanceof_(
|
||||
$expr->left->args[0]->value,
|
||||
new Name($rightType->getValue())
|
||||
),
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
$expr->right instanceof FuncCall
|
||||
&& $expr->right->name instanceof Name
|
||||
&& strtolower($expr->right->name->toString()) === 'get_class'
|
||||
&& isset($expr->right->args[0])
|
||||
&& $leftType instanceof ConstantStringType
|
||||
) {
|
||||
return $this->specifyTypesInCondition(
|
||||
$scope,
|
||||
new Instanceof_(
|
||||
$expr->right->args[0]->value,
|
||||
new Name($leftType->getValue())
|
||||
),
|
||||
$context
|
||||
);
|
||||
}
|
||||
} elseif ($expr instanceof Node\Expr\BinaryOp\NotEqual) {
|
||||
return $this->specifyTypesInCondition(
|
||||
$scope,
|
||||
|
@ -373,6 +443,10 @@ class TypeSpecifier
|
|||
}
|
||||
}
|
||||
|
||||
if (count($vars) === 0) {
|
||||
throw new \PHPStan\ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$types = null;
|
||||
foreach ($vars as $var) {
|
||||
if ($expr instanceof Expr\Isset_) {
|
||||
|
@ -401,6 +475,26 @@ class TypeSpecifier
|
|||
TypeSpecifierContext::createFalse()
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
$var instanceof PropertyFetch
|
||||
&& $var->name instanceof Node\Identifier
|
||||
) {
|
||||
$type = $type->unionWith($this->create($var->var, new IntersectionType([
|
||||
new ObjectWithoutClassType(),
|
||||
new HasPropertyType($var->name->toString()),
|
||||
]), TypeSpecifierContext::createTruthy()));
|
||||
} elseif (
|
||||
$var instanceof StaticPropertyFetch
|
||||
&& $var->class instanceof Expr
|
||||
&& $var->name instanceof Node\VarLikeIdentifier
|
||||
) {
|
||||
$type = $type->unionWith($this->create($var->class, new IntersectionType([
|
||||
new ObjectWithoutClassType(),
|
||||
new HasPropertyType($var->name->toString()),
|
||||
]), TypeSpecifierContext::createTruthy()));
|
||||
}
|
||||
|
||||
if ($types === null) {
|
||||
$types = $type;
|
||||
} else {
|
||||
|
@ -408,9 +502,6 @@ class TypeSpecifier
|
|||
}
|
||||
}
|
||||
|
||||
/** @var SpecifiedTypes $types */
|
||||
$types = $types;
|
||||
|
||||
if (
|
||||
$expr instanceof Expr\Empty_
|
||||
&& (new ArrayType(new MixedType(), new MixedType()))->isSuperTypeOf($scope->getType($expr->expr))->yes()) {
|
||||
|
@ -480,7 +571,7 @@ class TypeSpecifier
|
|||
|
||||
public function create(Expr $expr, Type $type, TypeSpecifierContext $context): SpecifiedTypes
|
||||
{
|
||||
if ($expr instanceof New_) {
|
||||
if ($expr instanceof New_ || $expr instanceof Instanceof_) {
|
||||
return new SpecifiedTypes();
|
||||
}
|
||||
|
||||
|
@ -500,7 +591,7 @@ class TypeSpecifier
|
|||
/**
|
||||
* @return \PHPStan\Type\FunctionTypeSpecifyingExtension[]
|
||||
*/
|
||||
public function getFunctionTypeSpecifyingExtensions(): array
|
||||
private function getFunctionTypeSpecifyingExtensions(): array
|
||||
{
|
||||
return $this->functionTypeSpecifyingExtensions;
|
||||
}
|
||||
|
@ -509,7 +600,7 @@ class TypeSpecifier
|
|||
* @param string $className
|
||||
* @return \PHPStan\Type\MethodTypeSpecifyingExtension[]
|
||||
*/
|
||||
public function getMethodTypeSpecifyingExtensionsForClass(string $className): array
|
||||
private function getMethodTypeSpecifyingExtensionsForClass(string $className): array
|
||||
{
|
||||
if ($this->methodTypeSpecifyingExtensionsByClass === null) {
|
||||
$byClass = [];
|
||||
|
@ -526,7 +617,7 @@ class TypeSpecifier
|
|||
* @param string $className
|
||||
* @return \PHPStan\Type\StaticMethodTypeSpecifyingExtension[]
|
||||
*/
|
||||
public function getStaticMethodTypeSpecifyingExtensionsForClass(string $className): array
|
||||
private function getStaticMethodTypeSpecifyingExtensionsForClass(string $className): array
|
||||
{
|
||||
if ($this->staticMethodTypeSpecifyingExtensionsByClass === null) {
|
||||
$byClass = [];
|
||||
|
|
|
@ -36,8 +36,13 @@ class VariableTypeHolder
|
|||
|
||||
public function and(self $other): self
|
||||
{
|
||||
if ($this->getType()->equals($other->getType())) {
|
||||
$type = $this->getType();
|
||||
} else {
|
||||
$type = TypeCombinator::union($this->getType(), $other->getType());
|
||||
}
|
||||
return new self(
|
||||
TypeCombinator::union($this->getType(), $other->getType()),
|
||||
$type,
|
||||
$this->getCertainty()->and($other->getCertainty())
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,11 +24,11 @@ class AnonymousClassNameHelper
|
|||
}
|
||||
|
||||
public function getAnonymousClassName(
|
||||
\PhpParser\Node\Expr\New_ $node,
|
||||
\PhpParser\Node\Stmt\Class_ $classNode,
|
||||
string $filename
|
||||
): string
|
||||
{
|
||||
if (!$node->class instanceof \PhpParser\Node\Stmt\Class_) {
|
||||
if (isset($classNode->namespacedName)) {
|
||||
throw new \PHPStan\ShouldNotHappenException();
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ class AnonymousClassNameHelper
|
|||
|
||||
return sprintf(
|
||||
'AnonymousClass%s',
|
||||
md5(sprintf('%s:%s', $filename, $node->class->getLine()))
|
||||
md5(sprintf('%s:%s', $filename, $classNode->getLine()))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
12
vendor/phpstan/phpstan/src/Broker/Broker.php
vendored
12
vendor/phpstan/phpstan/src/Broker/Broker.php
vendored
|
@ -269,11 +269,11 @@ class Broker
|
|||
}
|
||||
|
||||
public function getAnonymousClassReflection(
|
||||
\PhpParser\Node\Expr\New_ $node,
|
||||
\PhpParser\Node\Stmt\Class_ $classNode,
|
||||
Scope $scope
|
||||
): ClassReflection
|
||||
{
|
||||
if (!$node->class instanceof \PhpParser\Node\Stmt\Class_) {
|
||||
if (isset($classNode->namespacedName)) {
|
||||
throw new \PHPStan\ShouldNotHappenException();
|
||||
}
|
||||
|
||||
|
@ -289,22 +289,20 @@ class Broker
|
|||
$filename = $this->relativePathHelper->getRelativePath($scopeFile);
|
||||
|
||||
$className = $this->anonymousClassNameHelper->getAnonymousClassName(
|
||||
$node,
|
||||
$classNode,
|
||||
$filename
|
||||
);
|
||||
$classNode->name = new \PhpParser\Node\Identifier($className);
|
||||
|
||||
if (isset(self::$anonymousClasses[$className])) {
|
||||
return self::$anonymousClasses[$className];
|
||||
}
|
||||
|
||||
$classNode = $node->class;
|
||||
$classNode->name = new \PhpParser\Node\Identifier($className);
|
||||
eval($this->printer->prettyPrint([$classNode]));
|
||||
unset($classNode);
|
||||
|
||||
self::$anonymousClasses[$className] = $this->getClassFromReflection(
|
||||
new \ReflectionClass('\\' . $className),
|
||||
sprintf('class@anonymous/%s:%s', $filename, $node->getLine()),
|
||||
sprintf('class@anonymous/%s:%s', $filename, $classNode->getLine()),
|
||||
$scopeFile
|
||||
);
|
||||
$this->classReflections[$className] = self::$anonymousClasses[$className];
|
||||
|
|
|
@ -173,6 +173,11 @@ class ParametersAcceptorSelector
|
|||
*/
|
||||
public static function combineAcceptors(array $acceptors): ParametersAcceptor
|
||||
{
|
||||
if (count($acceptors) === 0) {
|
||||
throw new \PHPStan\ShouldNotHappenException(
|
||||
'getVariants() must return at least one variant.'
|
||||
);
|
||||
}
|
||||
if (count($acceptors) === 1) {
|
||||
return $acceptors[0];
|
||||
}
|
||||
|
@ -236,9 +241,6 @@ class ParametersAcceptorSelector
|
|||
}
|
||||
}
|
||||
|
||||
/** @var \PHPStan\Type\Type $returnType */
|
||||
$returnType = $returnType;
|
||||
|
||||
return new FunctionVariant($parameters, $isVariadic, $returnType);
|
||||
}
|
||||
|
||||
|
|
|
@ -2174,7 +2174,7 @@ return [
|
|||
'Ds\Set::contains' => ['bool', '...values='=>'mixed'],
|
||||
'Ds\Set::diff' => ['Ds\Set', 'set'=>'Ds\Set'],
|
||||
'Ds\Set::filter' => ['Ds\Set', 'callback='=>'callable'],
|
||||
'Ds\Set::first' => ['void'],
|
||||
'Ds\Set::first' => ['mixed'],
|
||||
'Ds\Set::get' => ['mixed', 'index'=>'int'],
|
||||
'Ds\Set::intersect' => ['Ds\Set', 'set'=>'Ds\Set'],
|
||||
'Ds\Set::join' => ['void', 'glue='=>'string'],
|
||||
|
|
|
@ -96,8 +96,8 @@ class InvalidBinaryOperationRule implements \PHPStan\Rules\Rule
|
|||
}
|
||||
|
||||
$scope = $scope
|
||||
->assignVariable($leftName, $leftType, \PHPStan\TrinaryLogic::createYes())
|
||||
->assignVariable($rightName, $rightType, \PHPStan\TrinaryLogic::createYes());
|
||||
->assignVariable($leftName, $leftType)
|
||||
->assignVariable($rightName, $rightType);
|
||||
|
||||
if (!$scope->getType($newNode) instanceof ErrorType) {
|
||||
return [];
|
||||
|
|
39
vendor/phpstan/phpstan/src/Rules/Properties/AccessPropertiesInAssignRule.php
vendored
Normal file
39
vendor/phpstan/phpstan/src/Rules/Properties/AccessPropertiesInAssignRule.php
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Rules\Properties;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Rules\Rule;
|
||||
|
||||
class AccessPropertiesInAssignRule implements Rule
|
||||
{
|
||||
|
||||
/** @var \PHPStan\Rules\Properties\AccessPropertiesRule */
|
||||
private $accessPropertiesRule;
|
||||
|
||||
public function __construct(AccessPropertiesRule $accessPropertiesRule)
|
||||
{
|
||||
$this->accessPropertiesRule = $accessPropertiesRule;
|
||||
}
|
||||
|
||||
public function getNodeType(): string
|
||||
{
|
||||
return Node\Expr\Assign::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PhpParser\Node\Expr\Assign $node
|
||||
* @param \PHPStan\Analyser\Scope $scope
|
||||
* @return (string|\PHPStan\Rules\RuleError)[]
|
||||
*/
|
||||
public function processNode(Node $node, Scope $scope): array
|
||||
{
|
||||
if (!$node->var instanceof Node\Expr\PropertyFetch) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->accessPropertiesRule->processNode($node->var, $scope);
|
||||
}
|
||||
|
||||
}
|
|
@ -63,6 +63,10 @@ class AccessPropertiesRule implements \PHPStan\Rules\Rule
|
|||
return $typeResult->getUnknownClassErrors();
|
||||
}
|
||||
|
||||
if ($scope->isInExpressionAssign($node)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$type->canAccessProperties()->yes()) {
|
||||
return [
|
||||
sprintf('Cannot access property $%s on %s.', $name, $type->describe(VerbosityLevel::typeOnly())),
|
||||
|
|
39
vendor/phpstan/phpstan/src/Rules/Properties/AccessStaticPropertiesInAssignRule.php
vendored
Normal file
39
vendor/phpstan/phpstan/src/Rules/Properties/AccessStaticPropertiesInAssignRule.php
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Rules\Properties;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Rules\Rule;
|
||||
|
||||
class AccessStaticPropertiesInAssignRule implements Rule
|
||||
{
|
||||
|
||||
/** @var \PHPStan\Rules\Properties\AccessStaticPropertiesRule */
|
||||
private $accessStaticPropertiesRule;
|
||||
|
||||
public function __construct(AccessStaticPropertiesRule $accessStaticPropertiesRule)
|
||||
{
|
||||
$this->accessStaticPropertiesRule = $accessStaticPropertiesRule;
|
||||
}
|
||||
|
||||
public function getNodeType(): string
|
||||
{
|
||||
return Node\Expr\Assign::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PhpParser\Node\Expr\Assign $node
|
||||
* @param \PHPStan\Analyser\Scope $scope
|
||||
* @return (string|\PHPStan\Rules\RuleError)[]
|
||||
*/
|
||||
public function processNode(Node $node, Scope $scope): array
|
||||
{
|
||||
if (!$node->var instanceof Node\Expr\StaticPropertyFetch) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->accessStaticPropertiesRule->processNode($node->var, $scope);
|
||||
}
|
||||
|
||||
}
|
|
@ -144,6 +144,10 @@ class AccessStaticPropertiesRule implements \PHPStan\Rules\Rule
|
|||
$typeForDescribe = $classType;
|
||||
$classType = TypeCombinator::remove($classType, new StringType());
|
||||
|
||||
if ($scope->isInExpressionAssign($node)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$classType->canAccessProperties()->yes()) {
|
||||
return array_merge($messages, [
|
||||
sprintf('Cannot access static property $%s on %s.', $name, $typeForDescribe->describe(VerbosityLevel::typeOnly())),
|
||||
|
|
|
@ -10,7 +10,6 @@ use PHPStan\TrinaryLogic;
|
|||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\BooleanType;
|
||||
use PHPStan\Type\CompoundType;
|
||||
use PHPStan\Type\ConstantScalarType;
|
||||
use PHPStan\Type\ConstantType;
|
||||
use PHPStan\Type\ErrorType;
|
||||
use PHPStan\Type\MixedType;
|
||||
|
@ -360,7 +359,8 @@ class ConstantArrayType extends ArrayType implements ConstantType
|
|||
|
||||
if (!$preserveKeys) {
|
||||
$i = 0;
|
||||
$keyTypes = array_map(static function (ConstantScalarType $keyType) use (&$i): ConstantScalarType {
|
||||
/** @var array<int, ConstantIntegerType|ConstantStringType> $keyTypes */
|
||||
$keyTypes = array_map(static function ($keyType) use (&$i) {
|
||||
if ($keyType instanceof ConstantIntegerType) {
|
||||
$i++;
|
||||
return new ConstantIntegerType($i - 1);
|
||||
|
@ -370,12 +370,14 @@ class ConstantArrayType extends ArrayType implements ConstantType
|
|||
}, $keyTypes);
|
||||
}
|
||||
|
||||
/** @var int|float $nextAutoIndex */
|
||||
$nextAutoIndex = 0;
|
||||
foreach ($keyTypes as $keyType) {
|
||||
if (!$keyType instanceof ConstantIntegerType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var int|float $nextAutoIndex */
|
||||
$nextAutoIndex = max($nextAutoIndex, $keyType->getValue() + 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -178,10 +178,7 @@ class FileTypeMapper
|
|||
throw new \PHPStan\ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$className = $this->anonymousClassNameHelper->getAnonymousClassName(
|
||||
new Node\Expr\New_($node),
|
||||
$fileName
|
||||
);
|
||||
$className = $this->anonymousClassNameHelper->getAnonymousClassName($node, $fileName);
|
||||
} else {
|
||||
$className = ltrim(sprintf('%s\\%s', $namespace, $node->name->name), '\\');
|
||||
}
|
||||
|
@ -198,6 +195,9 @@ class FileTypeMapper
|
|||
if ($traitReflection->getFileName() === false) {
|
||||
continue;
|
||||
}
|
||||
if (!file_exists($traitReflection->getFileName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$className = $classStack[count($classStack) - 1] ?? null;
|
||||
if ($className === null) {
|
||||
|
|
12
vendor/phpstan/phpstan/src/Type/ObjectType.php
vendored
12
vendor/phpstan/phpstan/src/Type/ObjectType.php
vendored
|
@ -20,10 +20,7 @@ class ObjectType implements TypeWithClassName
|
|||
|
||||
use TruthyBooleanTypeTrait;
|
||||
|
||||
private const EXTRA_OFFSET_CLASSES = [
|
||||
'SimpleXMLElement' => true,
|
||||
'DOMNodeList' => true,
|
||||
];
|
||||
private const EXTRA_OFFSET_CLASSES = ['SimpleXMLElement', 'DOMNodeList'];
|
||||
|
||||
/** @var string */
|
||||
private $className;
|
||||
|
@ -454,9 +451,14 @@ class ObjectType implements TypeWithClassName
|
|||
|
||||
$classReflection = $broker->getClass($this->className);
|
||||
|
||||
if (array_key_exists($classReflection->getName(), self::EXTRA_OFFSET_CLASSES)) {
|
||||
foreach (self::EXTRA_OFFSET_CLASSES as $extraOffsetClass) {
|
||||
if ($classReflection->getName() === $extraOffsetClass) {
|
||||
return TrinaryLogic::createYes();
|
||||
}
|
||||
if ($classReflection->isSubclassOf($extraOffsetClass)) {
|
||||
return TrinaryLogic::createYes();
|
||||
}
|
||||
}
|
||||
|
||||
return TrinaryLogic::createNo();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use PhpParser\Node\Expr\Variable;
|
|||
use PhpParser\Node\Stmt\Return_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\FunctionReflection;
|
||||
use PHPStan\TrinaryLogic;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\BenevolentUnionType;
|
||||
use PHPStan\Type\Constant\ConstantArrayType;
|
||||
|
@ -63,7 +62,7 @@ class ArrayFilterFunctionReturnTypeReturnTypeExtension implements \PHPStan\Type\
|
|||
throw new \PHPStan\ShouldNotHappenException();
|
||||
}
|
||||
$itemVariableName = $callbackArg->params[0]->var->name;
|
||||
$scope = $scope->assignVariable($itemVariableName, $itemType, TrinaryLogic::createYes());
|
||||
$scope = $scope->assignVariable($itemVariableName, $itemType);
|
||||
$scope = $scope->filterByTruthyValue($statement->expr);
|
||||
$itemType = $scope->getVariableType($itemVariableName);
|
||||
}
|
||||
|
|
|
@ -61,13 +61,6 @@ class ArraySliceFunctionReturnTypeExtension implements \PHPStan\Type\DynamicFunc
|
|||
|
||||
$constantArrays = TypeUtils::getConstantArrays($valueType);
|
||||
if (count($constantArrays) === 0) {
|
||||
if (!$valueType instanceof ArrayType) {
|
||||
return new ArrayType(
|
||||
new MixedType(),
|
||||
new MixedType()
|
||||
);
|
||||
}
|
||||
|
||||
return $valueType;
|
||||
}
|
||||
|
||||
|
|
80
vendor/phpstan/phpstan/src/Type/Php/FilterVarDynamicReturnTypeExtension.php
vendored
Normal file
80
vendor/phpstan/phpstan/src/Type/Php/FilterVarDynamicReturnTypeExtension.php
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace PHPStan\Type\Php;
|
||||
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\FunctionReflection;
|
||||
use PHPStan\Type\BooleanType;
|
||||
use PHPStan\Type\Constant\ConstantBooleanType;
|
||||
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
|
||||
use PHPStan\Type\FloatType;
|
||||
use PHPStan\Type\IntegerType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\StringType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\UnionType;
|
||||
|
||||
class FilterVarDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
|
||||
{
|
||||
|
||||
/** @var array<string, Type> */
|
||||
private $filterTypesHashMaps;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$booleanType = new BooleanType();
|
||||
$floatOrFalseType = new UnionType([new FloatType(), new ConstantBooleanType(false)]);
|
||||
$intOrFalseType = new UnionType([new IntegerType(), new ConstantBooleanType(false)]);
|
||||
$stringOrFalseType = new UnionType([new StringType(), new ConstantBooleanType(false)]);
|
||||
|
||||
$this->filterTypesHashMaps = [
|
||||
'FILTER_SANITIZE_EMAIL' => $stringOrFalseType,
|
||||
'FILTER_SANITIZE_ENCODED' => $stringOrFalseType,
|
||||
'FILTER_SANITIZE_MAGIC_QUOTES' => $stringOrFalseType,
|
||||
'FILTER_SANITIZE_NUMBER_FLOAT' => $stringOrFalseType,
|
||||
'FILTER_SANITIZE_NUMBER_INT' => $stringOrFalseType,
|
||||
'FILTER_SANITIZE_SPECIAL_CHARS' => $stringOrFalseType,
|
||||
'FILTER_SANITIZE_STRING' => $stringOrFalseType,
|
||||
'FILTER_SANITIZE_URL' => $stringOrFalseType,
|
||||
'FILTER_VALIDATE_BOOLEAN' => $booleanType,
|
||||
'FILTER_VALIDATE_EMAIL' => $stringOrFalseType,
|
||||
'FILTER_VALIDATE_FLOAT' => $floatOrFalseType,
|
||||
'FILTER_VALIDATE_INT' => $intOrFalseType,
|
||||
'FILTER_VALIDATE_IP' => $stringOrFalseType,
|
||||
'FILTER_VALIDATE_MAC' => $stringOrFalseType,
|
||||
'FILTER_VALIDATE_REGEXP' => $stringOrFalseType,
|
||||
'FILTER_VALIDATE_URL' => $stringOrFalseType,
|
||||
];
|
||||
}
|
||||
|
||||
public function isFunctionSupported(FunctionReflection $functionReflection): bool
|
||||
{
|
||||
return strtolower($functionReflection->getName()) === 'filter_var';
|
||||
}
|
||||
|
||||
public function getTypeFromFunctionCall(
|
||||
FunctionReflection $functionReflection,
|
||||
FuncCall $functionCall,
|
||||
Scope $scope
|
||||
): Type
|
||||
{
|
||||
$mixedType = new MixedType();
|
||||
|
||||
$filterArg = $functionCall->args[1] ?? null;
|
||||
if ($filterArg === null) {
|
||||
return $mixedType;
|
||||
}
|
||||
|
||||
$filterExpr = $filterArg->value;
|
||||
if (!$filterExpr instanceof ConstFetch) {
|
||||
return $mixedType;
|
||||
}
|
||||
|
||||
$filterName = (string) $filterExpr->name;
|
||||
|
||||
return $this->filterTypesHashMaps[$filterName] ?? $mixedType;
|
||||
}
|
||||
|
||||
}
|
|
@ -77,7 +77,13 @@ class StaticType implements StaticResolvableType, TypeWithClassName
|
|||
|
||||
public function equals(Type $type): bool
|
||||
{
|
||||
return $this->staticObjectType->equals($type);
|
||||
if (get_class($type) !== static::class) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var StaticType $type */
|
||||
$type = $type;
|
||||
return $this->staticObjectType->equals($type->staticObjectType);
|
||||
}
|
||||
|
||||
public function describe(VerbosityLevel $level): string
|
||||
|
|
|
@ -77,9 +77,13 @@ class TypeCombinator
|
|||
|
||||
public static function removeNull(Type $type): Type
|
||||
{
|
||||
if (self::containsNull($type)) {
|
||||
return self::remove($type, new NullType());
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
public static function containsNull(Type $type): bool
|
||||
{
|
||||
if ($type instanceof UnionType) {
|
||||
|
@ -146,14 +150,14 @@ class TypeCombinator
|
|||
continue;
|
||||
}
|
||||
if ($innerType instanceof AccessoryType || $innerType instanceof CallableType) {
|
||||
$intermediateAccessoryTypes[] = $innerType;
|
||||
$intermediateAccessoryTypes[$innerType->describe(VerbosityLevel::precise())] = $innerType;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($intermediateArrayType !== null) {
|
||||
$arrayTypes[] = $intermediateArrayType;
|
||||
$arrayAccessoryTypes = array_merge($arrayAccessoryTypes, $intermediateAccessoryTypes);
|
||||
$arrayAccessoryTypes[] = $intermediateAccessoryTypes;
|
||||
unset($types[$i]);
|
||||
continue;
|
||||
}
|
||||
|
@ -163,14 +167,25 @@ class TypeCombinator
|
|||
}
|
||||
|
||||
$arrayTypes[] = $types[$i];
|
||||
$arrayAccessoryTypes[] = [];
|
||||
unset($types[$i]);
|
||||
}
|
||||
|
||||
/** @var ArrayType[] $arrayTypes */
|
||||
$arrayTypes = $arrayTypes;
|
||||
|
||||
$arrayAccessoryTypesToProcess = [];
|
||||
if (count($arrayAccessoryTypes) > 1) {
|
||||
$arrayAccessoryTypesToProcess = array_values(array_intersect_key(...$arrayAccessoryTypes));
|
||||
} elseif (count($arrayAccessoryTypes) > 0) {
|
||||
$arrayAccessoryTypesToProcess = array_values($arrayAccessoryTypes[0]);
|
||||
}
|
||||
|
||||
$types = array_values(
|
||||
array_merge($types, self::processArrayTypes($arrayTypes, $arrayAccessoryTypes))
|
||||
array_merge(
|
||||
$types,
|
||||
self::processArrayTypes($arrayTypes, $arrayAccessoryTypesToProcess)
|
||||
)
|
||||
);
|
||||
|
||||
// simplify string[] | int[] to (string|int)[]
|
||||
|
@ -322,18 +337,18 @@ class TypeCombinator
|
|||
$constantKeyTypesNumbered = $constantKeyTypesNumbered;
|
||||
|
||||
$constantArraysBuckets = [];
|
||||
foreach ($arrayTypes as $arrayType) {
|
||||
foreach ($arrayTypes as $arrayTypeAgain) {
|
||||
$arrayIndex = 0;
|
||||
foreach ($arrayType->getKeyTypes() as $keyType) {
|
||||
foreach ($arrayTypeAgain->getKeyTypes() as $keyType) {
|
||||
$arrayIndex += $constantKeyTypesNumbered[$keyType->getValue()];
|
||||
}
|
||||
|
||||
if (!array_key_exists($arrayIndex, $constantArraysBuckets)) {
|
||||
$bucket = [];
|
||||
foreach ($arrayType->getKeyTypes() as $i => $keyType) {
|
||||
foreach ($arrayTypeAgain->getKeyTypes() as $i => $keyType) {
|
||||
$bucket[$keyType->getValue()] = [
|
||||
'keyType' => $keyType,
|
||||
'valueType' => $arrayType->getValueTypes()[$i],
|
||||
'valueType' => $arrayTypeAgain->getValueTypes()[$i],
|
||||
];
|
||||
}
|
||||
$constantArraysBuckets[$arrayIndex] = $bucket;
|
||||
|
@ -341,10 +356,10 @@ class TypeCombinator
|
|||
}
|
||||
|
||||
$bucket = $constantArraysBuckets[$arrayIndex];
|
||||
foreach ($arrayType->getKeyTypes() as $i => $keyType) {
|
||||
foreach ($arrayTypeAgain->getKeyTypes() as $i => $keyType) {
|
||||
$bucket[$keyType->getValue()]['valueType'] = self::union(
|
||||
$bucket[$keyType->getValue()]['valueType'],
|
||||
$arrayType->getValueTypes()[$i]
|
||||
$arrayTypeAgain->getValueTypes()[$i]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
30
vendor/phpstan/phpstan/src/Type/TypeUtils.php
vendored
30
vendor/phpstan/phpstan/src/Type/TypeUtils.php
vendored
|
@ -45,6 +45,24 @@ class TypeUtils
|
|||
return self::map(ConstantType::class, $type, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PHPStan\Type\Type $type
|
||||
* @return \PHPStan\Type\ConstantType[]
|
||||
*/
|
||||
public static function getAnyConstantTypes(Type $type): array
|
||||
{
|
||||
return self::map(ConstantType::class, $type, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PHPStan\Type\Type $type
|
||||
* @return \PHPStan\Type\ArrayType[]
|
||||
*/
|
||||
public static function getAnyArrays(Type $type): array
|
||||
{
|
||||
return self::map(ArrayType::class, $type, true, false);
|
||||
}
|
||||
|
||||
public static function generalizeType(Type $type): Type
|
||||
{
|
||||
if ($type instanceof ConstantType) {
|
||||
|
@ -97,12 +115,14 @@ class TypeUtils
|
|||
* @param string $typeClass
|
||||
* @param Type $type
|
||||
* @param bool $inspectIntersections
|
||||
* @param bool $stopOnUnmatched
|
||||
* @return mixed[]
|
||||
*/
|
||||
private static function map(
|
||||
string $typeClass,
|
||||
Type $type,
|
||||
bool $inspectIntersections
|
||||
bool $inspectIntersections,
|
||||
bool $stopOnUnmatched = true
|
||||
): array
|
||||
{
|
||||
if ($type instanceof $typeClass) {
|
||||
|
@ -113,9 +133,13 @@ class TypeUtils
|
|||
$matchingTypes = [];
|
||||
foreach ($type->getTypes() as $innerType) {
|
||||
if (!$innerType instanceof $typeClass) {
|
||||
if ($stopOnUnmatched) {
|
||||
return [];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$matchingTypes[] = $innerType;
|
||||
}
|
||||
|
||||
|
@ -126,6 +150,10 @@ class TypeUtils
|
|||
$matchingTypes = [];
|
||||
foreach ($type->getTypes() as $innerType) {
|
||||
if (!$innerType instanceof $typeClass) {
|
||||
if ($stopOnUnmatched) {
|
||||
return [];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
7
vendor/symfony/console/Application.php
vendored
7
vendor/symfony/console/Application.php
vendored
|
@ -199,6 +199,13 @@ class Application
|
|||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
// Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.
|
||||
$input->bind($this->getDefinition());
|
||||
} catch (ExceptionInterface $e) {
|
||||
// Errors must be ignored, full binding/validation happens later when the command is known.
|
||||
}
|
||||
|
||||
$name = $this->getCommandName($input);
|
||||
if (true === $input->hasParameterOption(['--help', '-h'], true)) {
|
||||
if (!$name) {
|
||||
|
|
13
vendor/symfony/console/Helper/ProgressBar.php
vendored
13
vendor/symfony/console/Helper/ProgressBar.php
vendored
|
@ -381,20 +381,17 @@ final class ProgressBar
|
|||
$lines = floor(Helper::strlen($message) / $this->terminal->getWidth()) + $this->formatLineCount + 1;
|
||||
$this->output->clear($lines);
|
||||
} else {
|
||||
// Move the cursor to the beginning of the line
|
||||
$this->output->write("\x0D");
|
||||
|
||||
// Erase the line
|
||||
$this->output->write("\x1B[2K");
|
||||
|
||||
// Erase previous lines
|
||||
if ($this->formatLineCount > 0) {
|
||||
$this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount));
|
||||
$message = str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount).$message;
|
||||
}
|
||||
|
||||
// Move the cursor to the beginning of the line and erase the line
|
||||
$message = "\x0D\x1B[2K$message";
|
||||
}
|
||||
}
|
||||
} elseif ($this->step > 0) {
|
||||
$this->output->writeln('');
|
||||
$message = PHP_EOL.$message;
|
||||
}
|
||||
|
||||
$this->firstRun = false;
|
||||
|
|
14
vendor/symfony/console/Helper/QuestionHelper.php
vendored
14
vendor/symfony/console/Helper/QuestionHelper.php
vendored
|
@ -126,7 +126,7 @@ class QuestionHelper extends Helper
|
|||
if (false === $ret) {
|
||||
$ret = fgets($inputStream, 4096);
|
||||
if (false === $ret) {
|
||||
throw new RuntimeException('Aborted');
|
||||
throw new RuntimeException('Aborted.');
|
||||
}
|
||||
$ret = trim($ret);
|
||||
}
|
||||
|
@ -213,8 +213,10 @@ class QuestionHelper extends Helper
|
|||
while (!feof($inputStream)) {
|
||||
$c = fread($inputStream, 1);
|
||||
|
||||
// Backspace Character
|
||||
if ("\177" === $c) {
|
||||
// as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false.
|
||||
if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) {
|
||||
throw new RuntimeException('Aborted.');
|
||||
} elseif ("\177" === $c) { // Backspace Character
|
||||
if (0 === $numMatches && 0 !== $i) {
|
||||
--$i;
|
||||
// Move cursor backwards
|
||||
|
@ -267,6 +269,10 @@ class QuestionHelper extends Helper
|
|||
|
||||
continue;
|
||||
} else {
|
||||
if ("\x80" <= $c) {
|
||||
$c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]);
|
||||
}
|
||||
|
||||
$output->write($c);
|
||||
$ret .= $c;
|
||||
++$i;
|
||||
|
@ -339,7 +345,7 @@ class QuestionHelper extends Helper
|
|||
shell_exec(sprintf('stty %s', $sttyMode));
|
||||
|
||||
if (false === $value) {
|
||||
throw new RuntimeException('Aborted');
|
||||
throw new RuntimeException('Aborted.');
|
||||
}
|
||||
|
||||
$value = trim($value);
|
||||
|
|
21
vendor/symfony/console/Input/ArgvInput.php
vendored
21
vendor/symfony/console/Input/ArgvInput.php
vendored
|
@ -257,8 +257,27 @@ class ArgvInput extends Input
|
|||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
foreach ($this->tokens as $token) {
|
||||
$isOption = false;
|
||||
foreach ($this->tokens as $i => $token) {
|
||||
if ($token && '-' === $token[0]) {
|
||||
if (false !== strpos($token, '=') || !isset($this->tokens[$i + 1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's a long option, consider that everything after "--" is the option name.
|
||||
// Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator)
|
||||
$name = '-' === $token[1] ? substr($token, 2) : substr($token, -1);
|
||||
if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
|
||||
// noop
|
||||
} elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
|
||||
$isOption = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isOption) {
|
||||
$isOption = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
2
vendor/symfony/console/Input/ArrayInput.php
vendored
2
vendor/symfony/console/Input/ArrayInput.php
vendored
|
@ -19,7 +19,7 @@ use Symfony\Component\Console\Exception\InvalidOptionException;
|
|||
*
|
||||
* Usage:
|
||||
*
|
||||
* $input = new ArrayInput(['name' => 'foo', '--bar' => 'foobar']);
|
||||
* $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']);
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
|
|
4
vendor/symfony/console/Input/Input.php
vendored
4
vendor/symfony/console/Input/Input.php
vendored
|
@ -69,7 +69,7 @@ abstract class Input implements InputInterface, StreamableInputInterface
|
|||
$givenArguments = $this->arguments;
|
||||
|
||||
$missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) {
|
||||
return !array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
|
||||
return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
|
||||
});
|
||||
|
||||
if (\count($missingArguments) > 0) {
|
||||
|
@ -150,7 +150,7 @@ abstract class Input implements InputInterface, StreamableInputInterface
|
|||
throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
return array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
|
||||
return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -338,8 +338,10 @@ class InputDefinition
|
|||
* @return string The InputOption name
|
||||
*
|
||||
* @throws InvalidArgumentException When option given does not exist
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
private function shortcutToName($shortcut)
|
||||
public function shortcutToName($shortcut)
|
||||
{
|
||||
if (!isset($this->shortcuts[$shortcut])) {
|
||||
throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
|
|
|
@ -60,9 +60,8 @@ class CommandTester
|
|||
}
|
||||
|
||||
$this->input = new ArrayInput($input);
|
||||
if ($this->inputs) {
|
||||
// Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN.
|
||||
$this->input->setStream(self::createStream($this->inputs));
|
||||
}
|
||||
|
||||
if (isset($options['interactive'])) {
|
||||
$this->input->setInteractive($options['interactive']);
|
||||
|
|
|
@ -126,7 +126,7 @@ trait TesterTrait
|
|||
*/
|
||||
private function initOutput(array $options)
|
||||
{
|
||||
$this->captureStreamsIndependently = array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];
|
||||
$this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];
|
||||
if (!$this->captureStreamsIndependently) {
|
||||
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
|
||||
if (isset($options['decorated'])) {
|
||||
|
|
13
vendor/symfony/console/Tests/ApplicationTest.php
vendored
13
vendor/symfony/console/Tests/ApplicationTest.php
vendored
|
@ -968,6 +968,19 @@ class ApplicationTest extends TestCase
|
|||
$this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if -n is passed');
|
||||
}
|
||||
|
||||
public function testRunWithGlobalOptionAndNoCommand()
|
||||
{
|
||||
$application = new Application();
|
||||
$application->setAutoExit(false);
|
||||
$application->setCatchExceptions(false);
|
||||
$application->getDefinition()->addOption(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL));
|
||||
|
||||
$output = new StreamOutput(fopen('php://memory', 'w', false));
|
||||
$input = new ArgvInput(['cli.php', '--foo', 'bar']);
|
||||
|
||||
$this->assertSame(0, $application->run($input, $output));
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue #9285.
|
||||
*
|
||||
|
|
|
@ -237,6 +237,43 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
|
|||
$this->assertSame('b', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||
}
|
||||
|
||||
public function getInputs()
|
||||
{
|
||||
return [
|
||||
['$'], // 1 byte character
|
||||
['¢'], // 2 bytes character
|
||||
['€'], // 3 bytes character
|
||||
['𐍈'], // 4 bytes character
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInputs
|
||||
*/
|
||||
public function testAskWithAutocompleteWithMultiByteCharacter($character)
|
||||
{
|
||||
if (!$this->hasSttyAvailable()) {
|
||||
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
|
||||
}
|
||||
|
||||
$inputStream = $this->getInputStream("$character\n");
|
||||
|
||||
$possibleChoices = [
|
||||
'$' => '1 byte character',
|
||||
'¢' => '2 bytes character',
|
||||
'€' => '3 bytes character',
|
||||
'𐍈' => '4 bytes character',
|
||||
];
|
||||
|
||||
$dialog = new QuestionHelper();
|
||||
$dialog->setHelperSet(new HelperSet([new FormatterHelper()]));
|
||||
|
||||
$question = new ChoiceQuestion('Please select a character', $possibleChoices);
|
||||
$question->setMaxAttempts(1);
|
||||
|
||||
$this->assertSame($character, $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
|
||||
}
|
||||
|
||||
public function testAutocompleteWithTrailingBackslash()
|
||||
{
|
||||
if (!$this->hasSttyAvailable()) {
|
||||
|
@ -549,7 +586,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
|
|||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Aborted
|
||||
* @expectedExceptionMessage Aborted.
|
||||
*/
|
||||
public function testAskThrowsExceptionOnMissingInput()
|
||||
{
|
||||
|
@ -559,7 +596,17 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
|
|||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Aborted
|
||||
* @expectedExceptionMessage Aborted.
|
||||
*/
|
||||
public function testAskThrowsExceptionOnMissingInputForChoiceQuestion()
|
||||
{
|
||||
$dialog = new QuestionHelper();
|
||||
$dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new ChoiceQuestion('Choice', ['a', 'b']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Aborted.
|
||||
*/
|
||||
public function testAskThrowsExceptionOnMissingInputWithValidator()
|
||||
{
|
||||
|
|
|
@ -124,7 +124,7 @@ class SymfonyQuestionHelperTest extends AbstractQuestionHelperTest
|
|||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Console\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Aborted
|
||||
* @expectedExceptionMessage Aborted.
|
||||
*/
|
||||
public function testAskThrowsExceptionOnMissingInput()
|
||||
{
|
||||
|
|
|
@ -312,6 +312,14 @@ class ArgvInputTest extends TestCase
|
|||
|
||||
$input = new ArgvInput(['cli.php', '-fbbar', 'foo']);
|
||||
$this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input');
|
||||
|
||||
$input = new ArgvInput(['cli.php', '--foo', 'fooval', 'bar']);
|
||||
$input->bind(new InputDefinition([new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('arg')]));
|
||||
$this->assertSame('bar', $input->getFirstArgument());
|
||||
|
||||
$input = new ArgvInput(['cli.php', '-bf', 'fooval', 'argval']);
|
||||
$input->bind(new InputDefinition([new InputOption('bar', 'b', InputOption::VALUE_NONE), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('arg')]));
|
||||
$this->assertSame('argval', $input->getFirstArgument());
|
||||
}
|
||||
|
||||
public function testHasParameterOption()
|
||||
|
|
|
@ -17,6 +17,7 @@ use Symfony\Component\Console\Command\Command;
|
|||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Output\Output;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
@ -139,7 +140,7 @@ class CommandTesterTest extends TestCase
|
|||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedMessage Aborted
|
||||
* @expectedExceptionMessage Aborted.
|
||||
*/
|
||||
public function testCommandWithWrongInputsNumber()
|
||||
{
|
||||
|
@ -153,13 +154,40 @@ class CommandTesterTest extends TestCase
|
|||
$command->setHelperSet(new HelperSet([new QuestionHelper()]));
|
||||
$command->setCode(function ($input, $output) use ($questions, $command) {
|
||||
$helper = $command->getHelper('question');
|
||||
$helper->ask($input, $output, new ChoiceQuestion('choice', ['a', 'b']));
|
||||
$helper->ask($input, $output, new Question($questions[0]));
|
||||
$helper->ask($input, $output, new Question($questions[1]));
|
||||
$helper->ask($input, $output, new Question($questions[2]));
|
||||
});
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->setInputs(['a', 'Bobby', 'Fine']);
|
||||
$tester->execute([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessage Aborted.
|
||||
*/
|
||||
public function testCommandWithQuestionsButNoInputs()
|
||||
{
|
||||
$questions = [
|
||||
'What\'s your name?',
|
||||
'How are you?',
|
||||
'Where do you come from?',
|
||||
];
|
||||
|
||||
$command = new Command('foo');
|
||||
$command->setHelperSet(new HelperSet([new QuestionHelper()]));
|
||||
$command->setCode(function ($input, $output) use ($questions, $command) {
|
||||
$helper = $command->getHelper('question');
|
||||
$helper->ask($input, $output, new ChoiceQuestion('choice', ['a', 'b']));
|
||||
$helper->ask($input, $output, new Question($questions[0]));
|
||||
$helper->ask($input, $output, new Question($questions[1]));
|
||||
$helper->ask($input, $output, new Question($questions[2]));
|
||||
});
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->setInputs(['Bobby', 'Fine']);
|
||||
$tester->execute([]);
|
||||
}
|
||||
|
||||
|
|
17
vendor/symfony/finder/Finder.php
vendored
17
vendor/symfony/finder/Finder.php
vendored
|
@ -29,7 +29,7 @@ use Symfony\Component\Finder\Iterator\SortableIterator;
|
|||
*
|
||||
* All rules may be invoked several times.
|
||||
*
|
||||
* All methods return the current Finder object to allow easy chaining:
|
||||
* All methods return the current Finder object to allow chaining:
|
||||
*
|
||||
* $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
|
||||
*
|
||||
|
@ -674,12 +674,15 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
private function searchInDirectory(string $dir): \Iterator
|
||||
{
|
||||
$exclude = $this->exclude;
|
||||
$notPaths = $this->notPaths;
|
||||
|
||||
if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
|
||||
$this->exclude = array_merge($this->exclude, self::$vcsPatterns);
|
||||
$exclude = array_merge($exclude, self::$vcsPatterns);
|
||||
}
|
||||
|
||||
if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
|
||||
$this->notPaths[] = '#(^|/)\..+(/|$)#';
|
||||
$notPaths[] = '#(^|/)\..+(/|$)#';
|
||||
}
|
||||
|
||||
$minDepth = 0;
|
||||
|
@ -712,8 +715,8 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
|
||||
$iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
|
||||
|
||||
if ($this->exclude) {
|
||||
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
|
||||
if ($exclude) {
|
||||
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude);
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
|
@ -746,8 +749,8 @@ class Finder implements \IteratorAggregate, \Countable
|
|||
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
|
||||
}
|
||||
|
||||
if ($this->paths || $this->notPaths) {
|
||||
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
|
||||
if ($this->paths || $notPaths) {
|
||||
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths);
|
||||
}
|
||||
|
||||
if ($this->sort || $this->reverseSorting) {
|
||||
|
|
100
vendor/symfony/finder/Tests/FinderTest.php
vendored
100
vendor/symfony/finder/Tests/FinderTest.php
vendored
|
@ -421,6 +421,59 @@ class FinderTest extends Iterator\RealIteratorTestCase
|
|||
]), $finder->in(self::$tmpDir)->getIterator());
|
||||
}
|
||||
|
||||
public function testIgnoreVCSCanBeDisabledAfterFirstIteration()
|
||||
{
|
||||
$finder = $this->buildFinder();
|
||||
$finder->in(self::$tmpDir);
|
||||
$finder->ignoreDotFiles(false);
|
||||
|
||||
$this->assertIterator($this->toAbsolute([
|
||||
'foo',
|
||||
'foo/bar.tmp',
|
||||
'qux',
|
||||
'qux/baz_100_1.py',
|
||||
'qux/baz_1_2.py',
|
||||
'qux_0_1.php',
|
||||
'qux_1000_1.php',
|
||||
'qux_1002_0.php',
|
||||
'qux_10_2.php',
|
||||
'qux_12_0.php',
|
||||
'qux_2_0.php',
|
||||
'test.php',
|
||||
'test.py',
|
||||
'toto',
|
||||
'.bar',
|
||||
'.foo',
|
||||
'.foo/.bar',
|
||||
'.foo/bar',
|
||||
'foo bar',
|
||||
]), $finder->getIterator());
|
||||
|
||||
$finder->ignoreVCS(false);
|
||||
$this->assertIterator($this->toAbsolute(['.git',
|
||||
'foo',
|
||||
'foo/bar.tmp',
|
||||
'qux',
|
||||
'qux/baz_100_1.py',
|
||||
'qux/baz_1_2.py',
|
||||
'qux_0_1.php',
|
||||
'qux_1000_1.php',
|
||||
'qux_1002_0.php',
|
||||
'qux_10_2.php',
|
||||
'qux_12_0.php',
|
||||
'qux_2_0.php',
|
||||
'test.php',
|
||||
'test.py',
|
||||
'toto',
|
||||
'toto/.git',
|
||||
'.bar',
|
||||
'.foo',
|
||||
'.foo/.bar',
|
||||
'.foo/bar',
|
||||
'foo bar',
|
||||
]), $finder->getIterator());
|
||||
}
|
||||
|
||||
public function testIgnoreDotFiles()
|
||||
{
|
||||
$finder = $this->buildFinder();
|
||||
|
@ -496,6 +549,53 @@ class FinderTest extends Iterator\RealIteratorTestCase
|
|||
]), $finder->in(self::$tmpDir)->getIterator());
|
||||
}
|
||||
|
||||
public function testIgnoreDotFilesCanBeDisabledAfterFirstIteration()
|
||||
{
|
||||
$finder = $this->buildFinder();
|
||||
$finder->in(self::$tmpDir);
|
||||
|
||||
$this->assertIterator($this->toAbsolute([
|
||||
'foo',
|
||||
'foo/bar.tmp',
|
||||
'qux',
|
||||
'qux/baz_100_1.py',
|
||||
'qux/baz_1_2.py',
|
||||
'qux_0_1.php',
|
||||
'qux_1000_1.php',
|
||||
'qux_1002_0.php',
|
||||
'qux_10_2.php',
|
||||
'qux_12_0.php',
|
||||
'qux_2_0.php',
|
||||
'test.php',
|
||||
'test.py',
|
||||
'toto',
|
||||
'foo bar',
|
||||
]), $finder->getIterator());
|
||||
|
||||
$finder->ignoreDotFiles(false);
|
||||
$this->assertIterator($this->toAbsolute([
|
||||
'foo',
|
||||
'foo/bar.tmp',
|
||||
'qux',
|
||||
'qux/baz_100_1.py',
|
||||
'qux/baz_1_2.py',
|
||||
'qux_0_1.php',
|
||||
'qux_1000_1.php',
|
||||
'qux_1002_0.php',
|
||||
'qux_10_2.php',
|
||||
'qux_12_0.php',
|
||||
'qux_2_0.php',
|
||||
'test.php',
|
||||
'test.py',
|
||||
'toto',
|
||||
'.bar',
|
||||
'.foo',
|
||||
'.foo/.bar',
|
||||
'.foo/bar',
|
||||
'foo bar',
|
||||
]), $finder->getIterator());
|
||||
}
|
||||
|
||||
public function testSortByName()
|
||||
{
|
||||
$finder = $this->buildFinder();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue