Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 4.2.1 under development

- New #278: Add dedicated classes for missing HTML tags (@Mister-42)
- New #279: Add support for conditional CSS classes in `Html::addCssClass()` (@Mister-42)

## 4.2.0 June 05, 2026

Expand Down
19 changes: 15 additions & 4 deletions src/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -2405,11 +2405,11 @@
/** @psalm-var array<array-key, scalar[]|string|Stringable|null> $value */
foreach ($value as $n => $v) {
if (!isset($v)) {
continue;

Check warning on line 2408 in src/Html.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.5-ubuntu-latest

Escaped Mutant for Mutator "Continue_": @@ @@ /** @psalm-var array<array-key, scalar[]|string|Stringable|null> $value */ foreach ($value as $n => $v) { if (!isset($v)) { - continue; + break; } $fullName = "$name-$n"; if (in_array($fullName, self::ATTRIBUTES_WITH_CONCATENATED_VALUES, true)) {
}
$fullName = "$name-$n";
if (in_array($fullName, self::ATTRIBUTES_WITH_CONCATENATED_VALUES, true)) {
$html .= self::renderAttribute(

Check warning on line 2412 in src/Html.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.5-ubuntu-latest

Escaped Mutant for Mutator "Assignment": @@ @@ } $fullName = "$name-$n"; if (in_array($fullName, self::ATTRIBUTES_WITH_CONCATENATED_VALUES, true)) { - $html .= self::renderAttribute( + $html = self::renderAttribute( $fullName, self::encodeAttribute( is_array($v) ? implode(' ', $v) : $v,
$fullName,
self::encodeAttribute(
is_array($v) ? implode(' ', $v) : $v,
Expand Down Expand Up @@ -2462,10 +2462,10 @@
*
* @param array $attributes The attributes to be modified. All string values in the array must be valid UTF-8
* strings.
* @param BackedEnum|BackedEnum[]|null[]|string|string[]|null $class The CSS class(es) to be added. Null values will
* be ignored.
* @param (BackedEnum|null|bool|string)[]|BackedEnum|string|null $class The CSS class(es) to be added. Null values will
* be ignored. When passing an array, use a boolean value to conditionally include/exclude a class by its key.
*
* @psalm-param BackedEnum|string|array<array-key,BackedEnum|string|null>|null $class
* @psalm-param BackedEnum|string|array<array-key,BackedEnum|bool|string|null>|null $class
*/
public static function addCssClass(array &$attributes, BackedEnum|array|string|null $class): void
{
Expand All @@ -2483,12 +2483,23 @@
if (is_array($class)) {
$filteredClass = [];
foreach ($class as $key => $value) {
if (is_bool($value)) {
Comment thread
Mister-42 marked this conversation as resolved.
Comment thread
Mister-42 marked this conversation as resolved.
if ($value && is_string($key)) {
$filteredClass[] = $key;
Comment thread
Mister-42 marked this conversation as resolved.
}
continue;
}

if ($value instanceof BackedEnum) {
$value = is_string($value->value) ? $value->value : null;
}

if ($value !== null) {
$filteredClass[$key] = $value;
if (is_int($key) && array_key_exists($key, $filteredClass)) {
$filteredClass[] = $value;
} else {
$filteredClass[$key] = $value;
}
}
}
if (empty($filteredClass)) {
Expand Down
11 changes: 11 additions & 0 deletions tests/HtmlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,17 @@ public static function dataAddCssClass(): array
16 => [['id' => 'w2', 'class' => 't1'], ['id' => 'w2'], 't1'],
17 => [['id' => 'w2', 'class' => ['t3', 2 => 't4']], ['id' => 'w2'], ['t3', null, 't4']],
18 => [['id' => 'w2', 'class' => ['t3', 2 => 't4']], ['id' => 'w2'], ['t3', null, 't4', null]],
19 => [['class' => ['btn-active']], [], ['btn-active' => true]],
20 => [[], [], ['btn-active' => false]],
21 => [['class' => ['btn', 'btn-active']], [], ['btn', 'btn-active' => true]],
22 => [['class' => ['btn']], [], ['btn', 'btn-active' => false]],
23 => [['class' => ['btn', 'btn-active']], ['class' => 'btn'], ['btn-active' => true]],
24 => [['class' => 'btn'], ['class' => 'btn'], ['btn-active' => false]],
25 => [['class' => ['btn', 'btn-active']], ['class' => 'btn'], ['btn-active' => true, 'hidden' => false]],
26 => [['class' => ['btn']], ['class' => 'btn'], ['btn' => true]],
27 => [['class' => ['persistent' => 'widget', 'btn', 'btn-active']], ['class' => ['persistent' => 'widget']], ['btn', 'btn-active' => true]],
28 => [['class' => ['persistent' => 'widget', 'btn-active', 'btn']], ['class' => ['persistent' => 'widget']], ['btn-active' => true, 'btn']],
29 => [['class' => ['persistent' => 'widget', 'btn-active', 'btn', 'btn-sm']], ['class' => ['persistent' => 'widget']], ['btn-active' => true, 'btn', 'btn-sm' => true]],
];
}

Expand Down
Loading