default services conflit ?

This commit is contained in:
armansansd
2022-04-27 11:30:43 +02:00
parent 28190a5749
commit 8bb1064a3b
8132 changed files with 900138 additions and 426 deletions

1
old.vendor/stack/builder/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
vendor

View File

@@ -0,0 +1,14 @@
language: php
php:
- 7.2
- 7.3
- 7.4
before_script:
- composer install --no-interaction --prefer-source
script: phpunit --coverage-text
matrix:
fast_finish: true

View File

@@ -0,0 +1,31 @@
CHANGELOG
=========
* 1.0.6 (2020-01-30)
* Add compability with Symfony 5.
* Remove Silex dependencies for tests.
* 1.0.5 (2017-11-18)
* Add compability with Symfony 4.
* 1.0.4 (2016-06-02)
* Add compability with Symfony 3.
* 1.0.3 (2014-11-23)
* Only call Terminable middlewares once.
* 1.0.2 (2014-05-18)
* Validate missing arguments (@bajbnet).
* 1.0.1 (2013-10-25)
* Lower PHP requirement to 5.3.
* 1.0.0 (2013-08-02)
* Initial release.

View File

@@ -0,0 +1,19 @@
Copyright (c) 2013 Igor Wiedler
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,69 @@
# Stack/Builder
Builder for stack middlewares based on HttpKernelInterface.
Stack/Builder is a small library that helps you construct a nested
HttpKernelInterface decorator tree. It models it as a stack of middlewares.
## Example
If you want to decorate a [silex](https://github.com/fabpot/Silex) app with
session and cache middlewares, you'll have to do something like this:
```php
use Symfony\Component\HttpKernel\HttpCache\Store;
$app = new Silex\Application();
$app->get('/', function () {
return 'Hello World!';
});
$app = new Stack\Session(
new Symfony\Component\HttpKernel\HttpCache\HttpCache(
$app,
new Store(__DIR__.'/cache')
)
);
```
This can get quite annoying indeed. Stack/Builder simplifies that:
```php
$stack = (new Stack\Builder())
->push('Stack\Session')
->push('Symfony\Component\HttpKernel\HttpCache\HttpCache', new Store(__DIR__.'/cache'));
$app = $stack->resolve($app);
```
As you can see, by arranging the layers as a stack, they become a lot easier
to work with.
In the front controller, you need to serve the request:
```php
use Symfony\Component\HttpFoundation\Request;
$request = Request::createFromGlobals();
$response = $app->handle($request)->send();
$app->terminate($request, $response);
```
Stack/Builder also supports pushing a `callable` on to the stack, for situations
where instantiating middlewares might be more complicated. The `callable` should
accept a `HttpKernelInterface` as the first argument and should also return a
`HttpKernelInterface`. The example above could be rewritten as:
```php
$stack = (new Stack\Builder())
->push('Stack\Session')
->push(function ($app) {
$cache = new HttpCache($app, new Store(__DIR__.'/cache'));
return $cache;
})
;
```
## Inspiration
* [Rack::Builder](http://rack.rubyforge.org/doc/Rack/Builder.html)
* [HttpKernel middlewares](https://igor.io/2013/02/02/http-kernel-middlewares.html)

View File

@@ -0,0 +1,30 @@
{
"name": "stack/builder",
"description": "Builder for stack middleware based on HttpKernelInterface.",
"keywords": ["stack"],
"license": "MIT",
"authors": [
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
}
],
"require": {
"php": ">=7.2.0",
"symfony/http-foundation": "~2.1|~3.0|~4.0|~5.0",
"symfony/http-kernel": "~2.1|~3.0|~4.0|~5.0"
},
"require-dev": {
"phpunit/phpunit": "~8.0",
"symfony/routing": "^5.0"
},
"scripts": {
"test": "phpunit --coverage-text"
},
"autoload": {
"psr-0": { "Stack": "src" }
},
"extra": {
"branch-alias": { "dev-master": "1.0-dev" }
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
colors="true"
bootstrap="./tests/bootstrap.php"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
>
<testsuites>
<testsuite name="unit">
<directory>./tests/unit/</directory>
</testsuite>
<testsuite name="integration">
<directory>./tests/integration/</directory>
</testsuite>
<testsuite name="functional">
<directory>./tests/functional/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,63 @@
<?php
namespace Stack;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class Builder
{
private $specs;
public function __construct()
{
$this->specs = new \SplStack();
}
public function unshift(/*$kernelClass, $args...*/)
{
if (func_num_args() === 0) {
throw new \InvalidArgumentException("Missing argument(s) when calling unshift");
}
$spec = func_get_args();
$this->specs->unshift($spec);
return $this;
}
public function push(/*$kernelClass, $args...*/)
{
if (func_num_args() === 0) {
throw new \InvalidArgumentException("Missing argument(s) when calling push");
}
$spec = func_get_args();
$this->specs->push($spec);
return $this;
}
public function resolve(HttpKernelInterface $app)
{
$middlewares = array($app);
foreach ($this->specs as $spec) {
$args = $spec;
$firstArg = array_shift($args);
if (is_callable($firstArg)) {
$app = $firstArg($app);
} else {
$kernelClass = $firstArg;
array_unshift($args, $app);
$reflection = new \ReflectionClass($kernelClass);
$app = $reflection->newInstanceArgs($args);
}
array_unshift($middlewares, $app);
}
return new StackedHttpKernel($app, $middlewares);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Stack;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\TerminableInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class StackedHttpKernel implements HttpKernelInterface, TerminableInterface
{
private $app;
private $middlewares = array();
public function __construct(HttpKernelInterface $app, array $middlewares)
{
$this->app = $app;
$this->middlewares = $middlewares;
}
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
return $this->app->handle($request, $type, $catch);
}
public function terminate(Request $request, Response $response)
{
$prevKernel = null;
foreach ($this->middlewares as $kernel) {
// if prev kernel was terminable we can assume this middleware has already been called
if (!$prevKernel instanceof TerminableInterface && $kernel instanceof TerminableInterface) {
$kernel->terminate($request, $response);
}
$prevKernel = $kernel;
}
}
}

View File

@@ -0,0 +1,93 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
use Symfony\Component\HttpKernel\EventListener\RouterListener;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
class Application implements HttpKernelInterface
{
private $kernel;
private $dispatcher;
public function __construct()
{
$routes = new RouteCollection();
$routes->add('hello', new Route('/foo', [
'_controller' => function (Request $request) {
return new Response('bar');
}]
));
$matcher = new UrlMatcher($routes, new RequestContext());
$this->dispatcher = new EventDispatcher();
$this->dispatcher->addSubscriber(new RouterListener($matcher, new RequestStack()));
$controllerResolver = new ControllerResolver();
$argumentResolver = new ArgumentResolver();
$this->kernel = new HttpKernel($this->dispatcher, $controllerResolver, new RequestStack(), $argumentResolver);
}
public function handle(Request $request, int $type = HttpKernelInterface::MASTER_REQUEST, bool $catch = true)
{
return $this->kernel->handle($request);
}
public function terminate(Request $request, Response $response)
{
$this->kernel->terminate($request, $response);
}
public function finish(callable $callback)
{
$dispatcher = $this->dispatcher;
$app = $this;
$request = Request::createFromGlobals();
$response = $app->handle($request);
$app->terminate($request, $response);
$event = new TerminateEvent($app, $request, $response);
$dispatcher->addSubscriber(new KernelTerminatedSubscriber($callback));
$dispatcher->dispatch($event, KernelEvents::TERMINATE);
}
}
class KernelTerminatedSubscriber implements EventSubscriberInterface
{
protected $callback;
public function __construct(callable $callback)
{
$this->callback = $callback;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::TERMINATE => 'onKernelTerminated'
];
}
public function onKernelTerminated(TerminateEvent $event)
{
call_user_func($this->callback);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace functional;
use Application;
use PHPUnit\Framework\TestCase;
use Stack\Builder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class ApplicationTest extends TestCase
{
public function testWithAppendMiddlewares()
{
$request = Request::create('/foo');
$app = new Application();
$finished = false;
$app->finish(function () use (&$finished) {
$finished = true;
});
$stack = new Builder();
$stack
->push('functional\Append', '.A')
->push('functional\Append', '.B');
$app = $stack->resolve($app);
$response = $app->handle($request);
$app->terminate($request, $response);
$this->assertSame('bar.B.A', $response->getContent());
$this->assertTrue($finished);
}
}
class Append implements HttpKernelInterface
{
private $app;
private $appendix;
public function __construct(HttpKernelInterface $app, $appendix)
{
$this->app = $app;
$this->appendix = $appendix;
}
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
$response = clone $this->app->handle($request, $type, $catch);
$response->setContent($response->getContent().$this->appendix);
return $response;
}
}

View File

@@ -0,0 +1,219 @@
<?php
namespace Stack;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\TerminableInterface;
/** @covers Stack\Builder */
class BuilderTest extends TestCase
{
/** @test */
public function withoutMiddlewaresItShouldReturnOriginalResponse()
{
$app = $this->getHttpKernelMock(new Response('ok'));
$stack = new Builder();
$resolved = $stack->resolve($app);
$request = Request::create('/');
$response = $resolved->handle($request);
$this->assertInstanceOf('Stack\StackedHttpKernel', $resolved);
$this->assertSame('ok', $response->getContent());
}
/** @test */
public function resolvedKernelShouldDelegateTerminateCalls()
{
$app = $this->getTerminableMock();
$stack = new Builder();
$resolved = $stack->resolve($app);
$request = Request::create('/');
$response = new Response('ok');
$resolved->handle($request);
$resolved->terminate($request, $response);
}
/** @test */
public function pushShouldReturnSelf()
{
$stack = new Builder();
$this->assertSame($stack, $stack->push('Stack\AppendA'));
}
/** @test */
public function pushShouldThrowOnInvalidInput()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Missing argument(s) when calling push');
$stack = new Builder();
$stack->push();
}
/** @test */
public function unshiftShouldReturnSelf()
{
$stack = new Builder();
$this->assertSame($stack, $stack->unshift('Stack\AppendA'));
}
/** @test */
public function unshiftShouldThrowOnInvalidInput()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Missing argument(s) when calling unshift');
$stack = new Builder();
$stack->unshift();
}
/** @test */
public function appendMiddlewareShouldAppendToBody()
{
$app = $this->getHttpKernelMock(new Response('ok'));
$stack = new Builder();
$stack->push('Stack\AppendA');
$resolved = $stack->resolve($app);
$request = Request::create('/');
$response = $resolved->handle($request);
$this->assertSame('ok.A', $response->getContent());
}
/** @test */
public function unshiftMiddlewareShouldPutMiddlewareBeforePushed()
{
$app = $this->getHttpKernelMock(new Response('ok'));
$stack = new Builder();
$stack->push('Stack\Append', '2.');
$stack->unshift('Stack\Append', '1.');
$resolved = $stack->resolve($app);
$request = Request::create('/');
$response = $resolved->handle($request);
$this->assertSame('ok2.1.', $response->getContent());
}
/** @test */
public function stackedMiddlewaresShouldWrapInReverseOrder()
{
$app = $this->getHttpKernelMock(new Response('ok'));
$stack = new Builder();
$stack->push('Stack\AppendA');
$stack->push('Stack\AppendB');
$resolved = $stack->resolve($app);
$request = Request::create('/');
$response = $resolved->handle($request);
$this->assertSame('ok.B.A', $response->getContent());
}
/** @test */
public function resolveShouldPassPushArgumentsToMiddlewareConstructor()
{
$app = $this->getHttpKernelMock(new Response('ok'));
$stack = new Builder();
$stack->push('Stack\Append', '.foo');
$stack->push('Stack\Append', '.bar');
$resolved = $stack->resolve($app);
$request = Request::create('/');
$response = $resolved->handle($request);
$this->assertSame('ok.bar.foo', $response->getContent());
}
/** @test */
public function resolveShouldCallSpecFactories()
{
$app = $this->getHttpKernelMock(new Response('ok'));
$stack = new Builder();
$stack->push(function ($app) { return new Append($app, '.foo'); });
$stack->push(function ($app) { return new Append($app, '.bar'); });
$resolved = $stack->resolve($app);
$request = Request::create('/');
$response = $resolved->handle($request);
$this->assertSame('ok.bar.foo', $response->getContent());
}
private function getHttpKernelMock(Response $response)
{
$app = $this->createMock(HttpKernelInterface::class);
$app->expects($this->any())
->method('handle')
->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
->will($this->returnValue($response));
return $app;
}
private function getTerminableMock()
{
$app = $this->createMock(TerminableHttpKernel::class);
$app->expects($this->once())
->method('terminate')
->with(
$this->isInstanceOf('Symfony\Component\HttpFoundation\Request'),
$this->isInstanceOf('Symfony\Component\HttpFoundation\Response')
);
return $app;
}
}
abstract class TerminableHttpKernel implements HttpKernelInterface, TerminableInterface
{
}
class Append implements HttpKernelInterface
{
private $app;
private $appendix;
public function __construct(HttpKernelInterface $app, $appendix)
{
$this->app = $app;
$this->appendix = $appendix;
}
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
$response = clone $this->app->handle($request, $type, $catch);
$response->setContent($response->getContent().$this->appendix);
return $response;
}
}
class AppendA extends Append
{
public function __construct(HttpKernelInterface $app)
{
parent::__construct($app, '.A');
}
}
class AppendB extends Append
{
public function __construct(HttpKernelInterface $app)
{
parent::__construct($app, '.B');
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace Stack;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\TerminableInterface;
class StackedHttpKernelTest extends TestCase
{
/** @test */
public function handleShouldDelegateToApp()
{
$app = $this->getHttpKernelMock(new Response('ok'));
$kernel = new StackedHttpKernel($app, array($app));
$request = Request::create('/');
$response = $kernel->handle($request);
$this->assertSame('ok', $response->getContent());
}
/** @test */
public function handleShouldStillDelegateToAppWithMiddlewares()
{
$app = $this->getHttpKernelMock(new Response('ok'));
$bar = $this->getHttpKernelMock(new Response('bar'));
$foo = $this->getHttpKernelMock(new Response('foo'));
$kernel = new StackedHttpKernel($app, array($foo, $bar, $app));
$request = Request::create('/');
$response = $kernel->handle($request);
$this->assertSame('ok', $response->getContent());
}
/** @test */
public function terminateShouldDelegateToMiddlewares()
{
$first = new TerminableKernelSpy();
$second = new TerminableKernelSpy($first);
$third = new KernelSpy($second);
$fourth = new TerminableKernelSpy($third);
$fifth = new TerminableKernelSpy($fourth);
$kernel = new StackedHttpKernel($fifth, $middlewares = array($fifth, $fourth, $third, $second, $first));
$request = Request::create('/');
$response = $kernel->handle($request);
$kernel->terminate($request, $response);
$this->assertTerminablesCalledOnce($middlewares);
}
private function assertTerminablesCalledOnce(array $middlewares)
{
foreach ($middlewares as $kernel) {
if ($kernel instanceof TerminableInterface) {
$this->assertEquals(1, $kernel->terminateCallCount(), "Terminate was called {$kernel->terminateCallCount()} times");
}
}
}
private function getHttpKernelMock(Response $response)
{
$app = $this->createMock(HttpKernelInterface::class);
$app->expects($this->any())
->method('handle')
->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
->will($this->returnValue($response));
return $app;
}
private function getTerminableMock(Response $response = null)
{
$app = $this->getMock('Stack\TerminableHttpKernel');
if ($response) {
$app->expects($this->any())
->method('handle')
->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
->will($this->returnValue($response));
}
$app->expects($this->once())
->method('terminate')
->with(
$this->isInstanceOf('Symfony\Component\HttpFoundation\Request'),
$this->isInstanceOf('Symfony\Component\HttpFoundation\Response')
);
return $app;
}
private function getDelegatingTerminableMock(TerminableInterface $next)
{
$app = $this->getMock('Stack\TerminableHttpKernel');
$app->expects($this->once())
->method('terminate')
->with(
$this->isInstanceOf('Symfony\Component\HttpFoundation\Request'),
$this->isInstanceOf('Symfony\Component\HttpFoundation\Response')
)
->will($this->returnCallback(function ($request, $response) use ($next) {
$next->terminate($request, $response);
}));
return $app;
}
}
class KernelSpy implements HttpKernelInterface
{
private $handleCallCount = 0;
public function __construct(HttpKernelInterface $kernel = null)
{
$this->kernel = $kernel;
}
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
$this->handleCallCount++;
if ($this->kernel) {
return $this->kernel->handle($request, $type, $catch);
}
return new Response('OK');
}
public function handleCallCount()
{
return $this->handleCallCount;
}
}
class TerminableKernelSpy extends KernelSpy implements TerminableInterface
{
private $terminateCallCount = 0;
public function terminate(Request $request, Response $response)
{
$this->terminateCallCount++;
if ($this->kernel && $this->kernel instanceof TerminableInterface) {
return $this->kernel->terminate($request, $response);
}
}
public function terminateCallCount()
{
return $this->terminateCallCount;
}
}