From 6f5d5d5b53d258bc1ded793bbb98c2f8c680d420 Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Tue, 17 Apr 2018 23:22:27 +0200 Subject: [PATCH 01/12] Disable and enable debug bar using header --- src/PhpDebugBarMiddleware.php | 8 +++++- test/PhpDebugBarMiddlewareTest.php | 42 +++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/PhpDebugBarMiddleware.php b/src/PhpDebugBarMiddleware.php index c29defd..7d1f7ba 100644 --- a/src/PhpDebugBarMiddleware.php +++ b/src/PhpDebugBarMiddleware.php @@ -23,6 +23,8 @@ */ final class PhpDebugBarMiddleware implements MiddlewareInterface { + const FORCE_HEADER = 'X-Debug-Bar'; + protected $debugBarRenderer; public function __construct(DebugBarRenderer $debugbarRenderer) @@ -41,7 +43,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $response = $handler->handle($request); - if (!$this->isHtmlAccepted($request)) { + $forceHeaderValue = $request->getHeaderLine('X-Debug-Bar'); + $isForceEnable = $forceHeaderValue === 'true'; + $isForceDisable = $forceHeaderValue === 'false'; + + if ($isForceDisable || (!$isForceEnable && !$this->isHtmlAccepted($request))) { return $response; } diff --git a/test/PhpDebugBarMiddlewareTest.php b/test/PhpDebugBarMiddlewareTest.php index f405259..d0fa591 100644 --- a/test/PhpDebugBarMiddlewareTest.php +++ b/test/PhpDebugBarMiddlewareTest.php @@ -24,6 +24,9 @@ class PhpDebugBarMiddlewareTest extends TestCase protected function setUp() { $this->debugbarRenderer = $this->getMockBuilder(JavascriptRenderer::class)->disableOriginalConstructor()->getMock(); + $this->debugbarRenderer->method('renderHead')->willReturn('RenderHead'); + $this->debugbarRenderer->method('render')->willReturn('RenderBody'); + $this->middleware = new PhpDebugBarMiddleware($this->debugbarRenderer); } @@ -31,6 +34,7 @@ public function testTwoPassCallingForCompatibility(): void { $request = new ServerRequest(); $response = new Response(); + $response->getBody()->write('ResponseBody'); $calledOut = false; $outFunction = function ($request, $response) use (&$calledOut) { $calledOut = true; @@ -40,6 +44,7 @@ public function testTwoPassCallingForCompatibility(): void $result = call_user_func($this->middleware, $request, $response, $outFunction); $this->assertTrue($calledOut, 'Out is not called'); + $this->assertSame('ResponseBody', (string) $result->getBody()); $this->assertSame($response, $result); } @@ -47,14 +52,28 @@ public function testNotAttachIfNotAccept(): void { $request = new ServerRequest(); $response = new Response(); + $response->getBody()->write('ResponseBody'); $requestHandler = new RequestHandlerStub($response); $result = $this->middleware->process($request, $requestHandler); $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); + $this->assertSame('ResponseBody', (string) $result->getBody()); $this->assertSame($response, $result); } + public function testForceAttachDebugbarIfHeaderPresents(): void + { + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'application/json', 'X-Debug-Bar' => 'true']); + $response = new Response(); + $response->getBody()->write('ResponseBody'); + $requestHandler = new RequestHandlerStub($response); + + $result = $this->middleware->process($request, $requestHandler); + + $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); + } + public function testAttachToNoneHtmlResponse(): void { $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html']); @@ -63,9 +82,6 @@ public function testAttachToNoneHtmlResponse(): void $requestHandler = new RequestHandlerStub($response); - $this->debugbarRenderer->expects($this->once())->method('renderHead')->willReturn('RenderHead'); - $this->debugbarRenderer->expects($this->once())->method('render')->willReturn('RenderBody'); - $result = $this->middleware->process($request, $requestHandler); $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); @@ -80,9 +96,6 @@ public function testAttachToHtmlResponse(): void $response->getBody()->write('ResponseBody'); $requestHandler = new RequestHandlerStub($response); - $this->debugbarRenderer->expects($this->once())->method('renderHead')->willReturn('RenderHead'); - $this->debugbarRenderer->expects($this->once())->method('render')->willReturn('RenderBody'); - $result = $this->middleware->process($request, $requestHandler); $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); @@ -90,6 +103,20 @@ public function testAttachToHtmlResponse(): void $this->assertSame("ResponseBodyRenderHeadRenderBody", (string) $result->getBody()); } + public function testForceNotAttachDebugbarIfHeaderPresents(): void + { + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html', 'X-Debug-Bar' => 'false']); + $response = new Response('php://memory', 200, ['Content-Type' => 'text/html']); + $response->getBody()->write('ResponseBody'); + $requestHandler = new RequestHandlerStub($response); + + $result = $this->middleware->process($request, $requestHandler); + + $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); + $this->assertSame($response, $result); + $this->assertSame("ResponseBody", (string) $result->getBody()); + } + public function testAppendsToEndOfHtmlResponse(): void { $html = 'FooContent'; @@ -97,9 +124,6 @@ public function testAppendsToEndOfHtmlResponse(): void $response = new Response\HtmlResponse($html); $requestHandler = new RequestHandlerStub($response); - $this->debugbarRenderer->expects($this->once())->method('renderHead')->willReturn('RenderHead'); - $this->debugbarRenderer->expects($this->once())->method('render')->willReturn('RenderBody'); - $result = $this->middleware->process($request, $requestHandler); $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); From eb2cb2d54e59b157d2d508559781150fe4f19336 Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Tue, 17 Apr 2018 23:24:50 +0200 Subject: [PATCH 02/12] Use const to get header name --- src/PhpDebugBarMiddleware.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpDebugBarMiddleware.php b/src/PhpDebugBarMiddleware.php index 7d1f7ba..7a4e935 100644 --- a/src/PhpDebugBarMiddleware.php +++ b/src/PhpDebugBarMiddleware.php @@ -43,7 +43,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $response = $handler->handle($request); - $forceHeaderValue = $request->getHeaderLine('X-Debug-Bar'); + $forceHeaderValue = $request->getHeaderLine(self::FORCE_HEADER); $isForceEnable = $forceHeaderValue === 'true'; $isForceDisable = $forceHeaderValue === 'false'; From 1e9dc620a4c401b487fd80356dce0763557130a1 Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Tue, 17 Apr 2018 23:36:22 +0200 Subject: [PATCH 03/12] Force disable / enable by cookie --- src/PhpDebugBarMiddleware.php | 9 ++++++--- test/PhpDebugBarMiddlewareTest.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/PhpDebugBarMiddleware.php b/src/PhpDebugBarMiddleware.php index 7a4e935..52d3348 100644 --- a/src/PhpDebugBarMiddleware.php +++ b/src/PhpDebugBarMiddleware.php @@ -23,7 +23,9 @@ */ final class PhpDebugBarMiddleware implements MiddlewareInterface { - const FORCE_HEADER = 'X-Debug-Bar'; + const FORCE_KEY = 'X-Debug-Bar'; + const FORCE_HEADER = self::FORCE_KEY; + const FORCE_COOKIE = self::FORCE_KEY; protected $debugBarRenderer; @@ -44,8 +46,9 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $response = $handler->handle($request); $forceHeaderValue = $request->getHeaderLine(self::FORCE_HEADER); - $isForceEnable = $forceHeaderValue === 'true'; - $isForceDisable = $forceHeaderValue === 'false'; + $forceCookieValue = $request->getCookieParams()[self::FORCE_COOKIE] ?? ''; + $isForceEnable = $forceHeaderValue === 'true' || $forceCookieValue === 'true'; + $isForceDisable = $forceHeaderValue === 'false' || $forceCookieValue === 'false'; if ($isForceDisable || (!$isForceEnable && !$this->isHtmlAccepted($request))) { return $response; diff --git a/test/PhpDebugBarMiddlewareTest.php b/test/PhpDebugBarMiddlewareTest.php index d0fa591..54cba44 100644 --- a/test/PhpDebugBarMiddlewareTest.php +++ b/test/PhpDebugBarMiddlewareTest.php @@ -74,6 +74,19 @@ public function testForceAttachDebugbarIfHeaderPresents(): void $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); } + public function testForceAttachDebugbarIfCookiePresents(): void + { + $cookies = ['X-Debug-Bar' => 'true']; + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'application/json'], $cookies); + $response = new Response(); + $response->getBody()->write('ResponseBody'); + $requestHandler = new RequestHandlerStub($response); + + $result = $this->middleware->process($request, $requestHandler); + + $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); + } + public function testAttachToNoneHtmlResponse(): void { $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html']); @@ -117,6 +130,21 @@ public function testForceNotAttachDebugbarIfHeaderPresents(): void $this->assertSame("ResponseBody", (string) $result->getBody()); } + public function testForceNotAttachDebugbarIfCookiePresents(): void + { + $cookie = ['X-Debug-Bar' => 'false']; + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html'], $cookie); + $response = new Response('php://memory', 200, ['Content-Type' => 'text/html']); + $response->getBody()->write('ResponseBody'); + $requestHandler = new RequestHandlerStub($response); + + $result = $this->middleware->process($request, $requestHandler); + + $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); + $this->assertSame($response, $result); + $this->assertSame("ResponseBody", (string) $result->getBody()); + } + public function testAppendsToEndOfHtmlResponse(): void { $html = 'FooContent'; From 43242c57bd6d115fd421c578fcd1100dd0ec57ce Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Tue, 17 Apr 2018 23:43:38 +0200 Subject: [PATCH 04/12] Add readme --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 3abdfb7..6cec6c1 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,15 @@ $app->run($request, $response); You don't need to copy any static assets from phpdebugbar vendor! +### How to force disable or enable PHP Debug Bar? + +Sometimes you want to have control when show or not PHP Debug Bar: +* custom content negotiation, +* allow to make redirects. + +We allow you to disable attaching phpdebugbar using `X-Debug-Bar: false` header or cookie. +To force enable just send request with `X-Debug-Bar` header or cookie with `true` value. + ### How to install on Zend Expressive? You need to register ConfigProvider and pipe provided middleware: From c34401409d9967ba4982d396e832c15417714869 Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Tue, 17 Apr 2018 23:53:28 +0200 Subject: [PATCH 05/12] Allow to disable/enable using attribute --- README.md | 4 ++-- src/PhpDebugBarMiddleware.php | 6 ++++-- test/PhpDebugBarMiddlewareTest.php | 28 ++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6cec6c1..f91a8d7 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ Sometimes you want to have control when show or not PHP Debug Bar: * custom content negotiation, * allow to make redirects. -We allow you to disable attaching phpdebugbar using `X-Debug-Bar: false` header or cookie. -To force enable just send request with `X-Debug-Bar` header or cookie with `true` value. +We allow you to disable attaching phpdebugbar using `X-Debug-Bar: false` header, cookie or request attribute. +To force enable just send request with `X-Debug-Bar` header, cookie or request attribute with `true` value. ### How to install on Zend Expressive? diff --git a/src/PhpDebugBarMiddleware.php b/src/PhpDebugBarMiddleware.php index 52d3348..7f8a1c7 100644 --- a/src/PhpDebugBarMiddleware.php +++ b/src/PhpDebugBarMiddleware.php @@ -26,6 +26,7 @@ final class PhpDebugBarMiddleware implements MiddlewareInterface const FORCE_KEY = 'X-Debug-Bar'; const FORCE_HEADER = self::FORCE_KEY; const FORCE_COOKIE = self::FORCE_KEY; + const FORCE_ATTRIBUTE = self::FORCE_KEY; protected $debugBarRenderer; @@ -47,8 +48,9 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $forceHeaderValue = $request->getHeaderLine(self::FORCE_HEADER); $forceCookieValue = $request->getCookieParams()[self::FORCE_COOKIE] ?? ''; - $isForceEnable = $forceHeaderValue === 'true' || $forceCookieValue === 'true'; - $isForceDisable = $forceHeaderValue === 'false' || $forceCookieValue === 'false'; + $forceAttibuteValue = $request->getAttribute(self::FORCE_ATTRIBUTE, ''); + $isForceEnable = $forceHeaderValue === 'true' || $forceCookieValue === 'true' || $forceAttibuteValue === 'true'; + $isForceDisable = $forceHeaderValue === 'false' || $forceCookieValue === 'false' || $forceAttibuteValue === 'false'; if ($isForceDisable || (!$isForceEnable && !$this->isHtmlAccepted($request))) { return $response; diff --git a/test/PhpDebugBarMiddlewareTest.php b/test/PhpDebugBarMiddlewareTest.php index 54cba44..fb0a88d 100644 --- a/test/PhpDebugBarMiddlewareTest.php +++ b/test/PhpDebugBarMiddlewareTest.php @@ -87,6 +87,19 @@ public function testForceAttachDebugbarIfCookiePresents(): void $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); } + public function testForceAttachDebugbarIfAttributePresents(): void + { + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'application/json']); + $request = $request->withAttribute('X-Debug-Bar', 'true'); + $response = new Response(); + $response->getBody()->write('ResponseBody'); + $requestHandler = new RequestHandlerStub($response); + + $result = $this->middleware->process($request, $requestHandler); + + $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); + } + public function testAttachToNoneHtmlResponse(): void { $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html']); @@ -145,6 +158,21 @@ public function testForceNotAttachDebugbarIfCookiePresents(): void $this->assertSame("ResponseBody", (string) $result->getBody()); } + public function testForceNotAttachDebugbarIfAttributePresents(): void + { + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html']); + $request = $request->withAttribute('X-Debug-Bar', 'false'); + $response = new Response('php://memory', 200, ['Content-Type' => 'text/html']); + $response->getBody()->write('ResponseBody'); + $requestHandler = new RequestHandlerStub($response); + + $result = $this->middleware->process($request, $requestHandler); + + $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); + $this->assertSame($response, $result); + $this->assertSame("ResponseBody", (string) $result->getBody()); + } + public function testAppendsToEndOfHtmlResponse(): void { $html = 'FooContent'; From 230d40168b2e4fb063a35e35124c83424a076a75 Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Tue, 17 Apr 2018 23:56:17 +0200 Subject: [PATCH 06/12] Small refactor --- src/PhpDebugBarMiddleware.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpDebugBarMiddleware.php b/src/PhpDebugBarMiddleware.php index 7f8a1c7..52a9e2b 100644 --- a/src/PhpDebugBarMiddleware.php +++ b/src/PhpDebugBarMiddleware.php @@ -49,8 +49,8 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $forceHeaderValue = $request->getHeaderLine(self::FORCE_HEADER); $forceCookieValue = $request->getCookieParams()[self::FORCE_COOKIE] ?? ''; $forceAttibuteValue = $request->getAttribute(self::FORCE_ATTRIBUTE, ''); - $isForceEnable = $forceHeaderValue === 'true' || $forceCookieValue === 'true' || $forceAttibuteValue === 'true'; - $isForceDisable = $forceHeaderValue === 'false' || $forceCookieValue === 'false' || $forceAttibuteValue === 'false'; + $isForceEnable = in_array('true', [$forceHeaderValue, $forceCookieValue, $forceAttibuteValue], true); + $isForceDisable = in_array('false', [$forceHeaderValue, $forceCookieValue, $forceAttibuteValue], true); if ($isForceDisable || (!$isForceEnable && !$this->isHtmlAccepted($request))) { return $response; From bb59bfe9642e29b9f9e677379e6cc0c44c86d670 Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Wed, 25 Apr 2018 23:47:45 +0200 Subject: [PATCH 07/12] Cr fixes --- src/PhpDebugBarMiddleware.php | 11 ++++------- test/PhpDebugBarMiddlewareTest.php | 12 ++++++------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/PhpDebugBarMiddleware.php b/src/PhpDebugBarMiddleware.php index 52a9e2b..c652dca 100644 --- a/src/PhpDebugBarMiddleware.php +++ b/src/PhpDebugBarMiddleware.php @@ -23,10 +23,7 @@ */ final class PhpDebugBarMiddleware implements MiddlewareInterface { - const FORCE_KEY = 'X-Debug-Bar'; - const FORCE_HEADER = self::FORCE_KEY; - const FORCE_COOKIE = self::FORCE_KEY; - const FORCE_ATTRIBUTE = self::FORCE_KEY; + public const FORCE_KEY = 'X-Enable-Debug-Bar'; protected $debugBarRenderer; @@ -46,9 +43,9 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $response = $handler->handle($request); - $forceHeaderValue = $request->getHeaderLine(self::FORCE_HEADER); - $forceCookieValue = $request->getCookieParams()[self::FORCE_COOKIE] ?? ''; - $forceAttibuteValue = $request->getAttribute(self::FORCE_ATTRIBUTE, ''); + $forceHeaderValue = $request->getHeaderLine(self::FORCE_KEY); + $forceCookieValue = $request->getCookieParams()[self::FORCE_KEY] ?? ''; + $forceAttibuteValue = $request->getAttribute(self::FORCE_KEY, ''); $isForceEnable = in_array('true', [$forceHeaderValue, $forceCookieValue, $forceAttibuteValue], true); $isForceDisable = in_array('false', [$forceHeaderValue, $forceCookieValue, $forceAttibuteValue], true); diff --git a/test/PhpDebugBarMiddlewareTest.php b/test/PhpDebugBarMiddlewareTest.php index fb0a88d..5b99e00 100644 --- a/test/PhpDebugBarMiddlewareTest.php +++ b/test/PhpDebugBarMiddlewareTest.php @@ -64,7 +64,7 @@ public function testNotAttachIfNotAccept(): void public function testForceAttachDebugbarIfHeaderPresents(): void { - $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'application/json', 'X-Debug-Bar' => 'true']); + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'application/json', 'X-Enable-Debug-Bar' => 'true']); $response = new Response(); $response->getBody()->write('ResponseBody'); $requestHandler = new RequestHandlerStub($response); @@ -76,7 +76,7 @@ public function testForceAttachDebugbarIfHeaderPresents(): void public function testForceAttachDebugbarIfCookiePresents(): void { - $cookies = ['X-Debug-Bar' => 'true']; + $cookies = ['X-Enable-Debug-Bar' => 'true']; $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'application/json'], $cookies); $response = new Response(); $response->getBody()->write('ResponseBody'); @@ -90,7 +90,7 @@ public function testForceAttachDebugbarIfCookiePresents(): void public function testForceAttachDebugbarIfAttributePresents(): void { $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'application/json']); - $request = $request->withAttribute('X-Debug-Bar', 'true'); + $request = $request->withAttribute('X-Enable-Debug-Bar', 'true'); $response = new Response(); $response->getBody()->write('ResponseBody'); $requestHandler = new RequestHandlerStub($response); @@ -131,7 +131,7 @@ public function testAttachToHtmlResponse(): void public function testForceNotAttachDebugbarIfHeaderPresents(): void { - $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html', 'X-Debug-Bar' => 'false']); + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html', 'X-Enable-Debug-Bar' => 'false']); $response = new Response('php://memory', 200, ['Content-Type' => 'text/html']); $response->getBody()->write('ResponseBody'); $requestHandler = new RequestHandlerStub($response); @@ -145,7 +145,7 @@ public function testForceNotAttachDebugbarIfHeaderPresents(): void public function testForceNotAttachDebugbarIfCookiePresents(): void { - $cookie = ['X-Debug-Bar' => 'false']; + $cookie = ['X-Enable-Debug-Bar' => 'false']; $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html'], $cookie); $response = new Response('php://memory', 200, ['Content-Type' => 'text/html']); $response->getBody()->write('ResponseBody'); @@ -161,7 +161,7 @@ public function testForceNotAttachDebugbarIfCookiePresents(): void public function testForceNotAttachDebugbarIfAttributePresents(): void { $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html']); - $request = $request->withAttribute('X-Debug-Bar', 'false'); + $request = $request->withAttribute('X-Enable-Debug-Bar', 'false'); $response = new Response('php://memory', 200, ['Content-Type' => 'text/html']); $response->getBody()->write('ResponseBody'); $requestHandler = new RequestHandlerStub($response); From c25e703be0a5d02d1822f8d62960dad2b9ae8d5d Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Wed, 25 Apr 2018 23:48:55 +0200 Subject: [PATCH 08/12] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f91a8d7..34dd901 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ Sometimes you want to have control when show or not PHP Debug Bar: * custom content negotiation, * allow to make redirects. -We allow you to disable attaching phpdebugbar using `X-Debug-Bar: false` header, cookie or request attribute. -To force enable just send request with `X-Debug-Bar` header, cookie or request attribute with `true` value. +We allow you to disable attaching phpdebugbar using `X-Enable-Debug-Bar: false` header, cookie or request attribute. +To force enable just send request with `X-Enable-Debug-Bar` header, cookie or request attribute with `true` value. ### How to install on Zend Expressive? From 5bf435c96252763bc71cb79dbd8b3fe9f8e4827b Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Wed, 25 Apr 2018 23:55:21 +0200 Subject: [PATCH 09/12] Update readme and test convention --- README.md | 4 ++-- test/PhpDebugBarMiddlewareTest.php | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 34dd901..0e4cd82 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,9 @@ You don't need to copy any static assets from phpdebugbar vendor! ### How to force disable or enable PHP Debug Bar? -Sometimes you want to have control when show or not PHP Debug Bar: +Sometimes you want to have control when enable (or not) PHP Debug Bar: * custom content negotiation, -* allow to make redirects. +* allow to debug redirects responses. We allow you to disable attaching phpdebugbar using `X-Enable-Debug-Bar: false` header, cookie or request attribute. To force enable just send request with `X-Enable-Debug-Bar` header, cookie or request attribute with `true` value. diff --git a/test/PhpDebugBarMiddlewareTest.php b/test/PhpDebugBarMiddlewareTest.php index 5b99e00..b36fa13 100644 --- a/test/PhpDebugBarMiddlewareTest.php +++ b/test/PhpDebugBarMiddlewareTest.php @@ -71,7 +71,7 @@ public function testForceAttachDebugbarIfHeaderPresents(): void $result = $this->middleware->process($request, $requestHandler); - $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); + $this->assertSame('RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody', (string) $result->getBody()); } public function testForceAttachDebugbarIfCookiePresents(): void @@ -84,7 +84,7 @@ public function testForceAttachDebugbarIfCookiePresents(): void $result = $this->middleware->process($request, $requestHandler); - $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); + $this->assertSame('RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody', (string) $result->getBody()); } public function testForceAttachDebugbarIfAttributePresents(): void @@ -97,7 +97,7 @@ public function testForceAttachDebugbarIfAttributePresents(): void $result = $this->middleware->process($request, $requestHandler); - $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); + $this->assertSame('RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody', (string) $result->getBody()); } public function testAttachToNoneHtmlResponse(): void @@ -112,7 +112,7 @@ public function testAttachToNoneHtmlResponse(): void $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); $this->assertNotSame($response, $result); - $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); + $this->assertSame('RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody', (string) $result->getBody()); } public function testAttachToHtmlResponse(): void @@ -126,7 +126,7 @@ public function testAttachToHtmlResponse(): void $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); $this->assertSame($response, $result); - $this->assertSame("ResponseBodyRenderHeadRenderBody", (string) $result->getBody()); + $this->assertSame('ResponseBodyRenderHeadRenderBody', (string) $result->getBody()); } public function testForceNotAttachDebugbarIfHeaderPresents(): void @@ -140,7 +140,7 @@ public function testForceNotAttachDebugbarIfHeaderPresents(): void $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); $this->assertSame($response, $result); - $this->assertSame("ResponseBody", (string) $result->getBody()); + $this->assertSame('ResponseBody', (string) $result->getBody()); } public function testForceNotAttachDebugbarIfCookiePresents(): void @@ -155,7 +155,7 @@ public function testForceNotAttachDebugbarIfCookiePresents(): void $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); $this->assertSame($response, $result); - $this->assertSame("ResponseBody", (string) $result->getBody()); + $this->assertSame('ResponseBody', (string) $result->getBody()); } public function testForceNotAttachDebugbarIfAttributePresents(): void @@ -170,7 +170,7 @@ public function testForceNotAttachDebugbarIfAttributePresents(): void $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); $this->assertSame($response, $result); - $this->assertSame("ResponseBody", (string) $result->getBody()); + $this->assertSame('ResponseBody', (string) $result->getBody()); } public function testAppendsToEndOfHtmlResponse(): void From d584e06ca02f9f0cd8bac18f405a3f0f866f4c8e Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Wed, 25 Apr 2018 23:57:59 +0200 Subject: [PATCH 10/12] Fix test convention --- test/PhpDebugBarMiddlewareTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/PhpDebugBarMiddlewareTest.php b/test/PhpDebugBarMiddlewareTest.php index b36fa13..9028156 100644 --- a/test/PhpDebugBarMiddlewareTest.php +++ b/test/PhpDebugBarMiddlewareTest.php @@ -71,7 +71,7 @@ public function testForceAttachDebugbarIfHeaderPresents(): void $result = $this->middleware->process($request, $requestHandler); - $this->assertSame('RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody', (string) $result->getBody()); + $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); } public function testForceAttachDebugbarIfCookiePresents(): void @@ -84,7 +84,7 @@ public function testForceAttachDebugbarIfCookiePresents(): void $result = $this->middleware->process($request, $requestHandler); - $this->assertSame('RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody', (string) $result->getBody()); + $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); } public function testForceAttachDebugbarIfAttributePresents(): void @@ -97,7 +97,7 @@ public function testForceAttachDebugbarIfAttributePresents(): void $result = $this->middleware->process($request, $requestHandler); - $this->assertSame('RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody', (string) $result->getBody()); + $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); } public function testAttachToNoneHtmlResponse(): void @@ -112,7 +112,7 @@ public function testAttachToNoneHtmlResponse(): void $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); $this->assertNotSame($response, $result); - $this->assertSame('RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody', (string) $result->getBody()); + $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); } public function testAttachToHtmlResponse(): void From d49a687810dfa4a3c21e855f4b58f8f5ca87cda4 Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Thu, 26 Apr 2018 00:29:12 +0200 Subject: [PATCH 11/12] Improve code --- src/PhpDebugBarMiddleware.php | 85 ++++++++++-------------------- test/PhpDebugBarMiddlewareTest.php | 41 ++++++++++++++ 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/src/PhpDebugBarMiddleware.php b/src/PhpDebugBarMiddleware.php index c652dca..57157db 100644 --- a/src/PhpDebugBarMiddleware.php +++ b/src/PhpDebugBarMiddleware.php @@ -5,13 +5,13 @@ use DebugBar\JavascriptRenderer as DebugBarRenderer; use Psr\Http\Message\MessageInterface; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\UriInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; -use Slim\Http\Uri; -use Zend\Diactoros\Response; +use Slim\Http\Uri as SlimUri; +use Zend\Diactoros\Response as DiactorosResponse; use Zend\Diactoros\Response\HtmlResponse; use Zend\Diactoros\Response\Serializer; use Zend\Diactoros\Stream; @@ -35,7 +35,7 @@ public function __construct(DebugBarRenderer $debugbarRenderer) /** * @inheritDoc */ - public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + public function process(Request $request, RequestHandlerInterface $handler): Response { if ($staticFile = $this->getStaticFile($request->getUri())) { return $staticFile; @@ -49,7 +49,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $isForceEnable = in_array('true', [$forceHeaderValue, $forceCookieValue, $forceAttibuteValue], true); $isForceDisable = in_array('false', [$forceHeaderValue, $forceCookieValue, $forceAttibuteValue], true); - if ($isForceDisable || (!$isForceEnable && !$this->isHtmlAccepted($request))) { + if ($isForceDisable || (!$isForceEnable && ($this->isRedirect($response) || !$this->isHtmlAccepted($request)))) { return $response; } @@ -59,19 +59,19 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface return $this->prepareHtmlResponseWithDebugBar($response); } - public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface + public function __invoke(Request $request, Response $response, callable $next): Response { $handler = new class($next, $response) implements RequestHandlerInterface { private $next; private $response; - public function __construct(callable $next, ResponseInterface $response) + public function __construct(callable $next, Response $response) { $this->next = $next; $this->response = $response; } - public function handle(ServerRequestInterface $request): ResponseInterface + public function handle(Request $request): Response { return ($this->next)($request, $this->response); } @@ -79,10 +79,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface return $this->process($request, $handler); } - /** - * @return HtmlResponse - */ - private function prepareHtmlResponseWithDebugBar(ResponseInterface $response) + private function prepareHtmlResponseWithDebugBar(Response $response): HtmlResponse { $head = $this->debugBarRenderer->renderHead(); $body = $this->debugBarRenderer->render(); @@ -94,10 +91,7 @@ private function prepareHtmlResponseWithDebugBar(ResponseInterface $response) return new HtmlResponse($result); } - /** - * @return ResponseInterface - */ - private function attachDebugBarToResponse(ResponseInterface $response) + private function attachDebugBarToResponse(Response $response): Response { $head = $this->debugBarRenderer->renderHead(); $body = $this->debugBarRenderer->render(); @@ -111,15 +105,12 @@ private function attachDebugBarToResponse(ResponseInterface $response) return $response; } - /** - * @return ResponseInterface|null - */ - private function getStaticFile(UriInterface $uri) + private function getStaticFile(UriInterface $uri): ?Response { $path = $this->extractPath($uri); if (strpos($path, $this->debugBarRenderer->getBaseUrl()) !== 0) { - return; + return null; } $pathToFile = substr($path, strlen($this->debugBarRenderer->getBaseUrl())); @@ -127,26 +118,21 @@ private function getStaticFile(UriInterface $uri) $fullPathToFile = $this->debugBarRenderer->getBasePath() . $pathToFile; if (!file_exists($fullPathToFile)) { - return; + return null; } $contentType = $this->getContentTypeByFileName($fullPathToFile); $stream = new Stream($fullPathToFile, 'r'); - return new Response($stream, 200, [ + return new DiactorosResponse($stream, 200, [ 'Content-type' => $contentType, ]); } - /** - * @param UriInterface $uri - * - * @return string - */ - private function extractPath(UriInterface $uri) + private function extractPath(UriInterface $uri): string { // Slim3 compatibility - if ($uri instanceof Uri) { + if ($uri instanceof SlimUri) { $basePath = $uri->getBasePath(); if (!empty($basePath)) { return $basePath; @@ -155,12 +141,7 @@ private function extractPath(UriInterface $uri) return $uri->getPath(); } - /** - * @param string $filename - * - * @return string - */ - private function getContentTypeByFileName($filename) + private function getContentTypeByFileName(string $filename): string { $ext = pathinfo($filename, PATHINFO_EXTENSION); @@ -178,35 +159,25 @@ private function getContentTypeByFileName($filename) return isset($map[$ext]) ? $map[$ext] : 'text/plain'; } - /** - * @param ResponseInterface $response - * - * @return bool - */ - private function isHtmlResponse(ResponseInterface $response) + private function isHtmlResponse(Response $response): bool { return $this->hasHeaderContains($response, 'Content-Type', 'text/html'); } - /** - * @param ServerRequestInterface $request - * - * @return bool - */ - private function isHtmlAccepted(ServerRequestInterface $request) + private function isHtmlAccepted(Request $request): bool { return $this->hasHeaderContains($request, 'Accept', 'text/html'); } - /** - * @param MessageInterface $message - * @param string $headerName - * @param string $value - * - * @return bool - */ - private function hasHeaderContains(MessageInterface $message, $headerName, $value) + private function hasHeaderContains(MessageInterface $message, string $headerName, string $value): bool { return strpos($message->getHeaderLine($headerName), $value) !== false; } + + private function isRedirect(Response $response): bool + { + $statusCode = $response->getStatusCode(); + + return ($statusCode >= 300 || $statusCode < 400) && $response->getHeaderLine('Location') !== ''; + } } diff --git a/test/PhpDebugBarMiddlewareTest.php b/test/PhpDebugBarMiddlewareTest.php index 9028156..9f912c7 100644 --- a/test/PhpDebugBarMiddlewareTest.php +++ b/test/PhpDebugBarMiddlewareTest.php @@ -115,6 +115,47 @@ public function testAttachToNoneHtmlResponse(): void $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 200 OK\r\n\r\nResponseBody
RenderBody", (string) $result->getBody()); } + public function testNotAttachToRedirectResponse(): void + { + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html']); + $response = (new Response())->withStatus(302)->withAddedHeader('Location', 'some-location'); + + $requestHandler = new RequestHandlerStub($response); + + $result = $this->middleware->process($request, $requestHandler); + + $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); + $this->assertSame($response, $result); + } + + public function testAttachToRedirectResponseWithoutLocation(): void + { + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html']); + $response = (new Response())->withStatus(302); + + $requestHandler = new RequestHandlerStub($response); + + $result = $this->middleware->process($request, $requestHandler); + + $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); + $this->assertNotSame($response, $result); + $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 302 Found\r\n\r\n
RenderBody", (string) $result->getBody()); + } + + public function testForceAttachToRedirectResponse(): void + { + $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html', 'X-Enable-Debug-Bar' => 'true']); + $response = (new Response())->withStatus(302)->withAddedHeader('Location', 'some-location'); + + $requestHandler = new RequestHandlerStub($response); + + $result = $this->middleware->process($request, $requestHandler); + + $this->assertTrue($requestHandler->isCalled(), 'Request handler is not called'); + $this->assertNotSame($response, $result); + $this->assertSame("RenderHead

DebugBar

Response:

HTTP/1.1 302 Found\r\nLocation: some-location\r\n\r\n
RenderBody", (string) $result->getBody()); + } + public function testAttachToHtmlResponse(): void { $request = new ServerRequest([], [], null, null, 'php://input', ['Accept' => 'text/html']); From 3ff0af2811ee24cfd5c1580c9f47a0401d6aa4a3 Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Thu, 26 Apr 2018 00:43:29 +0200 Subject: [PATCH 12/12] Improvements --- src/ConfigProvider.php | 3 +- src/JavascriptRendererFactory.php | 3 +- src/PhpDebugBarMiddleware.php | 14 +++---- src/PhpDebugBarMiddlewareFactory.php | 3 +- src/ResponseInjector/AlwaysInjector.php | 40 ------------------- .../ResponseInjectorInterface.php | 15 ------- src/StandardDebugBarFactory.php | 2 +- 7 files changed, 11 insertions(+), 69 deletions(-) delete mode 100644 src/ResponseInjector/AlwaysInjector.php delete mode 100644 src/ResponseInjector/ResponseInjectorInterface.php diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 018c386..fd20daa 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -7,8 +7,7 @@ final class ConfigProvider { public static function getConfig(): array { - $self = new self(); - return $self(); + return (new self())(); } public function __invoke(): array diff --git a/src/JavascriptRendererFactory.php b/src/JavascriptRendererFactory.php index 5d961cd..6fa7ec4 100644 --- a/src/JavascriptRendererFactory.php +++ b/src/JavascriptRendererFactory.php @@ -12,8 +12,7 @@ final class JavascriptRendererFactory public function __invoke(ContainerInterface $container = null): JavascriptRenderer { if ($container === null || !$container->has(DebugBar::class)) { - $standardDebugBarFactory = new StandardDebugBarFactory(); - $debugbar = $standardDebugBarFactory($container); + $debugbar = (new StandardDebugBarFactory())($container); } else { $debugbar = $container->get(DebugBar::class); } diff --git a/src/PhpDebugBarMiddleware.php b/src/PhpDebugBarMiddleware.php index 57157db..5331054 100644 --- a/src/PhpDebugBarMiddleware.php +++ b/src/PhpDebugBarMiddleware.php @@ -6,10 +6,10 @@ use DebugBar\JavascriptRenderer as DebugBarRenderer; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\ResponseInterface as Response; -use Psr\Http\Message\ServerRequestInterface as Request; +use Psr\Http\Message\ServerRequestInterface as ServerRequest; use Psr\Http\Message\UriInterface; use Psr\Http\Server\MiddlewareInterface; -use Psr\Http\Server\RequestHandlerInterface; +use Psr\Http\Server\RequestHandlerInterface as RequestHandler; use Slim\Http\Uri as SlimUri; use Zend\Diactoros\Response as DiactorosResponse; use Zend\Diactoros\Response\HtmlResponse; @@ -35,7 +35,7 @@ public function __construct(DebugBarRenderer $debugbarRenderer) /** * @inheritDoc */ - public function process(Request $request, RequestHandlerInterface $handler): Response + public function process(ServerRequest $request, RequestHandler $handler): Response { if ($staticFile = $this->getStaticFile($request->getUri())) { return $staticFile; @@ -59,9 +59,9 @@ public function process(Request $request, RequestHandlerInterface $handler): Res return $this->prepareHtmlResponseWithDebugBar($response); } - public function __invoke(Request $request, Response $response, callable $next): Response + public function __invoke(ServerRequest $request, Response $response, callable $next): Response { - $handler = new class($next, $response) implements RequestHandlerInterface { + $handler = new class($next, $response) implements RequestHandler { private $next; private $response; @@ -71,7 +71,7 @@ public function __construct(callable $next, Response $response) $this->response = $response; } - public function handle(Request $request): Response + public function handle(ServerRequest $request): Response { return ($this->next)($request, $this->response); } @@ -164,7 +164,7 @@ private function isHtmlResponse(Response $response): bool return $this->hasHeaderContains($response, 'Content-Type', 'text/html'); } - private function isHtmlAccepted(Request $request): bool + private function isHtmlAccepted(ServerRequest $request): bool { return $this->hasHeaderContains($request, 'Accept', 'text/html'); } diff --git a/src/PhpDebugBarMiddlewareFactory.php b/src/PhpDebugBarMiddlewareFactory.php index 8135d75..27dfea3 100644 --- a/src/PhpDebugBarMiddlewareFactory.php +++ b/src/PhpDebugBarMiddlewareFactory.php @@ -11,8 +11,7 @@ final class PhpDebugBarMiddlewareFactory public function __invoke(ContainerInterface $container = null): PhpDebugBarMiddleware { if ($container === null || !$container->has(JavascriptRenderer::class)) { - $rendererFactory = new JavascriptRendererFactory(); - $renderer = $rendererFactory($container); + $renderer = (new JavascriptRendererFactory())($container); } else { $renderer = $container->get(JavascriptRenderer::class); } diff --git a/src/ResponseInjector/AlwaysInjector.php b/src/ResponseInjector/AlwaysInjector.php deleted file mode 100644 index 1b84a42..0000000 --- a/src/ResponseInjector/AlwaysInjector.php +++ /dev/null @@ -1,40 +0,0 @@ -renderHead(); - $debugBarBody = $debugBarRenderer->render(); - - if ($this->isHtmlResponse($outResponse)) { - $body = $outResponse->getBody(); - if (! $body->eof() && $body->isSeekable()) { - $body->seek(0, SEEK_END); - } - $body->write($debugBarHead . $debugBarBody); - - return $outResponse; - } - - $outResponseBody = Serializer::toString($outResponse); - $template = '%s

DebugBar

Response:

%s
%s'; - $escapedOutResponseBody = htmlspecialchars($outResponseBody); - $result = sprintf($template, $debugBarHead, $escapedOutResponseBody, $debugBarBody); - - return new HtmlResponse($result); - } - - private function isHtmlResponse(ResponseInterface $response): bool - { - return $this->hasHeaderContains($response, 'Content-Type', 'text/html'); - } -} diff --git a/src/ResponseInjector/ResponseInjectorInterface.php b/src/ResponseInjector/ResponseInjectorInterface.php deleted file mode 100644 index 2c1910e..0000000 --- a/src/ResponseInjector/ResponseInjectorInterface.php +++ /dev/null @@ -1,15 +0,0 @@ - - */ -interface ResponseInjectorInterface -{ - public function injectPhpDebugBar(ResponseInterface $response, JavascriptRenderer $debugBar): ResponseInterface; -} diff --git a/src/StandardDebugBarFactory.php b/src/StandardDebugBarFactory.php index aedfb83..b21ac63 100644 --- a/src/StandardDebugBarFactory.php +++ b/src/StandardDebugBarFactory.php @@ -15,7 +15,7 @@ public function __invoke(ContainerInterface $container = null): StandardDebugBar if ($container !== null) { $config = $container->has('config') ? $container->get('config') : []; - $collectors = isset($config['phpmiddleware']['phpdebugbar']['collectors']) ? $config['phpmiddleware']['phpdebugbar']['collectors'] : []; + $collectors = $config['phpmiddleware']['phpdebugbar']['collectors'] ?: []; foreach ($collectors as $collectorName) { $collector = $container->get($collectorName);