Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

psr-17 support #27

Merged
merged 3 commits into from
Oct 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 39 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
# phpdebugbar middleware [![Build Status](https://travis-ci.org/php-middleware/phpdebugbar.svg?branch=master)](https://travis-ci.org/php-middleware/phpdebugbar)
PHP Debug bar [PSR-15](https://www.php-fig.org/psr/psr-15/) middleware with [PSR-7](https://www.php-fig.org/psr/psr-7/). Also supports [PSR-11](https://www.php-fig.org/psr/psr-11/)
[PHP Debug Bar](http://phpdebugbar.com/) as framework-agnostic [PSR-15 middleware](https://www.php-fig.org/psr/psr-15/) with [PSR-7 messages](https://www.php-fig.org/psr/psr-7/) created by [PSR-17 message factories](https://www.php-fig.org/psr/psr-17/). Also provides [PSR-11 container invokable factories](https://www.php-fig.org/psr/psr-11/).

This middleware provide framework-agnostic possibility to attach [PHP Debug Bar](http://phpdebugbar.com/) to your response (html on non-html!).
Framework-agnostic way to attach [PHP Debug Bar](http://phpdebugbar.com/) to your response (html or non-html!).

## Installation

```
composer require php-middleware/php-debug-bar
composer require --dev php-middleware/php-debug-bar
```

To build this middleware you need to injecting inside `PhpDebugBarMiddleware` instance `DebugBar\JavascriptRenderer` (you can get it from `DebugBar\StandardDebugBar`) and add middleware to your middleware runner. Or use default factory.
To build middleware you need to inject `DebugBar\JavascriptRenderer` (you can get it from `DebugBar\StandardDebugBar`) inside `PhpDebugBarMiddleware` and add it into your middleware runner:

```php
$debugbar = new DebugBar\StandardDebugBar();
$debugbarRenderer = $debugbar->getJavascriptRenderer('/phpdebugbar');
$middleware = new PhpMiddleware\PhpDebugBar\PhpDebugBarMiddleware($debugbarRenderer);

// OR
$middleware = new PhpMiddleware\PhpDebugBar\PhpDebugBarMiddleware($debugbarRenderer, $psr17ResponseFactory, $psr17StreamFactory);

// or use provided factory
$factory = new PhpMiddleware\PhpDebugBar\PhpDebugBarMiddlewareFactory();
$middleware = $factory();
$middleware = $factory($psr11Container);

$app = new MiddlewareRunner();
$app->add($middleware);
Expand All @@ -30,40 +29,57 @@ 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 enable (or not) PHP Debug Bar:
Sometimes you want to have control when enable or disable PHP Debug Bar:
* custom content negotiation,
* 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.

### PSR-17

This package isn't require any PSR-7 implementation - you need to provide it by own. Middleware require ResponseFactory and StreamFactory interfaces. [List of existing interfaces](https://packagist.org/providers/psr/http-factory-implementation).

#### ... and PSR-11

If you use provided PSR-11 factories, then you container must have services registered as PSR-17 interface's name. Example for [zend-diactoros](https://github.com/zendframework/zend-diactoros) implementation and [Pimple](https://pimple.symfony.com/):

```php
$container[Psr\Http\Message\ResponseInterface::class] = new Zend\Diactoros\ResponseFactory();
$container[Psr\Http\Message\StreamFactoryInterface] = new Zend\Diactoros\StreamFactory();
```

### How to install on Zend Expressive?

You need to register ConfigProvider and pipe provided middleware:
You need to register `PhpMiddleware\PhpDebugBar\ConfigProvider` and pipe provided middleware:

```php
$app->pipe(PhpDebugBarMiddleware::class);
$app->pipe(\PhpMiddleware\PhpDebugBar\PhpDebugBarMiddleware::class);
```

For more follow Zend Expressive [documentation](https://docs.zendframework.com/zend-expressive/v3/features/modular-applications/).
For more - follow Zend Expressive [documentation](https://docs.zendframework.com/zend-expressive/v3/features/modular-applications/).

### How to install on Slim 3?

Add existing factory to container:
Register factories in container:

```php
$container['debugbar_middleware'] = new PhpMiddleware\PhpDebugBar\PhpDebugBarMiddlewareFactory();
foreach (ConfigProvider::getConfig()['dependencies']['factories'] as $key => $factory) {
$container[$key] = new $factory();
}
```

and add middleware from container to app:

```php
$app->add($app->getContainer()->get('debugbar_middleware'));
$app->add(
$app->getContainer()->get(\PhpMiddleware\PhpDebugBar\PhpDebugBarMiddleware::class)
);
```

### How to configure using existing factories?

Put array with configuration into `config` service in your container:
Put array with configuration into `PhpMiddleware\PhpDebugBar\ConfigProvider` service in your container:

```php
return [
Expand All @@ -81,10 +97,16 @@ return [
];
```

You can override existing configuration by merge default configuration with your own (example):

```php
return array_merge(PhpMiddleware\PhpDebugBar\ConfigProvider::getConfig(), $myOverritenConfig);
```

## It's just works with any modern php framework!

Middleware tested on:
* [Zend Expressive](https://github.com/zendframework/zend-expressive)
* [Slim 3.x](https://github.com/slimphp/Slim)

And any other modern framework [supported middlewares and PSR-7](https://mwop.net/blog/2015-01-08-on-http-middleware-and-psr-7.html).
And any other modern framework [supported PSR-17 middlewares and PSR-7](https://mwop.net/blog/2015-01-08-on-http-middleware-and-psr-7.html).
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@
"psr/http-server-middleware": "^1.0",
"psr/container": "^1.0",
"psr/http-message": "^1.0.1",
"zendframework/zend-diactoros": "^1.1.3 || ^2.0"
"psr/http-factory": "^1.0",
"psr/http-factory-implementation": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^7.1.2",
"mikey179/vfsStream": "^1.6.4",
"slim/slim": "^3.0",
"zendframework/zend-expressive": "^3.0",
"zendframework/zend-expressive-fastroute": "^3.0.1",
"zendframework/zend-servicemanager": "^3.3.2"
"zendframework/zend-servicemanager": "^3.3.2",
"zendframework/zend-diactoros": "^2.0"
},
"autoload": {
"psr-4": {
Expand Down
7 changes: 5 additions & 2 deletions config/dependency.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

return [
'factories' => [
PhpMiddleware\PhpDebugBar\PhpDebugBarMiddleware::class => PhpMiddleware\PhpDebugBar\PhpDebugBarMiddlewareFactory::class,
DebugBar\DataCollector\ConfigCollector::class => PhpMiddleware\PhpDebugBar\ConfigCollectorFactory::class,
\PhpMiddleware\PhpDebugBar\PhpDebugBarMiddleware::class => \PhpMiddleware\PhpDebugBar\PhpDebugBarMiddlewareFactory::class,
\DebugBar\DataCollector\ConfigCollector::class => \PhpMiddleware\PhpDebugBar\ConfigCollectorFactory::class,
\PhpMiddleware\PhpDebugBar\ConfigProvider::class => \PhpMiddleware\PhpDebugBar\ConfigProvider::class,
\DebugBar\DebugBar::class => \PhpMiddleware\PhpDebugBar\StandardDebugBarFactory::class,
\DebugBar\JavascriptRenderer::class => \PhpMiddleware\PhpDebugBar\JavascriptRendererFactory::class,
],
];
2 changes: 1 addition & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<phpunit bootstrap="./vendor/autoload.php" colors="true">
<testsuites>
<testsuite>
<testsuite name="unit">
<directory>./test</directory>
</testsuite>
</testsuites>
Expand Down
2 changes: 1 addition & 1 deletion src/ConfigCollectorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ final class ConfigCollectorFactory
{
public function __invoke(ContainerInterface $container): ConfigCollector
{
$data = $container->get('config');
$data = $container->get(ConfigProvider::class);

return new ConfigCollector($data, 'Config');
}
Expand Down
21 changes: 4 additions & 17 deletions src/JavascriptRendererFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,13 @@

final class JavascriptRendererFactory
{
public function __invoke(ContainerInterface $container = null): JavascriptRenderer
public function __invoke(ContainerInterface $container): JavascriptRenderer
{
if ($container === null || !$container->has(DebugBar::class)) {
$debugbar = (new StandardDebugBarFactory())($container);
} else {
$debugbar = $container->get(DebugBar::class);
}
$debugbar = $container->get(DebugBar::class);
$config = $container->get(ConfigProvider::class);
$rendererOptions = $config['phpmiddleware']['phpdebugbar']['javascript_renderer'];

$renderer = new JavascriptRenderer($debugbar);

$config = $container !== null && $container->has('config') ? $container->get('config') : [];

if (isset($config['phpmiddleware']['phpdebugbar']['javascript_renderer'])) {
$rendererOptions = $config['phpmiddleware']['phpdebugbar']['javascript_renderer'];
} else {
$rendererOptions = [
'base_url' => '/phpdebugbar',
];
}

$renderer->setOptions($rendererOptions);

return $renderer;
Expand Down
82 changes: 66 additions & 16 deletions src/PhpDebugBarMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,34 @@

use DebugBar\JavascriptRenderer as DebugBarRenderer;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as ServerRequest;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UriInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
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;

/**
* PhpDebugBarMiddleware
*
* @author Witold Wasiczko <[email protected]>
*/
final class PhpDebugBarMiddleware implements MiddlewareInterface
{
public const FORCE_KEY = 'X-Enable-Debug-Bar';

protected $debugBarRenderer;
private $debugBarRenderer;
private $responseFactory;
private $streamFactory;

public function __construct(DebugBarRenderer $debugbarRenderer)
{
public function __construct(
DebugBarRenderer $debugbarRenderer,
ResponseFactoryInterface $responseFactory,
StreamFactoryInterface $streamFactory
) {
$this->debugBarRenderer = $debugbarRenderer;
$this->responseFactory = $responseFactory;
$this->streamFactory = $streamFactory;
}

/**
Expand Down Expand Up @@ -79,16 +82,20 @@ public function handle(ServerRequest $request): Response
return $this->process($request, $handler);
}

private function prepareHtmlResponseWithDebugBar(Response $response): HtmlResponse
private function prepareHtmlResponseWithDebugBar(Response $response): Response
{
$head = $this->debugBarRenderer->renderHead();
$body = $this->debugBarRenderer->render();
$outResponseBody = Serializer::toString($response);
$outResponseBody = $this->serializeResponse($response);
$template = '<html><head>%s</head><body><h1>DebugBar</h1><p>Response:</p><pre>%s</pre>%s</body></html>';
$escapedOutResponseBody = htmlspecialchars($outResponseBody);
$result = sprintf($template, $head, $escapedOutResponseBody, $body);

return new HtmlResponse($result);
$stream = $this->streamFactory->createStream($result);

return $this->responseFactory->createResponse(200)
->withBody($stream)
->withAddedHeader('Content-type', 'text/html');
}

private function attachDebugBarToResponse(Response $response): Response
Expand Down Expand Up @@ -122,11 +129,11 @@ private function getStaticFile(UriInterface $uri): ?Response
}

$contentType = $this->getContentTypeByFileName($fullPathToFile);
$stream = new Stream($fullPathToFile, 'r');
$stream = $this->streamFactory->createStreamFromResource(fopen($fullPathToFile, 'r'));

return new DiactorosResponse($stream, 200, [
'Content-type' => $contentType,
]);
return $this->responseFactory->createResponse(200)
->withBody($stream)
->withAddedHeader('Content-type', $contentType);
}

private function extractPath(UriInterface $uri): string
Expand Down Expand Up @@ -180,4 +187,47 @@ private function isRedirect(Response $response): bool

return ($statusCode >= 300 || $statusCode < 400) && $response->getHeaderLine('Location') !== '';
}

private function serializeResponse(Response $response) : string
{
$reasonPhrase = $response->getReasonPhrase();
$headers = $this->serializeHeaders($response->getHeaders());
$body = (string) $response->getBody();
$format = 'HTTP/%s %d%s%s%s';

if (! empty($headers)) {
$headers = "\r\n" . $headers;
}

$headers .= "\r\n\r\n";

return sprintf(
$format,
$response->getProtocolVersion(),
$response->getStatusCode(),
($reasonPhrase ? ' ' . $reasonPhrase : ''),
$headers,
$body
);
}

private function serializeHeaders(array $headers) : string
{
$lines = [];
foreach ($headers as $header => $values) {
$normalized = $this->filterHeader($header);
foreach ($values as $value) {
$lines[] = sprintf('%s: %s', $normalized, $value);
}
}

return implode("\r\n", $lines);
}

private function filterHeader(string $header) : string
{
$filtered = str_replace('-', ' ', $header);
$filtered = ucwords($filtered);
return str_replace(' ', '-', $filtered);
}
}
15 changes: 8 additions & 7 deletions src/PhpDebugBarMiddlewareFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@

use DebugBar\JavascriptRenderer;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;

final class PhpDebugBarMiddlewareFactory
{
public function __invoke(ContainerInterface $container = null): PhpDebugBarMiddleware
public function __invoke(ContainerInterface $container): PhpDebugBarMiddleware
{
if ($container === null || !$container->has(JavascriptRenderer::class)) {
$renderer = (new JavascriptRendererFactory())($container);
} else {
$renderer = $container->get(JavascriptRenderer::class);
}
return new PhpDebugBarMiddleware($renderer);
$renderer = $container->get(JavascriptRenderer::class);
$responseFactory = $container->get(ResponseFactoryInterface::class);
$streamFactory = $container->get(StreamFactoryInterface::class);

return new PhpDebugBarMiddleware($renderer, $responseFactory, $streamFactory);
}
}
25 changes: 13 additions & 12 deletions src/StandardDebugBarFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,25 @@

final class StandardDebugBarFactory
{
public function __invoke(ContainerInterface $container = null): StandardDebugBar
public function __invoke(ContainerInterface $container): StandardDebugBar
{
$debugBar = new StandardDebugBar();

if ($container !== null) {
$config = $container->has('config') ? $container->get('config') : [];
$config = $container->get(ConfigProvider::class);

$collectors = $config['phpmiddleware']['phpdebugbar']['collectors'] ?: [];
$collectors = $config['phpmiddleware']['phpdebugbar']['collectors'];

foreach ($collectors as $collectorName) {
$collector = $container->get($collectorName);
$debugBar->addCollector($collector);
}
foreach ($collectors as $collectorName) {
$collector = $container->get($collectorName);
$debugBar->addCollector($collector);
}

$storage = $config['phpmiddleware']['phpdebugbar']['storage'];

if (isset($config['phpmiddleware']['phpdebugbar']['storage']) && is_string($config['phpmiddleware']['phpdebugbar']['storage'])) {
$storage = $container->get($config['phpmiddleware']['phpdebugbar']['storage']);
$debugBar->setStorage($config['phpmiddleware']['phpdebugbar']['storage']);
}
if (is_string($storage)) {
$debugBar->setStorage(
$container->get($storage)
);
}

return $debugBar;
Expand Down
Loading