multitube php-ipfs

This commit is contained in:
qo-op 2021-03-20 01:33:02 +01:00
parent 2b107405b9
commit c6bb759a7a
1460 changed files with 143253 additions and 10 deletions

View File

@ -36,7 +36,7 @@ foreach ($videos as $v) {
<head>
<title>AstroCrowdBuster</title>
<link rel="stylesheet" href="crowdbunker.css" type="text/css" />
<link rel="icon" type="image/png" href="/astrocrowdbunker.png" />
<link rel="icon" type="image/png" href="./astrocrowdbunker.png" />
</head>
<body>

View File

@ -0,0 +1,5 @@
{
"require": {
"ipfs/php-client": "^1.4"
}
}

1881
www/multitube/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

7
www/multitube/vendor/autoload.php vendored Normal file
View File

@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitbf8c14254ed88976607b4d25d8ae4b79::getLoader();

1
www/multitube/vendor/bin/php-parse vendored Symbolic link
View File

@ -0,0 +1 @@
../nikic/php-parser/bin/php-parse

View File

@ -0,0 +1,2 @@
github: clue
custom: https://clue.engineering/support

View File

@ -0,0 +1,75 @@
# Changelog
## 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

View File

@ -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.

View File

@ -0,0 +1,323 @@
# clue/stream-filter [![Build Status](https://travis-ci.org/clue/php-stream-filter.svg?branch=master)](https://travis-ci.org/clue/php-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 assume you use an import statement similar to this:
```php
use Clue\StreamFilter as Filter;
Filter\append(…);
```
Alternatively, you can also refer to them with their fully-qualified name:
```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(…);
```
### 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 = Filter\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
Filter\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
Filter\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
Filter\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
Filter\append($stream, function ($chunk) {
// will be called each time you write to the stream
return $chunk;
}, STREAM_FILTER_WRITE);
Filter\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 = Filter\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 = Filter\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
Filter\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 = Filter\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 = Filter\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 = Filter\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 = Filter\append($stream, function () {
// …
});
Filter\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.5
```
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 7+ and
HHVM.
It's *highly recommended to use PHP 7+* 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
$ php 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.

View File

@ -0,0 +1,26 @@
{
"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/php-stream-filter",
"license": "MIT",
"authors": [
{
"name": "Christian Lück",
"email": "christian@clue.engineering"
}
],
"require": {
"php": ">=5.3"
},
"require-dev": {
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36"
},
"autoload": {
"psr-4": { "Clue\\StreamFilter\\": "src/" },
"files": [ "src/functions_include.php" ]
},
"autoload-dev": {
"psr-4": { "Clue\\Tests\\StreamFilter\\": "tests/" }
}
}

View File

@ -0,0 +1,114 @@
<?php
namespace Clue\StreamFilter;
/**
* @internal
* @see append()
* @see prepend()
*/
class CallbackFilter extends \php_user_filter
{
private $callback;
private $closed = true;
private $supportsClose = false;
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;
}
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;
}
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;
}
}

View File

@ -0,0 +1,327 @@
<?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 = Filter\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
* Filter\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
* Filter\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
* Filter\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
* Filter\append($stream, function ($chunk) {
* // will be called each time you write to the stream
* return $chunk;
* }, STREAM_FILTER_WRITE);
*
* Filter\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)
{
$ret = @\stream_filter_append($stream, register(), $read_write, $callback);
// PHP 8 throws above on type errors, older PHP and memory issues can throw here
// @codeCoverageIgnoreStart
if ($ret === false) {
$error = \error_get_last() + array('message' => '');
throw new \RuntimeException('Unable to append filter: ' . $error['message']);
}
// @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 = Filter\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)
{
$ret = @\stream_filter_prepend($stream, register(), $read_write, $callback);
// PHP 8 throws above on type errors, older PHP and memory issues can throw here
// @codeCoverageIgnoreStart
if ($ret === false) {
$error = \error_get_last() + array('message' => '');
throw new \RuntimeException('Unable to prepend filter: ' . $error['message']);
}
// @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 = Filter\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
* Filter\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 = Filter\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 = Filter\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 = Filter\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');
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);
}
if ($filter === false) {
\fclose($fp);
$error = \error_get_last() + array('message' => '');
throw new \RuntimeException('Unable to access built-in filter: ' . $error['message']);
}
// 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 = Filter\append($stream, function () {
* // …
* });
* Filter\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)
{
if (@\stream_filter_remove($filter) === false) {
// PHP 8 throws above on type errors, older PHP and memory issues can throw here
$error = \error_get_last();
throw new \RuntimeException('Unable to remove filter: ' . $error['message']);
}
}
/**
* 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;
}

View File

@ -0,0 +1,6 @@
<?php
// @codeCoverageIgnoreStart
if (!\function_exists('Clue\\StreamFilter\\append')) {
require __DIR__ . '/functions.php';
}

View File

@ -0,0 +1,445 @@
<?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 http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
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 array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $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 array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $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] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $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 array|string $paths The PSR-0 base directories
*/
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 array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
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
*/
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
*/
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
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $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
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* 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;
}
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;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}

56
www/multitube/vendor/composer/LICENSE vendored Normal file
View File

@ -0,0 +1,56 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: Composer
Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be>
Source: https://github.com/composer/composer
Files: *
Copyright: 2016, Nils Adermann <naderman@naderman.de>
2016, Jordi Boggiano <j.boggiano@seld.be>
License: Expat
Files: src/Composer/Util/TlsHelper.php
Copyright: 2016, Nils Adermann <naderman@naderman.de>
2016, Jordi Boggiano <j.boggiano@seld.be>
2013, Evan Coury <me@evancoury.com>
License: Expat and BSD-2-Clause
License: BSD-2-Clause
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
.
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License: Expat
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.

View File

@ -0,0 +1,14 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.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',
);

View File

@ -0,0 +1,16 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'9c67151ae59aff4788964ce8eb2a0f43' => $vendorDir . '/clue/stream-filter/src/functions_include.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'8cff32064859f4559445b89279f3199c' => $vendorDir . '/php-http/message/src/filters.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
);

View File

@ -0,0 +1,11 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Pimple' => array($vendorDir . '/pimple/pimple/src'),
'Camel' => array($vendorDir . '/mattketmo/camel/src'),
);

View File

@ -0,0 +1,36 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'),
'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
'Symfony\\Component\\DomCrawler\\' => array($vendorDir . '/symfony/dom-crawler'),
'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'),
'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'),
'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
'IPFS\\' => array($vendorDir . '/ipfs/php-client/src'),
'Http\\Promise\\' => array($vendorDir . '/php-http/promise/src'),
'Http\\Message\\MultipartStream\\' => array($vendorDir . '/php-http/multipart-stream-builder/src'),
'Http\\Message\\' => array($vendorDir . '/php-http/message/src', $vendorDir . '/php-http/message-factory/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'),
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib/Doctrine/Common/Lexer'),
'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'),
'Clue\\StreamFilter\\' => array($vendorDir . '/clue/stream-filter/src'),
'ArgumentsResolver\\' => array($vendorDir . '/rybakit/arguments-resolver/src'),
);

View File

@ -0,0 +1,70 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitbf8c14254ed88976607b4d25d8ae4b79
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitbf8c14254ed88976607b4d25d8ae4b79', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitbf8c14254ed88976607b4d25d8ae4b79', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitbf8c14254ed88976607b4d25d8ae4b79::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInitbf8c14254ed88976607b4d25d8ae4b79::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequirebf8c14254ed88976607b4d25d8ae4b79($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequirebf8c14254ed88976607b4d25d8ae4b79($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View File

@ -0,0 +1,226 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInitbf8c14254ed88976607b4d25d8ae4b79
{
public static $files = array (
'9c67151ae59aff4788964ce8eb2a0f43' => __DIR__ . '/..' . '/clue/stream-filter/src/functions_include.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'8cff32064859f4559445b89279f3199c' => __DIR__ . '/..' . '/php-http/message/src/filters.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
);
public static $prefixLengthsPsr4 = array (
'p' =>
array (
'phpDocumentor\\Reflection\\' => 25,
),
'W' =>
array (
'Webmozart\\Assert\\' => 17,
),
'S' =>
array (
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Php73\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Component\\Process\\' => 26,
'Symfony\\Component\\OptionsResolver\\' => 34,
'Symfony\\Component\\DomCrawler\\' => 29,
'Symfony\\Component\\Debug\\' => 24,
'Symfony\\Component\\CssSelector\\' => 30,
'Symfony\\Component\\Console\\' => 26,
),
'P' =>
array (
'Psr\\Log\\' => 8,
'Psr\\Http\\Message\\' => 17,
'Psr\\Container\\' => 14,
'PhpParser\\' => 10,
),
'I' =>
array (
'IPFS\\' => 5,
),
'H' =>
array (
'Http\\Promise\\' => 13,
'Http\\Message\\MultipartStream\\' => 29,
'Http\\Message\\' => 13,
'Http\\Discovery\\' => 15,
'Http\\Client\\Common\\' => 19,
'Http\\Client\\' => 12,
),
'D' =>
array (
'Doctrine\\Common\\Lexer\\' => 22,
'Doctrine\\Common\\Annotations\\' => 28,
),
'C' =>
array (
'Clue\\StreamFilter\\' => 18,
),
'A' =>
array (
'ArgumentsResolver\\' => 18,
),
);
public static $prefixDirsPsr4 = array (
'phpDocumentor\\Reflection\\' =>
array (
0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src',
1 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src',
2 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src',
),
'Webmozart\\Assert\\' =>
array (
0 => __DIR__ . '/..' . '/webmozart/assert/src',
),
'Symfony\\Polyfill\\Php80\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Polyfill\\Php73\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php73',
),
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'Symfony\\Component\\Process\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/process',
),
'Symfony\\Component\\OptionsResolver\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/options-resolver',
),
'Symfony\\Component\\DomCrawler\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/dom-crawler',
),
'Symfony\\Component\\Debug\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/debug',
),
'Symfony\\Component\\CssSelector\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/css-selector',
),
'Symfony\\Component\\Console\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/console',
),
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
),
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-factory/src',
1 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Psr\\Container\\' =>
array (
0 => __DIR__ . '/..' . '/psr/container/src',
),
'PhpParser\\' =>
array (
0 => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser',
),
'IPFS\\' =>
array (
0 => __DIR__ . '/..' . '/ipfs/php-client/src',
),
'Http\\Promise\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/promise/src',
),
'Http\\Message\\MultipartStream\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/multipart-stream-builder/src',
),
'Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/message/src',
1 => __DIR__ . '/..' . '/php-http/message-factory/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',
),
'Doctrine\\Common\\Lexer\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/lexer/lib/Doctrine/Common/Lexer',
),
'Doctrine\\Common\\Annotations\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/annotations/lib/Doctrine/Common/Annotations',
),
'Clue\\StreamFilter\\' =>
array (
0 => __DIR__ . '/..' . '/clue/stream-filter/src',
),
'ArgumentsResolver\\' =>
array (
0 => __DIR__ . '/..' . '/rybakit/arguments-resolver/src',
),
);
public static $prefixesPsr0 = array (
'P' =>
array (
'Pimple' =>
array (
0 => __DIR__ . '/..' . '/pimple/pimple/src',
),
),
'C' =>
array (
'Camel' =>
array (
0 => __DIR__ . '/..' . '/mattketmo/camel/src',
),
),
);
public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.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 = ComposerStaticInitbf8c14254ed88976607b4d25d8ae4b79::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitbf8c14254ed88976607b4d25d8ae4b79::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInitbf8c14254ed88976607b4d25d8ae4b79::$prefixesPsr0;
$loader->classMap = ComposerStaticInitbf8c14254ed88976607b4d25d8ae4b79::$classMap;
}, null, ClassLoader::class);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,162 @@
## Changelog
### 1.6.1
This release fixes an issue in which annotations such as `@foo-bar`
and `@foo-` were incorrectly recognised as valid, and both erroneously
parsed as `@foo`.
Any annotation with `@name-*` format will now silently be ignored,
allowing vendor-specific annotations to be prefixed with the tool
name.
Total issues resolved: **3**
- [165: Update the composer branch alias](https://github.com/doctrine/annotations/pull/165) thanks to @mikeSimonson
- [209: Change Annotation::value typehint to mixed](https://github.com/doctrine/annotations/pull/209) thanks to @malarzm
- [257: Skip parsing annotations containing dashes, such as `@Foo-bar`, or `@Foo-`](https://github.com/doctrine/annotations/pull/257) thanks to @Ocramius
### 1.6.0
This release brings a new endpoint that make sure that you can't shoot yourself in the foot by calling ```registerLoader``` multiple times and a few tests improvements.
Total issues resolved: **7**
- [145: Memory leak in AnnotationRegistry::registerLoader() when called multiple times](https://github.com/doctrine/annotations/issues/145) thanks to @TriAnMan
- [146: Import error on @experimental Annotation](https://github.com/doctrine/annotations/issues/146) thanks to @aturki
- [147: Ignoring @experimental annotation used by Symfony 3.3 CacheAdapter](https://github.com/doctrine/annotations/pull/147) thanks to @aturki
- [151: Remove duplicate code in `DCOM58Test`](https://github.com/doctrine/annotations/pull/151) thanks to @tuanphpvn
- [161: Prevent loading class&#95;exists multiple times](https://github.com/doctrine/annotations/pull/161) thanks to @jrjohnson
- [162: Add registerUniqueLoader to AnnotationRegistry](https://github.com/doctrine/annotations/pull/162) thanks to @jrjohnson
- [163: Use assertDirectoryExists and assertDirectoryNotExists](https://github.com/doctrine/annotations/pull/163) thanks to @carusogabriel
Thanks to everyone involved in this release.
### 1.5.0
This release increments the minimum supported PHP version to 7.1.0.
Also, HHVM official support has been dropped.
Some noticeable performance improvements to annotation autoloading
have been applied, making failed annotation autoloading less heavy
on the filesystem access.
- [133: Add @throws annotation in AnnotationReader#__construct()](https://github.com/doctrine/annotations/issues/133) thanks to @SenseException
- [134: Require PHP 7.1, drop HHVM support](https://github.com/doctrine/annotations/issues/134) thanks to @lcobucci
- [135: Prevent the same loader from being registered twice](https://github.com/doctrine/annotations/issues/135) thanks to @jrjohnson
- [137: #135 optimise multiple class load attempts in AnnotationRegistry](https://github.com/doctrine/annotations/issues/137) thanks to @Ocramius
### 1.4.0
This release fix an issue were some annotations could be not loaded if the namespace in the use statement started with a backslash.
It also update the tests and drop the support for php 5.X
- [115: Missing annotations with the latest composer version](https://github.com/doctrine/annotations/issues/115) thanks to @pascalporedda
- [120: Missing annotations with the latest composer version](https://github.com/doctrine/annotations/pull/120) thanks to @gnat42
- [121: Adding a more detailed explanation of the test](https://github.com/doctrine/annotations/pull/121) thanks to @mikeSimonson
- [101: Test annotation parameters containing space](https://github.com/doctrine/annotations/pull/101) thanks to @mikeSimonson
- [111: Cleanup: move to correct phpunit assertions](https://github.com/doctrine/annotations/pull/111) thanks to @Ocramius
- [112: Removes support for PHP 5.x](https://github.com/doctrine/annotations/pull/112) thanks to @railto
- [113: bumped phpunit version to 5.7](https://github.com/doctrine/annotations/pull/113) thanks to @gabbydgab
- [114: Enhancement: Use SVG Travis build badge](https://github.com/doctrine/annotations/pull/114) thanks to @localheinz
- [118: Integrating PHPStan](https://github.com/doctrine/annotations/pull/118) thanks to @ondrejmirtes
### 1.3.1 - 2016-12-30
This release fixes an issue with ignored annotations that were already
autoloaded, causing the `SimpleAnnotationReader` to pick them up
anyway. [#110](https://github.com/doctrine/annotations/pull/110)
Additionally, an issue was fixed in the `CachedReader`, which was
not correctly checking the freshness of cached annotations when
traits were defined on a class. [#105](https://github.com/doctrine/annotations/pull/105)
Total issues resolved: **2**
- [105: Return single max timestamp](https://github.com/doctrine/annotations/pull/105)
- [110: setIgnoreNotImportedAnnotations(true) didn&rsquo;t work for existing classes](https://github.com/doctrine/annotations/pull/110)
### 1.3.0
This release introduces a PHP version bump. `doctrine/annotations` now requires PHP
5.6 or later to be installed.
A series of additional improvements have been introduced:
* support for PHP 7 "grouped use statements"
* support for ignoring entire namespace names
via `Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredNamespace()` and
`Doctrine\Common\Annotations\DocParser::setIgnoredAnnotationNamespaces()`. This will
allow you to ignore annotations from namespaces that you cannot autoload
* testing all parent classes and interfaces when checking if the annotation cache
in the `CachedReader` is fresh
* simplifying the cache keys used by the `CachedReader`: keys are no longer artificially
namespaced, since `Doctrine\Common\Cache` already supports that
* corrected parsing of multibyte strings when `mbstring.func_overload` is enabled
* corrected parsing of annotations when `"\t"` is put before the first annotation
in a docblock
* allow skipping non-imported annotations when a custom `DocParser` is passed to
the `AnnotationReader` constructor
Total issues resolved: **15**
- [45: DocParser can now ignore whole namespaces](https://github.com/doctrine/annotations/pull/45)
- [57: Switch to the docker-based infrastructure on Travis](https://github.com/doctrine/annotations/pull/57)
- [59: opcache.load&#95;comments has been removed from PHP 7](https://github.com/doctrine/annotations/pull/59)
- [62: &#91;CachedReader&#92; Test traits and parent class to see if cache is fresh](https://github.com/doctrine/annotations/pull/62)
- [65: Remove cache salt making key unnecessarily long](https://github.com/doctrine/annotations/pull/65)
- [66: Fix of incorrect parsing multibyte strings](https://github.com/doctrine/annotations/pull/66)
- [68: Annotations that are indented by tab are not processed.](https://github.com/doctrine/annotations/issues/68)
- [69: Support for Group Use Statements](https://github.com/doctrine/annotations/pull/69)
- [70: Allow tab character before first annotation in DocBlock](https://github.com/doctrine/annotations/pull/70)
- [74: Ignore not registered annotations fix](https://github.com/doctrine/annotations/pull/74)
- [92: Added tests for AnnotationRegistry class.](https://github.com/doctrine/annotations/pull/92)
- [96: Fix/#62 check trait and parent class ttl in annotations](https://github.com/doctrine/annotations/pull/96)
- [97: Feature - #45 - allow ignoring entire namespaces](https://github.com/doctrine/annotations/pull/97)
- [98: Enhancement/#65 remove cache salt from cached reader](https://github.com/doctrine/annotations/pull/98)
- [99: Fix - #70 - allow tab character before first annotation in docblock](https://github.com/doctrine/annotations/pull/99)
### 1.2.4
Total issues resolved: **1**
- [51: FileCacheReader::saveCacheFile::unlink fix](https://github.com/doctrine/annotations/pull/51)
### 1.2.3
Total issues resolved: [**2**](https://github.com/doctrine/annotations/milestones/v1.2.3)
- [49: #46 - applying correct `chmod()` to generated cache file](https://github.com/doctrine/annotations/pull/49)
- [50: Hotfix: match escaped quotes (revert #44)](https://github.com/doctrine/annotations/pull/50)
### 1.2.2
Total issues resolved: **4**
- [43: Exclude files from distribution with .gitattributes](https://github.com/doctrine/annotations/pull/43)
- [44: Update DocLexer.php](https://github.com/doctrine/annotations/pull/44)
- [46: A plain &quot;file&#95;put&#95;contents&quot; can cause havoc](https://github.com/doctrine/annotations/pull/46)
- [48: Deprecating the `FileCacheReader` in 1.2.2: will be removed in 2.0.0](https://github.com/doctrine/annotations/pull/48)
### 1.2.1
Total issues resolved: **4**
- [38: fixes doctrine/common#326](https://github.com/doctrine/annotations/pull/38)
- [39: Remove superfluous NS](https://github.com/doctrine/annotations/pull/39)
- [41: Warn if load_comments is not enabled.](https://github.com/doctrine/annotations/pull/41)
- [42: Clean up unused uses](https://github.com/doctrine/annotations/pull/42)
### 1.2.0
* HHVM support
* Allowing dangling comma in annotations
* Excluded annotations are no longer autoloaded
* Importing namespaces also in traits
* Added support for `::class` 5.5-style constant, works also in 5.3 and 5.4
### 1.1.0
* Add Exception when ZendOptimizer+ or Opcache is configured to drop comments

View File

@ -0,0 +1,19 @@
Copyright (c) 2006-2013 Doctrine Project
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.

View File

@ -0,0 +1,22 @@
# Doctrine Annotations
[![Build Status](https://github.com/doctrine/annotations/workflows/Continuous%20Integration/badge.svg?label=build)](https://github.com/doctrine/persistence/actions)
[![Dependency Status](https://www.versioneye.com/package/php--doctrine--annotations/badge.png)](https://www.versioneye.com/package/php--doctrine--annotations)
[![Reference Status](https://www.versioneye.com/php/doctrine:annotations/reference_badge.svg)](https://www.versioneye.com/php/doctrine:annotations/references)
[![Total Downloads](https://poser.pugx.org/doctrine/annotations/downloads.png)](https://packagist.org/packages/doctrine/annotations)
[![Latest Stable Version](https://img.shields.io/packagist/v/doctrine/annotations.svg?label=stable)](https://packagist.org/packages/doctrine/annotations)
Docblock Annotations Parser library (extracted from [Doctrine Common](https://github.com/doctrine/common)).
## Documentation
See the [doctrine-project website](https://www.doctrine-project.org/projects/doctrine-annotations/en/latest/index.html).
## Contributing
When making a pull request, make sure your changes follow the
[Coding Standard Guidelines](https://www.doctrine-project.org/projects/doctrine-coding-standard/en/current/reference/index.html#introduction).
## Changelog
See [CHANGELOG.md](CHANGELOG.md).

View File

@ -0,0 +1,42 @@
{
"name": "doctrine/annotations",
"type": "library",
"description": "Docblock Annotations Parser",
"keywords": ["annotations", "docblock", "parser"],
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": "^7.1 || ^8.0",
"ext-tokenizer": "*",
"doctrine/lexer": "1.*"
},
"require-dev": {
"doctrine/cache": "1.*",
"doctrine/coding-standard": "^6.0 || ^8.1",
"phpstan/phpstan": "^0.12.20",
"phpunit/phpunit": "^7.5 || ^9.1.5"
},
"config": {
"sort-packages": true
},
"autoload": {
"psr-4": { "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" }
},
"autoload-dev": {
"psr-4": {
"Doctrine\\Performance\\Common\\Annotations\\": "tests/Doctrine/Performance/Common/Annotations",
"Doctrine\\Tests\\Common\\Annotations\\": "tests/Doctrine/Tests/Common/Annotations"
},
"files": [
"tests/Doctrine/Tests/Common/Annotations/Fixtures/functions.php",
"tests/Doctrine/Tests/Common/Annotations/Fixtures/SingleClassLOC1000.php"
]
}
}

View File

@ -0,0 +1,271 @@
Handling Annotations
====================
There are several different approaches to handling annotations in PHP.
Doctrine Annotations maps docblock annotations to PHP classes. Because
not all docblock annotations are used for metadata purposes a filter is
applied to ignore or skip classes that are not Doctrine annotations.
Take a look at the following code snippet:
.. code-block:: php
namespace MyProject\Entities;
use Doctrine\ORM\Mapping AS ORM;
use Symfony\Component\Validator\Constraints AS Assert;
/**
* @author Benjamin Eberlei
* @ORM\Entity
* @MyProject\Annotations\Foobarable
*/
class User
{
/**
* @ORM\Id @ORM\Column @ORM\GeneratedValue
* @dummy
* @var int
*/
private $id;
/**
* @ORM\Column(type="string")
* @Assert\NotEmpty
* @Assert\Email
* @var string
*/
private $email;
}
In this snippet you can see a variety of different docblock annotations:
- Documentation annotations such as ``@var`` and ``@author``. These
annotations are ignored and never considered for throwing an
exception due to wrongly used annotations.
- Annotations imported through use statements. The statement ``use
Doctrine\ORM\Mapping AS ORM`` makes all classes under that namespace
available as ``@ORM\ClassName``. Same goes for the import of
``@Assert``.
- The ``@dummy`` annotation. It is not a documentation annotation and
not ignored. For Doctrine Annotations it is not entirely clear how
to handle this annotation. Depending on the configuration an exception
(unknown annotation) will be thrown when parsing this annotation.
- The fully qualified annotation ``@MyProject\Annotations\Foobarable``.
This is transformed directly into the given class name.
How are these annotations loaded? From looking at the code you could
guess that the ORM Mapping, Assert Validation and the fully qualified
annotation can just be loaded using
the defined PHP autoloaders. This is not the case however: For error
handling reasons every check for class existence inside the
``AnnotationReader`` sets the second parameter $autoload
of ``class_exists($name, $autoload)`` to false. To work flawlessly the
``AnnotationReader`` requires silent autoloaders which many autoloaders are
not. Silent autoloading is NOT part of the `PSR-0 specification
<https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md>`_
for autoloading.
This is why Doctrine Annotations uses its own autoloading mechanism
through a global registry. If you are wondering about the annotation
registry being global, there is no other way to solve the architectural
problems of autoloading annotation classes in a straightforward fashion.
Additionally if you think about PHP autoloading then you recognize it is
a global as well.
To anticipate the configuration section, making the above PHP class work
with Doctrine Annotations requires this setup:
.. code-block:: php
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
AnnotationRegistry::registerFile("/path/to/doctrine/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php");
AnnotationRegistry::registerAutoloadNamespace("Symfony\Component\Validator\Constraint", "/path/to/symfony/src");
AnnotationRegistry::registerAutoloadNamespace("MyProject\Annotations", "/path/to/myproject/src");
$reader = new AnnotationReader();
AnnotationReader::addGlobalIgnoredName('dummy');
The second block with the annotation registry calls registers all the
three different annotation namespaces that are used.
Doctrine Annotations saves all its annotations in a single file, that is
why ``AnnotationRegistry#registerFile`` is used in contrast to
``AnnotationRegistry#registerAutoloadNamespace`` which creates a PSR-0
compatible loading mechanism for class to file names.
In the third block, we create the actual ``AnnotationReader`` instance.
Note that we also add ``dummy`` to the global list of ignored
annotations for which we do not throw exceptions. Setting this is
necessary in our example case, otherwise ``@dummy`` would trigger an
exception to be thrown during the parsing of the docblock of
``MyProject\Entities\User#id``.
Setup and Configuration
-----------------------
To use the annotations library is simple, you just need to create a new
``AnnotationReader`` instance:
.. code-block:: php
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
This creates a simple annotation reader with no caching other than in
memory (in php arrays). Since parsing docblocks can be expensive you
should cache this process by using a caching reader.
You can use a file caching reader, but please note it is deprecated to
do so:
.. code-block:: php
use Doctrine\Common\Annotations\FileCacheReader;
use Doctrine\Common\Annotations\AnnotationReader;
$reader = new FileCacheReader(
new AnnotationReader(),
"/path/to/cache",
$debug = true
);
If you set the ``debug`` flag to ``true`` the cache reader will check
for changes in the original files, which is very important during
development. If you don't set it to ``true`` you have to delete the
directory to clear the cache. This gives faster performance, however
should only be used in production, because of its inconvenience during
development.
You can also use one of the ``Doctrine\Common\Cache\Cache`` cache
implementations to cache the annotations:
.. code-block:: php
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Cache\ApcCache;
$reader = new CachedReader(
new AnnotationReader(),
new ApcCache(),
$debug = true
);
The ``debug`` flag is used here as well to invalidate the cache files
when the PHP class with annotations changed and should be used during
development.
.. warning ::
The ``AnnotationReader`` works and caches under the
assumption that all annotations of a doc-block are processed at
once. That means that annotation classes that do not exist and
aren't loaded and cannot be autoloaded (using the
AnnotationRegistry) would never be visible and not accessible if a
cache is used unless the cache is cleared and the annotations
requested again, this time with all annotations defined.
By default the annotation reader returns a list of annotations with
numeric indexes. If you want your annotations to be indexed by their
class name you can wrap the reader in an ``IndexedReader``:
.. code-block:: php
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\IndexedReader;
$reader = new IndexedReader(new AnnotationReader());
.. warning::
You should never wrap the indexed reader inside a cached reader,
only the other way around. This way you can re-use the cache with
indexed or numeric keys, otherwise your code may experience failures
due to caching in a numerical or indexed format.
Registering Annotations
~~~~~~~~~~~~~~~~~~~~~~~
As explained in the introduction, Doctrine Annotations uses its own
autoloading mechanism to determine if a given annotation has a
corresponding PHP class that can be autoloaded. For annotation
autoloading you have to configure the
``Doctrine\Common\Annotations\AnnotationRegistry``. There are three
different mechanisms to configure annotation autoloading:
- Calling ``AnnotationRegistry#registerFile($file)`` to register a file
that contains one or more annotation classes.
- Calling ``AnnotationRegistry#registerNamespace($namespace, $dirs =
null)`` to register that the given namespace contains annotations and
that their base directory is located at the given $dirs or in the
include path if ``NULL`` is passed. The given directories should *NOT*
be the directory where classes of the namespace are in, but the base
directory of the root namespace. The AnnotationRegistry uses a
namespace to directory separator approach to resolve the correct path.
- Calling ``AnnotationRegistry#registerLoader($callable)`` to register
an autoloader callback. The callback accepts the class as first and
only parameter and has to return ``true`` if the corresponding file
was found and included.
.. note::
Loaders have to fail silently, if a class is not found even if it
matches for example the namespace prefix of that loader. Never is a
loader to throw a warning or exception if the loading failed
otherwise parsing doc block annotations will become a huge pain.
A sample loader callback could look like:
.. code-block:: php
use Doctrine\Common\Annotations\AnnotationRegistry;
use Symfony\Component\ClassLoader\UniversalClassLoader;
AnnotationRegistry::registerLoader(function($class) {
$file = str_replace("\\", DIRECTORY_SEPARATOR, $class) . ".php";
if (file_exists("/my/base/path/" . $file)) {
// file_exists() makes sure that the loader fails silently
require "/my/base/path/" . $file;
}
});
$loader = new UniversalClassLoader();
AnnotationRegistry::registerLoader(array($loader, "loadClass"));
Ignoring missing exceptions
~~~~~~~~~~~~~~~~~~~~~~~~~~~
By default an exception is thrown from the ``AnnotationReader`` if an
annotation was found that:
- is not part of the list of ignored "documentation annotations";
- was not imported through a use statement;
- is not a fully qualified class that exists.
You can disable this behavior for specific names if your docblocks do
not follow strict requirements:
.. code-block:: php
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
AnnotationReader::addGlobalIgnoredName('foo');
PHP Imports
~~~~~~~~~~~
By default the annotation reader parses the use-statement of a php file
to gain access to the import rules and register them for the annotation
processing. Only if you are using PHP Imports can you validate the
correct usage of annotations and throw exceptions if you misspelled an
annotation. This mechanism is enabled by default.
To ease the upgrade path, we still allow you to disable this mechanism.
Note however that we will remove this in future versions:
.. code-block:: php
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
$reader->setEnabledPhpImports(false);

View File

@ -0,0 +1,443 @@
Custom Annotation Classes
=========================
If you want to define your own annotations, you just have to group them
in a namespace and register this namespace in the ``AnnotationRegistry``.
Annotation classes have to contain a class-level docblock with the text
``@Annotation``:
.. code-block:: php
namespace MyCompany\Annotations;
/** @Annotation */
class Bar
{
// some code
}
Inject annotation values
------------------------
The annotation parser checks if the annotation constructor has arguments,
if so then it will pass the value array, otherwise it will try to inject
values into public properties directly:
.. code-block:: php
namespace MyCompany\Annotations;
/**
* @Annotation
*
* Some Annotation using a constructor
*/
class Bar
{
private $foo;
public function __construct(array $values)
{
$this->foo = $values['foo'];
}
}
/**
* @Annotation
*
* Some Annotation without a constructor
*/
class Foo
{
public $bar;
}
Optional: Constructors with Named Parameters
--------------------------------------------
Starting with Annotations v1.11 a new annotation instantiation strategy
is available that aims at compatibility of Annotation classes with the PHP 8
attribute feature. You need to declare a constructor with regular parameter
names that match the named arguments in the annotation syntax.
To enable this feature, you can tag your annotation class with
``@NamedArgumentConstructor`` (available from v1.12) or implement the
``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation`` interface
(available from v1.11 and deprecated as of v1.12).
When using the ``@NamedArgumentConstructor`` tag, the first argument of the
constructor is considered as the default one.
Usage with the ``@NamedArgumentContrustor`` tag
.. code-block:: php
namespace MyCompany\Annotations;
/**
* @Annotation
* @NamedArgumentConstructor
*/
class Bar implements NamedArgumentConstructorAnnotation
{
private $foo;
public function __construct(string $foo)
{
$this->foo = $foo;
}
}
/** Usable with @Bar(foo="baz") */
/** Usable with @Bar("baz") */
In combination with PHP 8's constructor property promotion feature
you can simplify this to:
.. code-block:: php
namespace MyCompany\Annotations;
/**
* @Annotation
* @NamedArgumentConstructor
*/
class Bar implements NamedArgumentConstructorAnnotation
{
public function __construct(private string $foo) {}
}
Usage with the
``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation``
interface (v1.11, deprecated as of v1.12):
.. code-block:: php
namespace MyCompany\Annotations;
use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation;
/** @Annotation */
class Bar implements NamedArgumentConstructorAnnotation
{
private $foo;
public function __construct(private string $foo) {}
}
/** Usable with @Bar(foo="baz") */
Annotation Target
-----------------
``@Target`` indicates the kinds of class elements to which an annotation
type is applicable. Then you could define one or more targets:
- ``CLASS`` Allowed in class docblocks
- ``PROPERTY`` Allowed in property docblocks
- ``METHOD`` Allowed in the method docblocks
- ``FUNCTION`` Allowed in function dockblocks
- ``ALL`` Allowed in class, property, method and function docblocks
- ``ANNOTATION`` Allowed inside other annotations
If the annotations is not allowed in the current context, an
``AnnotationException`` is thrown.
.. code-block:: php
namespace MyCompany\Annotations;
/**
* @Annotation
* @Target({"METHOD","PROPERTY"})
*/
class Bar
{
// some code
}
/**
* @Annotation
* @Target("CLASS")
*/
class Foo
{
// some code
}
Attribute types
---------------
The annotation parser checks the given parameters using the phpdoc
annotation ``@var``, The data type could be validated using the ``@var``
annotation on the annotation properties or using the ``@Attributes`` and
``@Attribute`` annotations.
If the data type does not match you get an ``AnnotationException``
.. code-block:: php
namespace MyCompany\Annotations;
/**
* @Annotation
* @Target({"METHOD","PROPERTY"})
*/
class Bar
{
/** @var mixed */
public $mixed;
/** @var boolean */
public $boolean;
/** @var bool */
public $bool;
/** @var float */
public $float;
/** @var string */
public $string;
/** @var integer */
public $integer;
/** @var array */
public $array;
/** @var SomeAnnotationClass */
public $annotation;
/** @var array<integer> */
public $arrayOfIntegers;
/** @var array<SomeAnnotationClass> */
public $arrayOfAnnotations;
}
/**
* @Annotation
* @Target({"METHOD","PROPERTY"})
* @Attributes({
* @Attribute("stringProperty", type = "string"),
* @Attribute("annotProperty", type = "SomeAnnotationClass"),
* })
*/
class Foo
{
public function __construct(array $values)
{
$this->stringProperty = $values['stringProperty'];
$this->annotProperty = $values['annotProperty'];
}
// some code
}
Annotation Required
-------------------
``@Required`` indicates that the field must be specified when the
annotation is used. If it is not used you get an ``AnnotationException``
stating that this value can not be null.
Declaring a required field:
.. code-block:: php
/**
* @Annotation
* @Target("ALL")
*/
class Foo
{
/** @Required */
public $requiredField;
}
Usage:
.. code-block:: php
/** @Foo(requiredField="value") */
public $direction; // Valid
/** @Foo */
public $direction; // Required field missing, throws an AnnotationException
Enumerated values
-----------------
- An annotation property marked with ``@Enum`` is a field that accepts a
fixed set of scalar values.
- You should use ``@Enum`` fields any time you need to represent fixed
values.
- The annotation parser checks the given value and throws an
``AnnotationException`` if the value does not match.
Declaring an enumerated property:
.. code-block:: php
/**
* @Annotation
* @Target("ALL")
*/
class Direction
{
/**
* @Enum({"NORTH", "SOUTH", "EAST", "WEST"})
*/
public $value;
}
Annotation usage:
.. code-block:: php
/** @Direction("NORTH") */
public $direction; // Valid value
/** @Direction("NORTHEAST") */
public $direction; // Invalid value, throws an AnnotationException
Constants
---------
The use of constants and class constants is available on the annotations
parser.
The following usages are allowed:
.. code-block:: php
namespace MyCompany\Entity;
use MyCompany\Annotations\Foo;
use MyCompany\Annotations\Bar;
use MyCompany\Entity\SomeClass;
/**
* @Foo(PHP_EOL)
* @Bar(Bar::FOO)
* @Foo({SomeClass::FOO, SomeClass::BAR})
* @Bar({SomeClass::FOO_KEY = SomeClass::BAR_VALUE})
*/
class User
{
}
Be careful with constants and the cache !
.. note::
The cached reader will not re-evaluate each time an annotation is
loaded from cache. When a constant is changed the cache must be
cleaned.
Usage
-----
Using the library API is simple. Using the annotations described in the
previous section, you can now annotate other classes with your
annotations:
.. code-block:: php
namespace MyCompany\Entity;
use MyCompany\Annotations\Foo;
use MyCompany\Annotations\Bar;
/**
* @Foo(bar="foo")
* @Bar(foo="bar")
*/
class User
{
}
Now we can write a script to get the annotations above:
.. code-block:: php
$reflClass = new ReflectionClass('MyCompany\Entity\User');
$classAnnotations = $reader->getClassAnnotations($reflClass);
foreach ($classAnnotations AS $annot) {
if ($annot instanceof \MyCompany\Annotations\Foo) {
echo $annot->bar; // prints "foo";
} else if ($annot instanceof \MyCompany\Annotations\Bar) {
echo $annot->foo; // prints "bar";
}
}
You have a complete API for retrieving annotation class instances from a
class, property or method docblock:
Reader API
~~~~~~~~~~
Access all annotations of a class
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: php
public function getClassAnnotations(\ReflectionClass $class);
Access one annotation of a class
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: php
public function getClassAnnotation(\ReflectionClass $class, $annotationName);
Access all annotations of a method
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: php
public function getMethodAnnotations(\ReflectionMethod $method);
Access one annotation of a method
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: php
public function getMethodAnnotation(\ReflectionMethod $method, $annotationName);
Access all annotations of a property
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: php
public function getPropertyAnnotations(\ReflectionProperty $property);
Access one annotation of a property
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: php
public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName);
Access all annotations of a function
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: php
public function getFunctionAnnotations(\ReflectionFunction $property);
Access one annotation of a function
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: php
public function getFunctionAnnotation(\ReflectionFunction $property, $annotationName);

View File

@ -0,0 +1,101 @@
Introduction
============
Doctrine Annotations allows to implement custom annotation
functionality for PHP classes and functions.
.. code-block:: php
class Foo
{
/**
* @MyAnnotation(myProperty="value")
*/
private $bar;
}
Annotations aren't implemented in PHP itself which is why this component
offers a way to use the PHP doc-blocks as a place for the well known
annotation syntax using the ``@`` char.
Annotations in Doctrine are used for the ORM configuration to build the
class mapping, but it can be used in other projects for other purposes
too.
Installation
============
You can install the Annotation component with composer:
.. code-block::
  $ composer require doctrine/annotations
Create an annotation class
==========================
An annotation class is a representation of the later used annotation
configuration in classes. The annotation class of the previous example
looks like this:
.. code-block:: php
/**
* @Annotation
*/
final class MyAnnotation
{
public $myProperty;
}
The annotation class is declared as an annotation by ``@Annotation``.
:ref:`Read more about custom annotations. <custom>`
Reading annotations
===================
The access to the annotations happens by reflection of the class or function
containing them. There are multiple reader-classes implementing the
``Doctrine\Common\Annotations\Reader`` interface, that can access the
annotations of a class. A common one is
``Doctrine\Common\Annotations\AnnotationReader``:
.. code-block:: php
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
// Deprecated and will be removed in 2.0 but currently needed
AnnotationRegistry::registerLoader('class_exists');
$reflectionClass = new ReflectionClass(Foo::class);
$property = $reflectionClass->getProperty('bar');
$reader = new AnnotationReader();
$myAnnotation = $reader->getPropertyAnnotation(
$property,
MyAnnotation::class
);
echo $myAnnotation->myProperty; // result: "value"
Note that ``AnnotationRegistry::registerLoader('class_exists')`` only works
if you already have an autoloader configured (i.e. composer autoloader).
Otherwise, :ref:`please take a look to the other annotation autoload mechanisms <annotations>`.
A reader has multiple methods to access the annotations of a class or
function.
:ref:`Read more about handling annotations. <annotations>`
IDE Support
-----------
Some IDEs already provide support for annotations:
- Eclipse via the `Symfony2 Plugin <http://symfony.dubture.com/>`_
- PhpStorm via the `PHP Annotations Plugin <https://plugins.jetbrains.com/plugin/7320-php-annotations>`_ or the `Symfony Plugin <https://plugins.jetbrains.com/plugin/7219-symfony-support>`_
.. _Read more about handling annotations.: annotations
.. _Read more about custom annotations.: custom

View File

@ -0,0 +1,6 @@
.. toctree::
:depth: 3
index
annotations
custom

View File

@ -0,0 +1,59 @@
<?php
namespace Doctrine\Common\Annotations;
use BadMethodCallException;
use function sprintf;
/**
* Annotations class.
*/
class Annotation
{
/**
* Value property. Common among all derived classes.
*
* @var mixed
*/
public $value;
/**
* @param array<string, mixed> $data Key-value for properties to be defined in this class.
*/
final public function __construct(array $data)
{
foreach ($data as $key => $value) {
$this->$key = $value;
}
}
/**
* Error handler for unknown property accessor in Annotation class.
*
* @param string $name Unknown property name.
*
* @throws BadMethodCallException
*/
public function __get($name)
{
throw new BadMethodCallException(
sprintf("Unknown property '%s' on annotation '%s'.", $name, static::class)
);
}
/**
* Error handler for unknown property mutator in Annotation class.
*
* @param string $name Unknown property name.
* @param mixed $value Property value.
*
* @throws BadMethodCallException
*/
public function __set($name, $value)
{
throw new BadMethodCallException(
sprintf("Unknown property '%s' on annotation '%s'.", $name, static::class)
);
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Doctrine\Common\Annotations\Annotation;
/**
* Annotation that can be used to signal to the parser
* to check the attribute type during the parsing process.
*
* @Annotation
*/
final class Attribute
{
/** @var string */
public $name;
/** @var string */
public $type;
/** @var bool */
public $required = false;
}

View File

@ -0,0 +1,15 @@
<?php
namespace Doctrine\Common\Annotations\Annotation;
/**
* Annotation that can be used to signal to the parser
* to check the types of all declared attributes during the parsing process.
*
* @Annotation
*/
final class Attributes
{
/** @var array<Attribute> */
public $value;
}

View File

@ -0,0 +1,69 @@
<?php
namespace Doctrine\Common\Annotations\Annotation;
use InvalidArgumentException;
use function get_class;
use function gettype;
use function in_array;
use function is_object;
use function is_scalar;
use function sprintf;
/**
* Annotation that can be used to signal to the parser
* to check the available values during the parsing process.
*
* @Annotation
* @Attributes({
* @Attribute("value", required = true, type = "array"),
* @Attribute("literal", required = false, type = "array")
* })
*/
final class Enum
{
/** @phpstan-var list<scalar> */
public $value;
/**
* Literal target declaration.
*
* @var mixed[]
*/
public $literal;
/**
* @throws InvalidArgumentException
*
* @phpstan-param array{literal?: mixed[], value: list<scalar>} $values
*/
public function __construct(array $values)
{
if (! isset($values['literal'])) {
$values['literal'] = [];
}
foreach ($values['value'] as $var) {
if (! is_scalar($var)) {
throw new InvalidArgumentException(sprintf(
'@Enum supports only scalar values "%s" given.',
is_object($var) ? get_class($var) : gettype($var)
));
}
}
foreach ($values['literal'] as $key => $var) {
if (! in_array($key, $values['value'])) {
throw new InvalidArgumentException(sprintf(
'Undefined enumerator value "%s" for literal "%s".',
$key,
$var
));
}
}
$this->value = $values['value'];
$this->literal = $values['literal'];
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Doctrine\Common\Annotations\Annotation;
use RuntimeException;
use function is_array;
use function is_string;
use function json_encode;
use function sprintf;
/**
* Annotation that can be used to signal to the parser to ignore specific
* annotations during the parsing process.
*
* @Annotation
*/
final class IgnoreAnnotation
{
/** @phpstan-var list<string> */
public $names;
/**
* @throws RuntimeException
*
* @phpstan-param array{value: string|list<string>} $values
*/
public function __construct(array $values)
{
if (is_string($values['value'])) {
$values['value'] = [$values['value']];
}
if (! is_array($values['value'])) {
throw new RuntimeException(sprintf(
'@IgnoreAnnotation expects either a string name, or an array of strings, but got %s.',
json_encode($values['value'])
));
}
$this->names = $values['value'];
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Doctrine\Common\Annotations\Annotation;
/**
* Annotation that indicates that the annotated class should be constructed with a named argument call.
*
* @Annotation
* @Target("CLASS")
*/
final class NamedArgumentConstructor
{
}

View File

@ -0,0 +1,13 @@
<?php
namespace Doctrine\Common\Annotations\Annotation;
/**
* Annotation that can be used to signal to the parser
* to check if that attribute is required during the parsing process.
*
* @Annotation
*/
final class Required
{
}

View File

@ -0,0 +1,101 @@
<?php
namespace Doctrine\Common\Annotations\Annotation;
use InvalidArgumentException;
use function array_keys;
use function get_class;
use function gettype;
use function implode;
use function is_array;
use function is_object;
use function is_string;
use function sprintf;
/**
* Annotation that can be used to signal to the parser
* to check the annotation target during the parsing process.
*
* @Annotation
*/
final class Target
{
public const TARGET_CLASS = 1;
public const TARGET_METHOD = 2;
public const TARGET_PROPERTY = 4;
public const TARGET_ANNOTATION = 8;
public const TARGET_FUNCTION = 16;
public const TARGET_ALL = 31;
/** @var array<string, int> */
private static $map = [
'ALL' => self::TARGET_ALL,
'CLASS' => self::TARGET_CLASS,
'METHOD' => self::TARGET_METHOD,
'PROPERTY' => self::TARGET_PROPERTY,
'FUNCTION' => self::TARGET_FUNCTION,
'ANNOTATION' => self::TARGET_ANNOTATION,
];
/** @phpstan-var list<string> */
public $value;
/**
* Targets as bitmask.
*
* @var int
*/
public $targets;
/**
* Literal target declaration.
*
* @var string
*/
public $literal;
/**
* @throws InvalidArgumentException
*
* @phpstan-param array{value?: string|list<string>} $values
*/
public function __construct(array $values)
{
if (! isset($values['value'])) {
$values['value'] = null;
}
if (is_string($values['value'])) {
$values['value'] = [$values['value']];
}
if (! is_array($values['value'])) {
throw new InvalidArgumentException(
sprintf(
'@Target expects either a string value, or an array of strings, "%s" given.',
is_object($values['value']) ? get_class($values['value']) : gettype($values['value'])
)
);
}
$bitmask = 0;
foreach ($values['value'] as $literal) {
if (! isset(self::$map[$literal])) {
throw new InvalidArgumentException(
sprintf(
'Invalid Target "%s". Available targets: [%s]',
$literal,
implode(', ', array_keys(self::$map))
)
);
}
$bitmask |= self::$map[$literal];
}
$this->targets = $bitmask;
$this->value = $values['value'];
$this->literal = implode(', ', $this->value);
}
}

View File

@ -0,0 +1,171 @@
<?php
namespace Doctrine\Common\Annotations;
use Exception;
use function get_class;
use function gettype;
use function implode;
use function is_object;
use function sprintf;
/**
* Description of AnnotationException
*/
class AnnotationException extends Exception
{
/**
* Creates a new AnnotationException describing a Syntax error.
*
* @param string $message Exception message
*
* @return AnnotationException
*/
public static function syntaxError($message)
{
return new self('[Syntax Error] ' . $message);
}
/**
* Creates a new AnnotationException describing a Semantical error.
*
* @param string $message Exception message
*
* @return AnnotationException
*/
public static function semanticalError($message)
{
return new self('[Semantical Error] ' . $message);
}
/**
* Creates a new AnnotationException describing an error which occurred during
* the creation of the annotation.
*
* @param string $message
*
* @return AnnotationException
*/
public static function creationError($message)
{
return new self('[Creation Error] ' . $message);
}
/**
* Creates a new AnnotationException describing a type error.
*
* @param string $message
*
* @return AnnotationException
*/
public static function typeError($message)
{
return new self('[Type Error] ' . $message);
}
/**
* Creates a new AnnotationException describing a constant semantical error.
*
* @param string $identifier
* @param string $context
*
* @return AnnotationException
*/
public static function semanticalErrorConstants($identifier, $context = null)
{
return self::semanticalError(sprintf(
"Couldn't find constant %s%s.",
$identifier,
$context ? ', ' . $context : ''
));
}
/**
* Creates a new AnnotationException describing an type error of an attribute.
*
* @param string $attributeName
* @param string $annotationName
* @param string $context
* @param string $expected
* @param mixed $actual
*
* @return AnnotationException
*/
public static function attributeTypeError($attributeName, $annotationName, $context, $expected, $actual)
{
return self::typeError(sprintf(
'Attribute "%s" of @%s declared on %s expects %s, but got %s.',
$attributeName,
$annotationName,
$context,
$expected,
is_object($actual) ? 'an instance of ' . get_class($actual) : gettype($actual)
));
}
/**
* Creates a new AnnotationException describing an required error of an attribute.
*
* @param string $attributeName
* @param string $annotationName
* @param string $context
* @param string $expected
*
* @return AnnotationException
*/
public static function requiredError($attributeName, $annotationName, $context, $expected)
{
return self::typeError(sprintf(
'Attribute "%s" of @%s declared on %s expects %s. This value should not be null.',
$attributeName,
$annotationName,
$context,
$expected
));
}
/**
* Creates a new AnnotationException describing a invalid enummerator.
*
* @param string $attributeName
* @param string $annotationName
* @param string $context
* @param mixed $given
*
* @return AnnotationException
*
* @phpstan-param list<string> $available
*/
public static function enumeratorError($attributeName, $annotationName, $context, $available, $given)
{
return new self(sprintf(
'[Enum Error] Attribute "%s" of @%s declared on %s accepts only [%s], but got %s.',
$attributeName,
$annotationName,
$context,
implode(', ', $available),
is_object($given) ? get_class($given) : $given
));
}
/**
* @return AnnotationException
*/
public static function optimizerPlusSaveComments()
{
return new self(
'You have to enable opcache.save_comments=1 or zend_optimizerplus.save_comments=1.'
);
}
/**
* @return AnnotationException
*/
public static function optimizerPlusLoadComments()
{
return new self(
'You have to enable opcache.load_comments=1 or zend_optimizerplus.load_comments=1.'
);
}
}

View File

@ -0,0 +1,389 @@
<?php
namespace Doctrine\Common\Annotations;
use Doctrine\Common\Annotations\Annotation\IgnoreAnnotation;
use Doctrine\Common\Annotations\Annotation\Target;
use ReflectionClass;
use ReflectionFunction;
use ReflectionMethod;
use ReflectionProperty;
use function array_merge;
use function class_exists;
use function extension_loaded;
use function ini_get;
/**
* A reader for docblock annotations.
*/
class AnnotationReader implements Reader
{
/**
* Global map for imports.
*
* @var array<string, class-string>
*/
private static $globalImports = [
'ignoreannotation' => Annotation\IgnoreAnnotation::class,
];
/**
* A list with annotations that are not causing exceptions when not resolved to an annotation class.
*
* The names are case sensitive.
*
* @var array<string, true>
*/
private static $globalIgnoredNames = ImplicitlyIgnoredAnnotationNames::LIST;
/**
* A list with annotations that are not causing exceptions when not resolved to an annotation class.
*
* The names are case sensitive.
*
* @var array<string, true>
*/
private static $globalIgnoredNamespaces = [];
/**
* Add a new annotation to the globally ignored annotation names with regard to exception handling.
*
* @param string $name
*/
public static function addGlobalIgnoredName($name)
{
self::$globalIgnoredNames[$name] = true;
}
/**
* Add a new annotation to the globally ignored annotation namespaces with regard to exception handling.
*
* @param string $namespace
*/
public static function addGlobalIgnoredNamespace($namespace)
{
self::$globalIgnoredNamespaces[$namespace] = true;
}
/**
* Annotations parser.
*
* @var DocParser
*/
private $parser;
/**
* Annotations parser used to collect parsing metadata.
*
* @var DocParser
*/
private $preParser;
/**
* PHP parser used to collect imports.
*
* @var PhpParser
*/
private $phpParser;
/**
* In-memory cache mechanism to store imported annotations per class.
*
* @psalm-var array<'class'|'function', array<string, array<string, class-string>>>
*/
private $imports = [];
/**
* In-memory cache mechanism to store ignored annotations per class.
*
* @psalm-var array<'class'|'function', array<string, array<string, true>>>
*/
private $ignoredAnnotationNames = [];
/**
* Initializes a new AnnotationReader.
*
* @throws AnnotationException
*/
public function __construct(?DocParser $parser = null)
{
if (
extension_loaded('Zend Optimizer+') && (ini_get('zend_optimizerplus.save_comments') === '0' ||
ini_get('opcache.save_comments') === '0')
) {
throw AnnotationException::optimizerPlusSaveComments();
}
if (extension_loaded('Zend OPcache') && ini_get('opcache.save_comments') === 0) {
throw AnnotationException::optimizerPlusSaveComments();
}
// Make sure that the IgnoreAnnotation annotation is loaded
class_exists(IgnoreAnnotation::class);
$this->parser = $parser ?: new DocParser();
$this->preParser = new DocParser();
$this->preParser->setImports(self::$globalImports);
$this->preParser->setIgnoreNotImportedAnnotations(true);
$this->preParser->setIgnoredAnnotationNames(self::$globalIgnoredNames);
$this->phpParser = new PhpParser();
}
/**
* {@inheritDoc}
*/
public function getClassAnnotations(ReflectionClass $class)
{
$this->parser->setTarget(Target::TARGET_CLASS);
$this->parser->setImports($this->getImports($class));
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
}
/**
* {@inheritDoc}
*/
public function getClassAnnotation(ReflectionClass $class, $annotationName)
{
$annotations = $this->getClassAnnotations($class);
foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(ReflectionProperty $property)
{
$class = $property->getDeclaringClass();
$context = 'property ' . $class->getName() . '::$' . $property->getName();
$this->parser->setTarget(Target::TARGET_PROPERTY);
$this->parser->setImports($this->getPropertyImports($property));
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
return $this->parser->parse($property->getDocComment(), $context);
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
{
$annotations = $this->getPropertyAnnotations($property);
foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotations(ReflectionMethod $method)
{
$class = $method->getDeclaringClass();
$context = 'method ' . $class->getName() . '::' . $method->getName() . '()';
$this->parser->setTarget(Target::TARGET_METHOD);
$this->parser->setImports($this->getMethodImports($method));
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
return $this->parser->parse($method->getDocComment(), $context);
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
{
$annotations = $this->getMethodAnnotations($method);
foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}
return null;
}
/**
* Gets the annotations applied to a function.
*
* @phpstan-return list<object> An array of Annotations.
*/
public function getFunctionAnnotations(ReflectionFunction $function): array
{
$context = 'function ' . $function->getName();
$this->parser->setTarget(Target::TARGET_FUNCTION);
$this->parser->setImports($this->getImports($function));
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($function));
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
return $this->parser->parse($function->getDocComment(), $context);
}
/**
* Gets a function annotation.
*
* @return object|null The Annotation or NULL, if the requested annotation does not exist.
*/
public function getFunctionAnnotation(ReflectionFunction $function, string $annotationName)
{
$annotations = $this->getFunctionAnnotations($function);
foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}
return null;
}
/**
* Returns the ignored annotations for the given class or function.
*
* @param ReflectionClass|ReflectionFunction $reflection
*
* @return array<string, true>
*/
private function getIgnoredAnnotationNames($reflection): array
{
$type = $reflection instanceof ReflectionClass ? 'class' : 'function';
$name = $reflection->getName();
if (isset($this->ignoredAnnotationNames[$type][$name])) {
return $this->ignoredAnnotationNames[$type][$name];
}
$this->collectParsingMetadata($reflection);
return $this->ignoredAnnotationNames[$type][$name];
}
/**
* Retrieves imports for a class or a function.
*
* @param ReflectionClass|ReflectionFunction $reflection
*
* @return array<string, class-string>
*/
private function getImports($reflection): array
{
$type = $reflection instanceof ReflectionClass ? 'class' : 'function';
$name = $reflection->getName();
if (isset($this->imports[$type][$name])) {
return $this->imports[$type][$name];
}
$this->collectParsingMetadata($reflection);
return $this->imports[$type][$name];
}
/**
* Retrieves imports for methods.
*
* @return array<string, class-string>
*/
private function getMethodImports(ReflectionMethod $method)
{
$class = $method->getDeclaringClass();
$classImports = $this->getImports($class);
$traitImports = [];
foreach ($class->getTraits() as $trait) {
if (
! $trait->hasMethod($method->getName())
|| $trait->getFileName() !== $method->getFileName()
) {
continue;
}
$traitImports = array_merge($traitImports, $this->phpParser->parseUseStatements($trait));
}
return array_merge($classImports, $traitImports);
}
/**
* Retrieves imports for properties.
*
* @return array<string, class-string>
*/
private function getPropertyImports(ReflectionProperty $property)
{
$class = $property->getDeclaringClass();
$classImports = $this->getImports($class);
$traitImports = [];
foreach ($class->getTraits() as $trait) {
if (! $trait->hasProperty($property->getName())) {
continue;
}
$traitImports = array_merge($traitImports, $this->phpParser->parseUseStatements($trait));
}
return array_merge($classImports, $traitImports);
}
/**
* Collects parsing metadata for a given class or function.
*
* @param ReflectionClass|ReflectionFunction $reflection
*/
private function collectParsingMetadata($reflection): void
{
$type = $reflection instanceof ReflectionClass ? 'class' : 'function';
$name = $reflection->getName();
$ignoredAnnotationNames = self::$globalIgnoredNames;
$annotations = $this->preParser->parse($reflection->getDocComment(), $type . ' ' . $name);
foreach ($annotations as $annotation) {
if (! ($annotation instanceof IgnoreAnnotation)) {
continue;
}
foreach ($annotation->names as $annot) {
$ignoredAnnotationNames[$annot] = true;
}
}
$this->imports[$type][$name] = array_merge(
self::$globalImports,
$this->phpParser->parseUseStatements($reflection),
[
'__NAMESPACE__' => $reflection->getNamespaceName(),
'self' => $name,
]
);
$this->ignoredAnnotationNames[$type][$name] = $ignoredAnnotationNames;
}
}

View File

@ -0,0 +1,190 @@
<?php
namespace Doctrine\Common\Annotations;
use function array_key_exists;
use function array_merge;
use function class_exists;
use function in_array;
use function is_file;
use function str_replace;
use function stream_resolve_include_path;
use function strpos;
use const DIRECTORY_SEPARATOR;
final class AnnotationRegistry
{
/**
* A map of namespaces to use for autoloading purposes based on a PSR-0 convention.
*
* Contains the namespace as key and an array of directories as value. If the value is NULL
* the include path is used for checking for the corresponding file.
*
* This autoloading mechanism does not utilize the PHP autoloading but implements autoloading on its own.
*
* @var string[][]|string[]|null[]
*/
private static $autoloadNamespaces = [];
/**
* A map of autoloader callables.
*
* @var callable[]
*/
private static $loaders = [];
/**
* An array of classes which cannot be found
*
* @var null[] indexed by class name
*/
private static $failedToAutoload = [];
/**
* Whenever registerFile() was used. Disables use of standard autoloader.
*
* @var bool
*/
private static $registerFileUsed = false;
public static function reset(): void
{
self::$autoloadNamespaces = [];
self::$loaders = [];
self::$failedToAutoload = [];
self::$registerFileUsed = false;
}
/**
* Registers file.
*
* @deprecated This method is deprecated and will be removed in
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
*/
public static function registerFile(string $file): void
{
self::$registerFileUsed = true;
require_once $file;
}
/**
* Adds a namespace with one or many directories to look for files or null for the include path.
*
* Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
*
* @deprecated This method is deprecated and will be removed in
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
*
* @phpstan-param string|list<string>|null $dirs
*/
public static function registerAutoloadNamespace(string $namespace, $dirs = null): void
{
self::$autoloadNamespaces[$namespace] = $dirs;
}
/**
* Registers multiple namespaces.
*
* Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
*
* @deprecated This method is deprecated and will be removed in
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
*
* @param string[][]|string[]|null[] $namespaces indexed by namespace name
*/
public static function registerAutoloadNamespaces(array $namespaces): void
{
self::$autoloadNamespaces = array_merge(self::$autoloadNamespaces, $namespaces);
}
/**
* Registers an autoloading callable for annotations, much like spl_autoload_register().
*
* NOTE: These class loaders HAVE to be silent when a class was not found!
* IMPORTANT: Loaders have to return true if they loaded a class that could contain the searched annotation class.
*
* @deprecated This method is deprecated and will be removed in
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
*/
public static function registerLoader(callable $callable): void
{
// Reset our static cache now that we have a new loader to work with
self::$failedToAutoload = [];
self::$loaders[] = $callable;
}
/**
* Registers an autoloading callable for annotations, if it is not already registered
*
* @deprecated This method is deprecated and will be removed in
* doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
*/
public static function registerUniqueLoader(callable $callable): void
{
if (in_array($callable, self::$loaders, true)) {
return;
}
self::registerLoader($callable);
}
/**
* Autoloads an annotation class silently.
*/
public static function loadAnnotationClass(string $class): bool
{
if (class_exists($class, false)) {
return true;
}
if (array_key_exists($class, self::$failedToAutoload)) {
return false;
}
foreach (self::$autoloadNamespaces as $namespace => $dirs) {
if (strpos($class, $namespace) !== 0) {
continue;
}
$file = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
if ($dirs === null) {
$path = stream_resolve_include_path($file);
if ($path) {
require $path;
return true;
}
} else {
foreach ((array) $dirs as $dir) {
if (is_file($dir . DIRECTORY_SEPARATOR . $file)) {
require $dir . DIRECTORY_SEPARATOR . $file;
return true;
}
}
}
}
foreach (self::$loaders as $loader) {
if ($loader($class) === true) {
return true;
}
}
if (
self::$loaders === [] &&
self::$autoloadNamespaces === [] &&
self::$registerFileUsed === false &&
class_exists($class)
) {
return true;
}
self::$failedToAutoload[$class] = null;
return false;
}
}

View File

@ -0,0 +1,264 @@
<?php
namespace Doctrine\Common\Annotations;
use Doctrine\Common\Cache\Cache;
use ReflectionClass;
use ReflectionMethod;
use ReflectionProperty;
use function array_map;
use function array_merge;
use function assert;
use function filemtime;
use function max;
use function time;
/**
* A cache aware annotation reader.
*/
final class CachedReader implements Reader
{
/** @var Reader */
private $delegate;
/** @var Cache */
private $cache;
/** @var bool */
private $debug;
/** @var array<string, array<object>> */
private $loadedAnnotations = [];
/** @var int[] */
private $loadedFilemtimes = [];
/**
* @param bool $debug
*/
public function __construct(Reader $reader, Cache $cache, $debug = false)
{
$this->delegate = $reader;
$this->cache = $cache;
$this->debug = (bool) $debug;
}
/**
* {@inheritDoc}
*/
public function getClassAnnotations(ReflectionClass $class)
{
$cacheKey = $class->getName();
if (isset($this->loadedAnnotations[$cacheKey])) {
return $this->loadedAnnotations[$cacheKey];
}
$annots = $this->fetchFromCache($cacheKey, $class);
if ($annots === false) {
$annots = $this->delegate->getClassAnnotations($class);
$this->saveToCache($cacheKey, $annots);
}
return $this->loadedAnnotations[$cacheKey] = $annots;
}
/**
* {@inheritDoc}
*/
public function getClassAnnotation(ReflectionClass $class, $annotationName)
{
foreach ($this->getClassAnnotations($class) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(ReflectionProperty $property)
{
$class = $property->getDeclaringClass();
$cacheKey = $class->getName() . '$' . $property->getName();
if (isset($this->loadedAnnotations[$cacheKey])) {
return $this->loadedAnnotations[$cacheKey];
}
$annots = $this->fetchFromCache($cacheKey, $class);
if ($annots === false) {
$annots = $this->delegate->getPropertyAnnotations($property);
$this->saveToCache($cacheKey, $annots);
}
return $this->loadedAnnotations[$cacheKey] = $annots;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
{
foreach ($this->getPropertyAnnotations($property) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotations(ReflectionMethod $method)
{
$class = $method->getDeclaringClass();
$cacheKey = $class->getName() . '#' . $method->getName();
if (isset($this->loadedAnnotations[$cacheKey])) {
return $this->loadedAnnotations[$cacheKey];
}
$annots = $this->fetchFromCache($cacheKey, $class);
if ($annots === false) {
$annots = $this->delegate->getMethodAnnotations($method);
$this->saveToCache($cacheKey, $annots);
}
return $this->loadedAnnotations[$cacheKey] = $annots;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
{
foreach ($this->getMethodAnnotations($method) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
/**
* Clears loaded annotations.
*
* @return void
*/
public function clearLoadedAnnotations()
{
$this->loadedAnnotations = [];
$this->loadedFilemtimes = [];
}
/**
* Fetches a value from the cache.
*
* @param string $cacheKey The cache key.
*
* @return mixed The cached value or false when the value is not in cache.
*/
private function fetchFromCache($cacheKey, ReflectionClass $class)
{
$data = $this->cache->fetch($cacheKey);
if ($data !== false) {
if (! $this->debug || $this->isCacheFresh($cacheKey, $class)) {
return $data;
}
}
return false;
}
/**
* Saves a value to the cache.
*
* @param string $cacheKey The cache key.
* @param mixed $value The value.
*
* @return void
*/
private function saveToCache($cacheKey, $value)
{
$this->cache->save($cacheKey, $value);
if (! $this->debug) {
return;
}
$this->cache->save('[C]' . $cacheKey, time());
}
/**
* Checks if the cache is fresh.
*
* @param string $cacheKey
*
* @return bool
*/
private function isCacheFresh($cacheKey, ReflectionClass $class)
{
$lastModification = $this->getLastModification($class);
if ($lastModification === 0) {
return true;
}
return $this->cache->fetch('[C]' . $cacheKey) >= $lastModification;
}
/**
* Returns the time the class was last modified, testing traits and parents
*/
private function getLastModification(ReflectionClass $class): int
{
$filename = $class->getFileName();
if (isset($this->loadedFilemtimes[$filename])) {
return $this->loadedFilemtimes[$filename];
}
$parent = $class->getParentClass();
$lastModification = max(array_merge(
[$filename ? filemtime($filename) : 0],
array_map(function (ReflectionClass $reflectionTrait): int {
return $this->getTraitLastModificationTime($reflectionTrait);
}, $class->getTraits()),
array_map(function (ReflectionClass $class): int {
return $this->getLastModification($class);
}, $class->getInterfaces()),
$parent ? [$this->getLastModification($parent)] : []
));
assert($lastModification !== false);
return $this->loadedFilemtimes[$filename] = $lastModification;
}
private function getTraitLastModificationTime(ReflectionClass $reflectionTrait): int
{
$fileName = $reflectionTrait->getFileName();
if (isset($this->loadedFilemtimes[$fileName])) {
return $this->loadedFilemtimes[$fileName];
}
$lastModificationTime = max(array_merge(
[$fileName ? filemtime($fileName) : 0],
array_map(function (ReflectionClass $reflectionTrait): int {
return $this->getTraitLastModificationTime($reflectionTrait);
}, $reflectionTrait->getTraits())
));
assert($lastModificationTime !== false);
return $this->loadedFilemtimes[$fileName] = $lastModificationTime;
}
}

View File

@ -0,0 +1,129 @@
<?php
namespace Doctrine\Common\Annotations;
use Doctrine\Common\Lexer\AbstractLexer;
use function ctype_alpha;
use function is_numeric;
use function str_replace;
use function stripos;
use function strlen;
use function strpos;
use function strtolower;
use function substr;
/**
* Simple lexer for docblock annotations.
*/
final class DocLexer extends AbstractLexer
{
public const T_NONE = 1;
public const T_INTEGER = 2;
public const T_STRING = 3;
public const T_FLOAT = 4;
// All tokens that are also identifiers should be >= 100
public const T_IDENTIFIER = 100;
public const T_AT = 101;
public const T_CLOSE_CURLY_BRACES = 102;
public const T_CLOSE_PARENTHESIS = 103;
public const T_COMMA = 104;
public const T_EQUALS = 105;
public const T_FALSE = 106;
public const T_NAMESPACE_SEPARATOR = 107;
public const T_OPEN_CURLY_BRACES = 108;
public const T_OPEN_PARENTHESIS = 109;
public const T_TRUE = 110;
public const T_NULL = 111;
public const T_COLON = 112;
public const T_MINUS = 113;
/** @var array<string, int> */
protected $noCase = [
'@' => self::T_AT,
',' => self::T_COMMA,
'(' => self::T_OPEN_PARENTHESIS,
')' => self::T_CLOSE_PARENTHESIS,
'{' => self::T_OPEN_CURLY_BRACES,
'}' => self::T_CLOSE_CURLY_BRACES,
'=' => self::T_EQUALS,
':' => self::T_COLON,
'-' => self::T_MINUS,
'\\' => self::T_NAMESPACE_SEPARATOR,
];
/** @var array<string, int> */
protected $withCase = [
'true' => self::T_TRUE,
'false' => self::T_FALSE,
'null' => self::T_NULL,
];
/**
* Whether the next token starts immediately, or if there were
* non-captured symbols before that
*/
public function nextTokenIsAdjacent(): bool
{
return $this->token === null
|| ($this->lookahead !== null
&& ($this->lookahead['position'] - $this->token['position']) === strlen($this->token['value']));
}
/**
* {@inheritdoc}
*/
protected function getCatchablePatterns()
{
return [
'[a-z_\\\][a-z0-9_\:\\\]*[a-z_][a-z0-9_]*',
'(?:[+-]?[0-9]+(?:[\.][0-9]+)*)(?:[eE][+-]?[0-9]+)?',
'"(?:""|[^"])*+"',
];
}
/**
* {@inheritdoc}
*/
protected function getNonCatchablePatterns()
{
return ['\s+', '\*+', '(.)'];
}
/**
* {@inheritdoc}
*/
protected function getType(&$value)
{
$type = self::T_NONE;
if ($value[0] === '"') {
$value = str_replace('""', '"', substr($value, 1, strlen($value) - 2));
return self::T_STRING;
}
if (isset($this->noCase[$value])) {
return $this->noCase[$value];
}
if ($value[0] === '_' || $value[0] === '\\' || ctype_alpha($value[0])) {
return self::T_IDENTIFIER;
}
$lowerValue = strtolower($value);
if (isset($this->withCase[$lowerValue])) {
return $this->withCase[$lowerValue];
}
// Checking numeric value
if (is_numeric($value)) {
return strpos($value, '.') !== false || stripos($value, 'e') !== false
? self::T_FLOAT : self::T_INTEGER;
}
return $type;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,315 @@
<?php
namespace Doctrine\Common\Annotations;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionMethod;
use ReflectionProperty;
use RuntimeException;
use function chmod;
use function file_put_contents;
use function filemtime;
use function gettype;
use function is_dir;
use function is_file;
use function is_int;
use function is_writable;
use function mkdir;
use function rename;
use function rtrim;
use function serialize;
use function sha1;
use function sprintf;
use function strtr;
use function tempnam;
use function uniqid;
use function unlink;
use function var_export;
/**
* File cache reader for annotations.
*
* @deprecated the FileCacheReader is deprecated and will be removed
* in version 2.0.0 of doctrine/annotations. Please use the
* {@see \Doctrine\Common\Annotations\CachedReader} instead.
*/
class FileCacheReader implements Reader
{
/** @var Reader */
private $reader;
/** @var string */
private $dir;
/** @var bool */
private $debug;
/** @phpstan-var array<string, list<object>> */
private $loadedAnnotations = [];
/** @var array<string, string> */
private $classNameHashes = [];
/** @var int */
private $umask;
/**
* @param string $cacheDir
* @param bool $debug
* @param int $umask
*
* @throws InvalidArgumentException
*/
public function __construct(Reader $reader, $cacheDir, $debug = false, $umask = 0002)
{
if (! is_int($umask)) {
throw new InvalidArgumentException(sprintf(
'The parameter umask must be an integer, was: %s',
gettype($umask)
));
}
$this->reader = $reader;
$this->umask = $umask;
if (! is_dir($cacheDir) && ! @mkdir($cacheDir, 0777 & (~$this->umask), true)) {
throw new InvalidArgumentException(sprintf(
'The directory "%s" does not exist and could not be created.',
$cacheDir
));
}
$this->dir = rtrim($cacheDir, '\\/');
$this->debug = $debug;
}
/**
* {@inheritDoc}
*/
public function getClassAnnotations(ReflectionClass $class)
{
if (! isset($this->classNameHashes[$class->name])) {
$this->classNameHashes[$class->name] = sha1($class->name);
}
$key = $this->classNameHashes[$class->name];
if (isset($this->loadedAnnotations[$key])) {
return $this->loadedAnnotations[$key];
}
$path = $this->dir . '/' . strtr($key, '\\', '-') . '.cache.php';
if (! is_file($path)) {
$annot = $this->reader->getClassAnnotations($class);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}
$filename = $class->getFilename();
if (
$this->debug
&& $filename !== false
&& filemtime($path) < filemtime($filename)
) {
@unlink($path);
$annot = $this->reader->getClassAnnotations($class);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}
return $this->loadedAnnotations[$key] = include $path;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(ReflectionProperty $property)
{
$class = $property->getDeclaringClass();
if (! isset($this->classNameHashes[$class->name])) {
$this->classNameHashes[$class->name] = sha1($class->name);
}
$key = $this->classNameHashes[$class->name] . '$' . $property->getName();
if (isset($this->loadedAnnotations[$key])) {
return $this->loadedAnnotations[$key];
}
$path = $this->dir . '/' . strtr($key, '\\', '-') . '.cache.php';
if (! is_file($path)) {
$annot = $this->reader->getPropertyAnnotations($property);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}
$filename = $class->getFilename();
if (
$this->debug
&& $filename !== false
&& filemtime($path) < filemtime($filename)
) {
@unlink($path);
$annot = $this->reader->getPropertyAnnotations($property);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}
return $this->loadedAnnotations[$key] = include $path;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotations(ReflectionMethod $method)
{
$class = $method->getDeclaringClass();
if (! isset($this->classNameHashes[$class->name])) {
$this->classNameHashes[$class->name] = sha1($class->name);
}
$key = $this->classNameHashes[$class->name] . '#' . $method->getName();
if (isset($this->loadedAnnotations[$key])) {
return $this->loadedAnnotations[$key];
}
$path = $this->dir . '/' . strtr($key, '\\', '-') . '.cache.php';
if (! is_file($path)) {
$annot = $this->reader->getMethodAnnotations($method);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}
$filename = $class->getFilename();
if (
$this->debug
&& $filename !== false
&& filemtime($path) < filemtime($filename)
) {
@unlink($path);
$annot = $this->reader->getMethodAnnotations($method);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}
return $this->loadedAnnotations[$key] = include $path;
}
/**
* Saves the cache file.
*
* @param string $path
* @param mixed $data
*
* @return void
*/
private function saveCacheFile($path, $data)
{
if (! is_writable($this->dir)) {
throw new InvalidArgumentException(sprintf(
<<<'EXCEPTION'
The directory "%s" is not writable. Both the webserver and the console user need access.
You can manage access rights for multiple users with "chmod +a".
If your system does not support this, check out the acl package.,
EXCEPTION
,
$this->dir
));
}
$tempfile = tempnam($this->dir, uniqid('', true));
if ($tempfile === false) {
throw new RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir));
}
@chmod($tempfile, 0666 & (~$this->umask));
$written = file_put_contents(
$tempfile,
'<?php return unserialize(' . var_export(serialize($data), true) . ');'
);
if ($written === false) {
throw new RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile));
}
@chmod($tempfile, 0666 & (~$this->umask));
if (rename($tempfile, $path) === false) {
@unlink($tempfile);
throw new RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path));
}
}
/**
* {@inheritDoc}
*/
public function getClassAnnotation(ReflectionClass $class, $annotationName)
{
$annotations = $this->getClassAnnotations($class);
foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
{
$annotations = $this->getMethodAnnotations($method);
foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
{
$annotations = $this->getPropertyAnnotations($property);
foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}
return null;
}
/**
* Clears loaded annotations.
*
* @return void
*/
public function clearLoadedAnnotations()
{
$this->loadedAnnotations = [];
}
}

View File

@ -0,0 +1,171 @@
<?php
declare(strict_types=1);
namespace Doctrine\Common\Annotations;
/**
* A list of annotations that are implicitly ignored during the parsing process.
*
* All names are case sensitive.
*/
final class ImplicitlyIgnoredAnnotationNames
{
private const Reserved = [
'Annotation' => true,
'Attribute' => true,
'Attributes' => true,
/* Can we enable this? 'Enum' => true, */
'Required' => true,
'Target' => true,
];
private const WidelyUsedNonStandard = [
'fix' => true,
'fixme' => true,
'override' => true,
];
private const PhpDocumentor1 = [
'abstract' => true,
'access' => true,
'code' => true,
'deprec' => true,
'endcode' => true,
'exception' => true,
'final' => true,
'ingroup' => true,
'inheritdoc' => true,
'inheritDoc' => true,
'magic' => true,
'name' => true,
'private' => true,
'static' => true,
'staticvar' => true,
'staticVar' => true,
'toc' => true,
'tutorial' => true,
'throw' => true,
];
private const PhpDocumentor2 = [
'api' => true,
'author' => true,
'category' => true,
'copyright' => true,
'deprecated' => true,
'example' => true,
'filesource' => true,
'global' => true,
'ignore' => true,
/* Can we enable this? 'index' => true, */
'internal' => true,
'license' => true,
'link' => true,
'method' => true,
'package' => true,
'param' => true,
'property' => true,
'property-read' => true,
'property-write' => true,
'return' => true,
'see' => true,
'since' => true,
'source' => true,
'subpackage' => true,
'throws' => true,
'todo' => true,
'TODO' => true,
'usedby' => true,
'uses' => true,
'var' => true,
'version' => true,
];
private const PHPUnit = [
'author' => true,
'after' => true,
'afterClass' => true,
'backupGlobals' => true,
'backupStaticAttributes' => true,
'before' => true,
'beforeClass' => true,
'codeCoverageIgnore' => true,
'codeCoverageIgnoreStart' => true,
'codeCoverageIgnoreEnd' => true,
'covers' => true,
'coversDefaultClass' => true,
'coversNothing' => true,
'dataProvider' => true,
'depends' => true,
'doesNotPerformAssertions' => true,
'expectedException' => true,
'expectedExceptionCode' => true,
'expectedExceptionMessage' => true,
'expectedExceptionMessageRegExp' => true,
'group' => true,
'large' => true,
'medium' => true,
'preserveGlobalState' => true,
'requires' => true,
'runTestsInSeparateProcesses' => true,
'runInSeparateProcess' => true,
'small' => true,
'test' => true,
'testdox' => true,
'testWith' => true,
'ticket' => true,
'uses' => true,
];
private const PhpCheckStyle = ['SuppressWarnings' => true];
private const PhpStorm = ['noinspection' => true];
private const PEAR = ['package_version' => true];
private const PlainUML = [
'startuml' => true,
'enduml' => true,
];
private const Symfony = ['experimental' => true];
private const PhpCodeSniffer = [
'codingStandardsIgnoreStart' => true,
'codingStandardsIgnoreEnd' => true,
];
private const SlevomatCodingStandard = ['phpcsSuppress' => true];
private const PhpStan = [
'extends' => true,
'implements' => true,
'template' => true,
'use' => true,
];
private const Phan = ['suppress' => true];
private const Rector = ['noRector' => true];
public const LIST = self::Reserved
+ self::WidelyUsedNonStandard
+ self::PhpDocumentor1
+ self::PhpDocumentor2
+ self::PHPUnit
+ self::PhpCheckStyle
+ self::PhpStorm
+ self::PEAR
+ self::PlainUML
+ self::Symfony
+ self::SlevomatCodingStandard
+ self::PhpCodeSniffer
+ self::PhpStan
+ self::Phan
+ self::Rector;
private function __construct()
{
}
}

View File

@ -0,0 +1,100 @@
<?php
namespace Doctrine\Common\Annotations;
use ReflectionClass;
use ReflectionMethod;
use ReflectionProperty;
use function call_user_func_array;
use function get_class;
/**
* Allows the reader to be used in-place of Doctrine's reader.
*/
class IndexedReader implements Reader
{
/** @var Reader */
private $delegate;
public function __construct(Reader $reader)
{
$this->delegate = $reader;
}
/**
* {@inheritDoc}
*/
public function getClassAnnotations(ReflectionClass $class)
{
$annotations = [];
foreach ($this->delegate->getClassAnnotations($class) as $annot) {
$annotations[get_class($annot)] = $annot;
}
return $annotations;
}
/**
* {@inheritDoc}
*/
public function getClassAnnotation(ReflectionClass $class, $annotation)
{
return $this->delegate->getClassAnnotation($class, $annotation);
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotations(ReflectionMethod $method)
{
$annotations = [];
foreach ($this->delegate->getMethodAnnotations($method) as $annot) {
$annotations[get_class($annot)] = $annot;
}
return $annotations;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotation(ReflectionMethod $method, $annotation)
{
return $this->delegate->getMethodAnnotation($method, $annotation);
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(ReflectionProperty $property)
{
$annotations = [];
foreach ($this->delegate->getPropertyAnnotations($property) as $annot) {
$annotations[get_class($annot)] = $annot;
}
return $annotations;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(ReflectionProperty $property, $annotation)
{
return $this->delegate->getPropertyAnnotation($property, $annotation);
}
/**
* Proxies all methods to the delegate.
*
* @param string $method
* @param mixed[] $args
*
* @return mixed
*/
public function __call($method, $args)
{
return call_user_func_array([$this->delegate, $method], $args);
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace Doctrine\Common\Annotations;
/**
* Marker interface for PHP7/PHP8 compatible support
* for named arguments (and constructor property promotion).
*
* @deprecated Implementing this interface is deprecated
* Use the Annotation @NamedArgumentConstructor instead
*/
interface NamedArgumentConstructorAnnotation
{
}

View File

@ -0,0 +1,92 @@
<?php
namespace Doctrine\Common\Annotations;
use ReflectionClass;
use ReflectionFunction;
use SplFileObject;
use function is_file;
use function method_exists;
use function preg_quote;
use function preg_replace;
/**
* Parses a file for namespaces/use/class declarations.
*/
final class PhpParser
{
/**
* Parses a class.
*
* @deprecated use parseUseStatements instead
*
* @param ReflectionClass $class A <code>ReflectionClass</code> object.
*
* @return array<string, class-string> A list with use statements in the form (Alias => FQN).
*/
public function parseClass(ReflectionClass $class)
{
return $this->parseUseStatements($class);
}
/**
* Parse a class or function for use statements.
*
* @param ReflectionClass|ReflectionFunction $reflection
*
* @psalm-return array<string, string> a list with use statements in the form (Alias => FQN).
*/
public function parseUseStatements($reflection): array
{
if (method_exists($reflection, 'getUseStatements')) {
return $reflection->getUseStatements();
}
$filename = $reflection->getFileName();
if ($filename === false) {
return [];
}
$content = $this->getFileContent($filename, $reflection->getStartLine());
if ($content === null) {
return [];
}
$namespace = preg_quote($reflection->getNamespaceName());
$content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
$tokenizer = new TokenParser('<?php ' . $content);
return $tokenizer->parseUseStatements($reflection->getNamespaceName());
}
/**
* Gets the content of the file right up to the given line number.
*
* @param string $filename The name of the file to load.
* @param int $lineNumber The number of lines to read from file.
*
* @return string|null The content of the file or null if the file does not exist.
*/
private function getFileContent($filename, $lineNumber)
{
if (! is_file($filename)) {
return null;
}
$content = '';
$lineCnt = 0;
$file = new SplFileObject($filename);
while (! $file->eof()) {
if ($lineCnt++ === $lineNumber) {
break;
}
$content .= $file->fgets();
}
return $content;
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace Doctrine\Common\Annotations;
use ReflectionClass;
use ReflectionMethod;
use ReflectionProperty;
/**
* Interface for annotation readers.
*/
interface Reader
{
/**
* Gets the annotations applied to a class.
*
* @param ReflectionClass $class The ReflectionClass of the class from which
* the class annotations should be read.
*
* @return array<object> An array of Annotations.
*/
public function getClassAnnotations(ReflectionClass $class);
/**
* Gets a class annotation.
*
* @param ReflectionClass $class The ReflectionClass of the class from which
* the class annotations should be read.
* @param class-string<T> $annotationName The name of the annotation.
*
* @return T|null The Annotation or NULL, if the requested annotation does not exist.
*
* @template T
*/
public function getClassAnnotation(ReflectionClass $class, $annotationName);
/**
* Gets the annotations applied to a method.
*
* @param ReflectionMethod $method The ReflectionMethod of the method from which
* the annotations should be read.
*
* @return array<object> An array of Annotations.
*/
public function getMethodAnnotations(ReflectionMethod $method);
/**
* Gets a method annotation.
*
* @param ReflectionMethod $method The ReflectionMethod to read the annotations from.
* @param class-string<T> $annotationName The name of the annotation.
*
* @return T|null The Annotation or NULL, if the requested annotation does not exist.
*
* @template T
*/
public function getMethodAnnotation(ReflectionMethod $method, $annotationName);
/**
* Gets the annotations applied to a property.
*
* @param ReflectionProperty $property The ReflectionProperty of the property
* from which the annotations should be read.
*
* @return array<object> An array of Annotations.
*/
public function getPropertyAnnotations(ReflectionProperty $property);
/**
* Gets a property annotation.
*
* @param ReflectionProperty $property The ReflectionProperty to read the annotations from.
* @param class-string<T> $annotationName The name of the annotation.
*
* @return T|null The Annotation or NULL, if the requested annotation does not exist.
*
* @template T
*/
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName);
}

View File

@ -0,0 +1,114 @@
<?php
namespace Doctrine\Common\Annotations;
use ReflectionClass;
use ReflectionMethod;
use ReflectionProperty;
/**
* Simple Annotation Reader.
*
* This annotation reader is intended to be used in projects where you have
* full-control over all annotations that are available.
*
* @deprecated Deprecated in favour of using AnnotationReader
*/
class SimpleAnnotationReader implements Reader
{
/** @var DocParser */
private $parser;
/**
* Initializes a new SimpleAnnotationReader.
*/
public function __construct()
{
$this->parser = new DocParser();
$this->parser->setIgnoreNotImportedAnnotations(true);
}
/**
* Adds a namespace in which we will look for annotations.
*
* @param string $namespace
*
* @return void
*/
public function addNamespace($namespace)
{
$this->parser->addNamespace($namespace);
}
/**
* {@inheritDoc}
*/
public function getClassAnnotations(ReflectionClass $class)
{
return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotations(ReflectionMethod $method)
{
return $this->parser->parse(
$method->getDocComment(),
'method ' . $method->getDeclaringClass()->name . '::' . $method->getName() . '()'
);
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(ReflectionProperty $property)
{
return $this->parser->parse(
$property->getDocComment(),
'property ' . $property->getDeclaringClass()->name . '::$' . $property->getName()
);
}
/**
* {@inheritDoc}
*/
public function getClassAnnotation(ReflectionClass $class, $annotationName)
{
foreach ($this->getClassAnnotations($class) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
{
foreach ($this->getMethodAnnotations($method) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
{
foreach ($this->getPropertyAnnotations($property) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
}

View File

@ -0,0 +1,208 @@
<?php
namespace Doctrine\Common\Annotations;
use function array_merge;
use function count;
use function explode;
use function strtolower;
use function token_get_all;
use const PHP_VERSION_ID;
use const T_AS;
use const T_COMMENT;
use const T_DOC_COMMENT;
use const T_NAME_FULLY_QUALIFIED;
use const T_NAME_QUALIFIED;
use const T_NAMESPACE;
use const T_NS_SEPARATOR;
use const T_STRING;
use const T_USE;
use const T_WHITESPACE;
/**
* Parses a file for namespaces/use/class declarations.
*/
class TokenParser
{
/**
* The token list.
*
* @phpstan-var list<mixed[]>
*/
private $tokens;
/**
* The number of tokens.
*
* @var int
*/
private $numTokens;
/**
* The current array pointer.
*
* @var int
*/
private $pointer = 0;
/**
* @param string $contents
*/
public function __construct($contents)
{
$this->tokens = token_get_all($contents);
// The PHP parser sets internal compiler globals for certain things. Annoyingly, the last docblock comment it
// saw gets stored in doc_comment. When it comes to compile the next thing to be include()d this stored
// doc_comment becomes owned by the first thing the compiler sees in the file that it considers might have a
// docblock. If the first thing in the file is a class without a doc block this would cause calls to
// getDocBlock() on said class to return our long lost doc_comment. Argh.
// To workaround, cause the parser to parse an empty docblock. Sure getDocBlock() will return this, but at least
// it's harmless to us.
token_get_all("<?php\n/**\n *\n */");
$this->numTokens = count($this->tokens);
}
/**
* Gets the next non whitespace and non comment token.
*
* @param bool $docCommentIsComment If TRUE then a doc comment is considered a comment and skipped.
* If FALSE then only whitespace and normal comments are skipped.
*
* @return mixed[]|string|null The token if exists, null otherwise.
*/
public function next($docCommentIsComment = true)
{
for ($i = $this->pointer; $i < $this->numTokens; $i++) {
$this->pointer++;
if (
$this->tokens[$i][0] === T_WHITESPACE ||
$this->tokens[$i][0] === T_COMMENT ||
($docCommentIsComment && $this->tokens[$i][0] === T_DOC_COMMENT)
) {
continue;
}
return $this->tokens[$i];
}
return null;
}
/**
* Parses a single use statement.
*
* @return array<string, string> A list with all found class names for a use statement.
*/
public function parseUseStatement()
{
$groupRoot = '';
$class = '';
$alias = '';
$statements = [];
$explicitAlias = false;
while (($token = $this->next())) {
if (! $explicitAlias && $token[0] === T_STRING) {
$class .= $token[1];
$alias = $token[1];
} elseif ($explicitAlias && $token[0] === T_STRING) {
$alias = $token[1];
} elseif (
PHP_VERSION_ID >= 80000 &&
($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)
) {
$class .= $token[1];
$classSplit = explode('\\', $token[1]);
$alias = $classSplit[count($classSplit) - 1];
} elseif ($token[0] === T_NS_SEPARATOR) {
$class .= '\\';
$alias = '';
} elseif ($token[0] === T_AS) {
$explicitAlias = true;
$alias = '';
} elseif ($token === ',') {
$statements[strtolower($alias)] = $groupRoot . $class;
$class = '';
$alias = '';
$explicitAlias = false;
} elseif ($token === ';') {
$statements[strtolower($alias)] = $groupRoot . $class;
break;
} elseif ($token === '{') {
$groupRoot = $class;
$class = '';
} elseif ($token === '}') {
continue;
} else {
break;
}
}
return $statements;
}
/**
* Gets all use statements.
*
* @param string $namespaceName The namespace name of the reflected class.
*
* @return array<string, string> A list with all found use statements.
*/
public function parseUseStatements($namespaceName)
{
$statements = [];
while (($token = $this->next())) {
if ($token[0] === T_USE) {
$statements = array_merge($statements, $this->parseUseStatement());
continue;
}
if ($token[0] !== T_NAMESPACE || $this->parseNamespace() !== $namespaceName) {
continue;
}
// Get fresh array for new namespace. This is to prevent the parser to collect the use statements
// for a previous namespace with the same name. This is the case if a namespace is defined twice
// or if a namespace with the same name is commented out.
$statements = [];
}
return $statements;
}
/**
* Gets the namespace.
*
* @return string The found namespace.
*/
public function parseNamespace()
{
$name = '';
while (
($token = $this->next()) && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR || (
PHP_VERSION_ID >= 80000 &&
($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)
))
) {
$name .= $token[1];
}
return $name;
}
/**
* Gets the class name.
*
* @return string The found class name.
*/
public function parseClass()
{
// Namespaces and class names are tokenized the same: T_STRINGs
// separated by T_NS_SEPARATOR so we can use one function to provide
// both.
return $this->parseNamespace();
}
}

View File

@ -0,0 +1,19 @@
Copyright (c) 2006-2018 Doctrine Project
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.

View File

@ -0,0 +1,9 @@
# Doctrine Lexer
Build Status: [![Build Status](https://travis-ci.org/doctrine/lexer.svg?branch=master)](https://travis-ci.org/doctrine/lexer)
Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL).
https://www.doctrine-project.org/projects/lexer.html

View File

@ -0,0 +1,41 @@
{
"name": "doctrine/lexer",
"type": "library",
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
"keywords": [
"php",
"parser",
"lexer",
"annotations",
"docblock"
],
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"phpstan/phpstan": "^0.11.8",
"phpunit/phpunit": "^8.2"
},
"autoload": {
"psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" }
},
"autoload-dev": {
"psr-4": { "Doctrine\\Tests\\": "tests/Doctrine" }
},
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"config": {
"sort-packages": true
}
}

View File

@ -0,0 +1,328 @@
<?php
declare(strict_types=1);
namespace Doctrine\Common\Lexer;
use ReflectionClass;
use const PREG_SPLIT_DELIM_CAPTURE;
use const PREG_SPLIT_NO_EMPTY;
use const PREG_SPLIT_OFFSET_CAPTURE;
use function implode;
use function in_array;
use function preg_split;
use function sprintf;
use function substr;
/**
* Base class for writing simple lexers, i.e. for creating small DSLs.
*/
abstract class AbstractLexer
{
/**
* Lexer original input string.
*
* @var string
*/
private $input;
/**
* Array of scanned tokens.
*
* Each token is an associative array containing three items:
* - 'value' : the string value of the token in the input string
* - 'type' : the type of the token (identifier, numeric, string, input
* parameter, none)
* - 'position' : the position of the token in the input string
*
* @var array
*/
private $tokens = [];
/**
* Current lexer position in input string.
*
* @var int
*/
private $position = 0;
/**
* Current peek of current lexer position.
*
* @var int
*/
private $peek = 0;
/**
* The next token in the input.
*
* @var array|null
*/
public $lookahead;
/**
* The last matched/seen token.
*
* @var array|null
*/
public $token;
/**
* Composed regex for input parsing.
*
* @var string
*/
private $regex;
/**
* Sets the input data to be tokenized.
*
* The Lexer is immediately reset and the new input tokenized.
* Any unprocessed tokens from any previous input are lost.
*
* @param string $input The input to be tokenized.
*
* @return void
*/
public function setInput($input)
{
$this->input = $input;
$this->tokens = [];
$this->reset();
$this->scan($input);
}
/**
* Resets the lexer.
*
* @return void
*/
public function reset()
{
$this->lookahead = null;
$this->token = null;
$this->peek = 0;
$this->position = 0;
}
/**
* Resets the peek pointer to 0.
*
* @return void
*/
public function resetPeek()
{
$this->peek = 0;
}
/**
* Resets the lexer position on the input to the given position.
*
* @param int $position Position to place the lexical scanner.
*
* @return void
*/
public function resetPosition($position = 0)
{
$this->position = $position;
}
/**
* Retrieve the original lexer's input until a given position.
*
* @param int $position
*
* @return string
*/
public function getInputUntilPosition($position)
{
return substr($this->input, 0, $position);
}
/**
* Checks whether a given token matches the current lookahead.
*
* @param int|string $token
*
* @return bool
*/
public function isNextToken($token)
{
return $this->lookahead !== null && $this->lookahead['type'] === $token;
}
/**
* Checks whether any of the given tokens matches the current lookahead.
*
* @param array $tokens
*
* @return bool
*/
public function isNextTokenAny(array $tokens)
{
return $this->lookahead !== null && in_array($this->lookahead['type'], $tokens, true);
}
/**
* Moves to the next token in the input string.
*
* @return bool
*/
public function moveNext()
{
$this->peek = 0;
$this->token = $this->lookahead;
$this->lookahead = isset($this->tokens[$this->position])
? $this->tokens[$this->position++] : null;
return $this->lookahead !== null;
}
/**
* Tells the lexer to skip input tokens until it sees a token with the given value.
*
* @param string $type The token type to skip until.
*
* @return void
*/
public function skipUntil($type)
{
while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
$this->moveNext();
}
}
/**
* Checks if given value is identical to the given token.
*
* @param mixed $value
* @param int|string $token
*
* @return bool
*/
public function isA($value, $token)
{
return $this->getType($value) === $token;
}
/**
* Moves the lookahead token forward.
*
* @return array|null The next token or NULL if there are no more tokens ahead.
*/
public function peek()
{
if (isset($this->tokens[$this->position + $this->peek])) {
return $this->tokens[$this->position + $this->peek++];
}
return null;
}
/**
* Peeks at the next token, returns it and immediately resets the peek.
*
* @return array|null The next token or NULL if there are no more tokens ahead.
*/
public function glimpse()
{
$peek = $this->peek();
$this->peek = 0;
return $peek;
}
/**
* Scans the input string for tokens.
*
* @param string $input A query string.
*
* @return void
*/
protected function scan($input)
{
if (! isset($this->regex)) {
$this->regex = sprintf(
'/(%s)|%s/%s',
implode(')|(', $this->getCatchablePatterns()),
implode('|', $this->getNonCatchablePatterns()),
$this->getModifiers()
);
}
$flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
$matches = preg_split($this->regex, $input, -1, $flags);
if ($matches === false) {
// Work around https://bugs.php.net/78122
$matches = [[$input, 0]];
}
foreach ($matches as $match) {
// Must remain before 'value' assignment since it can change content
$type = $this->getType($match[0]);
$this->tokens[] = [
'value' => $match[0],
'type' => $type,
'position' => $match[1],
];
}
}
/**
* Gets the literal for a given token.
*
* @param int|string $token
*
* @return int|string
*/
public function getLiteral($token)
{
$className = static::class;
$reflClass = new ReflectionClass($className);
$constants = $reflClass->getConstants();
foreach ($constants as $name => $value) {
if ($value === $token) {
return $className . '::' . $name;
}
}
return $token;
}
/**
* Regex modifiers
*
* @return string
*/
protected function getModifiers()
{
return 'iu';
}
/**
* Lexical catchable patterns.
*
* @return array
*/
abstract protected function getCatchablePatterns();
/**
* Lexical non-catchable patterns.
*
* @return array
*/
abstract protected function getNonCatchablePatterns();
/**
* Retrieve token type. Also processes the token value if necessary.
*
* @param string $value
*
* @return int|string|null
*/
abstract protected function getType(&$value);
}

View File

@ -0,0 +1,8 @@
/bin/*
!bin/php-ipfs
!bin/rebuild
/vendor/
/composer.phar
/coverage
coverage.xml
phpspec.yml

View File

@ -0,0 +1,37 @@
<?php
$header = <<<EOF
This file is part of the "php-ipfs" package.
(c) Robert Schönthal <robert.schoenthal@gmail.com>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOF;
$finder = PhpCsFixer\Finder::create()
->exclude('vendor')
->exclude('bin')
->in(getenv('PWD')); // this may not be correct in a non-docker environment
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules([
'@Symfony' => true,
'header_comment' => ['header' => $header],
'@PSR2' => true,
'@PSR1' => true,
'array_syntax' => ['syntax' => 'short'],
'ordered_imports' => true,
'strict_comparison' => true,
'strict_param' => true,
'phpdoc_order' => true,
'no_useless_return' => true,
'ereg_to_preg' => true,
'concat_space' => ['spacing' => 'one'],
'binary_operator_spaces' => ['align_equals' => false, 'align_double_arrow' => true],
])
//->setUsingLinter(false)
->setFinder($finder)
->setUsingCache(false);

View File

@ -0,0 +1,44 @@
language: php
sudo: false
cache:
directories:
- $HOME/.composer/cache
php:
- 7.0
- 7.1
- 7.2
- nightly
env:
global:
- TEST_COMMAND="composer test"
matrix:
fast_finish: true
include:
- php: 7.0
env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" TEST_COMMAND="composer coverage" COVERAGE=true"
- php: 7.0
env: TEST_COMMAND="bin/rebuild" CS=true
- php: 7.0
env: TEST_COMMAND="composer cs-check" CS=true
allow_failures:
- php: hhvm
before_install:
- travis_retry composer self-update
- if [[ "$COVERAGE" = true ]]; then composer require --no-update --dev henrikbjorn/phpspec-code-coverage; fi
- if [[ "$CS" = true ]]; then composer global require friendsofphp/php-cs-fixer && export PATH="$PATH:$HOME/.composer/vendor/bin"; fi
install:
- travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction
script:
- $TEST_COMMAND
after_success:
- if [[ "$COVERAGE" = true ]]; then wget https://scrutinizer-ci.com/ocular.phar; fi
- if [[ "$COVERAGE" = true ]]; then php ocular.phar code-coverage:upload --format=php-clover coverage.xml; fi

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Robert Schönthal
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.

View File

@ -0,0 +1,263 @@
# PHP Adapter for IPFS
![ipfs](https://user-images.githubusercontent.com/1211152/29604883-ca3a4028-87e0-11e7-9f9a-75de49b06048.png)
Dont know what ipfs is? the future of filesystems :) read [here](https://ipfs.io) for more information!
[![Build Status](https://travis-ci.org/digitalkaoz/php-ipfs-api.svg?branch=master)](https://travis-ci.org/digitalkaoz/php-ipfs-api)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/digitalkaoz/php-ipfs-api/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/digitalkaoz/php-ipfs-api/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/digitalkaoz/php-ipfs-api/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/digitalkaoz/php-ipfs-api/?branch=master)
## Installation
as always, use composer!
```
$ composer require ipfs/php-client
```
### choosing the HTTP Adapter
If you plan to use the REST Interface of the ipfs-daemon you should choose a http-implementation. We use [php-http](http://docs.php-http.org/) for abstraction.
See [here](https://packagist.org/providers/php-http/async-client-implementation) for a list of available implementations!
if you only want to speak with a local ipfs-daemon you should use the `IPFS\\Drivers\\Cli` adapter.
### Annotations
as we use Annotations you should register the `AnnotationLoader`
```php
$loader = require __DIR__.'/../vendor/autoload.php';
use Doctrine\Common\Annotations\AnnotationRegistry;
AnnotationRegistry::registerLoader(array($loader, "loadClass"));
```
## Drivers
we ship with different adapters for communicating with the daemon.
### CLI
if you are using an `ipfs` binary that is not available in you `$PATH` variable, provide an `ENV` var for it:
```
$ export IPFS_BINARY=/my/location/to/ipfs
```
> make sure you set `IPFS_PATH` in you `ENV` if you are not using `~/.ipfs` as location.
to use this Driver from the commandline simply provide the option:
```
$ bin/php-ipfs version --driver=IPFS\\Driver\\Cli
```
### HTTP
if you are talking to a remote daemon provide an `ENV` var for it:
```
$ export IPFS_API=http://somehost:5001/api/v0
```
to use this Driver from the commandline simply provide the option (or leave it away since its the default):
```
$ bin/php-ipfs version --driver=IPFS\\Driver\\Http
$ bin/php-ipfs version
```
### Client
this Driver is intended for programmatically usage:
```php
$driver = $container[IPFS\Driver\Cli::class];
//$driver = $container[IPFS\Driver\Http::class];
$client = new IPFS\Client($driver);
$response = $client->execute((new \IPFS\Api\Basics())->version());
var_dump($response);
```
## Apis
All Api-Endpoints are autogenerated from the official [ipfs docs](https://ipfs.io/docs/api/) and are regulary checked for changes.
> To rebuild the Apis yourself, simply run `composer rebuild-api`
The following endpoints exists:
```
Available commands:
add Add a file or directory to ipfs.
cat Show IPFS object data.
commands List all available commands.
dns Resolve DNS links.
get Download IPFS objects.
help Displays help for a command
id Show ipfs node id info.
list Lists commands
ls List directory contents for Unix filesystem objects.
mount Mounts IPFS to the filesystem (read-only).
ping Send echo request packets to IPFS hosts.
rebuild rebuild api classes by parsing the official api doc
resolve Resolve the value of names to IPFS.
shutdown Shut down the ipfs daemon.
update
version Show ipfs version information.
bitswap
bitswap:ledger Show the current ledger for a peer.
bitswap:reprovide Trigger reprovider.
bitswap:stat Show some diagnostic information on the bitswap agent.
bitswap:unwant Remove a given block from your wantlist.
bitswap:wantlist Show blocks currently on the wantlist.
block
block:get Get a raw IPFS block.
block:put Store input as an IPFS block.
block:rm Remove IPFS block(s).
block:stat Print information of a raw IPFS block.
bootstrap
bootstrap:add:default Add default peers to the bootstrap list.
bootstrap:list Show peers in the bootstrap list.
bootstrap:rm:all Remove all peers from the bootstrap list.
config
config:edit Open the config file for editing in $EDITOR.
config:profile:apply Apply profile to config.
config:replace Replace the config with .
config:show Output config file contents.
dag
dag:get Get a dag node from ipfs.
dag:put Add a dag node to ipfs.
dag:resolve Resolve ipld block.
dht
dht:findpeer Query the DHT for all of the multiaddresses associated with a Peer ID.
dht:findprovs Find peers in the DHT that can provide a specific value, given a key.
dht:get Given a key, query the DHT for its best value.
dht:provide Announce to the network that you are providing given values.
dht:put Write a key/value pair to the DHT.
dht:query Find the closest Peer IDs to a given Peer ID by querying the DHT.
diag
diag:cmds:clear Clear inactive requests from the log.
diag:cmds:set-time Set how long to keep inactive requests in the log.
diag:sys Print system diagnostic information.
file
file:ls List directory contents for Unix filesystem objects.
files
files:chcid Change the cid version or hash function of the root node of a given path.
files:cp Copy files into mfs.
files:flush Flush a given paths data to disk.
files:ls List directories in the local mutable namespace.
files:mkdir Make directories.
files:mv Move files.
files:read Read a file in a given mfs.
files:rm Remove a file.
files:stat Display file status.
files:write Write to a mutable file in a given filesystem.
filestore
filestore:dups List blocks that are both in the filestore and standard block storage.
filestore:ls List objects in filestore.
filestore:verify Verify objects in filestore.
key
key:gen Create a new keypair.
key:list List all local keypairs.
key:rename Rename a keypair.
key:rm Remove a keypair.
log
log:level Change the logging level.
log:ls List the logging subsystems.
log:tail Read the event log.
name
name:publish Publish IPNS names.
name:pubsub:cancel Cancel a name subscription.
name:pubsub:state Query the state of IPNS pubsub.
name:pubsub:subs Show current name subscriptions.
name:resolve Resolve IPNS names.
object
object:data Output the raw bytes of an IPFS object.
object:diff Display the diff between two ipfs objects.
object:get Get and serialize the DAG node named by .
object:links Output the links pointed to by the specified object.
object:new Create a new object from an ipfs template.
object:patch:add-link Add a link to a given object.
object:patch:append-data Append data to the data segment of a dag node.
object:patch:rm-link Remove a link from an object.
object:patch:set-data Set the data field of an IPFS object.
object:put Store input as a DAG object, print its key.
object:stat Get stats for the DAG node named by .
p2p
p2p:listener:close Close active p2p listener.
p2p:listener:ls List active p2p listeners.
p2p:listener:open Forward p2p connections to a network multiaddr.
p2p:stream:close Close active p2p stream.
p2p:stream:dial Dial to a p2p listener.
p2p:stream:ls List active p2p streams.
pin
pin:add Pin objects to local storage.
pin:ls List objects pinned to local storage.
pin:rm Remove pinned objects from local storage.
pin:update Update a recursive pin.
pin:verify Verify that recursive pins are complete.
pubsub
pubsub:ls List subscribed topics by name.
pubsub:peers List peers we are currently pubsubbing with.
pubsub:pub Publish a message to a given pubsub topic.
pubsub:sub Subscribe to messages on a given topic.
refs
refs:local List all local references.
repo
repo:fsck Remove repo lockfiles.
repo:gc Perform a garbage collection sweep on the repo.
repo:stat Get stats for the currently used repo.
repo:verify Verify all blocks in repo are not corrupted.
repo:version Show the repo version.
stats
stats:bitswap Show some diagnostic information on the bitswap agent.
stats:bw Print ipfs bandwidth information.
stats:repo Get stats for the currently used repo.
swarm
swarm:addrs:listen List interface listening addresses.
swarm:addrs:local List local addresses.
swarm:connect Open connection to a given address.
swarm:disconnect Close connection to a given address.
swarm:filters:add Add an address filter.
swarm:filters:rm Remove an address filter.
swarm:peers List peers with open connections.
tar
tar:add Import a tar file into ipfs.
tar:cat Export a tar file from IPFS.
```
## Usage
simply use the commandline interface
```
$ bin/php-ipfs
$ bin/php-ipfs add ./composer.lock --wrap-with-directory --driver=IPFS\\Driver\\Cli
$ bin/php-ipfs add ./composer.lock --wrap-with-directory
```
## PHAR
to build a `phar` file simply run
> we assume you have https://box-project.github.io/box2/ installed!
```
$ composer build
```
## Tests
this library is well covered with [phpspec](http://www.phpspec.net/)
```
$ composer test
```

View File

@ -0,0 +1 @@
theme: jekyll-theme-minimal

View File

@ -0,0 +1,20 @@
#!/usr/bin/env php
<?php
$loader = require __DIR__.'/../vendor/autoload.php';
use Doctrine\Common\Annotations\AnnotationRegistry;
use IPFS\Container\ServiceProvider;
use Pimple\Container;
use Symfony\Component\Console\Application;
AnnotationRegistry::registerLoader(array($loader, "loadClass"));
function run()
{
$container = new Container();
$container->register(new ServiceProvider());
$container[Application::class]->run();
}
run();

View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
composer rebuild-api
echo "MODIFIED FILES:"
git ls-files -m src/Api
git diff src/Api
exit $(git ls-files -m src/Api | wc -l)

View File

@ -0,0 +1,33 @@
{
"alias": "php-ipfs.phar",
"chmod": "0755",
"compactors": [
"Herrera\\Box\\Compactor\\Php"
],
"directories": [
"src"
],
"directories-bin": [
"src/Api",
"src/Annotation"
],
"extract": true,
"files": [
"LICENSE"
],
"finder": [
{
"name": "*.php",
"exclude": [
"tests", "Tests"
],
"in": "vendor"
}
],
"git-commit": "git-commit",
"git-version": "git-version",
"main": "bin/php-ipfs",
"output": "php-ipfs.phar",
"stub": true
}

View File

@ -0,0 +1,58 @@
{
"name": "ipfs/php-client",
"description": "ipfs client library",
"keywords" : ["ipfs", "api"],
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Robert Schönthal",
"email": "robert.schoenthal@gmail.com"
}
],
"require": {
"php": "^7.0",
"pimple/pimple": "^3.0",
"php-http/httplug": "^1.1",
"symfony/process": "^3.2",
"webmozart/assert": "^1.2",
"symfony/console": "^3.0",
"doctrine/annotations": "^1.3",
"mattketmo/camel": "^1.1",
"phpdocumentor/reflection-docblock": "^3.0",
"phpdocumentor/type-resolver": ">=0.1.7",
"rybakit/arguments-resolver": "^0.5.0",
"php-http/message": "^1.4",
"php-http/multipart-stream-builder": "^1.0",
"php-http/client-common": "^1.4",
"php-http/discovery": "^1.1",
"symfony/dom-crawler": "^3.0",
"symfony/css-selector": "^3.0",
"nikic/php-parser": "^3.0"
},
"require-dev" :{
"symfony/var-dumper" : "^3.0",
"php-http/guzzle6-adapter": ">=1.1.1",
"phpspec/phpspec": ">=3.0"
},
"autoload": {
"psr-4": {
"IPFS\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"spec\\IPFS\\": "tests/spec"
}
},
"scripts" : {
"test": "vendor/bin/phpspec run -f pretty --ansi -vv $@",
"coverage": "vendor/bin/phpspec run -f pretty --ansi -vv -c phpspec.yml.coverage $@",
"cs": "php-cs-fixer fix",
"cs-check": "php-cs-fixer fix --dry-run -vv --diff",
"rebuild-api" : "php bin/php-ipfs rebuild && composer cs",
"build" : "rm -rf vendor/* && composer require php-http/guzzle6-adapter && composer install -q --ansi -a -o --no-dev && box --ansi -v build && composer --ansi -q update && git checkout -- composer.json"
}
}

2665
www/multitube/vendor/ipfs/php-client/composer.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
suites:
default:
namespace: IPFS
psr4_prefix: IPFS
spec_path: tests
extensions:
PhpSpecCodeCoverage\CodeCoverageExtension:
whitelist: [src]
format:
- text
- clover
- html
output:
clover: coverage.xml
html: coverage
bootstrap: tests/spec/bootstrap.php

View File

@ -0,0 +1,7 @@
suites:
default:
namespace: IPFS
psr4_prefix: IPFS
spec_path: tests
bootstrap: tests/spec/bootstrap.php

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Annotation;
use Doctrine\Common\Annotations\Annotation;
/**
* @Annotation()
* @Annotation\Target({"METHOD"})
* @Annotation\Attributes({
* @Annotation\Attribute("name", type="string", required=true)
* })
*/
class Api
{
public $name = null;
}

View File

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Annotation;
class Param
{
private $name;
private $description;
private $default;
public function __construct(string $name, string $description, $default = __CLASS__)
{
$this->name = $name;
$this->description = $description;
$this->default = $default;
}
public function getDefault()
{
return __CLASS__ === $this->default ? null : $this->default;
}
public function getName(): string
{
return $this->name;
}
public function getDescription(): string
{
return $this->description;
}
public function hasDefault(): bool
{
return __CLASS__ !== $this->default;
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
interface Api
{
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
class ApiBuilder
{
/**
* @var ApiParser
*/
private $parser;
/**
* @var ApiGenerator
*/
private $generator;
public function __construct(ApiParser $parser, ApiGenerator $generator)
{
$this->parser = $parser;
$this->generator = $generator;
}
public function build($url = 'https://docs.ipfs.io/reference/api/http/', $prefix = '#api-v0')
{
//parse
$config = $this->parser->build($url, $prefix);
//dump
$this->generator->build($config);
}
}

View File

@ -0,0 +1,158 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
use IPFS\Utils\CaseFormatter;
use PhpParser\Builder\Method;
use PhpParser\BuilderFactory;
use PhpParser\Node;
use PhpParser\PrettyPrinter\Standard;
class ApiGenerator
{
/**
* @var BuilderFactory
*/
private $builder;
/**
* @var string
*/
private $location;
public function __construct(BuilderFactory $builder, $location = __DIR__)
{
$this->builder = $builder;
$this->location = $location;
}
public function build(array $configs)
{
foreach ($configs as $name => $config) {
$methods = [];
foreach ($config as $methodConfig) {
$method = $this->buildMethodNode($methodConfig);
$methods[] = $method;
}
$header = $this->buildHeaderNode();
$class = $this->buildClassNode($name, $methods);
$prettyPrinter = new Standard();
file_put_contents(
$this->location . '/' . ucfirst(CaseFormatter::dashToCamel($this->generateClassName($name))) . '.php',
$prettyPrinter->prettyPrintFile([$header, $class])
);
}
}
private function buildMethodNode(array $methodConfig): Method
{
$method = $this->builder
->method($methodConfig['method'])
->makePublic()
->setReturnType('Command')
->setDocComment($this->buildDocBlock($methodConfig));
foreach ($methodConfig['arguments'] as $parameterConfig) {
$parameter = $this->builder
->param($parameterConfig['name'])
->setTypeHint($parameterConfig['type']);
if (!$parameterConfig['required']) {
$default = $parameterConfig['default'];
if ('int' === $parameterConfig['type']) {
$default = (int) $default;
}
$parameter->setDefault($default);
}
$method->addParam($parameter);
}
$method->addStmt(new Node\Stmt\Return_(
new Node\Expr\New_(new Node\Name('Command'), [
new Node\Scalar\MagicConst\Method(),
new Node\Expr\FuncCall(new Node\Name('get_defined_vars')),
])
));
return $method;
}
private function buildClassNode(string $name, array $methods): Node
{
return $this->builder->namespace('IPFS\Api')
->addStmt($this->builder->use(Endpoint::class)->as('Endpoint'))
->addStmt($this->builder->use(Command::class))
->addStmt(
$this->builder->class($this->generateClassName($name))
->implement('Api')
->addStmts($methods)
->setDocComment(
<<<'EOS'
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
EOS
)
->makeFinal()
)
->getNode();
}
private function generateClassName(string $name): string
{
if ('Object' === $name) {
return 'Cobject';
}
return $name;
}
private function buildDocBlock(array $methodConfig): string
{
$params = count($methodConfig['arguments']) ? '' : '*';
foreach ($methodConfig['arguments'] as $index => $argument) {
$suffix = $index + 1 === count($methodConfig['arguments']) ? "\n*" : "\n";
$params .= sprintf('* @param %s $%s %s%s', $argument['type'], $argument['name'], $argument['description'], $suffix);
}
return <<<EOS
/**
* {$methodConfig['description']}
*
* @Endpoint(name="{$methodConfig['parts']}")
*
{$params}
* @return Command
*/
EOS;
}
private function buildHeaderNode(): Node
{
return new Node\Stmt\Declare_(
[new Node\Stmt\DeclareDeclare('strict_types', new Node\Scalar\LNumber(1))]
);
}
}

View File

@ -0,0 +1,167 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use Http\Client\HttpAsyncClient;
use Http\Message\MessageFactory;
use IPFS\Utils\CaseFormatter;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\DomCrawler\Crawler;
class ApiParser
{
/**
* @var HttpAsyncClient
*/
private $client;
/**
* @var MessageFactory
*/
private $messageFactory;
/**
* @var Crawler
*/
private $crawler;
public function __construct(HttpAsyncClient $client, MessageFactory $messageFactory, Crawler $crawler)
{
$this->client = $client;
$this->messageFactory = $messageFactory;
$this->crawler = $crawler;
}
public function build(string $url = 'https://docs.ipfs.io/reference/api/http/', string $prefix = '#api-v0'): array
{
return $this->client
->sendAsyncRequest($this->messageFactory->createRequest('GET', $url))
->then(function (ResponseInterface $response) use ($prefix) {
return $this->buildMethods($response, $prefix);
})
->wait()
;
}
private function buildMethods(ResponseInterface $response, $prefix): array
{
$this->crawler->addHtmlContent($response->getBody()->getContents());
$links = $this->crawler->filter('main li a[href^="' . $prefix . '"]')->each(function (Crawler $node) {
return $node->attr('href');
});
$config = [];
foreach ($links as $link) {
$link = $this->fixDocumentationLinks($link);
$anchor = $this->crawler->filter($link)->first();
$description = 'p' === $anchor->nextAll()->first()->getNode(0)->nodeName ? $anchor->nextAll()->first()->text() : null;
$methodConfig = [
'parts' => str_replace('/', ':', str_replace('/api/v0/', '', $anchor->text())),
'description' => $description,
'arguments' => $this->parseArguments($anchor, $description ? 2 : 1),
];
$nameParts = explode(':', $methodConfig['parts']);
if (count($nameParts) > 1) {
$class = array_shift($nameParts);
$methodConfig['class'] = ucfirst(CaseFormatter::dashToCamel($class));
$methodConfig['method'] = CaseFormatter::dashToCamel(implode('-', $nameParts));
} else {
$methodConfig['class'] = 'Basics';
$methodConfig['method'] = CaseFormatter::dashToCamel($methodConfig['parts']);
}
$config[$methodConfig['class']][] = $methodConfig;
}
return $config;
}
private function parseArguments(Crawler $anchor, int $index): array
{
$argumentsRootNode = $anchor->nextAll()->eq($index)->first();
if ('ul' === $argumentsRootNode->getNode(0)->nodeName) {
$names = [];
return $argumentsRootNode->filter('li')->each(function (Crawler $argument) use (&$names) {
$description = $argument->filter('code')->first()->getNode(0)->nextSibling->textContent;
$name = CaseFormatter::dashToCamel($argument->filter('code')->first()->text());
if (!isset($names[$name])) {
$names[$name] = 0;
} else {
++$names[$name];
}
$config = [
'name' => 0 === $names[$name] ? $name : $name . $names[$name],
'required' => $argument->filter('strong')->count() > 0,
'description' => $this->parseDescription($description),
'default' => $this->parseDefaultValue($description),
'type' => $this->parseTypeHint($description),
];
$config['default'] = 'bool' === $config['type'] && null === $config['default'] ? false : $config['default'];
//fixup files
if ('file' === $config['type']) {
$config['type'] = 'string';
$config['name'] = 'file';
}
return $config;
});
}
return [];
}
private function parseDefaultValue(string $description)
{
preg_match('/Default.* [|"|“]([^\.]+)[|"|”]\./', $description, $default);
if (2 === count($default)) {
$default = preg_replace('/[^\x00-\x7f]/', '', $default[1]);
return CaseFormatter::stringToBool($default);
}
}
private function parseDescription($description): string
{
preg_match('/\]\: (.+)/', $description, $default);
if (count($default) > 1) {
return substr($default[1], 0, strpos($default[1], '.') ?: strlen($default[1])) . '.';
}
}
private function parseTypeHint(string $description): string
{
preg_match('/\[([^\]]+)\]/', $description, $default);
if (count($default) > 1) {
return $default[1];
}
}
private function fixDocumentationLinks(string $link): string
{
if ('#api-v0-statsrepo' === $link) {
return '#api-v0-stats-repo';
}
return $link;
}
}

View File

@ -0,0 +1,237 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Basics implements Api
{
/**
* Add a file or directory to ipfs.
*
* @Endpoint(name="add")
*
* @param string $file the path to a file to be added to ipfs
* @param bool $recursive add directory paths recursively
* @param bool $quiet write minimal output
* @param bool $quieter write only final hash
* @param bool $silent write no output
* @param bool $progress stream progress data
* @param bool $trickle use trickle-dag format for dag generation
* @param bool $onlyHash only chunk and hash - do not write to disk
* @param bool $wrapWithDirectory wrap files with a directory object
* @param bool $hidden include files that are hidden
* @param string $chunker chunking algorithm, size-[bytes] or rabin-[min]-[avg]-[max]
* @param bool $pin pin this object when adding
* @param bool $rawLeaves use raw blocks for leaf nodes
* @param bool $nocopy add the file using filestore
* @param bool $fscache check the filestore for pre-existing blocks
* @param int $cidVersion CID version
* @param string $hash hash function to use
*
* @return Command
*/
public function add(string $file, bool $recursive = false, bool $quiet = false, bool $quieter = false, bool $silent = false, bool $progress = false, bool $trickle = false, bool $onlyHash = false, bool $wrapWithDirectory = false, bool $hidden = false, string $chunker = 'size-262144', bool $pin = true, bool $rawLeaves = false, bool $nocopy = false, bool $fscache = false, int $cidVersion = 0, string $hash = 'sha2-256'): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Show IPFS object data.
*
* @Endpoint(name="cat")
*
* @param string $arg the path to the IPFS object(s) to be outputted
* @param int $offset byte offset to begin reading from
* @param int $length maximum number of bytes to read
*
* @return Command
*/
public function cat(string $arg, int $offset = 0, int $length = 0): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List all available commands.
*
* @Endpoint(name="commands")
*
* @param bool $flags show command flags
*
* @return Command
*/
public function commands(bool $flags = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Resolve DNS links.
*
* @Endpoint(name="dns")
*
* @param string $arg the domain-name name to resolve
* @param bool $recursive resolve until the result is not a DNS link
*
* @return Command
*/
public function dns(string $arg, bool $recursive = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Download IPFS objects.
*
* @Endpoint(name="get")
*
* @param string $arg the path to the IPFS object(s) to be outputted
* @param string $output the path where the output should be stored
* @param bool $archive output a TAR archive
* @param bool $compress compress the output with GZIP compression
* @param int $compressionLevel the level of compression (1-9)
*
* @return Command
*/
public function get(string $arg, string $output = null, bool $archive = false, bool $compress = false, int $compressionLevel = 0): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Show ipfs node id info.
*
* @Endpoint(name="id")
*
* @param string $arg peer
* @param string $format optional output format
*
* @return Command
*/
public function id(string $arg = null, string $format = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List directory contents for Unix filesystem objects.
*
* @Endpoint(name="ls")
*
* @param string $arg the path to the IPFS object(s) to list links from
* @param bool $headers print table headers (Hash, Size, Name)
* @param bool $resolveType resolve linked objects to find out their types
*
* @return Command
*/
public function ls(string $arg, bool $headers = false, bool $resolveType = true): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Mounts IPFS to the filesystem (read-only).
*
* @Endpoint(name="mount")
*
* @param string $ipfsPath the path where IPFS should be mounted
* @param string $ipnsPath the path where IPNS should be mounted
*
* @return Command
*/
public function mount(string $ipfsPath = null, string $ipnsPath = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Send echo request packets to IPFS hosts.
*
* @Endpoint(name="ping")
*
* @param string $arg ID of peer to be pinged
* @param int $count number of ping messages to send
*
* @return Command
*/
public function ping(string $arg, int $count = 10): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Resolve the value of names to IPFS.
*
* @Endpoint(name="resolve")
*
* @param string $arg the name to resolve
* @param bool $recursive resolve until the result is an IPFS name
* @param uint $dhtRecordCount number of records to request for DHT resolution
* @param string $dhtTimeout max time to collect values during DHT resolution eg “30s”
*
* @return Command
*/
public function resolve(string $arg, bool $recursive = false, uint $dhtRecordCount = null, string $dhtTimeout = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Shut down the ipfs daemon.
*
* @Endpoint(name="shutdown")
*
* @return Command
*/
public function shutdown(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* @Endpoint(name="update")
*
* @param string $arg arguments for subcommand
*
* @return Command
*/
public function update(string $arg = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Show ipfs version information.
*
* @Endpoint(name="version")
*
* @param bool $number only show the version number
* @param bool $commit show the commit hash
* @param bool $repo show repo version
* @param bool $all show all version information
*
* @return Command
*/
public function version(bool $number = false, bool $commit = false, bool $repo = false, bool $all = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Bitswap implements Api
{
/**
* Show the current ledger for a peer.
*
* @Endpoint(name="bitswap:ledger")
*
* @param string $arg the PeerID (B58) of the ledger to inspect
*
* @return Command
*/
public function ledger(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Trigger reprovider.
*
* @Endpoint(name="bitswap:reprovide")
*
* @return Command
*/
public function reprovide(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Show some diagnostic information on the bitswap agent.
*
* @Endpoint(name="bitswap:stat")
*
* @return Command
*/
public function stat(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Remove a given block from your wantlist.
*
* @Endpoint(name="bitswap:unwant")
*
* @param string $arg key(s) to remove from your wantlist
*
* @return Command
*/
public function unwant(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Show blocks currently on the wantlist.
*
* @Endpoint(name="bitswap:wantlist")
*
* @param string $peer specify which peer to show wantlist for
*
* @return Command
*/
public function wantlist(string $peer = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Block implements Api
{
/**
* Get a raw IPFS block.
*
* @Endpoint(name="block:get")
*
* @param string $arg the base58 multihash of an existing block to get
*
* @return Command
*/
public function get(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Store input as an IPFS block.
*
* @Endpoint(name="block:put")
*
* @param string $file the data to be stored as an IPFS block
* @param string $format cid format for blocks to be created with
* @param string $mhtype multihash hash function
* @param int $mhlen multihash hash length
*
* @return Command
*/
public function put(string $file, string $format = null, string $mhtype = 'sha2-256', int $mhlen = -1): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Remove IPFS block(s).
*
* @Endpoint(name="block:rm")
*
* @param string $arg bash58 encoded multihash of block(s) to remove
* @param bool $force ignore nonexistent blocks
* @param bool $quiet write minimal output
*
* @return Command
*/
public function rm(string $arg, bool $force = false, bool $quiet = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Print information of a raw IPFS block.
*
* @Endpoint(name="block:stat")
*
* @param string $arg the base58 multihash of an existing block to stat
*
* @return Command
*/
public function stat(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Bootstrap implements Api
{
/**
* Add default peers to the bootstrap list.
*
* @Endpoint(name="bootstrap:add:default")
*
* @return Command
*/
public function addDefault(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Show peers in the bootstrap list.
*
* @Endpoint(name="bootstrap:list")
*
* @return Command
*/
public function list(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Remove all peers from the bootstrap list.
*
* @Endpoint(name="bootstrap:rm:all")
*
* @return Command
*/
public function rmAll(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,192 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Cobject implements Api
{
/**
* Output the raw bytes of an IPFS object.
*
* @Endpoint(name="object:data")
*
* @param string $arg key of the object to retrieve, in base58-encoded multihash format
*
* @return Command
*/
public function data(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Display the diff between two ipfs objects.
*
* @Endpoint(name="object:diff")
*
* @param string $arg object to diff against
* @param string $arg1 object to diff
* @param bool $verbose print extra information
*
* @return Command
*/
public function diff(string $arg, string $arg1, bool $verbose = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Get and serialize the DAG node named by .
*
* @Endpoint(name="object:get")
*
* @param string $arg key of the object to retrieve, in base58-encoded multihash format
*
* @return Command
*/
public function get(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Output the links pointed to by the specified object.
*
* @Endpoint(name="object:links")
*
* @param string $arg key of the object to retrieve, in base58-encoded multihash format
* @param bool $headers print table headers (Hash, Size, Name)
*
* @return Command
*/
public function links(string $arg, bool $headers = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Create a new object from an ipfs template.
*
* @Endpoint(name="object:new")
*
* @param string $arg template to use
*
* @return Command
*/
public function new(string $arg = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Add a link to a given object.
*
* @Endpoint(name="object:patch:add-link")
*
* @param string $arg the hash of the node to modify
* @param string $arg1 name of link to create
* @param string $arg2 IPFS object to add link to
* @param bool $create create intermediary nodes
*
* @return Command
*/
public function patchAddLink(string $arg, string $arg1, string $arg2, bool $create = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Append data to the data segment of a dag node.
*
* @Endpoint(name="object:patch:append-data")
*
* @param string $arg the hash of the node to modify
* @param string $file data to append
*
* @return Command
*/
public function patchAppendData(string $arg, string $file): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Remove a link from an object.
*
* @Endpoint(name="object:patch:rm-link")
*
* @param string $arg the hash of the node to modify
* @param string $arg1 name of the link to remove
*
* @return Command
*/
public function patchRmLink(string $arg, string $arg1): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Set the data field of an IPFS object.
*
* @Endpoint(name="object:patch:set-data")
*
* @param string $arg the hash of the node to modify
* @param string $file the data to set the object to
*
* @return Command
*/
public function patchSetData(string $arg, string $file): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Store input as a DAG object, print its key.
*
* @Endpoint(name="object:put")
*
* @param string $file data to be stored as a DAG object
* @param string $inputenc encoding type of input data
* @param string $datafieldenc encoding type of the data field, either “text” or “base64”
* @param bool $pin pin this object when adding
* @param bool $quiet write minimal output
*
* @return Command
*/
public function put(string $file, string $inputenc = 'json', string $datafieldenc = 'text', bool $pin = false, bool $quiet = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Get stats for the DAG node named by .
*
* @Endpoint(name="object:stat")
*
* @param string $arg key of the object to retrieve, in base58-encoded multihash format
*
* @return Command
*/
public function stat(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Config implements Api
{
/**
* Open the config file for editing in $EDITOR.
*
* @Endpoint(name="config:edit")
*
* @return Command
*/
public function edit(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Apply profile to config.
*
* @Endpoint(name="config:profile:apply")
*
* @param string $arg the profile to apply to the config
*
* @return Command
*/
public function profileApply(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Replace the config with .
*
* @Endpoint(name="config:replace")
*
* @param string $file the file to use as the new config
*
* @return Command
*/
public function replace(string $file): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Output config file contents.
*
* @Endpoint(name="config:show")
*
* @return Command
*/
public function show(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Dag implements Api
{
/**
* Get a dag node from ipfs.
*
* @Endpoint(name="dag:get")
*
* @param string $arg the object to get Required:
*
* @return Command
*/
public function get(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Add a dag node to ipfs.
*
* @Endpoint(name="dag:put")
*
* @param string $file the object to put Required:
* @param string $format format that the object will be added as
* @param string $inputEnc format that the input object will be
* @param bool $pin pin this object when adding
* @param string $hash hash function to use
*
* @return Command
*/
public function put(string $file, string $format = 'cbor', string $inputEnc = 'json', bool $pin = false, string $hash = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Resolve ipld block.
*
* @Endpoint(name="dag:resolve")
*
* @param string $arg the path to resolve Required:
*
* @return Command
*/
public function resolve(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,118 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Dht implements Api
{
/**
* Query the DHT for all of the multiaddresses associated with a Peer ID.
*
* @Endpoint(name="dht:findpeer")
*
* @param string $arg the ID of the peer to search for
* @param bool $verbose print extra information
*
* @return Command
*/
public function findpeer(string $arg, bool $verbose = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Find peers in the DHT that can provide a specific value, given a key.
*
* @Endpoint(name="dht:findprovs")
*
* @param string $arg the key to find providers for
* @param bool $verbose print extra information
* @param int $numProviders the number of providers to find
*
* @return Command
*/
public function findprovs(string $arg, bool $verbose = false, int $numProviders = 20): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Given a key, query the DHT for its best value.
*
* @Endpoint(name="dht:get")
*
* @param string $arg the key to find a value for
* @param bool $verbose print extra information
*
* @return Command
*/
public function get(string $arg, bool $verbose = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Announce to the network that you are providing given values.
*
* @Endpoint(name="dht:provide")
*
* @param string $arg the key[s] to send provide records for
* @param bool $verbose print extra information
* @param bool $recursive recursively provide entire graph
*
* @return Command
*/
public function provide(string $arg, bool $verbose = false, bool $recursive = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Write a key/value pair to the DHT.
*
* @Endpoint(name="dht:put")
*
* @param string $arg the key to store the value at
* @param string $arg1 the value to store
* @param bool $verbose print extra information
*
* @return Command
*/
public function put(string $arg, string $arg1, bool $verbose = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Find the closest Peer IDs to a given Peer ID by querying the DHT.
*
* @Endpoint(name="dht:query")
*
* @param string $arg the peerID to run the query against
* @param bool $verbose print extra information
*
* @return Command
*/
public function query(string $arg, bool $verbose = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Diag implements Api
{
/**
* Clear inactive requests from the log.
*
* @Endpoint(name="diag:cmds:clear")
*
* @return Command
*/
public function cmdsClear(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Set how long to keep inactive requests in the log.
*
* @Endpoint(name="diag:cmds:set-time")
*
* @param string $arg time to keep inactive requests in log
*
* @return Command
*/
public function cmdsSetTime(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Print system diagnostic information.
*
* @Endpoint(name="diag:sys")
*
* @return Command
*/
public function sys(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class File implements Api
{
/**
* List directory contents for Unix filesystem objects.
*
* @Endpoint(name="file:ls")
*
* @param string $arg the path to the IPFS object(s) to list links from
*
* @return Command
*/
public function ls(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,188 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Files implements Api
{
/**
* Change the cid version or hash function of the root node of a given path.
*
* @Endpoint(name="files:chcid")
*
* @param string $arg path to change
* @param int $cidVersion cid version to use
* @param string $hash hash function to use
*
* @return Command
*/
public function chcid(string $arg = '/', int $cidVersion = 0, string $hash = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Copy files into mfs.
*
* @Endpoint(name="files:cp")
*
* @param string $arg source object to copy
* @param string $arg1 destination to copy object to
*
* @return Command
*/
public function cp(string $arg, string $arg1): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Flush a given paths data to disk.
*
* @Endpoint(name="files:flush")
*
* @param string $arg path to flush
*
* @return Command
*/
public function flush(string $arg = '/'): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List directories in the local mutable namespace.
*
* @Endpoint(name="files:ls")
*
* @param string $arg path to show listing for
* @param bool $l use long listing format
*
* @return Command
*/
public function ls(string $arg = '/', bool $l = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Make directories.
*
* @Endpoint(name="files:mkdir")
*
* @param string $arg path to dir to make
* @param bool $parents no error if existing, make parent directories as needed
* @param int $cidVersion cid version to use
* @param string $hash hash function to use
*
* @return Command
*/
public function mkdir(string $arg, bool $parents = false, int $cidVersion = 0, string $hash = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Move files.
*
* @Endpoint(name="files:mv")
*
* @param string $arg source file to move
* @param string $arg1 destination path for file to be moved to
*
* @return Command
*/
public function mv(string $arg, string $arg1): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Read a file in a given mfs.
*
* @Endpoint(name="files:read")
*
* @param string $arg path to file to be read
* @param int $offset byte offset to begin reading from
* @param int $count maximum number of bytes to read
*
* @return Command
*/
public function read(string $arg, int $offset = 0, int $count = 0): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Remove a file.
*
* @Endpoint(name="files:rm")
*
* @param string $arg file to remove
* @param bool $recursive recursively remove directories
*
* @return Command
*/
public function rm(string $arg, bool $recursive = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Display file status.
*
* @Endpoint(name="files:stat")
*
* @param string $arg path to node to stat
* @param string $format print statistics in given format
* @param bool $hash print only hash
* @param bool $size print only size
* @param bool $withLocal compute the amount of the dag that is local, and if possible the total size
*
* @return Command
*/
public function stat(string $arg, string $format = null, bool $hash = false, bool $size = false, bool $withLocal = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Write to a mutable file in a given filesystem.
*
* @Endpoint(name="files:write")
*
* @param string $arg path to write to
* @param string $file data to write
* @param int $offset byte offset to begin writing at
* @param bool $create create the file if it does not exist
* @param bool $truncate truncate the file to size zero before writing
* @param int $count maximum number of bytes to read
* @param bool $rawLeaves use raw blocks for newly created leaf nodes
* @param int $cidVersion cid version to use
* @param string $hash hash function to use
*
* @return Command
*/
public function write(string $arg, string $file, int $offset = 0, bool $create = false, bool $truncate = false, int $count = 0, bool $rawLeaves = false, int $cidVersion = 0, string $hash = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Filestore implements Api
{
/**
* List blocks that are both in the filestore and standard block storage.
*
* @Endpoint(name="filestore:dups")
*
* @return Command
*/
public function dups(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List objects in filestore.
*
* @Endpoint(name="filestore:ls")
*
* @param string $arg cid of objects to list
* @param bool $fileOrder sort the results based on the path of the backing file
*
* @return Command
*/
public function ls(string $arg = null, bool $fileOrder = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Verify objects in filestore.
*
* @Endpoint(name="filestore:verify")
*
* @param string $arg cid of objects to verify
* @param bool $fileOrder verify the objects based on the order of the backing file
*
* @return Command
*/
public function verify(string $arg = null, bool $fileOrder = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Key implements Api
{
/**
* Create a new keypair.
*
* @Endpoint(name="key:gen")
*
* @param string $arg name of key to create Required:
* @param string $type type of the key to create [rsa, ed25519]
* @param int $size size of the key to generate
*
* @return Command
*/
public function gen(string $arg, string $type = null, int $size = 0): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List all local keypairs.
*
* @Endpoint(name="key:list")
*
* @param bool $l show extra information about keys
*
* @return Command
*/
public function list(bool $l = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Rename a keypair.
*
* @Endpoint(name="key:rename")
*
* @param string $arg name of key to rename Required:
* @param string $arg1 new name of the key Required:
* @param bool $force allow to overwrite an existing key
*
* @return Command
*/
public function rename(string $arg, string $arg1, bool $force = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Remove a keypair.
*
* @Endpoint(name="key:rm")
*
* @param string $arg names of keys to remove Required:
* @param bool $l show extra information about keys
*
* @return Command
*/
public function rm(string $arg, bool $l = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Log implements Api
{
/**
* Change the logging level.
*
* @Endpoint(name="log:level")
*
* @param string $arg the subsystem logging identifier
* @param string $arg1 the log level, with debug the most verbose and critical the least verbose
*
* @return Command
*/
public function level(string $arg, string $arg1): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List the logging subsystems.
*
* @Endpoint(name="log:ls")
*
* @return Command
*/
public function ls(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Read the event log.
*
* @Endpoint(name="log:tail")
*
* @return Command
*/
public function tail(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,99 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Name implements Api
{
/**
* Publish IPNS names.
*
* @Endpoint(name="name:publish")
*
* @param string $arg ipfs path of the object to be published
* @param bool $resolve resolve given path before publishing
* @param string $lifetime time duration that the record will be valid for
* @param string $ttl time duration this record should be cached for (caution: experimental)
* @param string $key name of the key to be used or a valid PeerID, as listed by ipfs key list -l
*
* @return Command
*/
public function publish(string $arg, bool $resolve = true, string $lifetime = '24h', string $ttl = null, string $key = 'self'): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Cancel a name subscription.
*
* @Endpoint(name="name:pubsub:cancel")
*
* @param string $arg name to cancel the subscription for
*
* @return Command
*/
public function pubsubCancel(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Query the state of IPNS pubsub.
*
* @Endpoint(name="name:pubsub:state")
*
* @return Command
*/
public function pubsubState(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Show current name subscriptions.
*
* @Endpoint(name="name:pubsub:subs")
*
* @return Command
*/
public function pubsubSubs(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Resolve IPNS names.
*
* @Endpoint(name="name:resolve")
*
* @param string $arg the IPNS name to resolve
* @param bool $recursive resolve until the result is not an IPNS name
* @param bool $nocache do not use cached entries
* @param uint $dhtRecordCount number of records to request for DHT resolution
* @param string $dhtTimeout max time to collect values during DHT resolution eg “30s”
*
* @return Command
*/
public function resolve(string $arg = null, bool $recursive = false, bool $nocache = false, uint $dhtRecordCount = null, string $dhtTimeout = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class P2p implements Api
{
/**
* Close active p2p listener.
*
* @Endpoint(name="p2p:listener:close")
*
* @param string $arg P2P listener protocol Required: no
* @param bool $all close all listeners
*
* @return Command
*/
public function listenerClose(string $arg = null, bool $all = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List active p2p listeners.
*
* @Endpoint(name="p2p:listener:ls")
*
* @param bool $headers print table headers (HandlerID, Protocol, Local, Remote)
*
* @return Command
*/
public function listenerLs(bool $headers = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Forward p2p connections to a network multiaddr.
*
* @Endpoint(name="p2p:listener:open")
*
* @param string $arg protocol identifier
* @param string $arg1 request handling application address
*
* @return Command
*/
public function listenerOpen(string $arg, string $arg1): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Close active p2p stream.
*
* @Endpoint(name="p2p:stream:close")
*
* @param string $arg stream HandlerID Required: no
* @param bool $all close all streams
*
* @return Command
*/
public function streamClose(string $arg = null, bool $all = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Dial to a p2p listener.
*
* @Endpoint(name="p2p:stream:dial")
*
* @param string $arg remote peer to connect to Required:
* @param string $arg1 protocol identifier
* @param string $arg2 address to listen for connection/s (default: /ip4/127
*
* @return Command
*/
public function streamDial(string $arg, string $arg1, string $arg2 = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List active p2p streams.
*
* @Endpoint(name="p2p:stream:ls")
*
* @param bool $headers print table headers (HagndlerID, Protocol, Local, Remote)
*
* @return Command
*/
public function streamLs(bool $headers = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,103 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Pin implements Api
{
/**
* Pin objects to local storage.
*
* @Endpoint(name="pin:add")
*
* @param string $arg path to object(s) to be pinned
* @param bool $recursive recursively pin the object linked to by the specified object(s)
* @param bool $progress show progress
*
* @return Command
*/
public function add(string $arg, bool $recursive = true, bool $progress = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List objects pinned to local storage.
*
* @Endpoint(name="pin:ls")
*
* @param string $arg path to object(s) to be listed
* @param string $type the type of pinned keys to list
* @param bool $quiet write just hashes of objects
*
* @return Command
*/
public function ls(string $arg = null, string $type = 'all', bool $quiet = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Remove pinned objects from local storage.
*
* @Endpoint(name="pin:rm")
*
* @param string $arg path to object(s) to be unpinned
* @param bool $recursive recursively unpin the object linked to by the specified object(s)
*
* @return Command
*/
public function rm(string $arg, bool $recursive = true): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Update a recursive pin.
*
* @Endpoint(name="pin:update")
*
* @param string $arg path to old object
* @param string $arg1 path to new object to be pinned
* @param bool $unpin remove the old pin
*
* @return Command
*/
public function update(string $arg, string $arg1, bool $unpin = true): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Verify that recursive pins are complete.
*
* @Endpoint(name="pin:verify")
*
* @param bool $verbose also write the hashes of non-broken pins
* @param bool $quiet write just hashes of broken pins
*
* @return Command
*/
public function verify(bool $verbose = false, bool $quiet = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Pubsub implements Api
{
/**
* List subscribed topics by name.
*
* @Endpoint(name="pubsub:ls")
*
* @return Command
*/
public function ls(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List peers we are currently pubsubbing with.
*
* @Endpoint(name="pubsub:peers")
*
* @param string $arg topic to list connected peers of Required: no
*
* @return Command
*/
public function peers(string $arg = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Publish a message to a given pubsub topic.
*
* @Endpoint(name="pubsub:pub")
*
* @param string $arg topic to publish to
* @param string $arg1 payload of message to publish
*
* @return Command
*/
public function pub(string $arg, string $arg1): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Subscribe to messages on a given topic.
*
* @Endpoint(name="pubsub:sub")
*
* @param string $arg string name of topic to subscribe to
* @param bool $discover try to discover other peers subscribed to the same topic
*
* @return Command
*/
public function sub(string $arg, bool $discover = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Refs implements Api
{
/**
* List all local references.
*
* @Endpoint(name="refs:local")
*
* @return Command
*/
public function local(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Repo implements Api
{
/**
* Remove repo lockfiles.
*
* @Endpoint(name="repo:fsck")
*
* @return Command
*/
public function fsck(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Perform a garbage collection sweep on the repo.
*
* @Endpoint(name="repo:gc")
*
* @param bool $streamErrors stream errors
* @param bool $quiet write minimal output
*
* @return Command
*/
public function gc(bool $streamErrors = false, bool $quiet = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Get stats for the currently used repo.
*
* @Endpoint(name="repo:stat")
*
* @param bool $human output RepoSize in MiB
*
* @return Command
*/
public function stat(bool $human = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Verify all blocks in repo are not corrupted.
*
* @Endpoint(name="repo:verify")
*
* @return Command
*/
public function verify(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Show the repo version.
*
* @Endpoint(name="repo:version")
*
* @param bool $quiet write minimal output
*
* @return Command
*/
public function version(bool $quiet = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Stats implements Api
{
/**
* Show some diagnostic information on the bitswap agent.
*
* @Endpoint(name="stats:bitswap")
*
* @return Command
*/
public function bitswap(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Print ipfs bandwidth information.
*
* @Endpoint(name="stats:bw")
*
* @param string $peer specify a peer to print bandwidth for
* @param string $proto specify a protocol to print bandwidth for
* @param bool $poll print bandwidth at an interval
* @param string $interval time interval to wait between updating output, if poll is true
*
* @return Command
*/
public function bw(string $peer = null, string $proto = null, bool $poll = false, string $interval = null): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Get stats for the currently used repo.
*
* @Endpoint(name="stats:repo")
*
* @param bool $human output RepoSize in MiB
*
* @return Command
*/
public function repo(bool $human = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,123 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Swarm implements Api
{
/**
* List interface listening addresses.
*
* @Endpoint(name="swarm:addrs:listen")
*
* @return Command
*/
public function addrsListen(): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List local addresses.
*
* @Endpoint(name="swarm:addrs:local")
*
* @param bool $id show peer ID in addresses
*
* @return Command
*/
public function addrsLocal(bool $id = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Open connection to a given address.
*
* @Endpoint(name="swarm:connect")
*
* @param string $arg address of peer to connect to
*
* @return Command
*/
public function connect(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Close connection to a given address.
*
* @Endpoint(name="swarm:disconnect")
*
* @param string $arg address of peer to disconnect from
*
* @return Command
*/
public function disconnect(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Add an address filter.
*
* @Endpoint(name="swarm:filters:add")
*
* @param string $arg multiaddr to filter
*
* @return Command
*/
public function filtersAdd(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Remove an address filter.
*
* @Endpoint(name="swarm:filters:rm")
*
* @param string $arg multiaddr filter to remove
*
* @return Command
*/
public function filtersRm(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* List peers with open connections.
*
* @Endpoint(name="swarm:peers")
*
* @param bool $verbose display all extra information
* @param bool $streams also list information about open streams for each peer
* @param bool $latency also list information about latency to each peer
*
* @return Command
*/
public function peers(bool $verbose = false, bool $streams = false, bool $latency = false): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Api;
use IPFS\Annotation\Api as Endpoint;
use IPFS\Command\Command;
/**
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @autogenerated
* @codeCoverageIgnore
*/
final class Tar implements Api
{
/**
* Import a tar file into ipfs.
*
* @Endpoint(name="tar:add")
*
* @param string $file tar file to add
*
* @return Command
*/
public function add(string $file): Command
{
return new Command(__METHOD__, get_defined_vars());
}
/**
* Export a tar file from IPFS.
*
* @Endpoint(name="tar:cat")
*
* @param string $arg ipfs path of archive to export
*
* @return Command
*/
public function cat(string $arg): Command
{
return new Command(__METHOD__, get_defined_vars());
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS;
use IPFS\Command\Command;
use IPFS\Driver\Driver;
class Client implements Driver
{
/**
* @var Driver
*/
private $driver;
public function __construct(Driver $driver)
{
$this->driver = $driver;
}
public function execute(Command $command)
{
return $this->driver->execute($command);
}
}

View File

@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
/*
* This file is part of the "php-ipfs" package.
*
* (c) Robert Schönthal <robert.schoenthal@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace IPFS\Command;
use IPFS\Utils\CaseFormatter;
class Command
{
/**
* @var array
*/
private $args = [];
/**
* @var string
*/
private $method;
public function __construct(string $method, array $args = [])
{
$this->args = $args;
$this->method = $method;
}
public function getAction(): string
{
$parts = explode('\\', $this->method);
$shortName = array_pop($parts);
$name = CaseFormatter::camelToColon(str_replace('::', ':', $shortName));
// correct some naming workaround due to reserved keywords
$name = str_replace('basics:', '', $name);
$name = str_replace('cobject:', 'object:', $name);
return $name;
}
public function getArguments(): array
{
return $this->args;
}
public function getMethod(): string
{
return $this->method;
}
}

Some files were not shown because too many files have changed in this diff Show More