Skip to content

Commit

Permalink
[Icons] Add ignore_not_found config option
Browse files Browse the repository at this point in the history
  • Loading branch information
smnandre authored and kbond committed Aug 7, 2024
1 parent c69bd67 commit 2dea170
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 5 deletions.
10 changes: 10 additions & 0 deletions src/Icons/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# CHANGELOG

## 2.19.0

- Add `ignore_not_found` option to silence error during rendering if the
icon is not found.

## 2.17.0

- Add component
3 changes: 2 additions & 1 deletion src/Icons/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
"symfony/http-client": "6.4|^7.0",
"symfony/phpunit-bridge": "^6.3|^7.0",
"symfony/ux-twig-component": "^2.14",
"zenstruck/console-test": "^1.5"
"zenstruck/console-test": "^1.5",
"psr/log": "^2|^3"
},
"config": {
"sort-packages": true
Expand Down
10 changes: 9 additions & 1 deletion src/Icons/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Symfony\UX\Icons\Registry\LocalSvgIconRegistry;
use Symfony\UX\Icons\Twig\IconFinder;
use Symfony\UX\Icons\Twig\UXIconExtension;
use Symfony\UX\Icons\Twig\UXIconRuntime;

return static function (ContainerConfigurator $container): void {
$container->services()
Expand All @@ -44,11 +45,18 @@
->set('.ux_icons.twig_icon_extension', UXIconExtension::class)
->tag('twig.extension')

->set('.ux_icons.twig_icon_runtime', UXIconRuntime::class)
->args([
service('.ux_icons.icon_renderer'),
abstract_arg('ignore_not_found'),
service('logger')->ignoreOnInvalid(),
])
->tag('twig.runtime')

->set('.ux_icons.icon_renderer', IconRenderer::class)
->args([
service('.ux_icons.icon_registry'),
])
->tag('twig.runtime')

->alias('Symfony\UX\Icons\IconRendererInterface', '.ux_icons.icon_renderer')

Expand Down
16 changes: 16 additions & 0 deletions src/Icons/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,19 @@ Now, all icons will have the ``fill`` attribute set to ``currentColor`` by defau
# renders "user-profile.svg" with fill="red"
{{ ux_icon('user-profile', {fill: 'red'}) }}
Errors
------

If an icon is not found, an exception is thrown. This is useful during development,
but in production, you may want to render an error message instead. You can do this
by setting the ``ignore_not_found`` configuration option to ``true``:

.. code-block:: yaml
# config/packages/ux_icons.yaml
ux_icons:
ignore_not_found: true
Accessibility
-------------

Expand Down Expand Up @@ -515,6 +528,9 @@ Full Configuration
# The endpoint for the Iconify API.
endpoint: 'https://api.iconify.design'
# Whether to ignore errors when an icon is not found.
ignore_not_found: false
Learn more
----------
Expand Down
10 changes: 9 additions & 1 deletion src/Icons/src/DependencyInjection/UXIconsExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->end()
->end()
->booleanNode('ignore_not_found')
->info('Ignore error when an icon is not found.')
->defaultFalse()
->end()
->end()
;

Expand All @@ -69,7 +73,7 @@ public function getConfiguration(array $config, ContainerBuilder $container): Co
return $this;
}

protected function loadInternal(array $mergedConfig, ContainerBuilder $container): void // @phpstan-ignore-line
protected function loadInternal(array $mergedConfig, ContainerBuilder $container): void
{
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../config'));
$loader->load('services.php');
Expand All @@ -96,6 +100,10 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container
->setArgument(1, $mergedConfig['default_icon_attributes'])
;

$container->getDefinition('.ux_icons.twig_icon_runtime')
->setArgument(1, $mergedConfig['ignore_not_found'])
;

if ($mergedConfig['iconify']['enabled']) {
$loader->load('iconify.php');

Expand Down
3 changes: 1 addition & 2 deletions src/Icons/src/Twig/UXIconExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

namespace Symfony\UX\Icons\Twig;

use Symfony\UX\Icons\IconRenderer;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

Expand All @@ -25,7 +24,7 @@ final class UXIconExtension extends AbstractExtension
public function getFunctions(): array
{
return [
new TwigFunction('ux_icon', [IconRenderer::class, 'renderIcon'], ['is_safe' => ['html']]),
new TwigFunction('ux_icon', [UXIconRuntime::class, 'renderIcon'], ['is_safe' => ['html']]),
];
}
}
49 changes: 49 additions & 0 deletions src/Icons/src/Twig/UXIconRuntime.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\UX\Icons\Twig;

use Psr\Log\LoggerInterface;
use Symfony\UX\Icons\Exception\IconNotFoundException;
use Symfony\UX\Icons\IconRendererInterface;
use Twig\Extension\RuntimeExtensionInterface;

/**
* @author Simon André <[email protected]>
*
* @internal
*/
final class UXIconRuntime implements RuntimeExtensionInterface
{
public function __construct(
private readonly IconRendererInterface $iconRenderer,
private readonly bool $ignoreNotFound = false,
private readonly ?LoggerInterface $logger = null,
) {
}

/**
* @param array<string, bool|string> $attributes
*/
public function renderIcon(string $name, array $attributes = []): string
{
try {
return $this->iconRenderer->renderIcon($name, $attributes);
} catch (IconNotFoundException $e) {
if ($this->ignoreNotFound) {
$this->logger?->warning($e->getMessage());
return '';
}

throw $e;
}
}
}
43 changes: 43 additions & 0 deletions src/Icons/tests/Unit/Twig/UXIconRuntimeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\UX\Icons\Tests\Unit\Twig;

use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\UX\Icons\Exception\IconNotFoundException;
use Symfony\UX\Icons\IconRendererInterface;
use Symfony\UX\Icons\Twig\UXIconRuntime;

/**
* @author Simon André <[email protected]>
*/
class UXIconRuntimeTest extends TestCase
{
public function testRenderIconIgnoreNotFound(): void
{
$renderer = $this->createMock(IconRendererInterface::class);
$renderer->method('renderIcon')
->willThrowException(new IconNotFoundException('Icon "foo" not found.'));

$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->once())
->method('warning')
->with('Icon "foo" not found.');

$runtime = new UXIconRuntime($renderer, true, $logger);
$this->assertEquals('', $runtime->renderIcon('not_found'));

$runtime = new UXIconRuntime($renderer, false);
$this->expectException(IconNotFoundException::class);
$runtime->renderIcon('not_found');
}
}

0 comments on commit 2dea170

Please sign in to comment.