Skip to content

Commit 1b4c6b3

Browse files
committed
feature #2023 [Icons] Add ignore_not_found config option (smnandre)
This PR was squashed before being merged into the 2.x branch. Discussion ---------- [Icons] Add `ignore_not_found` config option | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Issues | Fix #2008 | License | MIT Allow to silence error during rendering when an icon is not found (then a warning is log) Commits ------- 2dea170 [Icons] Add `ignore_not_found` config option
2 parents 4a65595 + 2dea170 commit 1b4c6b3

File tree

8 files changed

+139
-5
lines changed

8 files changed

+139
-5
lines changed

src/Icons/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# CHANGELOG
2+
3+
## 2.19.0
4+
5+
- Add `ignore_not_found` option to silence error during rendering if the
6+
icon is not found.
7+
8+
## 2.17.0
9+
10+
- Add component

src/Icons/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"symfony/http-client": "6.4|^7.0",
4646
"symfony/phpunit-bridge": "^6.3|^7.0",
4747
"symfony/ux-twig-component": "^2.14",
48-
"zenstruck/console-test": "^1.5"
48+
"zenstruck/console-test": "^1.5",
49+
"psr/log": "^2|^3"
4950
},
5051
"config": {
5152
"sort-packages": true

src/Icons/config/services.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\UX\Icons\Registry\LocalSvgIconRegistry;
2020
use Symfony\UX\Icons\Twig\IconFinder;
2121
use Symfony\UX\Icons\Twig\UXIconExtension;
22+
use Symfony\UX\Icons\Twig\UXIconRuntime;
2223

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

48+
->set('.ux_icons.twig_icon_runtime', UXIconRuntime::class)
49+
->args([
50+
service('.ux_icons.icon_renderer'),
51+
abstract_arg('ignore_not_found'),
52+
service('logger')->ignoreOnInvalid(),
53+
])
54+
->tag('twig.runtime')
55+
4756
->set('.ux_icons.icon_renderer', IconRenderer::class)
4857
->args([
4958
service('.ux_icons.icon_registry'),
5059
])
51-
->tag('twig.runtime')
5260

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

src/Icons/doc/index.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,19 @@ Now, all icons will have the ``fill`` attribute set to ``currentColor`` by defau
336336
# renders "user-profile.svg" with fill="red"
337337
{{ ux_icon('user-profile', {fill: 'red'}) }}
338338
339+
Errors
340+
------
341+
342+
If an icon is not found, an exception is thrown. This is useful during development,
343+
but in production, you may want to render an error message instead. You can do this
344+
by setting the ``ignore_not_found`` configuration option to ``true``:
345+
346+
.. code-block:: yaml
347+
348+
# config/packages/ux_icons.yaml
349+
ux_icons:
350+
ignore_not_found: true
351+
339352
Accessibility
340353
-------------
341354

@@ -514,6 +527,9 @@ Full Configuration
514527
515528
# The endpoint for the Iconify API.
516529
endpoint: 'https://api.iconify.design'
530+
531+
# Whether to ignore errors when an icon is not found.
532+
ignore_not_found: false
517533
518534
Learn more
519535
----------

src/Icons/src/DependencyInjection/UXIconsExtension.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ public function getConfigTreeBuilder(): TreeBuilder
5858
->end()
5959
->end()
6060
->end()
61+
->booleanNode('ignore_not_found')
62+
->info('Ignore error when an icon is not found.')
63+
->defaultFalse()
64+
->end()
6165
->end()
6266
;
6367

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

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

103+
$container->getDefinition('.ux_icons.twig_icon_runtime')
104+
->setArgument(1, $mergedConfig['ignore_not_found'])
105+
;
106+
99107
if ($mergedConfig['iconify']['enabled']) {
100108
$loader->load('iconify.php');
101109

src/Icons/src/Twig/UXIconExtension.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\UX\Icons\Twig;
1313

14-
use Symfony\UX\Icons\IconRenderer;
1514
use Twig\Extension\AbstractExtension;
1615
use Twig\TwigFunction;
1716

@@ -25,7 +24,7 @@ final class UXIconExtension extends AbstractExtension
2524
public function getFunctions(): array
2625
{
2726
return [
28-
new TwigFunction('ux_icon', [IconRenderer::class, 'renderIcon'], ['is_safe' => ['html']]),
27+
new TwigFunction('ux_icon', [UXIconRuntime::class, 'renderIcon'], ['is_safe' => ['html']]),
2928
];
3029
}
3130
}

src/Icons/src/Twig/UXIconRuntime.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\Icons\Twig;
13+
14+
use Psr\Log\LoggerInterface;
15+
use Symfony\UX\Icons\Exception\IconNotFoundException;
16+
use Symfony\UX\Icons\IconRendererInterface;
17+
use Twig\Extension\RuntimeExtensionInterface;
18+
19+
/**
20+
* @author Simon André <smn.andre@gmail.com>
21+
*
22+
* @internal
23+
*/
24+
final class UXIconRuntime implements RuntimeExtensionInterface
25+
{
26+
public function __construct(
27+
private readonly IconRendererInterface $iconRenderer,
28+
private readonly bool $ignoreNotFound = false,
29+
private readonly ?LoggerInterface $logger = null,
30+
) {
31+
}
32+
33+
/**
34+
* @param array<string, bool|string> $attributes
35+
*/
36+
public function renderIcon(string $name, array $attributes = []): string
37+
{
38+
try {
39+
return $this->iconRenderer->renderIcon($name, $attributes);
40+
} catch (IconNotFoundException $e) {
41+
if ($this->ignoreNotFound) {
42+
$this->logger?->warning($e->getMessage());
43+
return '';
44+
}
45+
46+
throw $e;
47+
}
48+
}
49+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\Icons\Tests\Unit\Twig;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Psr\Log\LoggerInterface;
16+
use Symfony\UX\Icons\Exception\IconNotFoundException;
17+
use Symfony\UX\Icons\IconRendererInterface;
18+
use Symfony\UX\Icons\Twig\UXIconRuntime;
19+
20+
/**
21+
* @author Simon André <smn.andre@gmail.com>
22+
*/
23+
class UXIconRuntimeTest extends TestCase
24+
{
25+
public function testRenderIconIgnoreNotFound(): void
26+
{
27+
$renderer = $this->createMock(IconRendererInterface::class);
28+
$renderer->method('renderIcon')
29+
->willThrowException(new IconNotFoundException('Icon "foo" not found.'));
30+
31+
$logger = $this->createMock(LoggerInterface::class);
32+
$logger->expects($this->once())
33+
->method('warning')
34+
->with('Icon "foo" not found.');
35+
36+
$runtime = new UXIconRuntime($renderer, true, $logger);
37+
$this->assertEquals('', $runtime->renderIcon('not_found'));
38+
39+
$runtime = new UXIconRuntime($renderer, false);
40+
$this->expectException(IconNotFoundException::class);
41+
$runtime->renderIcon('not_found');
42+
}
43+
}

0 commit comments

Comments
 (0)