Skip to content

Commit

Permalink
psr-17 support (#27)
Browse files Browse the repository at this point in the history
* Add psr-17 support, require psr-11 container in factories, change config service key

* php 7.3 not existig in travis yet :)

* Readme improvements
  • Loading branch information
snapshotpl authored Oct 15, 2018
1 parent 160e792 commit daa1985
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 103 deletions.
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

0 comments on commit daa1985

Please sign in to comment.