Add files via upload
This commit is contained in:
+97
@@ -0,0 +1,97 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 1.7.0 (2023-12-20)
|
||||||
|
|
||||||
|
* Feature: Full PHP 8.3 and PHP 8.2 compatibility.
|
||||||
|
(#51 by @yadaiio and #50 by @clue)
|
||||||
|
|
||||||
|
* Feature / Fix: Improve error reporting when custom error handler is used.
|
||||||
|
(#47 by @SimonFrings)
|
||||||
|
|
||||||
|
* Improve test suite and ensure 100% code coverage.
|
||||||
|
(#46 by @SimonFrings, #48 and #50 by @clue and #51 by @yadaiio)
|
||||||
|
|
||||||
|
## 1.6.0 (2022-02-21)
|
||||||
|
|
||||||
|
* Feature: Support PHP 8.1 release.
|
||||||
|
(#45 by @clue)
|
||||||
|
|
||||||
|
* Improve documentation to use fully-qualified function names.
|
||||||
|
(#43 by @SimonFrings and #42 by @PaulRotmann)
|
||||||
|
|
||||||
|
* Improve test suite and use GitHub actions for continuous integration (CI).
|
||||||
|
(#39 and #40 by @SimonFrings)
|
||||||
|
|
||||||
|
## 1.5.0 (2020-10-02)
|
||||||
|
|
||||||
|
* Feature: Improve performance by using global imports.
|
||||||
|
(#38 by @clue)
|
||||||
|
|
||||||
|
* Improve API documentation and add support / sponsorship info.
|
||||||
|
(#30 by @clue and #35 by @SimonFrings)
|
||||||
|
|
||||||
|
* Improve test suite and add `.gitattributes` to exclude dev files from exports.
|
||||||
|
Prepare PHP 8 support, update to PHPUnit 9 and simplify test matrix.
|
||||||
|
(#32 and #37 by @clue and #34 and #36 by @SimonFrings)
|
||||||
|
|
||||||
|
## 1.4.1 (2019-04-09)
|
||||||
|
|
||||||
|
* Fix: Check if the function is declared before declaring it.
|
||||||
|
(#23 by @Niko9911)
|
||||||
|
|
||||||
|
* Improve test suite to also test against PHP 7.2 and
|
||||||
|
add test for base64 encoding and decoding filters.
|
||||||
|
(#22 by @arubacao and #25 by @Nyholm and @clue)
|
||||||
|
|
||||||
|
## 1.4.0 (2017-08-18)
|
||||||
|
|
||||||
|
* Feature / Fix: The `fun()` function does not pass filter parameter `null`
|
||||||
|
to underlying `stream_filter_append()` by default
|
||||||
|
(#15 by @Nyholm)
|
||||||
|
|
||||||
|
Certain filters (such as `convert.quoted-printable-encode`) do not accept
|
||||||
|
a filter parameter at all. If no explicit filter parameter is given, we no
|
||||||
|
longer pass a default `null` value.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$encode = Filter\fun('convert.quoted-printable-encode');
|
||||||
|
assert('t=C3=A4st' === $encode('täst'));
|
||||||
|
```
|
||||||
|
|
||||||
|
* Add examples and improve documentation
|
||||||
|
(#13 and #20 by @clue and #18 by @Nyholm)
|
||||||
|
|
||||||
|
* Improve test suite by adding PHPUnit to require-dev,
|
||||||
|
fix HHVM build for now again and ignore future HHVM build errors,
|
||||||
|
lock Travis distro so new future defaults will not break the build
|
||||||
|
and test on PHP 7.1
|
||||||
|
(#12, #14 and #19 by @clue and #16 by @Nyholm)
|
||||||
|
|
||||||
|
## 1.3.0 (2015-11-08)
|
||||||
|
|
||||||
|
* Feature: Support accessing built-in filters as callbacks
|
||||||
|
(#5 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
$fun = Filter\fun('zlib.deflate');
|
||||||
|
|
||||||
|
$ret = $fun('hello') . $fun('world') . $fun();
|
||||||
|
assert('helloworld' === gzinflate($ret));
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1.2.0 (2015-10-23)
|
||||||
|
|
||||||
|
* Feature: Invoke close event when closing filter (flush buffer)
|
||||||
|
(#9 by @clue)
|
||||||
|
|
||||||
|
## 1.1.0 (2015-10-22)
|
||||||
|
|
||||||
|
* Feature: Abort filter operation when catching an Exception
|
||||||
|
(#10 by @clue)
|
||||||
|
|
||||||
|
* Feature: Additional safeguards to prevent filter state corruption
|
||||||
|
(#7 by @clue)
|
||||||
|
|
||||||
|
## 1.0.0 (2015-10-18)
|
||||||
|
|
||||||
|
* First tagged release
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Christian Lück
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
+326
@@ -0,0 +1,326 @@
|
|||||||
|
# clue/stream-filter
|
||||||
|
|
||||||
|
[](https://github.com/clue/stream-filter/actions)
|
||||||
|
[](https://packagist.org/packages/clue/stream-filter)
|
||||||
|
|
||||||
|
A simple and modern approach to stream filtering in PHP
|
||||||
|
|
||||||
|
**Table of contents**
|
||||||
|
|
||||||
|
* [Why?](#why)
|
||||||
|
* [Support us](#support-us)
|
||||||
|
* [Usage](#usage)
|
||||||
|
* [append()](#append)
|
||||||
|
* [prepend()](#prepend)
|
||||||
|
* [fun()](#fun)
|
||||||
|
* [remove()](#remove)
|
||||||
|
* [Install](#install)
|
||||||
|
* [Tests](#tests)
|
||||||
|
* [License](#license)
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
PHP's stream filtering system is great!
|
||||||
|
|
||||||
|
It offers very powerful stream filtering options and comes with a useful set of built-in filters.
|
||||||
|
These filters can be used to easily and efficiently perform various transformations on-the-fly, such as:
|
||||||
|
|
||||||
|
* read from a gzip'ed input file,
|
||||||
|
* transcode from ISO-8859-1 (Latin1) to UTF-8,
|
||||||
|
* write to a bzip output file
|
||||||
|
* and much more.
|
||||||
|
|
||||||
|
But let's face it:
|
||||||
|
Its API is [*difficult to work with*](https://www.php.net/manual/en/php-user-filter.filter.php)
|
||||||
|
and its documentation is [*subpar*](https://stackoverflow.com/questions/27103269/what-is-a-bucket-brigade).
|
||||||
|
This combined means its powerful features are often neglected.
|
||||||
|
|
||||||
|
This project aims to make these features more accessible to a broader audience.
|
||||||
|
* **Lightweight, SOLID design** -
|
||||||
|
Provides a thin abstraction that is [*just good enough*](https://en.wikipedia.org/wiki/Principle_of_good_enough)
|
||||||
|
and does not get in your way.
|
||||||
|
Custom filters require trivial effort.
|
||||||
|
* **Good test coverage** -
|
||||||
|
Comes with an automated tests suite and is regularly tested in the *real world*
|
||||||
|
|
||||||
|
## Support us
|
||||||
|
|
||||||
|
We invest a lot of time developing, maintaining and updating our awesome
|
||||||
|
open-source projects. You can help us sustain this high-quality of our work by
|
||||||
|
[becoming a sponsor on GitHub](https://github.com/sponsors/clue). Sponsors get
|
||||||
|
numerous benefits in return, see our [sponsoring page](https://github.com/sponsors/clue)
|
||||||
|
for details.
|
||||||
|
|
||||||
|
Let's take these projects to the next level together! 🚀
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
This lightweight library consists only of a few simple functions.
|
||||||
|
All functions reside under the `Clue\StreamFilter` namespace.
|
||||||
|
|
||||||
|
The below examples refer to all functions with their fully-qualified names like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
Clue\StreamFilter\append(…);
|
||||||
|
```
|
||||||
|
|
||||||
|
As of PHP 5.6+ you can also import each required function into your code like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use function Clue\StreamFilter\append;
|
||||||
|
|
||||||
|
append(…);
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can also use an import statement similar to this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Clue\StreamFilter as Filter;
|
||||||
|
|
||||||
|
Filter\append(…);
|
||||||
|
```
|
||||||
|
|
||||||
|
### append()
|
||||||
|
|
||||||
|
The `append(resource<stream> $stream, callable $callback, int $read_write = STREAM_FILTER_ALL): resource<stream filter>` function can be used to
|
||||||
|
append a filter callback to the given stream.
|
||||||
|
|
||||||
|
Each stream can have a list of filters attached.
|
||||||
|
This function appends a filter to the end of this list.
|
||||||
|
|
||||||
|
If the given filter can not be added, it throws an `Exception`.
|
||||||
|
|
||||||
|
The `$stream` can be any valid stream resource, such as:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$stream = fopen('demo.txt', 'w+');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `$callback` should be a valid callable function which accepts
|
||||||
|
an individual chunk of data and should return the updated chunk:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$filter = Clue\StreamFilter\append($stream, function ($chunk) {
|
||||||
|
// will be called each time you read or write a $chunk to/from the stream
|
||||||
|
return $chunk;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
As such, you can also use native PHP functions or any other `callable`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
Clue\StreamFilter\append($stream, 'strtoupper');
|
||||||
|
|
||||||
|
// will write "HELLO" to the underlying stream
|
||||||
|
fwrite($stream, 'hello');
|
||||||
|
```
|
||||||
|
|
||||||
|
If the `$callback` accepts invocation without parameters,
|
||||||
|
then this signature will be invoked once ending (flushing) the filter:
|
||||||
|
|
||||||
|
```php
|
||||||
|
Clue\StreamFilter\append($stream, function ($chunk = null) {
|
||||||
|
if ($chunk === null) {
|
||||||
|
// will be called once ending the filter
|
||||||
|
return 'end';
|
||||||
|
}
|
||||||
|
// will be called each time you read or write a $chunk to/from the stream
|
||||||
|
return $chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
fclose($stream);
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: Legacy PHP versions (PHP < 5.4) do not support passing additional data
|
||||||
|
from the end signal handler if the stream is being closed.
|
||||||
|
|
||||||
|
If your callback throws an `Exception`, then the filter process will be aborted.
|
||||||
|
In order to play nice with PHP's stream handling,
|
||||||
|
the `Exception` will be transformed to a PHP warning instead:
|
||||||
|
|
||||||
|
```php
|
||||||
|
Clue\StreamFilter\append($stream, function ($chunk) {
|
||||||
|
throw new \RuntimeException('Unexpected chunk');
|
||||||
|
});
|
||||||
|
|
||||||
|
// raises an E_USER_WARNING with "Error invoking filter: Unexpected chunk"
|
||||||
|
fwrite($stream, 'hello');
|
||||||
|
```
|
||||||
|
|
||||||
|
The optional `$read_write` parameter can be used to only invoke the `$callback`
|
||||||
|
when either writing to the stream or only when reading from the stream:
|
||||||
|
|
||||||
|
```php
|
||||||
|
Clue\StreamFilter\append($stream, function ($chunk) {
|
||||||
|
// will be called each time you write to the stream
|
||||||
|
return $chunk;
|
||||||
|
}, STREAM_FILTER_WRITE);
|
||||||
|
|
||||||
|
Clue\StreamFilter\append($stream, function ($chunk) {
|
||||||
|
// will be called each time you read from the stream
|
||||||
|
return $chunk;
|
||||||
|
}, STREAM_FILTER_READ);
|
||||||
|
```
|
||||||
|
|
||||||
|
This function returns a filter resource which can be passed to [`remove()`](#remove).
|
||||||
|
|
||||||
|
> Note that once a filter has been added to stream, the stream can no longer be passed to
|
||||||
|
> [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php)
|
||||||
|
> (and family).
|
||||||
|
>
|
||||||
|
> > Warning: stream_select(): cannot cast a filtered stream on this system in {file} on line {line}
|
||||||
|
>
|
||||||
|
> This is due to limitations of PHP's stream filter support, as it can no longer reliably
|
||||||
|
> tell when the underlying stream resource is actually ready.
|
||||||
|
> As an alternative, consider calling `stream_select()` on the unfiltered stream and
|
||||||
|
> then pass the unfiltered data through the [`fun()`](#fun) function.
|
||||||
|
|
||||||
|
### prepend()
|
||||||
|
|
||||||
|
The `prepend(resource<stream> $stream, callable $callback, int $read_write = STREAM_FILTER_ALL): resource<stream filter>` function can be used to
|
||||||
|
prepend a filter callback to the given stream.
|
||||||
|
|
||||||
|
Each stream can have a list of filters attached.
|
||||||
|
This function prepends a filter to the start of this list.
|
||||||
|
|
||||||
|
If the given filter can not be added, it throws an `Exception`.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$filter = Clue\StreamFilter\prepend($stream, function ($chunk) {
|
||||||
|
// will be called each time you read or write a $chunk to/from the stream
|
||||||
|
return $chunk;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
This function returns a filter resource which can be passed to [`remove()`](#remove).
|
||||||
|
|
||||||
|
Except for the position in the list of filters, this function behaves exactly
|
||||||
|
like the [`append()`](#append) function.
|
||||||
|
For more details about its behavior, see also the [`append()`](#append) function.
|
||||||
|
|
||||||
|
### fun()
|
||||||
|
|
||||||
|
The `fun(string $filter, mixed $parameters = null): callable` function can be used to
|
||||||
|
create a filter function which uses the given built-in `$filter`.
|
||||||
|
|
||||||
|
PHP comes with a useful set of [built-in filters](https://www.php.net/manual/en/filters.php).
|
||||||
|
Using `fun()` makes accessing these as easy as passing an input string to filter
|
||||||
|
and getting the filtered output string.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$fun = Clue\StreamFilter\fun('string.rot13');
|
||||||
|
|
||||||
|
assert('grfg' === $fun('test'));
|
||||||
|
assert('test' === $fun($fun('test'));
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note that not all filter functions may be available depending
|
||||||
|
on installed PHP extensions and the PHP version in use.
|
||||||
|
In particular, [HHVM](https://hhvm.com/) may not offer the same filter functions
|
||||||
|
or parameters as Zend PHP.
|
||||||
|
Accessing an unknown filter function will result in a `RuntimeException`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
Clue\StreamFilter\fun('unknown'); // throws RuntimeException
|
||||||
|
```
|
||||||
|
|
||||||
|
Some filters may accept or require additional filter parameters – most
|
||||||
|
filters do not require filter parameters.
|
||||||
|
If given, the optional `$parameters` argument will be passed to the
|
||||||
|
underlying filter handler as-is.
|
||||||
|
In particular, note how *not passing* this parameter at all differs from
|
||||||
|
explicitly passing a `null` value (which many filters do not accept).
|
||||||
|
Please refer to the individual filter definition for more details.
|
||||||
|
For example, the `string.strip_tags` filter can be invoked like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$fun = Clue\StreamFilter\fun('string.strip_tags', '<a><b>');
|
||||||
|
|
||||||
|
$ret = $fun('<b>h<br>i</b>');
|
||||||
|
assert('<b>hi</b>' === $ret);
|
||||||
|
```
|
||||||
|
|
||||||
|
Under the hood, this function allocates a temporary memory stream, so it's
|
||||||
|
recommended to clean up the filter function after use.
|
||||||
|
Also, some filter functions (in particular the
|
||||||
|
[zlib compression filters](https://www.php.net/manual/en/filters.compression.php))
|
||||||
|
may use internal buffers and may emit a final data chunk on close.
|
||||||
|
The filter function can be closed by invoking without any arguments:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$fun = Clue\StreamFilter\fun('zlib.deflate');
|
||||||
|
|
||||||
|
$ret = $fun('hello') . $fun('world') . $fun();
|
||||||
|
assert('helloworld' === gzinflate($ret));
|
||||||
|
```
|
||||||
|
|
||||||
|
The filter function must not be used anymore after it has been closed.
|
||||||
|
Doing so will result in a `RuntimeException`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$fun = Clue\StreamFilter\fun('string.rot13');
|
||||||
|
$fun();
|
||||||
|
|
||||||
|
$fun('test'); // throws RuntimeException
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: If you're using the zlib compression filters, then you should be wary
|
||||||
|
about engine inconsistencies between different PHP versions and HHVM.
|
||||||
|
These inconsistencies exist in the underlying PHP engines and there's little we
|
||||||
|
can do about this in this library.
|
||||||
|
[Our test suite](tests/) contains several test cases that exhibit these issues.
|
||||||
|
If you feel some test case is missing or outdated, we're happy to accept PRs! :)
|
||||||
|
|
||||||
|
### remove()
|
||||||
|
|
||||||
|
The `remove(resource<stream filter> $filter): bool` function can be used to
|
||||||
|
remove a filter previously added via [`append()`](#append) or [`prepend()`](#prepend).
|
||||||
|
|
||||||
|
```php
|
||||||
|
$filter = Clue\StreamFilter\append($stream, function () {
|
||||||
|
// …
|
||||||
|
});
|
||||||
|
Clue\StreamFilter\remove($filter);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
The recommended way to install this library is [through Composer](https://getcomposer.org/).
|
||||||
|
[New to Composer?](https://getcomposer.org/doc/00-intro.md)
|
||||||
|
|
||||||
|
This project follows [SemVer](https://semver.org/).
|
||||||
|
This will install the latest supported version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ composer require clue/stream-filter:^1.7
|
||||||
|
```
|
||||||
|
|
||||||
|
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
|
||||||
|
|
||||||
|
This project aims to run on any platform and thus does not require any PHP
|
||||||
|
extensions and supports running on legacy PHP 5.3 through current PHP 8+ and
|
||||||
|
HHVM.
|
||||||
|
It's *highly recommended to use the latest supported PHP version* for this project.
|
||||||
|
Older PHP versions may suffer from a number of inconsistencies documented above.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
To run the test suite, you first need to clone this repo and then install all
|
||||||
|
dependencies [through Composer](https://getcomposer.org/):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ composer install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run the test suite, go to the project root and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ vendor/bin/phpunit
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is released under the permissive [MIT license](LICENSE).
|
||||||
|
|
||||||
|
> Did you know that I offer custom development services and issuing invoices for
|
||||||
|
sponsorships of releases and for contributions? Contact me (@clue) for details.
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "clue/stream-filter",
|
||||||
|
"description": "A simple and modern approach to stream filtering in PHP",
|
||||||
|
"keywords": ["stream", "callback", "filter", "php_user_filter", "stream_filter_append", "stream_filter_register", "bucket brigade"],
|
||||||
|
"homepage": "https://github.com/clue/stream-filter",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Christian Lück",
|
||||||
|
"email": "christian@clue.engineering"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Clue\\StreamFilter\\": "src/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/functions_include.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Clue\\Tests\\StreamFilter\\": "tests/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Clue\StreamFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @see append()
|
||||||
|
* @see prepend()
|
||||||
|
*/
|
||||||
|
class CallbackFilter extends \php_user_filter
|
||||||
|
{
|
||||||
|
private $callback;
|
||||||
|
private $closed = true;
|
||||||
|
private $supportsClose = false;
|
||||||
|
|
||||||
|
/** @return bool */
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function onCreate()
|
||||||
|
{
|
||||||
|
$this->closed = false;
|
||||||
|
|
||||||
|
if (!\is_callable($this->params)) {
|
||||||
|
throw new \InvalidArgumentException('No valid callback parameter given to stream_filter_(append|prepend)');
|
||||||
|
}
|
||||||
|
$this->callback = $this->params;
|
||||||
|
|
||||||
|
// callback supports end event if it accepts invocation without arguments
|
||||||
|
$ref = new \ReflectionFunction($this->callback);
|
||||||
|
$this->supportsClose = ($ref->getNumberOfRequiredParameters() === 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return void */
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function onClose()
|
||||||
|
{
|
||||||
|
$this->closed = true;
|
||||||
|
|
||||||
|
// callback supports closing and is not already closed
|
||||||
|
if ($this->supportsClose) {
|
||||||
|
$this->supportsClose = false;
|
||||||
|
// invoke without argument to signal end and discard resulting buffer
|
||||||
|
try {
|
||||||
|
\call_user_func($this->callback);
|
||||||
|
} catch (\Exception $ignored) {
|
||||||
|
// this might be called during engine shutdown, so it's not safe
|
||||||
|
// to raise any errors or exceptions here
|
||||||
|
// trigger_error('Error closing filter: ' . $ignored->getMessage(), E_USER_WARNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->callback = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return int */
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function filter($in, $out, &$consumed, $closing)
|
||||||
|
{
|
||||||
|
// concatenate whole buffer from input brigade
|
||||||
|
$data = '';
|
||||||
|
while ($bucket = \stream_bucket_make_writeable($in)) {
|
||||||
|
$consumed += $bucket->datalen;
|
||||||
|
$data .= $bucket->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip processing callback that already ended
|
||||||
|
if ($this->closed) {
|
||||||
|
return \PSFS_FEED_ME;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only invoke filter function if buffer is not empty
|
||||||
|
// this may skip flushing a closing filter
|
||||||
|
if ($data !== '') {
|
||||||
|
try {
|
||||||
|
$data = \call_user_func($this->callback, $data);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// exception should mark filter as closed
|
||||||
|
$this->onClose();
|
||||||
|
\trigger_error('Error invoking filter: ' . $e->getMessage(), \E_USER_WARNING);
|
||||||
|
|
||||||
|
return \PSFS_ERR_FATAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark filter as closed after processing closing chunk
|
||||||
|
if ($closing) {
|
||||||
|
$this->closed = true;
|
||||||
|
|
||||||
|
// callback supports closing and is not already closed
|
||||||
|
if ($this->supportsClose) {
|
||||||
|
$this->supportsClose = false;
|
||||||
|
|
||||||
|
// invoke without argument to signal end and append resulting buffer
|
||||||
|
try {
|
||||||
|
$data .= \call_user_func($this->callback);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\trigger_error('Error ending filter: ' . $e->getMessage(), \E_USER_WARNING);
|
||||||
|
|
||||||
|
return \PSFS_ERR_FATAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data !== '') {
|
||||||
|
// create a new bucket for writing the resulting buffer to the output brigade
|
||||||
|
// reusing an existing bucket turned out to be bugged in some environments (ancient PHP versions and HHVM)
|
||||||
|
$bucket = @\stream_bucket_new($this->stream, $data);
|
||||||
|
|
||||||
|
// legacy PHP versions (PHP < 5.4) do not support passing data from the event signal handler
|
||||||
|
// because closing the stream invalidates the stream and its stream bucket brigade before
|
||||||
|
// invoking the filter close handler.
|
||||||
|
if ($bucket !== false) {
|
||||||
|
\stream_bucket_append($out, $bucket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return \PSFS_PASS_ON;
|
||||||
|
}
|
||||||
|
}
|
||||||
+380
@@ -0,0 +1,380 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Clue\StreamFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a filter callback to the given stream.
|
||||||
|
*
|
||||||
|
* Each stream can have a list of filters attached.
|
||||||
|
* This function appends a filter to the end of this list.
|
||||||
|
*
|
||||||
|
* If the given filter can not be added, it throws an `Exception`.
|
||||||
|
*
|
||||||
|
* The `$stream` can be any valid stream resource, such as:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $stream = fopen('demo.txt', 'w+');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The `$callback` should be a valid callable function which accepts
|
||||||
|
* an individual chunk of data and should return the updated chunk:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $filter = Clue\StreamFilter\append($stream, function ($chunk) {
|
||||||
|
* // will be called each time you read or write a $chunk to/from the stream
|
||||||
|
* return $chunk;
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* As such, you can also use native PHP functions or any other `callable`:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* Clue\StreamFilter\append($stream, 'strtoupper');
|
||||||
|
*
|
||||||
|
* // will write "HELLO" to the underlying stream
|
||||||
|
* fwrite($stream, 'hello');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the `$callback` accepts invocation without parameters,
|
||||||
|
* then this signature will be invoked once ending (flushing) the filter:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* Clue\StreamFilter\append($stream, function ($chunk = null) {
|
||||||
|
* if ($chunk === null) {
|
||||||
|
* // will be called once ending the filter
|
||||||
|
* return 'end';
|
||||||
|
* }
|
||||||
|
* // will be called each time you read or write a $chunk to/from the stream
|
||||||
|
* return $chunk;
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* fclose($stream);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* > Note: Legacy PHP versions (PHP < 5.4) do not support passing additional data
|
||||||
|
* from the end signal handler if the stream is being closed.
|
||||||
|
*
|
||||||
|
* If your callback throws an `Exception`, then the filter process will be aborted.
|
||||||
|
* In order to play nice with PHP's stream handling,
|
||||||
|
* the `Exception` will be transformed to a PHP warning instead:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* Clue\StreamFilter\append($stream, function ($chunk) {
|
||||||
|
* throw new \RuntimeException('Unexpected chunk');
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // raises an E_USER_WARNING with "Error invoking filter: Unexpected chunk"
|
||||||
|
* fwrite($stream, 'hello');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The optional `$read_write` parameter can be used to only invoke the `$callback`
|
||||||
|
* when either writing to the stream or only when reading from the stream:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* Clue\StreamFilter\append($stream, function ($chunk) {
|
||||||
|
* // will be called each time you write to the stream
|
||||||
|
* return $chunk;
|
||||||
|
* }, STREAM_FILTER_WRITE);
|
||||||
|
*
|
||||||
|
* Clue\StreamFilter\append($stream, function ($chunk) {
|
||||||
|
* // will be called each time you read from the stream
|
||||||
|
* return $chunk;
|
||||||
|
* }, STREAM_FILTER_READ);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This function returns a filter resource which can be passed to [`remove()`](#remove).
|
||||||
|
*
|
||||||
|
* > Note that once a filter has been added to stream, the stream can no longer be passed to
|
||||||
|
* > [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php)
|
||||||
|
* > (and family).
|
||||||
|
* >
|
||||||
|
* > > Warning: stream_select(): cannot cast a filtered stream on this system in {file} on line {line}
|
||||||
|
* >
|
||||||
|
* > This is due to limitations of PHP's stream filter support, as it can no longer reliably
|
||||||
|
* > tell when the underlying stream resource is actually ready.
|
||||||
|
* > As an alternative, consider calling `stream_select()` on the unfiltered stream and
|
||||||
|
* > then pass the unfiltered data through the [`fun()`](#fun) function.
|
||||||
|
*
|
||||||
|
* @param resource $stream
|
||||||
|
* @param callable $callback
|
||||||
|
* @param int $read_write
|
||||||
|
* @return resource filter resource which can be used for `remove()`
|
||||||
|
* @throws \Exception on error
|
||||||
|
* @uses stream_filter_append()
|
||||||
|
*/
|
||||||
|
function append($stream, $callback, $read_write = STREAM_FILTER_ALL)
|
||||||
|
{
|
||||||
|
$errstr = '';
|
||||||
|
\set_error_handler(function ($_, $error) use (&$errstr) {
|
||||||
|
// Match errstr from PHP's warning message.
|
||||||
|
// stream_filter_append() expects parameter 1 to be resource,...
|
||||||
|
$errstr = $error; // @codeCoverageIgnore
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
$ret = \stream_filter_append($stream, register(), $read_write, $callback);
|
||||||
|
} catch (\TypeError $e) { // @codeCoverageIgnoreStart
|
||||||
|
// Throws TypeError on PHP 8.0+
|
||||||
|
\restore_error_handler();
|
||||||
|
throw $e;
|
||||||
|
} // @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
\restore_error_handler();
|
||||||
|
|
||||||
|
// PHP 8 throws above on type errors, older PHP and memory issues can throw here
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
if ($ret === false) {
|
||||||
|
throw new \RuntimeException('Unable to append filter: ' . $errstr);
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepend a filter callback to the given stream.
|
||||||
|
*
|
||||||
|
* Each stream can have a list of filters attached.
|
||||||
|
* This function prepends a filter to the start of this list.
|
||||||
|
*
|
||||||
|
* If the given filter can not be added, it throws an `Exception`.
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $filter = Clue\StreamFilter\prepend($stream, function ($chunk) {
|
||||||
|
* // will be called each time you read or write a $chunk to/from the stream
|
||||||
|
* return $chunk;
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This function returns a filter resource which can be passed to [`remove()`](#remove).
|
||||||
|
*
|
||||||
|
* Except for the position in the list of filters, this function behaves exactly
|
||||||
|
* like the [`append()`](#append) function.
|
||||||
|
* For more details about its behavior, see also the [`append()`](#append) function.
|
||||||
|
*
|
||||||
|
* @param resource $stream
|
||||||
|
* @param callable $callback
|
||||||
|
* @param int $read_write
|
||||||
|
* @return resource filter resource which can be used for `remove()`
|
||||||
|
* @throws \Exception on error
|
||||||
|
* @uses stream_filter_prepend()
|
||||||
|
*/
|
||||||
|
function prepend($stream, $callback, $read_write = STREAM_FILTER_ALL)
|
||||||
|
{
|
||||||
|
$errstr = '';
|
||||||
|
\set_error_handler(function ($_, $error) use (&$errstr) {
|
||||||
|
// Match errstr from PHP's warning message.
|
||||||
|
// stream_filter_prepend() expects parameter 1 to be resource,...
|
||||||
|
$errstr = $error; // @codeCoverageIgnore
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
$ret = \stream_filter_prepend($stream, register(), $read_write, $callback);
|
||||||
|
} catch (\TypeError $e) { // @codeCoverageIgnoreStart
|
||||||
|
// Throws TypeError on PHP 8.0+
|
||||||
|
\restore_error_handler();
|
||||||
|
throw $e;
|
||||||
|
} // @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
\restore_error_handler();
|
||||||
|
|
||||||
|
// PHP 8 throws above on type errors, older PHP and memory issues can throw here
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
if ($ret === false) {
|
||||||
|
throw new \RuntimeException('Unable to prepend filter: ' . $errstr);
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a filter function which uses the given built-in `$filter`.
|
||||||
|
*
|
||||||
|
* PHP comes with a useful set of [built-in filters](https://www.php.net/manual/en/filters.php).
|
||||||
|
* Using `fun()` makes accessing these as easy as passing an input string to filter
|
||||||
|
* and getting the filtered output string.
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $fun = Clue\StreamFilter\fun('string.rot13');
|
||||||
|
*
|
||||||
|
* assert('grfg' === $fun('test'));
|
||||||
|
* assert('test' === $fun($fun('test'));
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Please note that not all filter functions may be available depending
|
||||||
|
* on installed PHP extensions and the PHP version in use.
|
||||||
|
* In particular, [HHVM](https://hhvm.com/) may not offer the same filter functions
|
||||||
|
* or parameters as Zend PHP.
|
||||||
|
* Accessing an unknown filter function will result in a `RuntimeException`:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* Clue\StreamFilter\fun('unknown'); // throws RuntimeException
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Some filters may accept or require additional filter parameters – most
|
||||||
|
* filters do not require filter parameters.
|
||||||
|
* If given, the optional `$parameters` argument will be passed to the
|
||||||
|
* underlying filter handler as-is.
|
||||||
|
* In particular, note how *not passing* this parameter at all differs from
|
||||||
|
* explicitly passing a `null` value (which many filters do not accept).
|
||||||
|
* Please refer to the individual filter definition for more details.
|
||||||
|
* For example, the `string.strip_tags` filter can be invoked like this:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $fun = Clue\StreamFilter\fun('string.strip_tags', '<a><b>');
|
||||||
|
*
|
||||||
|
* $ret = $fun('<b>h<br>i</b>');
|
||||||
|
* assert('<b>hi</b>' === $ret);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Under the hood, this function allocates a temporary memory stream, so it's
|
||||||
|
* recommended to clean up the filter function after use.
|
||||||
|
* Also, some filter functions (in particular the
|
||||||
|
* [zlib compression filters](https://www.php.net/manual/en/filters.compression.php))
|
||||||
|
* may use internal buffers and may emit a final data chunk on close.
|
||||||
|
* The filter function can be closed by invoking without any arguments:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $fun = Clue\StreamFilter\fun('zlib.deflate');
|
||||||
|
*
|
||||||
|
* $ret = $fun('hello') . $fun('world') . $fun();
|
||||||
|
* assert('helloworld' === gzinflate($ret));
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The filter function must not be used anymore after it has been closed.
|
||||||
|
* Doing so will result in a `RuntimeException`:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $fun = Clue\StreamFilter\fun('string.rot13');
|
||||||
|
* $fun();
|
||||||
|
*
|
||||||
|
* $fun('test'); // throws RuntimeException
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* > Note: If you're using the zlib compression filters, then you should be wary
|
||||||
|
* about engine inconsistencies between different PHP versions and HHVM.
|
||||||
|
* These inconsistencies exist in the underlying PHP engines and there's little we
|
||||||
|
* can do about this in this library.
|
||||||
|
* [Our test suite](tests/) contains several test cases that exhibit these issues.
|
||||||
|
* If you feel some test case is missing or outdated, we're happy to accept PRs! :)
|
||||||
|
*
|
||||||
|
* @param string $filter built-in filter name. See stream_get_filters() or http://php.net/manual/en/filters.php
|
||||||
|
* @param mixed $parameters (optional) parameters to pass to the built-in filter as-is
|
||||||
|
* @return callable a filter callback which can be append()'ed or prepend()'ed
|
||||||
|
* @throws \RuntimeException on error
|
||||||
|
* @link http://php.net/manual/en/filters.php
|
||||||
|
* @see stream_get_filters()
|
||||||
|
* @see append()
|
||||||
|
*/
|
||||||
|
function fun($filter, $parameters = null)
|
||||||
|
{
|
||||||
|
$fp = \fopen('php://memory', 'w');
|
||||||
|
|
||||||
|
$errstr = '';
|
||||||
|
\set_error_handler(function ($_, $error) use (&$errstr) {
|
||||||
|
// Match errstr from PHP's warning message.
|
||||||
|
// stream_filter_append() expects parameter 1 to be resource,...
|
||||||
|
$errstr = $error;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (\func_num_args() === 1) {
|
||||||
|
$filter = \stream_filter_append($fp, $filter, \STREAM_FILTER_WRITE);
|
||||||
|
} else {
|
||||||
|
$filter = \stream_filter_append($fp, $filter, \STREAM_FILTER_WRITE, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
\restore_error_handler();
|
||||||
|
|
||||||
|
if ($filter === false) {
|
||||||
|
\fclose($fp);
|
||||||
|
throw new \RuntimeException('Unable to access built-in filter: ' . $errstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// append filter function which buffers internally
|
||||||
|
$buffer = '';
|
||||||
|
append($fp, function ($chunk) use (&$buffer) {
|
||||||
|
$buffer .= $chunk;
|
||||||
|
|
||||||
|
// always return empty string in order to skip actually writing to stream resource
|
||||||
|
return '';
|
||||||
|
}, \STREAM_FILTER_WRITE);
|
||||||
|
|
||||||
|
$closed = false;
|
||||||
|
|
||||||
|
return function ($chunk = null) use ($fp, $filter, &$buffer, &$closed) {
|
||||||
|
if ($closed) {
|
||||||
|
throw new \RuntimeException('Unable to perform operation on closed stream');
|
||||||
|
}
|
||||||
|
if ($chunk === null) {
|
||||||
|
$closed = true;
|
||||||
|
$buffer = '';
|
||||||
|
\fclose($fp);
|
||||||
|
return $buffer;
|
||||||
|
}
|
||||||
|
// initialize buffer and invoke filters by attempting to write to stream
|
||||||
|
$buffer = '';
|
||||||
|
\fwrite($fp, $chunk);
|
||||||
|
|
||||||
|
// buffer now contains everything the filter function returned
|
||||||
|
return $buffer;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a filter previously added via `append()` or `prepend()`.
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $filter = Clue\StreamFilter\append($stream, function () {
|
||||||
|
* // …
|
||||||
|
* });
|
||||||
|
* Clue\StreamFilter\remove($filter);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param resource $filter
|
||||||
|
* @return bool true on success or false on error
|
||||||
|
* @throws \RuntimeException on error
|
||||||
|
* @uses stream_filter_remove()
|
||||||
|
*/
|
||||||
|
function remove($filter)
|
||||||
|
{
|
||||||
|
$errstr = '';
|
||||||
|
\set_error_handler(function ($_, $error) use (&$errstr) {
|
||||||
|
// Match errstr from PHP's warning message.
|
||||||
|
// stream_filter_remove() expects parameter 1 to be resource,...
|
||||||
|
$errstr = $error;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
$ret = \stream_filter_remove($filter);
|
||||||
|
} catch (\TypeError $e) { // @codeCoverageIgnoreStart
|
||||||
|
// Throws TypeError on PHP 8.0+
|
||||||
|
\restore_error_handler();
|
||||||
|
throw $e;
|
||||||
|
} // @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
\restore_error_handler();
|
||||||
|
|
||||||
|
if ($ret === false) {
|
||||||
|
// PHP 8 throws above on type errors, older PHP and memory issues can throw here
|
||||||
|
throw new \RuntimeException('Unable to remove filter: ' . $errstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the callback filter and returns the resulting filter name
|
||||||
|
*
|
||||||
|
* There should be little reason to call this function manually.
|
||||||
|
*
|
||||||
|
* @return string filter name
|
||||||
|
* @uses CallbackFilter
|
||||||
|
*/
|
||||||
|
function register()
|
||||||
|
{
|
||||||
|
static $registered = null;
|
||||||
|
if ($registered === null) {
|
||||||
|
$registered = 'stream-callback';
|
||||||
|
\stream_filter_register($registered, __NAMESPACE__ . '\CallbackFilter');
|
||||||
|
}
|
||||||
|
return $registered;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Clue\StreamFilter;
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
if (!\function_exists(__NAMESPACE__ . '\\append')) {
|
||||||
|
require __DIR__ . '/functions.php';
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
Vendored
+579
@@ -0,0 +1,579 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see https://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see https://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
/** @var \Closure(string):void */
|
||||||
|
private static $includeFile;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $vendorDir;
|
||||||
|
|
||||||
|
// PSR-4
|
||||||
|
/**
|
||||||
|
* @var array<string, array<string, int>>
|
||||||
|
*/
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var array<string, list<string>>
|
||||||
|
*/
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
/**
|
||||||
|
* List of PSR-0 prefixes
|
||||||
|
*
|
||||||
|
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||||
|
*
|
||||||
|
* @var array<string, array<string, list<string>>>
|
||||||
|
*/
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $useIncludePath = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
private $classMap = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, bool>
|
||||||
|
*/
|
||||||
|
private $missingClasses = array();
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, self>
|
||||||
|
*/
|
||||||
|
private static $registeredLoaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|null $vendorDir
|
||||||
|
*/
|
||||||
|
public function __construct($vendorDir = null)
|
||||||
|
{
|
||||||
|
$this->vendorDir = $vendorDir;
|
||||||
|
self::initializeIncludeClosure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string> Array of classname => path
|
||||||
|
*/
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, string> $classMap Class to filename map
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 base directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
|
||||||
|
if (null === $this->vendorDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prepend) {
|
||||||
|
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||||
|
} else {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
|
||||||
|
if (null !== $this->vendorDir) {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return true|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
$includeFile = self::$includeFile;
|
||||||
|
$includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||||
|
*
|
||||||
|
* @return array<string, self>
|
||||||
|
*/
|
||||||
|
public static function getRegisteredLoaders()
|
||||||
|
{
|
||||||
|
return self::$registeredLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
* @param string $ext
|
||||||
|
* @return string|false
|
||||||
|
*/
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath . '\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function initializeIncludeClosure()
|
||||||
|
{
|
||||||
|
if (self::$includeFile !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
self::$includeFile = \Closure::bind(static function($file) {
|
||||||
|
include $file;
|
||||||
|
}, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
+359
@@ -0,0 +1,359 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer;
|
||||||
|
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
|
use Composer\Semver\VersionParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is copied in every Composer installed project and available to all
|
||||||
|
*
|
||||||
|
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||||
|
*
|
||||||
|
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||||
|
*
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class InstalledVersions
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var mixed[]|null
|
||||||
|
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||||
|
*/
|
||||||
|
private static $installed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool|null
|
||||||
|
*/
|
||||||
|
private static $canGetVendors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static $installedByVendor = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackages()
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
$packages[] = array_keys($installed['versions']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 === \count($packages)) {
|
||||||
|
return $packages[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names with a specific type e.g. 'library'
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackagesByType($type)
|
||||||
|
{
|
||||||
|
$packagesByType = array();
|
||||||
|
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
foreach ($installed['versions'] as $name => $package) {
|
||||||
|
if (isset($package['type']) && $package['type'] === $type) {
|
||||||
|
$packagesByType[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packagesByType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package is installed
|
||||||
|
*
|
||||||
|
* This also returns true if the package name is provided or replaced by another package
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @param bool $includeDevRequirements
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (isset($installed['versions'][$packageName])) {
|
||||||
|
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package satisfies a version constraint
|
||||||
|
*
|
||||||
|
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||||
|
*
|
||||||
|
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||||
|
*
|
||||||
|
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||||
|
* @param string $packageName
|
||||||
|
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||||
|
{
|
||||||
|
$constraint = $parser->parseConstraints((string) $constraint);
|
||||||
|
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||||
|
|
||||||
|
return $provided->matches($constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||||
|
*
|
||||||
|
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||||
|
* whether a given version of a package is installed, and not just whether it exists
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string Version constraint usable with composer/semver
|
||||||
|
*/
|
||||||
|
public static function getVersionRanges($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ranges = array();
|
||||||
|
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' || ', $ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getPrettyVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||||
|
*/
|
||||||
|
public static function getReference($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['reference'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||||
|
*/
|
||||||
|
public static function getInstallPath($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||||
|
*/
|
||||||
|
public static function getRootPackage()
|
||||||
|
{
|
||||||
|
$installed = self::getInstalled();
|
||||||
|
|
||||||
|
return $installed[0]['root'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw installed.php data for custom implementations
|
||||||
|
*
|
||||||
|
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||||
|
*/
|
||||||
|
public static function getRawData()
|
||||||
|
{
|
||||||
|
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
self::$installed = include __DIR__ . '/installed.php';
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||||
|
*
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
public static function getAllRawData()
|
||||||
|
{
|
||||||
|
return self::getInstalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lets you reload the static array from another file
|
||||||
|
*
|
||||||
|
* This is only useful for complex integrations in which a project needs to use
|
||||||
|
* this class but then also needs to execute another project's autoloader in process,
|
||||||
|
* and wants to ensure both projects have access to their version of installed.php.
|
||||||
|
*
|
||||||
|
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||||
|
* the data it needs from this class, then call reload() with
|
||||||
|
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||||
|
* the project in which it runs can then also use this class safely, without
|
||||||
|
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||||
|
*
|
||||||
|
* @param array[] $data A vendor/composer/installed.php data set
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||||
|
*/
|
||||||
|
public static function reload($data)
|
||||||
|
{
|
||||||
|
self::$installed = $data;
|
||||||
|
self::$installedByVendor = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static function getInstalled()
|
||||||
|
{
|
||||||
|
if (null === self::$canGetVendors) {
|
||||||
|
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed = array();
|
||||||
|
|
||||||
|
if (self::$canGetVendors) {
|
||||||
|
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||||
|
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir];
|
||||||
|
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||||
|
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||||
|
$required = require $vendorDir.'/composer/installed.php';
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir] = $required;
|
||||||
|
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||||
|
self::$installed = $installed[count($installed) - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||||
|
$required = require __DIR__ . '/installed.php';
|
||||||
|
self::$installed = $required;
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::$installed !== array()) {
|
||||||
|
$installed[] = self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed;
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||||
|
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||||
|
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
|
||||||
|
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
|
||||||
|
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
|
||||||
|
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
|
||||||
|
);
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_files.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
|
||||||
|
'9c67151ae59aff4788964ce8eb2a0f43' => $vendorDir . '/clue/stream-filter/src/functions_include.php',
|
||||||
|
'8cff32064859f4559445b89279f3199c' => $vendorDir . '/php-http/message/src/filters.php',
|
||||||
|
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
|
||||||
|
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
|
||||||
|
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
|
||||||
|
);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
);
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
|
||||||
|
'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
|
||||||
|
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
|
||||||
|
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
|
||||||
|
'InfluxDB2\\' => array($vendorDir . '/influxdata/influxdb-client-php/src/InfluxDB2'),
|
||||||
|
'Http\\Promise\\' => array($vendorDir . '/php-http/promise/src'),
|
||||||
|
'Http\\Message\\' => array($vendorDir . '/php-http/message/src'),
|
||||||
|
'Http\\Discovery\\' => array($vendorDir . '/php-http/discovery/src'),
|
||||||
|
'Http\\Client\\Common\\' => array($vendorDir . '/php-http/client-common/src'),
|
||||||
|
'Http\\Client\\' => array($vendorDir . '/php-http/httplug/src'),
|
||||||
|
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
|
||||||
|
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
|
||||||
|
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
|
||||||
|
'Clue\\StreamFilter\\' => array($vendorDir . '/clue/stream-filter/src'),
|
||||||
|
);
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
|
class ComposerAutoloaderInitc6b2a118695e0873d12f3e5a49047b2e
|
||||||
|
{
|
||||||
|
private static $loader;
|
||||||
|
|
||||||
|
public static function loadClassLoader($class)
|
||||||
|
{
|
||||||
|
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||||
|
require __DIR__ . '/ClassLoader.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Composer\Autoload\ClassLoader
|
||||||
|
*/
|
||||||
|
public static function getLoader()
|
||||||
|
{
|
||||||
|
if (null !== self::$loader) {
|
||||||
|
return self::$loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
require __DIR__ . '/platform_check.php';
|
||||||
|
|
||||||
|
spl_autoload_register(array('ComposerAutoloaderInitc6b2a118695e0873d12f3e5a49047b2e', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInitc6b2a118695e0873d12f3e5a49047b2e', 'loadClassLoader'));
|
||||||
|
|
||||||
|
require __DIR__ . '/autoload_static.php';
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInitc6b2a118695e0873d12f3e5a49047b2e::getInitializer($loader));
|
||||||
|
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
$filesToLoad = \Composer\Autoload\ComposerStaticInitc6b2a118695e0873d12f3e5a49047b2e::$files;
|
||||||
|
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||||
|
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||||
|
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||||
|
|
||||||
|
require $file;
|
||||||
|
}
|
||||||
|
}, null, null);
|
||||||
|
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||||
|
$requireFile($fileIdentifier, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
}
|
||||||
|
}
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInitc6b2a118695e0873d12f3e5a49047b2e
|
||||||
|
{
|
||||||
|
public static $files = array (
|
||||||
|
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
|
||||||
|
'9c67151ae59aff4788964ce8eb2a0f43' => __DIR__ . '/..' . '/clue/stream-filter/src/functions_include.php',
|
||||||
|
'8cff32064859f4559445b89279f3199c' => __DIR__ . '/..' . '/php-http/message/src/filters.php',
|
||||||
|
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
|
||||||
|
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
|
||||||
|
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'S' =>
|
||||||
|
array (
|
||||||
|
'Symfony\\Polyfill\\Php80\\' => 23,
|
||||||
|
'Symfony\\Component\\OptionsResolver\\' => 34,
|
||||||
|
),
|
||||||
|
'P' =>
|
||||||
|
array (
|
||||||
|
'Psr\\Http\\Message\\' => 17,
|
||||||
|
'Psr\\Http\\Client\\' => 16,
|
||||||
|
),
|
||||||
|
'I' =>
|
||||||
|
array (
|
||||||
|
'InfluxDB2\\' => 10,
|
||||||
|
),
|
||||||
|
'H' =>
|
||||||
|
array (
|
||||||
|
'Http\\Promise\\' => 13,
|
||||||
|
'Http\\Message\\' => 13,
|
||||||
|
'Http\\Discovery\\' => 15,
|
||||||
|
'Http\\Client\\Common\\' => 19,
|
||||||
|
'Http\\Client\\' => 12,
|
||||||
|
),
|
||||||
|
'G' =>
|
||||||
|
array (
|
||||||
|
'GuzzleHttp\\Psr7\\' => 16,
|
||||||
|
'GuzzleHttp\\Promise\\' => 19,
|
||||||
|
'GuzzleHttp\\' => 11,
|
||||||
|
),
|
||||||
|
'C' =>
|
||||||
|
array (
|
||||||
|
'Clue\\StreamFilter\\' => 18,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'Symfony\\Polyfill\\Php80\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
|
||||||
|
),
|
||||||
|
'Symfony\\Component\\OptionsResolver\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/options-resolver',
|
||||||
|
),
|
||||||
|
'Psr\\Http\\Message\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/psr/http-message/src',
|
||||||
|
1 => __DIR__ . '/..' . '/psr/http-factory/src',
|
||||||
|
),
|
||||||
|
'Psr\\Http\\Client\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/psr/http-client/src',
|
||||||
|
),
|
||||||
|
'InfluxDB2\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/influxdata/influxdb-client-php/src/InfluxDB2',
|
||||||
|
),
|
||||||
|
'Http\\Promise\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/php-http/promise/src',
|
||||||
|
),
|
||||||
|
'Http\\Message\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/php-http/message/src',
|
||||||
|
),
|
||||||
|
'Http\\Discovery\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/php-http/discovery/src',
|
||||||
|
),
|
||||||
|
'Http\\Client\\Common\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/php-http/client-common/src',
|
||||||
|
),
|
||||||
|
'Http\\Client\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/php-http/httplug/src',
|
||||||
|
),
|
||||||
|
'GuzzleHttp\\Psr7\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
|
||||||
|
),
|
||||||
|
'GuzzleHttp\\Promise\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
|
||||||
|
),
|
||||||
|
'GuzzleHttp\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
|
||||||
|
),
|
||||||
|
'Clue\\StreamFilter\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/clue/stream-filter/src',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $classMap = array (
|
||||||
|
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||||
|
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||||
|
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
|
||||||
|
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
|
||||||
|
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
|
||||||
|
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInitc6b2a118695e0873d12f3e5a49047b2e::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInitc6b2a118695e0873d12f3e5a49047b2e::$prefixDirsPsr4;
|
||||||
|
$loader->classMap = ComposerStaticInitc6b2a118695e0873d12f3e5a49047b2e::$classMap;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+1244
File diff suppressed because it is too large
Load Diff
Vendored
+215
@@ -0,0 +1,215 @@
|
|||||||
|
<?php return array(
|
||||||
|
'root' => array(
|
||||||
|
'name' => '__root__',
|
||||||
|
'pretty_version' => '1.0.0+no-version-set',
|
||||||
|
'version' => '1.0.0.0',
|
||||||
|
'reference' => NULL,
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev' => true,
|
||||||
|
),
|
||||||
|
'versions' => array(
|
||||||
|
'__root__' => array(
|
||||||
|
'pretty_version' => '1.0.0+no-version-set',
|
||||||
|
'version' => '1.0.0.0',
|
||||||
|
'reference' => NULL,
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'clue/stream-filter' => array(
|
||||||
|
'pretty_version' => 'v1.7.0',
|
||||||
|
'version' => '1.7.0.0',
|
||||||
|
'reference' => '049509fef80032cb3f051595029ab75b49a3c2f7',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../clue/stream-filter',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'guzzlehttp/guzzle' => array(
|
||||||
|
'pretty_version' => '7.8.1',
|
||||||
|
'version' => '7.8.1.0',
|
||||||
|
'reference' => '41042bc7ab002487b876a0683fc8dce04ddce104',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'guzzlehttp/promises' => array(
|
||||||
|
'pretty_version' => '2.0.2',
|
||||||
|
'version' => '2.0.2.0',
|
||||||
|
'reference' => 'bbff78d96034045e58e13dedd6ad91b5d1253223',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../guzzlehttp/promises',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'guzzlehttp/psr7' => array(
|
||||||
|
'pretty_version' => '2.6.2',
|
||||||
|
'version' => '2.6.2.0',
|
||||||
|
'reference' => '45b30f99ac27b5ca93cb4831afe16285f57b8221',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'influxdata/influxdb-client-php' => array(
|
||||||
|
'pretty_version' => '3.4.0',
|
||||||
|
'version' => '3.4.0.0',
|
||||||
|
'reference' => '9db0d74595cbca08d9e2ce59814fc967c1b36531',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../influxdata/influxdb-client-php',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'php-http/async-client-implementation' => array(
|
||||||
|
'dev_requirement' => false,
|
||||||
|
'provided' => array(
|
||||||
|
0 => '*',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'php-http/client-common' => array(
|
||||||
|
'pretty_version' => '2.7.1',
|
||||||
|
'version' => '2.7.1.0',
|
||||||
|
'reference' => '1e19c059b0e4d5f717bf5d524d616165aeab0612',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../php-http/client-common',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'php-http/client-implementation' => array(
|
||||||
|
'dev_requirement' => false,
|
||||||
|
'provided' => array(
|
||||||
|
0 => '*',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'php-http/discovery' => array(
|
||||||
|
'pretty_version' => '1.19.2',
|
||||||
|
'version' => '1.19.2.0',
|
||||||
|
'reference' => '61e1a1eb69c92741f5896d9e05fb8e9d7e8bb0cb',
|
||||||
|
'type' => 'composer-plugin',
|
||||||
|
'install_path' => __DIR__ . '/../php-http/discovery',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'php-http/httplug' => array(
|
||||||
|
'pretty_version' => '2.4.0',
|
||||||
|
'version' => '2.4.0.0',
|
||||||
|
'reference' => '625ad742c360c8ac580fcc647a1541d29e257f67',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../php-http/httplug',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'php-http/message' => array(
|
||||||
|
'pretty_version' => '1.16.0',
|
||||||
|
'version' => '1.16.0.0',
|
||||||
|
'reference' => '47a14338bf4ebd67d317bf1144253d7db4ab55fd',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../php-http/message',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'php-http/message-factory-implementation' => array(
|
||||||
|
'dev_requirement' => false,
|
||||||
|
'provided' => array(
|
||||||
|
0 => '1.0',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'php-http/promise' => array(
|
||||||
|
'pretty_version' => '1.3.0',
|
||||||
|
'version' => '1.3.0.0',
|
||||||
|
'reference' => '2916a606d3b390f4e9e8e2b8dd68581508be0f07',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../php-http/promise',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/http-client' => array(
|
||||||
|
'pretty_version' => '1.0.3',
|
||||||
|
'version' => '1.0.3.0',
|
||||||
|
'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../psr/http-client',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/http-client-implementation' => array(
|
||||||
|
'dev_requirement' => false,
|
||||||
|
'provided' => array(
|
||||||
|
0 => '*',
|
||||||
|
1 => '1.0',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'psr/http-factory' => array(
|
||||||
|
'pretty_version' => '1.0.2',
|
||||||
|
'version' => '1.0.2.0',
|
||||||
|
'reference' => 'e616d01114759c4c489f93b099585439f795fe35',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../psr/http-factory',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/http-factory-implementation' => array(
|
||||||
|
'dev_requirement' => false,
|
||||||
|
'provided' => array(
|
||||||
|
0 => '*',
|
||||||
|
1 => '1.0',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'psr/http-message' => array(
|
||||||
|
'pretty_version' => '2.0',
|
||||||
|
'version' => '2.0.0.0',
|
||||||
|
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../psr/http-message',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/http-message-implementation' => array(
|
||||||
|
'dev_requirement' => false,
|
||||||
|
'provided' => array(
|
||||||
|
0 => '*',
|
||||||
|
1 => '1.0',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'ralouphie/getallheaders' => array(
|
||||||
|
'pretty_version' => '3.0.3',
|
||||||
|
'version' => '3.0.3.0',
|
||||||
|
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../ralouphie/getallheaders',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'symfony/deprecation-contracts' => array(
|
||||||
|
'pretty_version' => 'v3.4.0',
|
||||||
|
'version' => '3.4.0.0',
|
||||||
|
'reference' => '7c3aff79d10325257a001fcf92d991f24fc967cf',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'symfony/options-resolver' => array(
|
||||||
|
'pretty_version' => 'v7.0.0',
|
||||||
|
'version' => '7.0.0.0',
|
||||||
|
'reference' => '700ff4096e346f54cb628ea650767c8130f1001f',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../symfony/options-resolver',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'symfony/polyfill-php80' => array(
|
||||||
|
'pretty_version' => 'v1.28.0',
|
||||||
|
'version' => '1.28.0.0',
|
||||||
|
'reference' => '6caa57379c4aec19c0a12a38b59b26487dcfe4b5',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// platform_check.php @generated by Composer
|
||||||
|
|
||||||
|
$issues = array();
|
||||||
|
|
||||||
|
if (!(PHP_VERSION_ID >= 80200)) {
|
||||||
|
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.2.0". You are running ' . PHP_VERSION . '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($issues) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger_error(
|
||||||
|
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
CHANGELOG
|
||||||
|
=========
|
||||||
|
|
||||||
|
The changelog is maintained for all Symfony contracts at the following URL:
|
||||||
|
https://github.com/symfony/contracts/blob/main/CHANGELOG.md
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020-present Fabien Potencier
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
Symfony Deprecation Contracts
|
||||||
|
=============================
|
||||||
|
|
||||||
|
A generic function and convention to trigger deprecation notices.
|
||||||
|
|
||||||
|
This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices.
|
||||||
|
|
||||||
|
By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component,
|
||||||
|
the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments.
|
||||||
|
|
||||||
|
The function requires at least 3 arguments:
|
||||||
|
- the name of the Composer package that is triggering the deprecation
|
||||||
|
- the version of the package that introduced the deprecation
|
||||||
|
- the message of the deprecation
|
||||||
|
- more arguments can be provided: they will be inserted in the message using `printf()` formatting
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```php
|
||||||
|
trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin');
|
||||||
|
```
|
||||||
|
|
||||||
|
This will generate the following message:
|
||||||
|
`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.`
|
||||||
|
|
||||||
|
While not recommended, the deprecation notices can be completely ignored by declaring an empty
|
||||||
|
`function trigger_deprecation() {}` in your application.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "symfony/deprecation-contracts",
|
||||||
|
"type": "library",
|
||||||
|
"description": "A generic function and convention to trigger deprecation notices",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"function.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.4-dev"
|
||||||
|
},
|
||||||
|
"thanks": {
|
||||||
|
"name": "symfony/contracts",
|
||||||
|
"url": "https://github.com/symfony/contracts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!function_exists('trigger_deprecation')) {
|
||||||
|
/**
|
||||||
|
* Triggers a silenced deprecation notice.
|
||||||
|
*
|
||||||
|
* @param string $package The name of the Composer package that is triggering the deprecation
|
||||||
|
* @param string $version The version of the package that introduced the deprecation
|
||||||
|
* @param string $message The message of the deprecation
|
||||||
|
* @param mixed ...$args Values to insert in the message using printf() formatting
|
||||||
|
*
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
function trigger_deprecation(string $package, string $version, string $message, mixed ...$args): void
|
||||||
|
{
|
||||||
|
@trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
CHANGELOG
|
||||||
|
=========
|
||||||
|
|
||||||
|
6.4
|
||||||
|
---
|
||||||
|
|
||||||
|
* Improve message with full path on invalid type in nested option
|
||||||
|
|
||||||
|
6.3
|
||||||
|
---
|
||||||
|
|
||||||
|
* Add `OptionsResolver::setIgnoreUndefined()` and `OptionConfigurator::ignoreUndefined()` to ignore not defined options while resolving
|
||||||
|
|
||||||
|
6.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* Remove `OptionsResolverIntrospector::getDeprecationMessage()`
|
||||||
|
|
||||||
|
5.3
|
||||||
|
---
|
||||||
|
|
||||||
|
* Add prototype definition for nested options
|
||||||
|
|
||||||
|
5.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added fluent configuration of options using `OptionResolver::define()`
|
||||||
|
* added `setInfo()` and `getInfo()` methods
|
||||||
|
* updated the signature of method `OptionsResolver::setDeprecated()` to `OptionsResolver::setDeprecation(string $option, string $package, string $version, $message)`
|
||||||
|
* deprecated `OptionsResolverIntrospector::getDeprecationMessage()`, use `OptionsResolverIntrospector::getDeprecation()` instead
|
||||||
|
|
||||||
|
5.0.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added argument `$triggerDeprecation` to `OptionsResolver::offsetGet()`
|
||||||
|
|
||||||
|
4.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added `OptionsResolver::addNormalizer` method
|
||||||
|
|
||||||
|
4.2.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added support for nested options definition
|
||||||
|
* added `setDeprecated` and `isDeprecated` methods
|
||||||
|
|
||||||
|
3.4.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added `OptionsResolverIntrospector` to inspect options definitions inside an `OptionsResolver` instance
|
||||||
|
* added array of types support in allowed types (e.g int[])
|
||||||
|
|
||||||
|
2.6.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* deprecated OptionsResolverInterface
|
||||||
|
* [BC BREAK] removed "array" type hint from OptionsResolverInterface methods
|
||||||
|
setRequired(), setAllowedValues(), addAllowedValues(), setAllowedTypes() and
|
||||||
|
addAllowedTypes()
|
||||||
|
* added OptionsResolver::setDefault()
|
||||||
|
* added OptionsResolver::hasDefault()
|
||||||
|
* added OptionsResolver::setNormalizer()
|
||||||
|
* added OptionsResolver::isRequired()
|
||||||
|
* added OptionsResolver::getRequiredOptions()
|
||||||
|
* added OptionsResolver::isMissing()
|
||||||
|
* added OptionsResolver::getMissingOptions()
|
||||||
|
* added OptionsResolver::setDefined()
|
||||||
|
* added OptionsResolver::isDefined()
|
||||||
|
* added OptionsResolver::getDefinedOptions()
|
||||||
|
* added OptionsResolver::remove()
|
||||||
|
* added OptionsResolver::clear()
|
||||||
|
* deprecated OptionsResolver::replaceDefaults()
|
||||||
|
* deprecated OptionsResolver::setOptional() in favor of setDefined()
|
||||||
|
* deprecated OptionsResolver::isKnown() in favor of isDefined()
|
||||||
|
* [BC BREAK] OptionsResolver::isRequired() returns true now if a required
|
||||||
|
option has a default value set
|
||||||
|
* [BC BREAK] merged Options into OptionsResolver and turned Options into an
|
||||||
|
interface
|
||||||
|
* deprecated Options::overload() (now in OptionsResolver)
|
||||||
|
* deprecated Options::set() (now in OptionsResolver)
|
||||||
|
* deprecated Options::get() (now in OptionsResolver)
|
||||||
|
* deprecated Options::has() (now in OptionsResolver)
|
||||||
|
* deprecated Options::replace() (now in OptionsResolver)
|
||||||
|
* [BC BREAK] Options::get() (now in OptionsResolver) can only be used within
|
||||||
|
lazy option/normalizer closures now
|
||||||
|
* [BC BREAK] removed Traversable interface from Options since using within
|
||||||
|
lazy option/normalizer closures resulted in exceptions
|
||||||
|
* [BC BREAK] removed Options::all() since using within lazy option/normalizer
|
||||||
|
closures resulted in exceptions
|
||||||
|
* [BC BREAK] OptionDefinitionException now extends LogicException instead of
|
||||||
|
RuntimeException
|
||||||
|
* [BC BREAK] normalizers are not executed anymore for unset options
|
||||||
|
* normalizers are executed after validating the options now
|
||||||
|
* [BC BREAK] an UndefinedOptionsException is now thrown instead of an
|
||||||
|
InvalidOptionsException when non-existing options are passed
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Debug;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\Exception\NoConfigurationException;
|
||||||
|
use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
||||||
|
*
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class OptionsResolverIntrospector
|
||||||
|
{
|
||||||
|
private \Closure $get;
|
||||||
|
|
||||||
|
public function __construct(OptionsResolver $optionsResolver)
|
||||||
|
{
|
||||||
|
$this->get = \Closure::bind(function ($property, $option, $message) {
|
||||||
|
/** @var OptionsResolver $this */
|
||||||
|
if (!$this->isDefined($option)) {
|
||||||
|
throw new UndefinedOptionsException(sprintf('The option "%s" does not exist.', $option));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\array_key_exists($option, $this->{$property})) {
|
||||||
|
throw new NoConfigurationException($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->{$property}[$option];
|
||||||
|
}, $optionsResolver, $optionsResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NoConfigurationException on no configured value
|
||||||
|
*/
|
||||||
|
public function getDefault(string $option): mixed
|
||||||
|
{
|
||||||
|
return ($this->get)('defaults', $option, sprintf('No default value was set for the "%s" option.', $option));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Closure[]
|
||||||
|
*
|
||||||
|
* @throws NoConfigurationException on no configured closures
|
||||||
|
*/
|
||||||
|
public function getLazyClosures(string $option): array
|
||||||
|
{
|
||||||
|
return ($this->get)('lazy', $option, sprintf('No lazy closures were set for the "%s" option.', $option));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*
|
||||||
|
* @throws NoConfigurationException on no configured types
|
||||||
|
*/
|
||||||
|
public function getAllowedTypes(string $option): array
|
||||||
|
{
|
||||||
|
return ($this->get)('allowedTypes', $option, sprintf('No allowed types were set for the "%s" option.', $option));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*
|
||||||
|
* @throws NoConfigurationException on no configured values
|
||||||
|
*/
|
||||||
|
public function getAllowedValues(string $option): array
|
||||||
|
{
|
||||||
|
return ($this->get)('allowedValues', $option, sprintf('No allowed values were set for the "%s" option.', $option));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NoConfigurationException on no configured normalizer
|
||||||
|
*/
|
||||||
|
public function getNormalizer(string $option): \Closure
|
||||||
|
{
|
||||||
|
return current($this->getNormalizers($option));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NoConfigurationException when no normalizer is configured
|
||||||
|
*/
|
||||||
|
public function getNormalizers(string $option): array
|
||||||
|
{
|
||||||
|
return ($this->get)('normalizers', $option, sprintf('No normalizer was set for the "%s" option.', $option));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NoConfigurationException on no configured deprecation
|
||||||
|
*/
|
||||||
|
public function getDeprecation(string $option): array
|
||||||
|
{
|
||||||
|
return ($this->get)('deprecated', $option, sprintf('No deprecation was set for the "%s" option.', $option));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when trying to read an option outside of or write it inside of
|
||||||
|
* {@link \Symfony\Component\OptionsResolver\Options::resolve()}.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class AccessException extends \LogicException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker interface for all exceptions thrown by the OptionsResolver component.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
interface ExceptionInterface extends \Throwable
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an argument is invalid.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when the value of an option does not match its validation rules.
|
||||||
|
*
|
||||||
|
* You should make sure a valid value is passed to the option.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class InvalidOptionsException extends InvalidArgumentException
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when a required option is missing.
|
||||||
|
*
|
||||||
|
* Add the option to the passed options array.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class MissingOptionsException extends InvalidArgumentException
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Exception;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\Debug\OptionsResolverIntrospector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when trying to introspect an option definition property
|
||||||
|
* for which no value was configured inside the OptionsResolver instance.
|
||||||
|
*
|
||||||
|
* @see OptionsResolverIntrospector
|
||||||
|
*
|
||||||
|
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
||||||
|
*/
|
||||||
|
class NoConfigurationException extends \RuntimeException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when trying to read an option that has no value set.
|
||||||
|
*
|
||||||
|
* When accessing optional options from within a lazy option or normalizer you should first
|
||||||
|
* check whether the optional option is set. You can do this with `isset($options['optional'])`.
|
||||||
|
* In contrast to the {@link UndefinedOptionsException}, this is a runtime exception that can
|
||||||
|
* occur when evaluating lazy options.
|
||||||
|
*
|
||||||
|
* @author Tobias Schultze <http://tobion.de>
|
||||||
|
*/
|
||||||
|
class NoSuchOptionException extends \OutOfBoundsException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when two lazy options have a cyclic dependency.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class OptionDefinitionException extends \LogicException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when an undefined option is passed.
|
||||||
|
*
|
||||||
|
* You should remove the options in question from your code or define them
|
||||||
|
* beforehand.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class UndefinedOptionsException extends InvalidArgumentException
|
||||||
|
{
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2004-present Fabien Potencier
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\Exception\AccessException;
|
||||||
|
|
||||||
|
final class OptionConfigurator
|
||||||
|
{
|
||||||
|
private string $name;
|
||||||
|
private OptionsResolver $resolver;
|
||||||
|
|
||||||
|
public function __construct(string $name, OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->resolver = $resolver;
|
||||||
|
$this->resolver->setDefined($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds allowed types for this option.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws AccessException If called from a lazy option or normalizer
|
||||||
|
*/
|
||||||
|
public function allowedTypes(string ...$types): static
|
||||||
|
{
|
||||||
|
$this->resolver->setAllowedTypes($this->name, $types);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets allowed values for this option.
|
||||||
|
*
|
||||||
|
* @param mixed ...$values One or more acceptable values/closures
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws AccessException If called from a lazy option or normalizer
|
||||||
|
*/
|
||||||
|
public function allowedValues(mixed ...$values): static
|
||||||
|
{
|
||||||
|
$this->resolver->setAllowedValues($this->name, $values);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default value for this option.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws AccessException If called from a lazy option or normalizer
|
||||||
|
*/
|
||||||
|
public function default(mixed $value): static
|
||||||
|
{
|
||||||
|
$this->resolver->setDefault($this->name, $value);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines an option configurator with the given name.
|
||||||
|
*/
|
||||||
|
public function define(string $option): self
|
||||||
|
{
|
||||||
|
return $this->resolver->define($option);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks this option as deprecated.
|
||||||
|
*
|
||||||
|
* @param string $package The name of the composer package that is triggering the deprecation
|
||||||
|
* @param string $version The version of the package that introduced the deprecation
|
||||||
|
* @param string|\Closure $message The deprecation message to use
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function deprecated(string $package, string $version, string|\Closure $message = 'The option "%name%" is deprecated.'): static
|
||||||
|
{
|
||||||
|
$this->resolver->setDeprecated($this->name, $package, $version, $message);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the normalizer for this option.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws AccessException If called from a lazy option or normalizer
|
||||||
|
*/
|
||||||
|
public function normalize(\Closure $normalizer): static
|
||||||
|
{
|
||||||
|
$this->resolver->setNormalizer($this->name, $normalizer);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks this option as required.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws AccessException If called from a lazy option or normalizer
|
||||||
|
*/
|
||||||
|
public function required(): static
|
||||||
|
{
|
||||||
|
$this->resolver->setRequired($this->name);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an info message for an option.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws AccessException If called from a lazy option or normalizer
|
||||||
|
*/
|
||||||
|
public function info(string $info): static
|
||||||
|
{
|
||||||
|
$this->resolver->setInfo($this->name, $info);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether ignore undefined options.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function ignoreUndefined(bool $ignore = true): static
|
||||||
|
{
|
||||||
|
$this->resolver->setIgnoreUndefined($ignore);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains resolved option values.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
* @author Tobias Schultze <http://tobion.de>
|
||||||
|
*/
|
||||||
|
interface Options extends \ArrayAccess, \Countable
|
||||||
|
{
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
+15
@@ -0,0 +1,15 @@
|
|||||||
|
OptionsResolver Component
|
||||||
|
=========================
|
||||||
|
|
||||||
|
The OptionsResolver component is `array_replace` on steroids. It allows you to
|
||||||
|
create an options system with required options, defaults, validation (type,
|
||||||
|
value), normalization and more.
|
||||||
|
|
||||||
|
Resources
|
||||||
|
---------
|
||||||
|
|
||||||
|
* [Documentation](https://symfony.com/doc/current/components/options_resolver.html)
|
||||||
|
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||||
|
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||||
|
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||||
|
in the [main Symfony repository](https://github.com/symfony/symfony)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "symfony/options-resolver",
|
||||||
|
"type": "library",
|
||||||
|
"description": "Provides an improved replacement for the array_replace PHP function",
|
||||||
|
"keywords": ["options", "config", "configuration"],
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"symfony/deprecation-contracts": "^2.5|^3"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": { "Symfony\\Component\\OptionsResolver\\": "" },
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev"
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020-present Fabien Potencier
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Polyfill\Php80;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ion Bazan <ion.bazan@gmail.com>
|
||||||
|
* @author Nico Oelgart <nicoswd@gmail.com>
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class Php80
|
||||||
|
{
|
||||||
|
public static function fdiv(float $dividend, float $divisor): float
|
||||||
|
{
|
||||||
|
return @($dividend / $divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get_debug_type($value): string
|
||||||
|
{
|
||||||
|
switch (true) {
|
||||||
|
case null === $value: return 'null';
|
||||||
|
case \is_bool($value): return 'bool';
|
||||||
|
case \is_string($value): return 'string';
|
||||||
|
case \is_array($value): return 'array';
|
||||||
|
case \is_int($value): return 'int';
|
||||||
|
case \is_float($value): return 'float';
|
||||||
|
case \is_object($value): break;
|
||||||
|
case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
|
||||||
|
default:
|
||||||
|
if (null === $type = @get_resource_type($value)) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('Unknown' === $type) {
|
||||||
|
$type = 'closed';
|
||||||
|
}
|
||||||
|
|
||||||
|
return "resource ($type)";
|
||||||
|
}
|
||||||
|
|
||||||
|
$class = \get_class($value);
|
||||||
|
|
||||||
|
if (false === strpos($class, '@')) {
|
||||||
|
return $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get_resource_id($res): int
|
||||||
|
{
|
||||||
|
if (!\is_resource($res) && null === @get_resource_type($res)) {
|
||||||
|
throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function preg_last_error_msg(): string
|
||||||
|
{
|
||||||
|
switch (preg_last_error()) {
|
||||||
|
case \PREG_INTERNAL_ERROR:
|
||||||
|
return 'Internal error';
|
||||||
|
case \PREG_BAD_UTF8_ERROR:
|
||||||
|
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
|
||||||
|
case \PREG_BAD_UTF8_OFFSET_ERROR:
|
||||||
|
return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
|
||||||
|
case \PREG_BACKTRACK_LIMIT_ERROR:
|
||||||
|
return 'Backtrack limit exhausted';
|
||||||
|
case \PREG_RECURSION_LIMIT_ERROR:
|
||||||
|
return 'Recursion limit exhausted';
|
||||||
|
case \PREG_JIT_STACKLIMIT_ERROR:
|
||||||
|
return 'JIT stack limit exhausted';
|
||||||
|
case \PREG_NO_ERROR:
|
||||||
|
return 'No error';
|
||||||
|
default:
|
||||||
|
return 'Unknown error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function str_contains(string $haystack, string $needle): bool
|
||||||
|
{
|
||||||
|
return '' === $needle || false !== strpos($haystack, $needle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function str_starts_with(string $haystack, string $needle): bool
|
||||||
|
{
|
||||||
|
return 0 === strncmp($haystack, $needle, \strlen($needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function str_ends_with(string $haystack, string $needle): bool
|
||||||
|
{
|
||||||
|
if ('' === $needle || $needle === $haystack) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('' === $haystack) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$needleLength = \strlen($needle);
|
||||||
|
|
||||||
|
return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Polyfill\Php80;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fedonyuk Anton <info@ensostudio.ru>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class PhpToken implements \Stringable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $line;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $pos;
|
||||||
|
|
||||||
|
public function __construct(int $id, string $text, int $line = -1, int $position = -1)
|
||||||
|
{
|
||||||
|
$this->id = $id;
|
||||||
|
$this->text = $text;
|
||||||
|
$this->line = $line;
|
||||||
|
$this->pos = $position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTokenName(): ?string
|
||||||
|
{
|
||||||
|
if ('UNKNOWN' === $name = token_name($this->id)) {
|
||||||
|
$name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int|string|array $kind
|
||||||
|
*/
|
||||||
|
public function is($kind): bool
|
||||||
|
{
|
||||||
|
foreach ((array) $kind as $value) {
|
||||||
|
if (\in_array($value, [$this->id, $this->text], true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isIgnorable(): bool
|
||||||
|
{
|
||||||
|
return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return (string) $this->text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return static[]
|
||||||
|
*/
|
||||||
|
public static function tokenize(string $code, int $flags = 0): array
|
||||||
|
{
|
||||||
|
$line = 1;
|
||||||
|
$position = 0;
|
||||||
|
$tokens = token_get_all($code, $flags);
|
||||||
|
foreach ($tokens as $index => $token) {
|
||||||
|
if (\is_string($token)) {
|
||||||
|
$id = \ord($token);
|
||||||
|
$text = $token;
|
||||||
|
} else {
|
||||||
|
[$id, $text, $line] = $token;
|
||||||
|
}
|
||||||
|
$tokens[$index] = new static($id, $text, $line, $position);
|
||||||
|
$position += \strlen($text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tokens;
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
Symfony Polyfill / Php80
|
||||||
|
========================
|
||||||
|
|
||||||
|
This component provides features added to PHP 8.0 core:
|
||||||
|
|
||||||
|
- [`Stringable`](https://php.net/stringable) interface
|
||||||
|
- [`fdiv`](https://php.net/fdiv)
|
||||||
|
- [`ValueError`](https://php.net/valueerror) class
|
||||||
|
- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class
|
||||||
|
- `FILTER_VALIDATE_BOOL` constant
|
||||||
|
- [`get_debug_type`](https://php.net/get_debug_type)
|
||||||
|
- [`PhpToken`](https://php.net/phptoken) class
|
||||||
|
- [`preg_last_error_msg`](https://php.net/preg_last_error_msg)
|
||||||
|
- [`str_contains`](https://php.net/str_contains)
|
||||||
|
- [`str_starts_with`](https://php.net/str_starts_with)
|
||||||
|
- [`str_ends_with`](https://php.net/str_ends_with)
|
||||||
|
- [`get_resource_id`](https://php.net/get_resource_id)
|
||||||
|
|
||||||
|
More information can be found in the
|
||||||
|
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
|
||||||
|
|
||||||
|
License
|
||||||
|
=======
|
||||||
|
|
||||||
|
This library is released under the [MIT license](LICENSE).
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_CLASS)]
|
||||||
|
final class Attribute
|
||||||
|
{
|
||||||
|
public const TARGET_CLASS = 1;
|
||||||
|
public const TARGET_FUNCTION = 2;
|
||||||
|
public const TARGET_METHOD = 4;
|
||||||
|
public const TARGET_PROPERTY = 8;
|
||||||
|
public const TARGET_CLASS_CONSTANT = 16;
|
||||||
|
public const TARGET_PARAMETER = 32;
|
||||||
|
public const TARGET_ALL = 63;
|
||||||
|
public const IS_REPEATABLE = 64;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $flags;
|
||||||
|
|
||||||
|
public function __construct(int $flags = self::TARGET_ALL)
|
||||||
|
{
|
||||||
|
$this->flags = $flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) {
|
||||||
|
class PhpToken extends Symfony\Polyfill\Php80\PhpToken
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID < 80000) {
|
||||||
|
interface Stringable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID < 80000) {
|
||||||
|
class UnhandledMatchError extends Error
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID < 80000) {
|
||||||
|
class ValueError extends Error
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Symfony\Polyfill\Php80 as p;
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID >= 80000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
|
||||||
|
define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('fdiv')) {
|
||||||
|
function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
|
||||||
|
}
|
||||||
|
if (!function_exists('preg_last_error_msg')) {
|
||||||
|
function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
|
||||||
|
}
|
||||||
|
if (!function_exists('str_contains')) {
|
||||||
|
function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
|
||||||
|
}
|
||||||
|
if (!function_exists('str_starts_with')) {
|
||||||
|
function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
|
||||||
|
}
|
||||||
|
if (!function_exists('str_ends_with')) {
|
||||||
|
function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
|
||||||
|
}
|
||||||
|
if (!function_exists('get_debug_type')) {
|
||||||
|
function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
|
||||||
|
}
|
||||||
|
if (!function_exists('get_resource_id')) {
|
||||||
|
function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "symfony/polyfill-php80",
|
||||||
|
"type": "library",
|
||||||
|
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
||||||
|
"keywords": ["polyfill", "shim", "compatibility", "portable"],
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ion Bazan",
|
||||||
|
"email": "ion.bazan@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": { "Symfony\\Polyfill\\Php80\\": "" },
|
||||||
|
"files": [ "bootstrap.php" ],
|
||||||
|
"classmap": [ "Resources/stubs" ]
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "1.28-dev"
|
||||||
|
},
|
||||||
|
"thanks": {
|
||||||
|
"name": "symfony/polyfill",
|
||||||
|
"url": "https://github.com/symfony/polyfill"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user