Vendor lock
This commit is contained in:
15
vendor/php-di/invoker/CONTRIBUTING.md
vendored
Normal file
15
vendor/php-di/invoker/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# Contributing
|
||||
|
||||
First of all, **thank you** for contributing!
|
||||
|
||||
Here are a few rules to follow in order to ease code reviews and merging:
|
||||
|
||||
- follow [PSR-1](http://www.php-fig.org/psr/1/) and [PSR-2](http://www.php-fig.org/psr/2/)
|
||||
- run the test suite
|
||||
- write (or update) unit tests when applicable
|
||||
- write documentation for new features
|
||||
- use [commit messages that make sense](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
||||
|
||||
One may ask you to [squash your commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) too. This is used to "clean" your pull request before merging it (we don't want commits such as `fix tests`, `fix 2`, `fix 3`, etc.).
|
||||
|
||||
When creating your pull request on GitHub, please write a description which gives the context and/or explains why you are creating it.
|
21
vendor/php-di/invoker/LICENSE
vendored
Normal file
21
vendor/php-di/invoker/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Matthieu Napoli
|
||||
|
||||
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.
|
234
vendor/php-di/invoker/README.md
vendored
Normal file
234
vendor/php-di/invoker/README.md
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
# Invoker
|
||||
|
||||
Generic and extensible callable invoker.
|
||||
|
||||
[](https://travis-ci.org/PHP-DI/Invoker)
|
||||
[](https://coveralls.io/r/PHP-DI/Invoker?branch=master)
|
||||
[](https://scrutinizer-ci.com/g/PHP-DI/Invoker/?branch=master)
|
||||
[](https://packagist.org/packages/PHP-DI/invoker)
|
||||
|
||||
## Why?
|
||||
|
||||
Who doesn't need an over-engineered `call_user_func()`?
|
||||
|
||||
### Named parameters
|
||||
|
||||
Does this [Silex](http://silex.sensiolabs.org) example look familiar:
|
||||
|
||||
```php
|
||||
$app->get('/project/{project}/issue/{issue}', function ($project, $issue) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Or this command defined with [Silly](https://github.com/mnapoli/silly#usage):
|
||||
|
||||
```php
|
||||
$app->command('greet [name] [--yell]', function ($name, $yell) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Same pattern in [Slim](http://www.slimframework.com):
|
||||
|
||||
```php
|
||||
$app->get('/hello/:name', function ($name) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
You get the point. These frameworks invoke the controller/command/handler using something akin to named parameters: whatever the order of the parameters, they are matched by their name.
|
||||
|
||||
**This library allows to invoke callables with named parameters in a generic and extensible way.**
|
||||
|
||||
### Dependency injection
|
||||
|
||||
Anyone familiar with AngularJS is familiar with how dependency injection is performed:
|
||||
|
||||
```js
|
||||
angular.controller('MyController', ['dep1', 'dep2', function(dep1, dep2) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
In PHP we find this pattern again in some frameworks and DI containers with partial to full support. For example in Silex you can type-hint the application to get it injected, but it only works with `Silex\Application`:
|
||||
|
||||
```php
|
||||
$app->get('/hello/{name}', function (Silex\Application $app, $name) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
In Silly, it only works with `OutputInterface` to inject the application output:
|
||||
|
||||
```php
|
||||
$app->command('greet [name]', function ($name, OutputInterface $output) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
[PHP-DI](http://php-di.org/doc/container.html) provides a way to invoke a callable and resolve all dependencies from the container using type-hints:
|
||||
|
||||
```php
|
||||
$container->call(function (Logger $logger, EntityManager $em) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
**This library provides clear extension points to let frameworks implement any kind of dependency injection support they want.**
|
||||
|
||||
### TL/DR
|
||||
|
||||
In short, this library is meant to be a base building block for calling a function with named parameters and/or dependency injection.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ composer require PHP-DI/invoker
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Default behavior
|
||||
|
||||
By default the `Invoker` can call using named parameters:
|
||||
|
||||
```php
|
||||
$invoker = new Invoker\Invoker;
|
||||
|
||||
$invoker->call(function () {
|
||||
echo 'Hello world!';
|
||||
});
|
||||
|
||||
// Simple parameter array
|
||||
$invoker->call(function ($name) {
|
||||
echo 'Hello ' . $name;
|
||||
}, ['John']);
|
||||
|
||||
// Named parameters
|
||||
$invoker->call(function ($name) {
|
||||
echo 'Hello ' . $name;
|
||||
}, [
|
||||
'name' => 'John'
|
||||
]);
|
||||
|
||||
// Use the default value
|
||||
$invoker->call(function ($name = 'world') {
|
||||
echo 'Hello ' . $name;
|
||||
});
|
||||
|
||||
// Invoke any PHP callable
|
||||
$invoker->call(['MyClass', 'myStaticMethod']);
|
||||
|
||||
// Using Class::method syntax
|
||||
$invoker->call('MyClass::myStaticMethod');
|
||||
```
|
||||
|
||||
Dependency injection in parameters is supported but needs to be configured with your container. Read on or jump to [*Built-in support for dependency injection*](#built-in-support-for-dependency-injection) if you are impatient.
|
||||
|
||||
Additionally, callables can also be resolved from your container. Read on or jump to [*Resolving callables from a container*](#resolving-callables-from-a-container) if you are impatient.
|
||||
|
||||
### Parameter resolvers
|
||||
|
||||
Extending the behavior of the `Invoker` is easy and is done by implementing a [`ParameterResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ParameterResolver.php).
|
||||
|
||||
This is explained in details the [Parameter resolvers documentation](doc/parameter-resolvers.md).
|
||||
|
||||
#### Built-in support for dependency injection
|
||||
|
||||
Rather than have you re-implement support for dependency injection with different containers every time, this package ships with 2 optional resolvers:
|
||||
|
||||
- [`TypeHintContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/TypeHintContainerResolver.php)
|
||||
|
||||
This resolver will inject container entries by searching for the class name using the type-hint:
|
||||
|
||||
```php
|
||||
$invoker->call(function (Psr\Logger\LoggerInterface $logger) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
In this example it will `->get('Psr\Logger\LoggerInterface')` from the container and inject it.
|
||||
|
||||
This resolver is only useful if you store objects in your container using the class (or interface) name. Silex or Symfony for example store services under a custom name (e.g. `twig`, `db`, etc.) instead of the class name: in that case use the resolver shown below.
|
||||
|
||||
- [`ParameterNameContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/ParameterNameContainerResolver.php)
|
||||
|
||||
This resolver will inject container entries by searching for the name of the parameter:
|
||||
|
||||
```php
|
||||
$invoker->call(function ($twig) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
In this example it will `->get('twig')` from the container and inject it.
|
||||
|
||||
These resolvers can work with any dependency injection container compliant with [PSR-11](http://www.php-fig.org/psr/psr-11/).
|
||||
|
||||
Setting up those resolvers is simple:
|
||||
|
||||
```php
|
||||
// $container must be an instance of Psr\Container\ContainerInterface
|
||||
$container = ...
|
||||
|
||||
$containerResolver = new TypeHintContainerResolver($container);
|
||||
// or
|
||||
$containerResolver = new ParameterNameContainerResolver($container);
|
||||
|
||||
$invoker = new Invoker\Invoker;
|
||||
// Register it before all the other parameter resolvers
|
||||
$invoker->getParameterResolver()->prependResolver($containerResolver);
|
||||
```
|
||||
|
||||
You can also register both resolvers at the same time if you wish by prepending both. Implementing support for more tricky things is easy and up to you!
|
||||
|
||||
### Resolving callables from a container
|
||||
|
||||
The `Invoker` can be wired to your DI container to resolve the callables.
|
||||
|
||||
For example with an invokable class:
|
||||
|
||||
```php
|
||||
class MyHandler
|
||||
{
|
||||
public function __invoke()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// By default this doesn't work: an instance of the class should be provided
|
||||
$invoker->call('MyHandler');
|
||||
|
||||
// If we set up the container to use
|
||||
$invoker = new Invoker\Invoker(null, $container);
|
||||
// Now 'MyHandler' is resolved using the container!
|
||||
$invoker->call('MyHandler');
|
||||
```
|
||||
|
||||
The same works for a class method:
|
||||
|
||||
```php
|
||||
class WelcomeController
|
||||
{
|
||||
public function home()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// By default this doesn't work: home() is not a static method
|
||||
$invoker->call(['WelcomeController', 'home']);
|
||||
|
||||
// If we set up the container to use
|
||||
$invoker = new Invoker\Invoker(null, $container);
|
||||
// Now 'WelcomeController' is resolved using the container!
|
||||
$invoker->call(['WelcomeController', 'home']);
|
||||
// Alternatively we can use the Class::method syntax
|
||||
$invoker->call('WelcomeController::home');
|
||||
```
|
||||
|
||||
That feature can be used as the base building block for a framework's dispatcher.
|
||||
|
||||
Again, any [PSR-11](http://www.php-fig.org/psr/psr-11/) compliant container can be provided.
|
25
vendor/php-di/invoker/composer.json
vendored
Normal file
25
vendor/php-di/invoker/composer.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "php-di/invoker",
|
||||
"description": "Generic and extensible callable invoker",
|
||||
"keywords": ["invoker", "dependency-injection", "dependency", "injection", "callable", "invoke"],
|
||||
"homepage": "https://github.com/PHP-DI/Invoker",
|
||||
"license": "MIT",
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Invoker\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Invoker\\Test\\": "tests/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"psr/container": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.5",
|
||||
"athletic/athletic": "~0.1.8"
|
||||
}
|
||||
}
|
109
vendor/php-di/invoker/doc/parameter-resolvers.md
vendored
Normal file
109
vendor/php-di/invoker/doc/parameter-resolvers.md
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
# Parameter resolvers
|
||||
|
||||
Extending the behavior of the `Invoker` is easy and is done by implementing a [`ParameterResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ParameterResolver.php):
|
||||
|
||||
```php
|
||||
interface ParameterResolver
|
||||
{
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
- `$providedParameters` contains the parameters provided by the user when calling `$invoker->call($callable, $parameters)`
|
||||
- `$resolvedParameters` contains parameters that have already been resolved by other parameter resolvers
|
||||
|
||||
An `Invoker` can chain multiple parameter resolvers to mix behaviors, e.g. you can mix "named parameters" support with "dependency injection" support. This is why a `ParameterResolver` should skip parameters that are already resolved in `$resolvedParameters`.
|
||||
|
||||
Here is an implementation example for dumb dependency injection that creates a new instance of the classes type-hinted:
|
||||
|
||||
```php
|
||||
class MyParameterResolver implements ParameterResolver
|
||||
{
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
) {
|
||||
foreach ($reflection->getParameters() as $index => $parameter) {
|
||||
if (array_key_exists($index, $resolvedParameters)) {
|
||||
// Skip already resolved parameters
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $parameter->getClass();
|
||||
|
||||
if ($class) {
|
||||
$resolvedParameters[$index] = $class->newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
return $resolvedParameters;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To use it:
|
||||
|
||||
```php
|
||||
$invoker = new Invoker\Invoker(new MyParameterResolver);
|
||||
|
||||
$invoker->call(function (ArticleManager $articleManager) {
|
||||
$articleManager->publishArticle('Hello world', 'This is the article content.');
|
||||
});
|
||||
```
|
||||
|
||||
A new instance of `ArticleManager` will be created by our parameter resolver.
|
||||
|
||||
## Chaining parameter resolvers
|
||||
|
||||
The fun starts to happen when we want to add support for many things:
|
||||
|
||||
- named parameters
|
||||
- dependency injection for type-hinted parameters
|
||||
- ...
|
||||
|
||||
This is where we should use the [`ResolverChain`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ResolverChain.php). This resolver implements the [Chain of responsibility](http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern) design pattern.
|
||||
|
||||
For example the default chain is:
|
||||
|
||||
```php
|
||||
$parameterResolver = new ResolverChain([
|
||||
new NumericArrayResolver,
|
||||
new AssociativeArrayResolver,
|
||||
new DefaultValueResolver,
|
||||
]);
|
||||
```
|
||||
|
||||
It allows to support even the weirdest use cases like:
|
||||
|
||||
```php
|
||||
$parameters = [];
|
||||
|
||||
// First parameter will receive "Welcome"
|
||||
$parameters[] = 'Welcome';
|
||||
|
||||
// Parameter named "content" will receive "Hello world!"
|
||||
$parameters['content'] = 'Hello world!';
|
||||
|
||||
// $published is not defined so it will use its default value
|
||||
$invoker->call(function ($title, $content, $published = true) {
|
||||
// ...
|
||||
}, $parameters);
|
||||
```
|
||||
|
||||
We can put our custom parameter resolver in the list and created a super-duper invoker that also supports basic dependency injection:
|
||||
|
||||
```php
|
||||
$parameterResolver = new ResolverChain([
|
||||
new MyParameterResolver, // Our resolver is at the top for highest priority
|
||||
new NumericArrayResolver,
|
||||
new AssociativeArrayResolver,
|
||||
new DefaultValueResolver,
|
||||
]);
|
||||
|
||||
$invoker = new Invoker\Invoker($parameterResolver);
|
||||
```
|
133
vendor/php-di/invoker/src/CallableResolver.php
vendored
Normal file
133
vendor/php-di/invoker/src/CallableResolver.php
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker;
|
||||
|
||||
use Invoker\Exception\NotCallableException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
/**
|
||||
* Resolves a callable from a container.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class CallableResolver
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
private $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given callable into a real PHP callable.
|
||||
*
|
||||
* @param callable|string|array $callable
|
||||
*
|
||||
* @return callable Real PHP callable.
|
||||
*
|
||||
* @throws NotCallableException
|
||||
*/
|
||||
public function resolve($callable)
|
||||
{
|
||||
if (is_string($callable) && strpos($callable, '::') !== false) {
|
||||
$callable = explode('::', $callable, 2);
|
||||
}
|
||||
|
||||
$callable = $this->resolveFromContainer($callable);
|
||||
|
||||
if (! is_callable($callable)) {
|
||||
throw NotCallableException::fromInvalidCallable($callable, true);
|
||||
}
|
||||
|
||||
return $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable|string|array $callable
|
||||
* @return callable
|
||||
* @throws NotCallableException
|
||||
*/
|
||||
private function resolveFromContainer($callable)
|
||||
{
|
||||
// Shortcut for a very common use case
|
||||
if ($callable instanceof \Closure) {
|
||||
return $callable;
|
||||
}
|
||||
|
||||
$isStaticCallToNonStaticMethod = false;
|
||||
|
||||
// If it's already a callable there is nothing to do
|
||||
if (is_callable($callable)) {
|
||||
$isStaticCallToNonStaticMethod = $this->isStaticCallToNonStaticMethod($callable);
|
||||
if (! $isStaticCallToNonStaticMethod) {
|
||||
return $callable;
|
||||
}
|
||||
}
|
||||
|
||||
// The callable is a container entry name
|
||||
if (is_string($callable)) {
|
||||
try {
|
||||
return $this->container->get($callable);
|
||||
} catch (NotFoundExceptionInterface $e) {
|
||||
if ($this->container->has($callable)) {
|
||||
throw $e;
|
||||
}
|
||||
throw NotCallableException::fromInvalidCallable($callable, true);
|
||||
}
|
||||
}
|
||||
|
||||
// The callable is an array whose first item is a container entry name
|
||||
// e.g. ['some-container-entry', 'methodToCall']
|
||||
if (is_array($callable) && is_string($callable[0])) {
|
||||
try {
|
||||
// Replace the container entry name by the actual object
|
||||
$callable[0] = $this->container->get($callable[0]);
|
||||
return $callable;
|
||||
} catch (NotFoundExceptionInterface $e) {
|
||||
if ($this->container->has($callable[0])) {
|
||||
throw $e;
|
||||
}
|
||||
if ($isStaticCallToNonStaticMethod) {
|
||||
throw new NotCallableException(sprintf(
|
||||
'Cannot call %s::%s() because %s() is not a static method and "%s" is not a container entry',
|
||||
$callable[0],
|
||||
$callable[1],
|
||||
$callable[1],
|
||||
$callable[0]
|
||||
));
|
||||
}
|
||||
throw new NotCallableException(sprintf(
|
||||
'Cannot call %s on %s because it is not a class nor a valid container entry',
|
||||
$callable[1],
|
||||
$callable[0]
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Unrecognized stuff, we let it fail later
|
||||
return $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the callable represents a static call to a non-static method.
|
||||
*
|
||||
* @param mixed $callable
|
||||
* @return bool
|
||||
*/
|
||||
private function isStaticCallToNonStaticMethod($callable)
|
||||
{
|
||||
if (is_array($callable) && is_string($callable[0])) {
|
||||
list($class, $method) = $callable;
|
||||
$reflection = new \ReflectionMethod($class, $method);
|
||||
|
||||
return ! $reflection->isStatic();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
12
vendor/php-di/invoker/src/Exception/InvocationException.php
vendored
Normal file
12
vendor/php-di/invoker/src/Exception/InvocationException.php
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\Exception;
|
||||
|
||||
/**
|
||||
* Impossible to invoke the callable.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class InvocationException extends \Exception
|
||||
{
|
||||
}
|
35
vendor/php-di/invoker/src/Exception/NotCallableException.php
vendored
Normal file
35
vendor/php-di/invoker/src/Exception/NotCallableException.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\Exception;
|
||||
|
||||
/**
|
||||
* The given callable is not actually callable.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class NotCallableException extends InvocationException
|
||||
{
|
||||
/**
|
||||
* @param string $value
|
||||
* @param bool $containerEntry
|
||||
* @return self
|
||||
*/
|
||||
public static function fromInvalidCallable($value, $containerEntry = false)
|
||||
{
|
||||
if (is_object($value)) {
|
||||
$message = sprintf('Instance of %s is not a callable', get_class($value));
|
||||
} elseif (is_array($value) && isset($value[0]) && isset($value[1])) {
|
||||
$class = is_object($value[0]) ? get_class($value[0]) : $value[0];
|
||||
$extra = method_exists($class, '__call') ? ' A __call() method exists but magic methods are not supported.' : '';
|
||||
$message = sprintf('%s::%s() is not a callable.%s', $class, $value[1], $extra);
|
||||
} else {
|
||||
if ($containerEntry) {
|
||||
$message = var_export($value, true) . ' is neither a callable nor a valid container entry';
|
||||
} else {
|
||||
$message = var_export($value, true) . ' is not a callable';
|
||||
}
|
||||
}
|
||||
|
||||
return new self($message);
|
||||
}
|
||||
}
|
12
vendor/php-di/invoker/src/Exception/NotEnoughParametersException.php
vendored
Normal file
12
vendor/php-di/invoker/src/Exception/NotEnoughParametersException.php
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\Exception;
|
||||
|
||||
/**
|
||||
* Not enough parameters could be resolved to invoke the callable.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class NotEnoughParametersException extends InvocationException
|
||||
{
|
||||
}
|
122
vendor/php-di/invoker/src/Invoker.php
vendored
Normal file
122
vendor/php-di/invoker/src/Invoker.php
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker;
|
||||
|
||||
use Invoker\Exception\NotCallableException;
|
||||
use Invoker\Exception\NotEnoughParametersException;
|
||||
use Invoker\ParameterResolver\AssociativeArrayResolver;
|
||||
use Invoker\ParameterResolver\DefaultValueResolver;
|
||||
use Invoker\ParameterResolver\NumericArrayResolver;
|
||||
use Invoker\ParameterResolver\ParameterResolver;
|
||||
use Invoker\ParameterResolver\ResolverChain;
|
||||
use Invoker\Reflection\CallableReflection;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Invoke a callable.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class Invoker implements InvokerInterface
|
||||
{
|
||||
/**
|
||||
* @var CallableResolver|null
|
||||
*/
|
||||
private $callableResolver;
|
||||
|
||||
/**
|
||||
* @var ParameterResolver
|
||||
*/
|
||||
private $parameterResolver;
|
||||
|
||||
/**
|
||||
* @var ContainerInterface|null
|
||||
*/
|
||||
private $container;
|
||||
|
||||
public function __construct(ParameterResolver $parameterResolver = null, ContainerInterface $container = null)
|
||||
{
|
||||
$this->parameterResolver = $parameterResolver ?: $this->createParameterResolver();
|
||||
$this->container = $container;
|
||||
|
||||
if ($container) {
|
||||
$this->callableResolver = new CallableResolver($container);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function call($callable, array $parameters = array())
|
||||
{
|
||||
if ($this->callableResolver) {
|
||||
$callable = $this->callableResolver->resolve($callable);
|
||||
}
|
||||
|
||||
if (! is_callable($callable)) {
|
||||
throw new NotCallableException(sprintf(
|
||||
'%s is not a callable',
|
||||
is_object($callable) ? 'Instance of ' . get_class($callable) : var_export($callable, true)
|
||||
));
|
||||
}
|
||||
|
||||
$callableReflection = CallableReflection::create($callable);
|
||||
|
||||
$args = $this->parameterResolver->getParameters($callableReflection, $parameters, array());
|
||||
|
||||
// Sort by array key because call_user_func_array ignores numeric keys
|
||||
ksort($args);
|
||||
|
||||
// Check all parameters are resolved
|
||||
$diff = array_diff_key($callableReflection->getParameters(), $args);
|
||||
if (! empty($diff)) {
|
||||
/** @var \ReflectionParameter $parameter */
|
||||
$parameter = reset($diff);
|
||||
throw new NotEnoughParametersException(sprintf(
|
||||
'Unable to invoke the callable because no value was given for parameter %d ($%s)',
|
||||
$parameter->getPosition() + 1,
|
||||
$parameter->name
|
||||
));
|
||||
}
|
||||
|
||||
return call_user_func_array($callable, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the default parameter resolver.
|
||||
*
|
||||
* @return ParameterResolver
|
||||
*/
|
||||
private function createParameterResolver()
|
||||
{
|
||||
return new ResolverChain(array(
|
||||
new NumericArrayResolver,
|
||||
new AssociativeArrayResolver,
|
||||
new DefaultValueResolver,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterResolver By default it's a ResolverChain
|
||||
*/
|
||||
public function getParameterResolver()
|
||||
{
|
||||
return $this->parameterResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContainerInterface|null
|
||||
*/
|
||||
public function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CallableResolver|null Returns null if no container was given in the constructor.
|
||||
*/
|
||||
public function getCallableResolver()
|
||||
{
|
||||
return $this->callableResolver;
|
||||
}
|
||||
}
|
29
vendor/php-di/invoker/src/InvokerInterface.php
vendored
Normal file
29
vendor/php-di/invoker/src/InvokerInterface.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker;
|
||||
|
||||
use Invoker\Exception\InvocationException;
|
||||
use Invoker\Exception\NotCallableException;
|
||||
use Invoker\Exception\NotEnoughParametersException;
|
||||
|
||||
/**
|
||||
* Invoke a callable.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
interface InvokerInterface
|
||||
{
|
||||
/**
|
||||
* Call the given function using the given parameters.
|
||||
*
|
||||
* @param callable $callable Function to call.
|
||||
* @param array $parameters Parameters to use.
|
||||
*
|
||||
* @return mixed Result of the function.
|
||||
*
|
||||
* @throws InvocationException Base exception class for all the sub-exceptions below.
|
||||
* @throws NotCallableException
|
||||
* @throws NotEnoughParametersException
|
||||
*/
|
||||
public function call($callable, array $parameters = array());
|
||||
}
|
39
vendor/php-di/invoker/src/ParameterResolver/AssociativeArrayResolver.php
vendored
Normal file
39
vendor/php-di/invoker/src/ParameterResolver/AssociativeArrayResolver.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\ParameterResolver;
|
||||
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
/**
|
||||
* Tries to map an associative array (string-indexed) to the parameter names.
|
||||
*
|
||||
* E.g. `->call($callable, ['foo' => 'bar'])` will inject the string `'bar'`
|
||||
* in the parameter named `$foo`.
|
||||
*
|
||||
* Parameters that are not indexed by a string are ignored.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class AssociativeArrayResolver implements ParameterResolver
|
||||
{
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
) {
|
||||
$parameters = $reflection->getParameters();
|
||||
|
||||
// Skip parameters already resolved
|
||||
if (! empty($resolvedParameters)) {
|
||||
$parameters = array_diff_key($parameters, $resolvedParameters);
|
||||
}
|
||||
|
||||
foreach ($parameters as $index => $parameter) {
|
||||
if (array_key_exists($parameter->name, $providedParameters)) {
|
||||
$resolvedParameters[$index] = $providedParameters[$parameter->name];
|
||||
}
|
||||
}
|
||||
|
||||
return $resolvedParameters;
|
||||
}
|
||||
}
|
51
vendor/php-di/invoker/src/ParameterResolver/Container/ParameterNameContainerResolver.php
vendored
Normal file
51
vendor/php-di/invoker/src/ParameterResolver/Container/ParameterNameContainerResolver.php
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\ParameterResolver\Container;
|
||||
|
||||
use Invoker\ParameterResolver\ParameterResolver;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
/**
|
||||
* Inject entries from a DI container using the parameter names.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class ParameterNameContainerResolver implements ParameterResolver
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container The container to get entries from.
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
) {
|
||||
$parameters = $reflection->getParameters();
|
||||
|
||||
// Skip parameters already resolved
|
||||
if (! empty($resolvedParameters)) {
|
||||
$parameters = array_diff_key($parameters, $resolvedParameters);
|
||||
}
|
||||
|
||||
foreach ($parameters as $index => $parameter) {
|
||||
$name = $parameter->name;
|
||||
|
||||
if ($name && $this->container->has($name)) {
|
||||
$resolvedParameters[$index] = $this->container->get($name);
|
||||
}
|
||||
}
|
||||
|
||||
return $resolvedParameters;
|
||||
}
|
||||
}
|
51
vendor/php-di/invoker/src/ParameterResolver/Container/TypeHintContainerResolver.php
vendored
Normal file
51
vendor/php-di/invoker/src/ParameterResolver/Container/TypeHintContainerResolver.php
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\ParameterResolver\Container;
|
||||
|
||||
use Invoker\ParameterResolver\ParameterResolver;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
/**
|
||||
* Inject entries from a DI container using the type-hints.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class TypeHintContainerResolver implements ParameterResolver
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container The container to get entries from.
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
) {
|
||||
$parameters = $reflection->getParameters();
|
||||
|
||||
// Skip parameters already resolved
|
||||
if (! empty($resolvedParameters)) {
|
||||
$parameters = array_diff_key($parameters, $resolvedParameters);
|
||||
}
|
||||
|
||||
foreach ($parameters as $index => $parameter) {
|
||||
$parameterClass = $parameter->getClass();
|
||||
|
||||
if ($parameterClass && $this->container->has($parameterClass->name)) {
|
||||
$resolvedParameters[$index] = $this->container->get($parameterClass->name);
|
||||
}
|
||||
}
|
||||
|
||||
return $resolvedParameters;
|
||||
}
|
||||
}
|
40
vendor/php-di/invoker/src/ParameterResolver/DefaultValueResolver.php
vendored
Normal file
40
vendor/php-di/invoker/src/ParameterResolver/DefaultValueResolver.php
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\ParameterResolver;
|
||||
|
||||
use ReflectionException;
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
/**
|
||||
* Finds the default value for a parameter, *if it exists*.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class DefaultValueResolver implements ParameterResolver
|
||||
{
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
) {
|
||||
$parameters = $reflection->getParameters();
|
||||
|
||||
// Skip parameters already resolved
|
||||
if (! empty($resolvedParameters)) {
|
||||
$parameters = array_diff_key($parameters, $resolvedParameters);
|
||||
}
|
||||
|
||||
foreach ($parameters as $index => $parameter) {
|
||||
/** @var \ReflectionParameter $parameter */
|
||||
if ($parameter->isOptional()) {
|
||||
try {
|
||||
$resolvedParameters[$index] = $parameter->getDefaultValue();
|
||||
} catch (ReflectionException $e) {
|
||||
// Can't get default values from PHP internal classes and functions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $resolvedParameters;
|
||||
}
|
||||
}
|
39
vendor/php-di/invoker/src/ParameterResolver/NumericArrayResolver.php
vendored
Normal file
39
vendor/php-di/invoker/src/ParameterResolver/NumericArrayResolver.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\ParameterResolver;
|
||||
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
/**
|
||||
* Simply returns all the values of the $providedParameters array that are
|
||||
* indexed by the parameter position (i.e. a number).
|
||||
*
|
||||
* E.g. `->call($callable, ['foo', 'bar'])` will simply resolve the parameters
|
||||
* to `['foo', 'bar']`.
|
||||
*
|
||||
* Parameters that are not indexed by a number (i.e. parameter position)
|
||||
* will be ignored.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class NumericArrayResolver implements ParameterResolver
|
||||
{
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
) {
|
||||
// Skip parameters already resolved
|
||||
if (! empty($resolvedParameters)) {
|
||||
$providedParameters = array_diff_key($providedParameters, $resolvedParameters);
|
||||
}
|
||||
|
||||
foreach ($providedParameters as $key => $value) {
|
||||
if (is_int($key)) {
|
||||
$resolvedParameters[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $resolvedParameters;
|
||||
}
|
||||
}
|
33
vendor/php-di/invoker/src/ParameterResolver/ParameterResolver.php
vendored
Normal file
33
vendor/php-di/invoker/src/ParameterResolver/ParameterResolver.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\ParameterResolver;
|
||||
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
/**
|
||||
* Resolves the parameters to use to call the callable.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
interface ParameterResolver
|
||||
{
|
||||
/**
|
||||
* Resolves the parameters to use to call the callable.
|
||||
*
|
||||
* `$resolvedParameters` contains parameters that have already been resolved.
|
||||
*
|
||||
* Each ParameterResolver must resolve parameters that are not already
|
||||
* in `$resolvedParameters`. That allows to chain multiple ParameterResolver.
|
||||
*
|
||||
* @param ReflectionFunctionAbstract $reflection Reflection object for the callable.
|
||||
* @param array $providedParameters Parameters provided by the caller.
|
||||
* @param array $resolvedParameters Parameters resolved (indexed by parameter position).
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
);
|
||||
}
|
69
vendor/php-di/invoker/src/ParameterResolver/ResolverChain.php
vendored
Normal file
69
vendor/php-di/invoker/src/ParameterResolver/ResolverChain.php
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\ParameterResolver;
|
||||
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
/**
|
||||
* Dispatches the call to other resolvers until all parameters are resolved.
|
||||
*
|
||||
* Chain of responsibility pattern.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class ResolverChain implements ParameterResolver
|
||||
{
|
||||
/**
|
||||
* @var ParameterResolver[]
|
||||
*/
|
||||
private $resolvers = array();
|
||||
|
||||
public function __construct(array $resolvers = array())
|
||||
{
|
||||
$this->resolvers = $resolvers;
|
||||
}
|
||||
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
) {
|
||||
$reflectionParameters = $reflection->getParameters();
|
||||
|
||||
foreach ($this->resolvers as $resolver) {
|
||||
$resolvedParameters = $resolver->getParameters(
|
||||
$reflection,
|
||||
$providedParameters,
|
||||
$resolvedParameters
|
||||
);
|
||||
|
||||
$diff = array_diff_key($reflectionParameters, $resolvedParameters);
|
||||
if (empty($diff)) {
|
||||
// Stop traversing: all parameters are resolved
|
||||
return $resolvedParameters;
|
||||
}
|
||||
}
|
||||
|
||||
return $resolvedParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a parameter resolver after the ones already registered.
|
||||
*
|
||||
* @param ParameterResolver $resolver
|
||||
*/
|
||||
public function appendResolver(ParameterResolver $resolver)
|
||||
{
|
||||
$this->resolvers[] = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a parameter resolver before the ones already registered.
|
||||
*
|
||||
* @param ParameterResolver $resolver
|
||||
*/
|
||||
public function prependResolver(ParameterResolver $resolver)
|
||||
{
|
||||
array_unshift($this->resolvers, $resolver);
|
||||
}
|
||||
}
|
39
vendor/php-di/invoker/src/ParameterResolver/TypeHintResolver.php
vendored
Normal file
39
vendor/php-di/invoker/src/ParameterResolver/TypeHintResolver.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\ParameterResolver;
|
||||
|
||||
use Invoker\ParameterResolver\ParameterResolver;
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
/**
|
||||
* Inject entries using type-hints.
|
||||
*
|
||||
* Tries to match type-hints with the parameters provided.
|
||||
*
|
||||
* @author Felix Becker <f.becker@outlook.com>
|
||||
*/
|
||||
class TypeHintResolver implements ParameterResolver
|
||||
{
|
||||
public function getParameters(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
array $providedParameters,
|
||||
array $resolvedParameters
|
||||
) {
|
||||
$parameters = $reflection->getParameters();
|
||||
|
||||
// Skip parameters already resolved
|
||||
if (! empty($resolvedParameters)) {
|
||||
$parameters = array_diff_key($parameters, $resolvedParameters);
|
||||
}
|
||||
|
||||
foreach ($parameters as $index => $parameter) {
|
||||
$parameterClass = $parameter->getClass();
|
||||
|
||||
if ($parameterClass && array_key_exists($parameterClass->name, $providedParameters)) {
|
||||
$resolvedParameters[$index] = $providedParameters[$parameterClass->name];
|
||||
}
|
||||
}
|
||||
|
||||
return $resolvedParameters;
|
||||
}
|
||||
}
|
61
vendor/php-di/invoker/src/Reflection/CallableReflection.php
vendored
Normal file
61
vendor/php-di/invoker/src/Reflection/CallableReflection.php
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Invoker\Reflection;
|
||||
|
||||
use Invoker\Exception\NotCallableException;
|
||||
|
||||
/**
|
||||
* Create a reflection object from a callable.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class CallableReflection
|
||||
{
|
||||
/**
|
||||
* @param callable $callable
|
||||
*
|
||||
* @return \ReflectionFunctionAbstract
|
||||
*
|
||||
* @throws NotCallableException
|
||||
*
|
||||
* TODO Use the `callable` type-hint once support for PHP 5.4 and up.
|
||||
*/
|
||||
public static function create($callable)
|
||||
{
|
||||
// Closure
|
||||
if ($callable instanceof \Closure) {
|
||||
return new \ReflectionFunction($callable);
|
||||
}
|
||||
|
||||
// Array callable
|
||||
if (is_array($callable)) {
|
||||
list($class, $method) = $callable;
|
||||
|
||||
if (! method_exists($class, $method)) {
|
||||
throw NotCallableException::fromInvalidCallable($callable);
|
||||
}
|
||||
|
||||
return new \ReflectionMethod($class, $method);
|
||||
}
|
||||
|
||||
// Callable object (i.e. implementing __invoke())
|
||||
if (is_object($callable) && method_exists($callable, '__invoke')) {
|
||||
return new \ReflectionMethod($callable, '__invoke');
|
||||
}
|
||||
|
||||
// Callable class (i.e. implementing __invoke())
|
||||
if (is_string($callable) && class_exists($callable) && method_exists($callable, '__invoke')) {
|
||||
return new \ReflectionMethod($callable, '__invoke');
|
||||
}
|
||||
|
||||
// Standard function
|
||||
if (is_string($callable) && function_exists($callable)) {
|
||||
return new \ReflectionFunction($callable);
|
||||
}
|
||||
|
||||
throw new NotCallableException(sprintf(
|
||||
'%s is not a callable',
|
||||
is_string($callable) ? $callable : 'Instance of ' . get_class($callable)
|
||||
));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user