Skip to content

Commit f3370e6

Browse files
authored
fix: correctly pass picture/img attribs (#223)
1 parent 7a1bb4e commit f3370e6

File tree

6 files changed

+82
-14
lines changed

6 files changed

+82
-14
lines changed

phpstan.baseline.neon

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,12 @@ parameters:
336336
count: 1
337337
path: src/Bridge/Twig/Extension/DatabaseExtension.php
338338

339+
-
340+
message: '#^Call to function array_filter\(\) requires parameter \#2 to be passed to avoid loose comparison semantics\.$#'
341+
identifier: arrayFilter.strict
342+
count: 2
343+
path: src/Bridge/Twig/Extension/ImageExtension.php
344+
339345
-
340346
message: '#^Call to function is_object\(\) with string will always evaluate to false\.$#'
341347
identifier: function.impossibleType
@@ -348,6 +354,36 @@ parameters:
348354
count: 1
349355
path: src/Bridge/Twig/Extension/ImageExtension.php
350356

357+
-
358+
message: '#^Cannot access offset ''alt'' on mixed\.$#'
359+
identifier: offsetAccess.nonOffsetAccessible
360+
count: 1
361+
path: src/Bridge/Twig/Extension/ImageExtension.php
362+
363+
-
364+
message: '#^Cannot access offset ''class'' on mixed\.$#'
365+
identifier: offsetAccess.nonOffsetAccessible
366+
count: 1
367+
path: src/Bridge/Twig/Extension/ImageExtension.php
368+
369+
-
370+
message: '#^Cannot access offset ''decoding'' on mixed\.$#'
371+
identifier: offsetAccess.nonOffsetAccessible
372+
count: 1
373+
path: src/Bridge/Twig/Extension/ImageExtension.php
374+
375+
-
376+
message: '#^Cannot access offset ''loading'' on mixed\.$#'
377+
identifier: offsetAccess.nonOffsetAccessible
378+
count: 1
379+
path: src/Bridge/Twig/Extension/ImageExtension.php
380+
381+
-
382+
message: '#^Cannot access offset ''style'' on mixed\.$#'
383+
identifier: offsetAccess.nonOffsetAccessible
384+
count: 1
385+
path: src/Bridge/Twig/Extension/ImageExtension.php
386+
351387
-
352388
message: '#^Cannot cast mixed to int\.$#'
353389
identifier: cast.int
@@ -384,6 +420,12 @@ parameters:
384420
count: 2
385421
path: src/Bridge/Twig/Extension/ImageExtension.php
386422

423+
-
424+
message: '#^Parameter \#1 \$string of function htmlspecialchars expects string, mixed given\.$#'
425+
identifier: argument.type
426+
count: 2
427+
path: src/Bridge/Twig/Extension/ImageExtension.php
428+
387429
-
388430
message: '#^Parameter \#2 \$context of method Sigwin\\YASSG\\Bridge\\Twig\\Extension\\ImageExtension\:\:buildOriginAbsolutePath\(\) expects array\{__path\?\: string\}, array given\.$#'
389431
identifier: argument.type

psalm.baseline.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,13 +461,21 @@
461461
<code><![CDATA[\is_object($item)]]></code>
462462
<code><![CDATA[\is_string($value)]]></code>
463463
</DocblockTypeContradiction>
464+
<InvalidArrayAccess>
465+
<code><![CDATA[$options['attributes']['class']]]></code>
466+
</InvalidArrayAccess>
467+
<InvalidArrayOffset>
468+
<code><![CDATA[$options['attributes']['class']]]></code>
469+
</InvalidArrayOffset>
464470
<InvalidCast>
465471
<code><![CDATA[$options['height']]]></code>
466472
<code><![CDATA[$options['width']]]></code>
467473
</InvalidCast>
468474
<MixedArgument>
469475
<code><![CDATA[$GLOBALS['YASSG_BASEDIR']]]></code>
470476
<code><![CDATA[$GLOBALS['YASSG_BASEDIR']]]></code>
477+
<code><![CDATA[$value]]></code>
478+
<code><![CDATA[$value]]></code>
471479
</MixedArgument>
472480
<MixedArgumentTypeCoercion>
473481
<code><![CDATA[$context]]></code>

src/Bridge/Twig/Extension/ImageExtension.php

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,19 +83,39 @@ function (array $context, string $path, array $options = []): string {
8383
$srcsetFallback = $srcFallback1x.' 1x'.($srcFallback2x ? ', '.$srcFallback2x.' 2x' : '');
8484

8585
// Build <picture> element
86-
$html = '<picture>';
86+
$attributes = array_filter([
87+
'class' => $options['attributes']['class'] ?? null,
88+
'style' => $options['attributes']['style'] ?? null,
89+
]);
90+
91+
$imgAttributes = array_filter([
92+
'src' => $srcFallback1x,
93+
'srcset' => $srcsetFallback,
94+
'width' => $width !== null ? (string) $width : null,
95+
'height' => $height !== null ? (string) $height : null,
96+
'alt' => $options['attributes']['alt'] ?? '',
97+
'loading' => $options['attributes']['loading'] ?? 'lazy',
98+
'decoding' => $options['attributes']['decoding'] ?? 'async',
99+
]);
100+
101+
$html = '<picture '.implode(' ', array_map(
102+
static fn ($key, $value) => htmlspecialchars($key, \ENT_QUOTES).'="'.htmlspecialchars($value, \ENT_QUOTES).'"',
103+
array_keys($attributes),
104+
$attributes
105+
)).'>';
87106
$html .= '<source type="image/avif" srcset="'.htmlspecialchars($srcsetAvif, \ENT_QUOTES).'"/>';
88107
$html .= '<source type="image/webp" srcset="'.htmlspecialchars($srcsetWebp, \ENT_QUOTES).'"/>';
89108
if ($fallbackFormat === 'png') {
90109
$html .= '<source type="image/png" srcset="'.htmlspecialchars($srcsetFallback, \ENT_QUOTES).'"/>';
91110
} else {
92111
$html .= '<source type="image/jpeg" srcset="'.htmlspecialchars($srcsetFallback, \ENT_QUOTES).'"/>';
93112
}
94-
$html .= '<img src="'.htmlspecialchars($srcFallback1x, \ENT_QUOTES).'"'
95-
.' srcset="'.htmlspecialchars($srcsetFallback, \ENT_QUOTES).'"'
96-
.($width !== null ? ' width="'.$width.'"' : '')
97-
.($height !== null ? ' height="'.$height.'"' : '')
98-
.' loading="lazy" decoding="async" />';
113+
$html .= '<img '
114+
.implode(' ', array_map(
115+
static fn ($key, $value) => htmlspecialchars($key, \ENT_QUOTES).'="'.htmlspecialchars($value, \ENT_QUOTES).'"',
116+
array_keys($imgAttributes),
117+
$imgAttributes
118+
)).' />';
99119
$html .= '</picture>';
100120

101121
return $html;
@@ -184,9 +204,7 @@ private function buildOriginAbsolutePath(string $path, array $context, array $op
184204
private function buildImgproxyFilter(array $options): string
185205
{
186206
$filter = '';
187-
if (isset($options['self'])) {
188-
unset($options['self']);
189-
}
207+
unset($options['self'], $options['attributes']);
190208

191209
if ($options !== []) {
192210
$filters = [];

tests/functional/default.mk

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ self/validate: ## Self: validate the database with yassg:validate
1616
export YASSG_SKIP_BUNDLES=${YASSG_SKIP_BUNDLES}; \
1717
php ../../../bin/yassg yassg:validate -vvv
1818
self/clean:
19-
rm -rf ${BUILD_DIR}
19+
rm -rf ${BUILD_DIR} var/cache
2020
self/test:
2121
sh -c "${PHPQA_DOCKER_COMMAND} diff -r fixtures/ public/"
22-
self/check: self/build ## Self: check the build
23-
lychee --verbose --offline --base ./${BUILD_DIR} ./${BUILD_DIR}
22+
self/check: ## Self: check the build
23+
lychee --base ${BASE_URL} --root-dir $(pwd)/${BUILD_DIR} ./${BUILD_DIR}
2424
self/serve: self/build ## Self: serve the build
2525
php -S localhost:9999 -t ${BUILD_DIR}/

tests/functional/site/content/articles/images/images.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ This is an asset lookup: {{ yassg_thumbnail(item.image) }}
1919

2020
![Logo]({{ yassg_thumbnail(item.image, {width: 400, height: 200, gravity: "no"}) }})
2121

22-
{{ yassg_picture(item.image, {width: 400, height: 200, gravity: "no"}) }}
22+
{{ yassg_picture(item.image, {width: 400, height: 200, gravity: "no", attributes: {alt: "Hello", class: "prose", style: "border: 1px solid red"}}) }}

tests/functional/site/fixtures/en/article/images/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ <h1>Images!</h1>
4646
<p>This is an asset lookup: /sub/dir/another/content/articles/images/image.6ec7e8a4.webp</p>
4747
<p><img src="/sub/dir/another/content/articles/images/image.4de2c22b.webp" alt="Logo" /></p>
4848
<p><img src="/sub/dir/another/content/articles/images/image.5c87cfff.webp" alt="Logo" /></p>
49-
<p><picture><source type="image/avif" srcset="/sub/dir/another/content/articles/images/image.f72ab4b6.avif 1x, /sub/dir/another/content/articles/images/image.db2a185c.avif 2x"/><source type="image/webp" srcset="/sub/dir/another/content/articles/images/image.5c87cfff.webp 1x, /sub/dir/another/content/articles/images/image.3fc9b4bd.webp 2x"/><source type="image/png" srcset="/sub/dir/another/content/articles/images/image.86315aa7.png 1x, /sub/dir/another/content/articles/images/image.6d24603a.png 2x"/><img src="/sub/dir/another/content/articles/images/image.86315aa7.png" srcset="/sub/dir/another/content/articles/images/image.86315aa7.png 1x, /sub/dir/another/content/articles/images/image.6d24603a.png 2x" width="400" height="200" loading="lazy" decoding="async" /></picture></p>
49+
<p><picture class="prose" style="border: 1px solid red"><source type="image/avif" srcset="/sub/dir/another/content/articles/images/image.f72ab4b6.avif 1x, /sub/dir/another/content/articles/images/image.db2a185c.avif 2x"/><source type="image/webp" srcset="/sub/dir/another/content/articles/images/image.5c87cfff.webp 1x, /sub/dir/another/content/articles/images/image.3fc9b4bd.webp 2x"/><source type="image/png" srcset="/sub/dir/another/content/articles/images/image.86315aa7.png 1x, /sub/dir/another/content/articles/images/image.6d24603a.png 2x"/><img src="/sub/dir/another/content/articles/images/image.86315aa7.png" srcset="/sub/dir/another/content/articles/images/image.86315aa7.png 1x, /sub/dir/another/content/articles/images/image.6d24603a.png 2x" width="400" height="200" alt="Hello" loading="lazy" decoding="async" /></picture></p>
5050

5151
</div>
5252
</div>

0 commit comments

Comments
 (0)