Skip to content

Commit

Permalink
+ App\Controller\AssetController like `Route::get('/assets/{filenam…
Browse files Browse the repository at this point in the history
…e}', ...)` in `be/routes/web.php`

+ `PrettyJsonResponse` & `ShowReactJsonView` like `App\Http\Middleware\DumpJsonResponse` in `be`
+ `SerializeToJson` for allowing controller methods to return an array instead of instance of class `Response` directly like laravel
@ `App\EventListener`

+ var `ASSETS_BASE_URL` for config `framework.assets.base_urls` in `config/framework.yaml` @ .env
@ symfony
  • Loading branch information
n0099 committed Oct 5, 2024
1 parent 75ae379 commit 48515f3
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 0 deletions.
2 changes: 2 additions & 0 deletions symfony/.env
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration

ASSETS_BASE_URL=

###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=
Expand Down
4 changes: 4 additions & 0 deletions symfony/config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ framework:
#esi: true
#fragments: true

assets:
base_urls:
- '%env(ASSETS_BASE_URL)%'

when@test:
framework:
test: true
Expand Down
37 changes: 37 additions & 0 deletions symfony/src/Controller/AssetController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Asset\Packages;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class AssetController extends AbstractController
{
public function __construct(
private readonly ParameterBagInterface $parameterBag,
private readonly Filesystem $filesystem,
private readonly Packages $assets,
) {}

#[Route('/assets/{filename}', requirements: [
'filename' => /** @lang JSRegexp */'(react(|-dom|-json-view)|scheduler)\.js'
])]
public function getAsset(string $filename) : Response
{
return new Response(
preg_replace_callback_array([
'#/npm/(?<filename>\w+)@(\d+\.?){3}/\+esm#' =>
fn(array $m) => $this->assets->getUrl("assets/{$m['filename']}.js"),
'@^//# sourceMappingURL=.+$@m' =>
static fn() => '',
], $this->filesystem->readFile(
$this->parameterBag->get('kernel.project_dir') . "/public/react-json-view/$filename"
)),
headers: ['Content-Type' => 'text/javascript']
);
}
}
20 changes: 20 additions & 0 deletions symfony/src/EventListener/PrettyJsonResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace App\EventListener;

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ResponseEvent;

#[AsEventListener]
class PrettyJsonResponse
{
public function __invoke(ResponseEvent $event): void
{
// https://github.com/laravel/framework/issues/3929#issuecomment-935123918
$response = $event->getResponse();
if ($response instanceof JsonResponse) {
$response->setEncodingOptions(JSON_PRETTY_PRINT);
}
}
}
21 changes: 21 additions & 0 deletions symfony/src/EventListener/SerializeToJson.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace App\EventListener;

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\Serializer\SerializerInterface;

#[AsEventListener]
readonly class SerializeToJson
{
public function __construct(private SerializerInterface $serializer) {}

public function __invoke(ViewEvent $event): void
{
$event->setResponse(JsonResponse::fromJsonString(
$this->serializer->serialize($event->getControllerResult(), 'json')
));
}
}
53 changes: 53 additions & 0 deletions symfony/src/EventListener/ShowReactJsonView.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace App\EventListener;

use Symfony\Component\Asset\Packages;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;

#[AsEventListener]
readonly class ShowReactJsonView
{
public function __construct(private Packages $assets) {}

public function __invoke(ResponseEvent $event): void
{
$request = $event->getRequest();
$response = $event->getResponse();
if (!$response instanceof JsonResponse
|| !in_array('text/html', $request->getAcceptableContentTypes(), true)) {
return;
}
$json = $response->getContent();
$jsonLength = mb_strlen($json);
$assetsUrl = collect(['react-json-view', 'react', 'react-dom'])
->mapWithKeys(fn($asset) => [$asset => $this->assets->getUrl("/assets/$asset.js")]);
$event->setResponse(new Response(<<<HTML
<html>
<head>
<title>$jsonLength bytes of json response for route {$request->getPathInfo()}</title>
</head>
<body>
<h4>$jsonLength bytes</h4>
<div id="root"></div>
<script type="module">
import ReactJsonView from '{$assetsUrl['react-json-view']}';
import { createElement } from '{$assetsUrl['react']}';
import { createRoot } from '{$assetsUrl['react-dom']}';
const root = createRoot(document.getElementById('root'));
root.render(createElement(ReactJsonView.default, { src: $json, quotesOnKeys: false }));
</script>
<style>
.object-content {
content-visibility: auto;
}
</style>
</body>
</html>
HTML));
}
}

0 comments on commit 48515f3

Please sign in to comment.