Refactoring including assets

This commit is contained in:
Zdeněk Drahoš 2021-06-27 10:00:43 +02:00
parent 5124f07ece
commit 9cb6006b69
5 changed files with 192 additions and 53 deletions

View File

@ -12,30 +12,82 @@
namespace Nelmio\ApiDocBundle\Render\Html; namespace Nelmio\ApiDocBundle\Render\Html;
use Symfony\Bridge\Twig\Extension\AssetExtension; use Symfony\Bridge\Twig\Extension\AssetExtension;
use Twig\TwigFunction;
class GetNelmioAsset class GetNelmioAsset
{ {
private $assetExtension; private $assetExtension;
private $defaultAssetsMode; private $resourcesDir;
private $cdnUrl;
private $assetsMode = AssetsMode::BUNDLE;
public function __construct(AssetExtension $assetExtension, $defaultAssetsMode) public function __construct(AssetExtension $assetExtension)
{ {
$this->assetExtension = $assetExtension; $this->assetExtension = $assetExtension;
$this->defaultAssetsMode = $defaultAssetsMode; $this->cdnUrl = 'https://cdn.jsdelivr.net/gh/nelmio/NelmioApiDocBundle/Resources/public';
$this->resourcesDir = __DIR__.'/../../Resources/public';
} }
public function __invoke($asset, $forcedMode = null) public function toTwigFunction($assetsMode): TwigFunction
{ {
$mode = $forcedMode ?: $this->defaultAssetsMode; $this->assetsMode = $assetsMode;
if (AssetsMode::CDN === $mode) {
return sprintf( return new TwigFunction('nelmioAsset', $this, ['is_safe' => ['html']]);
'https://cdn.jsdelivr.net/gh/nelmio/NelmioApiDocBundle@4.1/Resources/public/%s', }
$asset
); public function __invoke($asset)
} elseif (AssetsMode::OFFLINE === $mode) { {
return file_get_contents(__DIR__.sprintf('/../../Resources/public/%s', $asset)); [$extension, $mode] = $this->getExtension($asset);
[$resource, $isInline] = $this->getResource($asset, $mode);
if ('js' == $extension) {
return $this->renderJavascript($resource, $isInline);
} elseif ('css' == $extension) {
return $this->renderCss($resource, $isInline);
} else { } else {
return $this->assetExtension->getAssetUrl(sprintf('bundles/nelmioapidoc/%s', $asset)); return $resource;
}
}
private function getExtension($asset)
{
$extension = mb_substr($asset, -3, 3, 'utf-8');
if ('.js' === $extension) {
return ['js', $this->assetsMode];
} elseif ('png' === $extension) {
return ['png', AssetsMode::OFFLINE == $this->assetsMode ? AssetsMode::CDN : $this->assetsMode];
} else {
return ['css', $this->assetsMode];
}
}
private function getResource($asset, $mode)
{
if (filter_var($asset, FILTER_VALIDATE_URL)) {
return [$asset, false];
} elseif (AssetsMode::OFFLINE === $mode) {
return [file_get_contents($this->resourcesDir.'/'.$asset), true];
} elseif (AssetsMode::CDN === $mode) {
return [$this->cdnUrl.'/'.$asset, false];
} else {
return [$this->assetExtension->getAssetUrl(sprintf('bundles/nelmioapidoc/%s', $asset)), false];
}
}
private function renderJavascript(string $script, bool $isInline)
{
if ($isInline) {
return sprintf('<script>%s</script>', $script);
} else {
return sprintf('<script src="%s"></script>', $script);
}
}
private function renderCss(string $stylesheet, bool $isInline)
{
if ($isInline) {
return sprintf('<style>%s</style>', $stylesheet);
} else {
return sprintf('<link rel="stylesheet" href="%s">', $stylesheet);
} }
} }
} }

View File

@ -16,28 +16,23 @@ use Nelmio\ApiDocBundle\Render\OpenApiRenderer;
use Nelmio\ApiDocBundle\Render\RenderOpenApi; use Nelmio\ApiDocBundle\Render\RenderOpenApi;
use OpenApi\Annotations\OpenApi; use OpenApi\Annotations\OpenApi;
use OpenApi\Annotations\Server; use OpenApi\Annotations\Server;
use Symfony\Bridge\Twig\Extension\AssetExtension;
use Twig\Environment; use Twig\Environment;
use Twig\TwigFunction;
class HtmlOpenApiRenderer implements OpenApiRenderer class HtmlOpenApiRenderer implements OpenApiRenderer
{ {
/** /** @var Environment|\Twig_Environment */
* @var Environment|\Twig_Environment
*/
private $twig; private $twig;
/**
* @var AssetExtension
*/
private $assetExtension;
public function __construct($twig, AssetExtension $assetExtension) /** @var GetNelmioAsset */
private $getNelmioAsset;
public function __construct($twig, GetNelmioAsset $getNelmioAsset)
{ {
if (!$twig instanceof \Twig_Environment && !$twig instanceof Environment) { if (!$twig instanceof \Twig_Environment && !$twig instanceof Environment) {
throw new InvalidArgumentException(sprintf('Providing an instance of "%s" as twig is not supported.', get_class($twig))); throw new InvalidArgumentException(sprintf('Providing an instance of "%s" as twig is not supported.', get_class($twig)));
} }
$this->twig = $twig; $this->twig = $twig;
$this->assetExtension = $assetExtension; $this->getNelmioAsset = $getNelmioAsset;
} }
public function getFormat(): string public function getFormat(): string
@ -53,12 +48,7 @@ class HtmlOpenApiRenderer implements OpenApiRenderer
'swagger_ui_config' => [], 'swagger_ui_config' => [],
]; ];
$this->twig->addFunction( $this->twig->addFunction($this->getNelmioAsset->toTwigFunction($options['assets_mode']));
new TwigFunction(
'nelmioAsset',
new GetNelmioAsset($this->assetExtension, $options['assets_mode'])
)
);
return $this->twig->render( return $this->twig->render(
'@NelmioApiDoc/SwaggerUi/index.html.twig', '@NelmioApiDoc/SwaggerUi/index.html.twig',

View File

@ -33,6 +33,9 @@
</service> </service>
<service id="nelmio_api_doc.render_docs.html" class="Nelmio\ApiDocBundle\Render\Html\HtmlOpenApiRenderer" public="false"> <service id="nelmio_api_doc.render_docs.html" class="Nelmio\ApiDocBundle\Render\Html\HtmlOpenApiRenderer" public="false">
<argument type="service" id="twig" /> <argument type="service" id="twig" />
<argument type="service" id="nelmio_api_doc.render_docs.html.asset" />
</service>
<service id="nelmio_api_doc.render_docs.html.asset" class="Nelmio\ApiDocBundle\Render\Html\GetNelmioAsset" public="false">
<argument type="service" id="twig.extension.assets" /> <argument type="service" id="twig.extension.assets" />
</service> </service>
<service id="nelmio_api_doc.render_docs.json" class="Nelmio\ApiDocBundle\Render\Json\JsonOpenApiRenderer" public="false"> <service id="nelmio_api_doc.render_docs.json" class="Nelmio\ApiDocBundle\Render\Json\JsonOpenApiRenderer" public="false">

View File

@ -14,13 +14,8 @@ file that was distributed with this source code. #}
<title>{% block title %}{{ swagger_data.spec.info.title }}{% endblock title %}</title> <title>{% block title %}{{ swagger_data.spec.info.title }}{% endblock title %}</title>
{% block stylesheets %} {% block stylesheets %}
{% if assets_mode == 'offline' %} {{ nelmioAsset('swagger-ui/swagger-ui.css') }}
<style>{{ nelmioAsset('swagger-ui/swagger-ui.css')|raw }}</style> {{ nelmioAsset('style.css') }}
<style>{{ nelmioAsset('style.css')|raw }}</style>
{% else %}
<link rel="stylesheet" href="{{ nelmioAsset('swagger-ui/swagger-ui.css') }}">
<link rel="stylesheet" href="{{ nelmioAsset('style.css.css') }}">
{% endif %}
{% endblock stylesheets %} {% endblock stylesheets %}
{% block swagger_data %} {% block swagger_data %}
@ -59,11 +54,7 @@ file that was distributed with this source code. #}
<header> <header>
{% block header %} {% block header %}
<a id="logo" href="https://github.com/nelmio/NelmioApiDocBundle"> <a id="logo" href="https://github.com/nelmio/NelmioApiDocBundle">
{% if assets_mode in ['offline', 'cdn'] %}
<img src="{{ nelmioAsset('logo.png', 'cdn') }}" alt="NelmioApiDocBundle">
{% else %}
<img src="{{ nelmioAsset('logo.png') }}" alt="NelmioApiDocBundle"> <img src="{{ nelmioAsset('logo.png') }}" alt="NelmioApiDocBundle">
{% endif %}
</a> </a>
{% endblock header %} {% endblock header %}
</header> </header>
@ -73,20 +64,11 @@ file that was distributed with this source code. #}
{% endblock %} {% endblock %}
{% block javascripts %} {% block javascripts %}
{% if assets_mode == 'offline' %} {{ nelmioAsset('swagger-ui/swagger-ui-bundle.js') }}
<script>{{ nelmioAsset('swagger-ui/swagger-ui-bundle.js')|raw }}</script> {{ nelmioAsset('swagger-ui/swagger-ui-standalone-preset.js') }}
<script>{{ nelmioAsset('swagger-ui/swagger-ui-standalone-preset.js')|raw }}</script>
{% else %}
<script src="{{ nelmioAsset('swagger-ui/swagger-ui-bundle.js') }}"></script>
<script src="{{ nelmioAsset('swagger-ui/swagger-ui-standalone-preset.js') }}"></script>
{% endif %}
{% endblock javascripts %} {% endblock javascripts %}
{% if assets_mode == 'offline' %} {{ nelmioAsset('init-swagger-ui.js') }}
<script>{{ nelmioAsset('init-swagger-ui.js')|raw }}</script>
{% else %}
<script src="{{ nelmioAsset('init-swagger-ui.js') }}"></script>
{% endif %}
{% block swagger_initialization %} {% block swagger_initialization %}
<script type="text/javascript"> <script type="text/javascript">

View File

@ -0,0 +1,112 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Tests\Render\Html;
use Nelmio\ApiDocBundle\Render\Html\AssetsMode;
use Nelmio\ApiDocBundle\Render\Html\GetNelmioAsset;
use Nelmio\ApiDocBundle\Tests\Functional\WebTestCase;
class GetNelmioAssetTest extends WebTestCase
{
/** @dataProvider provideAsset */
public function test($mode, $asset, $expectedContent)
{
static::bootKernel();
/** @var GetNelmioAsset $getNelmioAsset */
$getNelmioAsset = self::getContainer()->get('nelmio_api_doc.render_docs.html.asset');
$twigFunction = $getNelmioAsset->toTwigFunction($mode);
self::assertSame($expectedContent, $twigFunction->getCallable()->__invoke($asset, $mode));
}
public function provideAsset()
{
$cdnDir = 'https://cdn.jsdelivr.net/gh/nelmio/NelmioApiDocBundle/Resources/public';
$resourceDir = __DIR__.'/../../../Resources/public';
return $this->provideCss($cdnDir, $resourceDir)
+ $this->provideJs($cdnDir, $resourceDir)
+ $this->provideImage($cdnDir);
}
private function provideCss($cdnDir, $resourceDir)
{
return [
'bundled css' => [
AssetsMode::BUNDLE,
'style.css',
'<link rel="stylesheet" href="/bundles/nelmioapidoc/style.css">',
],
'cdn css' => [
AssetsMode::CDN,
'style.css',
'<link rel="stylesheet" href="'.$cdnDir.'/style.css">',
],
'offline css' => [
AssetsMode::OFFLINE,
'style.css',
'<style>'.file_get_contents($resourceDir.'/style.css').'</style>',
],
'external css' => [
AssetsMode::BUNDLE,
'https://cdn.com/my.css',
'<link rel="stylesheet" href="https://cdn.com/my.css">',
],
];
}
private function provideJs($cdnDir, $resourceDir)
{
return [
'bundled js' => [
AssetsMode::BUNDLE,
'init-swagger-ui.js',
'<script src="/bundles/nelmioapidoc/init-swagger-ui.js"></script>',
],
'cdn js' => [
AssetsMode::CDN,
'init-swagger-ui.js',
'<script src="'.$cdnDir.'/init-swagger-ui.js"></script>',
],
'offline js' => [
AssetsMode::OFFLINE,
'init-swagger-ui.js',
'<script>'.file_get_contents($resourceDir.'/init-swagger-ui.js').'</script>',
],
'external js' => [
AssetsMode::BUNDLE,
'https://cdn.com/my.js',
'<script src="https://cdn.com/my.js"></script>',
],
];
}
private function provideImage($cdnDir)
{
return [
'bundled image' => [
AssetsMode::BUNDLE,
'logo.png',
'/bundles/nelmioapidoc/logo.png',
],
'cdn image' => [
AssetsMode::CDN,
'logo.png',
$cdnDir.'/logo.png',
],
'offline image fallbacks to cdn' => [
AssetsMode::OFFLINE,
'logo.png',
$cdnDir.'/logo.png',
],
];
}
}