Skip to content

Commit 113a663

Browse files
authored
Dumper added (#41)
1 parent 22ccff5 commit 113a663

24 files changed

+1068
-8
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ The format is based on [Keep a Changelog][keepachangelog] and this project adher
88

99
### Added
1010

11+
- Possibility to "dump" (using [Symfony VarDumper](https://github.com/symfony/var-dumper)) any variables in HTTP context (just call `\rr\dump(...)` or `\rr\dd(...)` instead `dump(...)` or `dd(...)` in your code)
12+
- Function `\rr\worker()` for easy access to the RoadRunner PSR worker instance (available only in HTTP context, of course)
1113
- Listener `FlushArrayCacheListener` for flushing `array`-based cache storages
1214
- Listener `FlushAuthenticationStateListener` for authentication state flushing
1315
- Listener `RebindAuthorizationGateListener` for the authorization gate container rebinding

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
Easy way for connecting [RoadRunner][roadrunner] and [Laravel][laravel] applications.
1515

16+
> 🐋 If you want to see an example of a laravel application in a docker container with RoadRunner as a web server - take a look at [this repository](https://github.com/tarampampam/laravel-roadrunner-in-docker).
17+
1618
## Installation
1719

1820
Make sure that [RR binary file][roadrunner-binary-releases] already installed on your system (or docker image). Require this package with composer using next command:
@@ -31,8 +33,6 @@ $ php ./artisan vendor:publish --provider='Spiral\RoadRunnerLaravel\ServiceProvi
3133

3234
**Important**: despite the fact that worker allows you to refresh application instance on each HTTP request _(if worker started with option `--refresh-app`, eg.: `php ./vendor/bin/rr-worker start --refresh-app`)_, we strongly recommend avoiding this for performance reasons. Large applications can be hard to integrate with RoadRunner _(you must decide which of service providers must be reloaded on each request, avoid "static optimization" in some cases)_, but it's worth it.
3335

34-
> 🐋 If you want to see an example of a laravel application in a docker container with RoadRunner as a web server - take a look at [this repository](https://github.com/tarampampam/laravel-roadrunner-in-docker).
35-
3636
### Upgrading guide (`v3.x` → `v4.x`)
3737

3838
- Update current package in your application:
@@ -99,6 +99,16 @@ $ rr serve -c ./.rr.yaml
9999
100100
This package provides event listeners for resetting application state without full application reload _(like cookies, HTTP request, application instance, service-providers and other)_. Some of them already declared in configuration file, but you can declare own without any limitations.
101101
102+
### Helpers
103+
104+
This package provides the following helpers:
105+
106+
Name | Description
107+
--------------- | -----------
108+
`\rr\dump(...)` | Dump passed values (dumped result will be available in the HTTP response)
109+
`\rr\dd(...)` | Dump passed values and stop the execution
110+
`\rr\worker()` | Easy access to the RoadRunner PSR worker instance
111+
102112
### Known issues
103113
104114
#### Controller constructors

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@
5353
"autoload": {
5454
"psr-4": {
5555
"Spiral\\RoadRunnerLaravel\\": "src/"
56-
}
56+
},
57+
"files": [
58+
"helpers/helpers.php"
59+
]
5760
},
5861
"autoload-dev": {
5962
"psr-4": {

helpers/helpers.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace rr;
6+
7+
use Illuminate\Container\Container;
8+
use Spiral\RoadRunner\Http\PSR7Worker;
9+
use Spiral\RoadRunnerLaravel\Dumper\Dumper;
10+
11+
if (!\function_exists('\\rr\\dump')) {
12+
/**
13+
* Dump passed values.
14+
*
15+
* USE THIS FUNCTION ONLY FOR DEBUGGING.
16+
*
17+
* @param mixed $var
18+
* @param mixed ...$vars
19+
*
20+
* @return void
21+
*
22+
* @throws \Throwable
23+
*/
24+
function dump($var, ...$vars): void
25+
{
26+
/** @var Dumper $dumper */
27+
$dumper = Container::getInstance()->make(Dumper::class);
28+
29+
$dumper->dump($var, ...$vars);
30+
}
31+
}
32+
33+
if (!\function_exists('\\rr\\dd')) {
34+
/**
35+
* Dump passed values and stop the execution (exit).
36+
*
37+
* USE THIS FUNCTION ONLY FOR DEBUGGING.
38+
*
39+
* @param mixed ...$vars
40+
*
41+
* @return void
42+
*
43+
* @throws \Throwable
44+
*/
45+
function dd(...$vars): void
46+
{
47+
/** @var Dumper $dumper */
48+
$dumper = Container::getInstance()->make(Dumper::class);
49+
50+
$dumper->dd(...$vars);
51+
}
52+
}
53+
54+
if (!\function_exists('\\rr\\worker')) {
55+
/**
56+
* Get the RoadRunner PSR worker.
57+
*
58+
* USE THIS FUNCTION ONLY FOR DEBUGGING.
59+
*
60+
* @return PSR7Worker
61+
*
62+
* @throws \Illuminate\Contracts\Container\BindingResolutionException If called outside of RR worker context
63+
*/
64+
function worker(): PSR7Worker
65+
{
66+
return Container::getInstance()->make(PSR7Worker::class);
67+
}
68+
}

src/Dumper/Dumper.php

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Spiral\RoadRunnerLaravel\Dumper;
6+
7+
use Illuminate\Support\Env;
8+
use Symfony\Component\VarDumper\VarDumper;
9+
use Symfony\Component\VarDumper\Cloner\VarCloner;
10+
11+
class Dumper
12+
{
13+
/**
14+
* @var Stack\StackInterface
15+
*/
16+
protected Stack\StackInterface $stack;
17+
18+
/**
19+
* @var Stoppers\StopperInterface
20+
*/
21+
protected Stoppers\StopperInterface $stopper;
22+
23+
/**
24+
* @var VarCloner
25+
*/
26+
protected VarCloner $cloner;
27+
28+
/**
29+
* RR constructor.
30+
*
31+
* @param Stack\StackInterface $stack
32+
* @param Stoppers\StopperInterface $stopper
33+
*/
34+
public function __construct(Stack\StackInterface $stack, Stoppers\StopperInterface $stopper)
35+
{
36+
$this->stopper = $stopper;
37+
$this->stack = $stack;
38+
$this->cloner = new VarCloner();
39+
}
40+
41+
/**
42+
* Dump passed values.
43+
*
44+
* @param mixed $var
45+
* @param mixed ...$vars
46+
*
47+
* @return void
48+
*
49+
* @throws \ErrorException On variables cloner errors
50+
*/
51+
public function dump($var, ...$vars): void
52+
{
53+
$ran_using_cli = $this->ranUsingCLI();
54+
55+
foreach ([$var, ...$vars] as $item) {
56+
if ($ran_using_cli) {
57+
// @codeCoverageIgnoreStart
58+
VarDumper::dump($item);
59+
// @codeCoverageIgnoreEnd
60+
} else {
61+
$this->stack->push($this->cloner->cloneVar($item));
62+
}
63+
}
64+
}
65+
66+
/**
67+
* Dump passed values and stop the execution.
68+
*
69+
* @param mixed ...$vars
70+
*
71+
* @return void
72+
*
73+
* @throws Exceptions\DumperException On execution in non-CLI context
74+
* @throws \ErrorException On variables cloner errors
75+
*/
76+
public function dd(...$vars)
77+
{
78+
if ($this->ranUsingCLI()) {
79+
// @codeCoverageIgnoreStart
80+
try {
81+
foreach ($vars as $item) {
82+
VarDumper::dump($item);
83+
}
84+
} finally {
85+
$this->stopper->stop();
86+
}
87+
// @codeCoverageIgnoreEnd
88+
} else {
89+
$stack = new Stack\FixedArrayStack();
90+
91+
foreach ($vars as $item) {
92+
$stack->push($this->cloner->cloneVar($item));
93+
}
94+
95+
throw Exceptions\DumperException::withStack($stack);
96+
}
97+
}
98+
99+
/**
100+
* @return bool
101+
*/
102+
protected function ranUsingCLI(): bool
103+
{
104+
/** @link https://roadrunner.dev/docs/php-environment */
105+
if (Env::get('RR_MODE') !== null && Env::get('RR_RPC') !== null && Env::get('RR_RELAY') !== null) {
106+
return false;
107+
}
108+
109+
/** @see VarDumper::register() */
110+
return \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true);
111+
}
112+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Spiral\RoadRunnerLaravel\Dumper\Exceptions;
6+
7+
use Illuminate\Http\Request;
8+
use Illuminate\Http\Response;
9+
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
10+
use Symfony\Component\VarDumper\Dumper\AbstractDumper;
11+
use Spiral\RoadRunnerLaravel\Dumper\Stack\StackInterface;
12+
13+
/**
14+
* @internal
15+
*/
16+
final class DumperException extends \RuntimeException
17+
{
18+
/**
19+
* @var HtmlDumper
20+
*/
21+
protected AbstractDumper $renderer;
22+
23+
/**
24+
* @var StackInterface $stack
25+
*/
26+
private StackInterface $stack;
27+
28+
/**
29+
* DumperException constructor.
30+
*
31+
* @param string $message
32+
* @param int $code
33+
* @param \Throwable|null $previous
34+
*/
35+
public function __construct(
36+
string $message = '',
37+
int $code = Response::HTTP_INTERNAL_SERVER_ERROR,
38+
\Throwable $previous = null
39+
) {
40+
$this->renderer = new HtmlDumper();
41+
42+
parent::__construct($message, $code, $previous);
43+
}
44+
45+
/**
46+
* @param StackInterface $stack
47+
*
48+
* @return self
49+
*/
50+
public static function withStack(StackInterface $stack): self
51+
{
52+
$exception = new self();
53+
$exception->stack = $stack;
54+
55+
return $exception;
56+
}
57+
58+
/**
59+
* Report the exception.
60+
*
61+
* @link https://laravel.com/docs/6.x/errors#renderable-exceptions
62+
*
63+
* @return void
64+
*/
65+
public function report(): void
66+
{
67+
// do nothing
68+
}
69+
70+
/**
71+
* Render the exception into an HTTP response.
72+
*
73+
* @link https://laravel.com/docs/6.x/errors#renderable-exceptions
74+
*
75+
* @param Request|null $request
76+
*
77+
* @return Response
78+
*/
79+
public function render(?Request $request = null): Response
80+
{
81+
$content = '';
82+
83+
if ($this->stack->count() > 0) {
84+
foreach ($this->stack->all() as $item) {
85+
/* @var \Symfony\Component\VarDumper\Cloner\Data $item */
86+
$content = $this->renderer->dump($item, true) . \PHP_EOL . $content;
87+
}
88+
} else {
89+
$content .= '(╯°□°)╯︵ ┻━┻';
90+
}
91+
92+
return new Response($this->generateView($content), $this->getCode());
93+
}
94+
95+
/**
96+
* Generate HTML representation for the passed content.
97+
*
98+
* @param string $content
99+
*
100+
* @return string
101+
*/
102+
protected function generateView(string $content): string
103+
{
104+
return <<<EOT
105+
<!DOCTYPE html>
106+
<html lang="en">
107+
<head>
108+
<meta charset="utf-8"/>
109+
<meta name="robots" content="noindex, nofollow"/>
110+
<style>html, body {background-color: #18171b} body{margin: 0 5% 0 5%}</style>
111+
<title>Dumper::dd()</title>
112+
</head>
113+
<body>
114+
${content}
115+
</body>
116+
</html>
117+
EOT;
118+
}
119+
}

0 commit comments

Comments
 (0)