Skip to content
Snippets Groups Projects

Issue #3474822 by pdureau, sea2709, smustgrave, just_like_good_vibes: Normalize attributes values

Files
3
@@ -4,8 +4,12 @@ declare(strict_types=1);
namespace Drupal\ui_patterns\Plugin\UiPatterns\PropType;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Url;
use Drupal\ui_patterns\Attribute\PropType;
use Drupal\ui_patterns\PropTypePluginBase;
@@ -49,12 +53,98 @@ class AttributesPropType extends PropTypePluginBase {
plugins are expected to return a mapping to not break SDC prop validation
against the prop type schema.
*/
if (is_a($value, '\Drupal\Core\Template\Attribute')) {
return $value->toArray();
if (is_array($value)) {
// Attribute::createAttributeValue() is alread normalizing some stuff:
// - 'class' attribute must be a list
// - MarkupInterface values must be resolved.
$value = (new Attribute($value))->toArray();
}
elseif (is_a($value, '\Drupal\Core\Template\Attribute')) {
$value = $value->toArray();
}
else {
return [];
}
if (array_is_list($value)) {
// @todo
}
foreach ($value as $attr => $attr_value) {
$value[$attr] = self::normalizeAttrValue($attr_value);
}
return $value;
}
/**
* Normalize attribute value.
*/
protected static function normalizeAttrValue(mixed $value): mixed {
if (is_object($value)) {
return self::normalizeObject($value);
}
if (is_array($value) && array_is_list($value)) {
return self::normalizeList($value);
}
if (is_array($value) && !array_is_list($value)) {
return self::normalizeMapping($value);
}
// Integer and number are always allowed values.
if (is_int($value) || is_float($value)) {
return $value;
}
// We don't allow markup in attribute value.
return strip_tags((string) $value);
}
/**
* Normalize object attribute value.
*/
protected static function normalizeObject(object $value): array|string {
if ($value instanceof Url) {
return $value->toString();
}
if ($value instanceof RenderableInterface) {
return static::normalizeMapping($value->toRenderable());
}
if ($value instanceof MarkupInterface) {
return (string) $value;
}
if ($value instanceof \Stringable) {
return (string) $value;
}
// Instead of keeping an unexpected object, we return PHP namespace.
// It will be valid and can inform the component user about its mistake.
return get_class($value);
}
/**
* Normalize list attribute value.
*/
protected static function normalizeList(array $value): array {
// Flatten nested arrays.
foreach ($value as $index => $item) {
if (is_array($item)) {
// We encode to JSON because we don't know how deep is the nesting.
$value[$index] = json_encode($item);
}
}
return $value;
}
/**
* Normalize mapping attribute value.
*/
protected static function normalizeMapping(array $value): array|string {
if (!empty(Element::properties($value))) {
// This is a render array.
// It would be great to render it here
// $value = \Drupal::service('renderer')->render($value);
// return strip_tags($value);
// But let's alert the component user by JSON encoding the value for now.
return (string) json_encode($value);
}
return static::normalizeList(array_values($value));
}
/**
* {@inheritdoc}
*/
Loading