Skip to content

Commit eb6c4da

Browse files
committed
[Icons] Add ignore_not_found config option
Allow to silence error during rendering when an icon is not found
1 parent c69bd67 commit eb6c4da

File tree

7 files changed

+127
-4
lines changed

7 files changed

+127
-4
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/config/services.php

Lines changed: 8 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,17 @@
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+
])
53+
->tag('twig.runtime')
54+
4755
->set('.ux_icons.icon_renderer', IconRenderer::class)
4856
->args([
4957
service('.ux_icons.icon_registry'),
5058
])
51-
->tag('twig.runtime')
5259

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

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

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

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: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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 Symfony\UX\Icons\Exception\IconNotFoundException;
15+
use Symfony\UX\Icons\IconRendererInterface;
16+
use Twig\Extension\RuntimeExtensionInterface;
17+
18+
/**
19+
* @author Simon André <[email protected]>
20+
*
21+
* @internal
22+
*/
23+
final class UXIconRuntime implements RuntimeExtensionInterface
24+
{
25+
public function __construct(
26+
private readonly IconRendererInterface $iconRenderer,
27+
private readonly bool $ignoreNotFound = false,
28+
) {
29+
}
30+
31+
/**
32+
* @param array<string, bool|string> $attributes
33+
*/
34+
public function renderIcon(string $name, array $attributes = []): string
35+
{
36+
try {
37+
return $this->iconRenderer->renderIcon($name, $attributes);
38+
} catch (IconNotFoundException $e) {
39+
if ($this->ignoreNotFound) {
40+
return '';
41+
}
42+
43+
throw $e;
44+
}
45+
}
46+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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 Symfony\UX\Icons\Exception\IconNotFoundException;
16+
use Symfony\UX\Icons\IconRendererInterface;
17+
use Symfony\UX\Icons\Twig\UXIconRuntime;
18+
19+
/**
20+
* @author Simon André <[email protected]>
21+
*/
22+
class UXIconRuntimeTest extends TestCase
23+
{
24+
public function testRenderIconIgnoreMissing(): void
25+
{
26+
$renderer = $this->createMock(IconRendererInterface::class);
27+
$renderer->method('renderIcon')
28+
->willThrowException(new IconNotFoundException('not_found'));
29+
30+
$runtime = new UXIconRuntime($renderer, true);
31+
$this->assertEquals('', $runtime->renderIcon('not_found'));
32+
33+
$runtime = new UXIconRuntime($renderer, false);
34+
$this->expectException(IconNotFoundException::class);
35+
$runtime->renderIcon('not_found');
36+
}
37+
}

0 commit comments

Comments
 (0)