Skip to content
Snippets Groups Projects
Commit c330a4d9 authored by Mikael Meulle's avatar Mikael Meulle Committed by Pierre Dureau
Browse files

Issue #3491369 by just_like_good_vibes, grimreaper, walli: Props with enum...

Issue #3491369 by just_like_good_vibes, grimreaper, walli: Props with enum should handle empty string or NULL value
parent afe7b3bd
No related branches found
No related tags found
1 merge request!282Resolve #3491369 "2.0.0 rc props with"
Pipeline #359609 passed
......@@ -50,6 +50,9 @@ trait EnumTrait {
* The converted value.
*/
protected static function convertValueToEnumType(mixed $value, array $enum) {
if (!is_scalar($value)) {
return $value;
}
return match (TRUE) {
in_array($value, $enum, TRUE) => $value,
in_array((string) $value, $enum, TRUE) => (string) $value,
......@@ -59,4 +62,141 @@ trait EnumTrait {
};
}
/**
* Normalize the value without returning a default value.
*
* @param mixed $value
* The value to normalize.
* @param array $enum
* The enum array.
*
* @return mixed
* The normalized value.
*/
protected static function normalizeEnumValue(mixed $value, ?array $enum = NULL): mixed {
if (!is_array($enum) || empty($enum)) {
return $value;
}
// We try to match first without casting.
if (in_array($value, $enum, TRUE)) {
return $value;
}
// We try to cast the value and retry to match.
$value = static::convertValueToEnumType($value, $enum);
if (in_array($value, $enum, TRUE)) {
return $value;
}
return NULL;
}
/**
* Get default value for an enum.
*
* @param array|null $definition
* The prop definition.
*
* @return mixed
* The default value.
*/
protected static function enumDefaultValue(?array $definition = NULL): mixed {
// First get the enum array.
$enum = (!is_array($definition)) ? [] : ($definition['enum'] ?? []);
if (!is_array($enum)) {
$enum = [];
}
// Fall back to default value (if defined)
if (is_array($definition) && isset($definition['default'])) {
return $definition['default'];
}
// If a type is defined, return the first enum value.
return (is_array($definition) && isset($definition['type']) && count($enum) > 0) ? $enum[0] : NULL;
}
/**
* Normalize enum values.
*
* @param mixed $values
* The values to normalize.
* @param array|null $enum
* The enum array.
*
* @return array
* The normalized values.
*/
protected static function normalizeEnumValues(mixed $values, ?array $enum = NULL): array {
if ($values === NULL) {
return [];
}
if (!is_array($values)) {
$values = [$values];
}
$values = array_map(function ($item) use ($enum) {
return static::normalizeEnumValue($item, $enum);
}, $values);
$values = array_filter($values, function ($item) {
return $item !== NULL;
});
return $values;
}
/**
* Normalize enum list values.
*
* @param array $values
* The values to normalize.
* @param array $definition
* The prop definition.
* @param bool $uniqueItems
* Whether the items should be unique.
*
* @return array
* The normalized values.
*/
protected static function normalizeEnumListSize(array $values, ?array $definition, bool $uniqueItems = FALSE): array {
$definition_items = (!is_array($definition)) ? [] : ($definition['items'] ?? []);
if (!is_array($definition_items) || empty($definition_items)) {
return $values;
}
if (isset($definition['minItems']) && count($values) < (int) $definition['minItems']) {
$default_value = static::enumDefaultValue($definition);
$minItems = (int) $definition['minItems'];
if (!$uniqueItems) {
$values = array_merge($values, array_fill(0, $minItems - count($values), $default_value));
}
else {
self::normalizeListMinSizeUniqueItems($values, $definition_items['enum'] ?? [], $default_value, $minItems);
}
}
if (isset($definition['maxItems'])) {
self::normalizeListMaxSize($values, (int) $definition['maxItems']);
}
return $values;
}
/**
* Normalize list max size.
*/
private static function normalizeListMaxSize(array &$values, int $maxItems): void {
if (count($values) > $maxItems) {
$values = array_slice($values, 0, $maxItems);
}
}
/**
* Normalize list min size unique items.
*/
private static function normalizeListMinSizeUniqueItems(array &$values, mixed $possible_values, mixed $default_value, int $minItems): void {
if (!is_array($possible_values)) {
return;
}
// First try to add the default value.
if (($default_value !== NULL) && !in_array($default_value, $values, TRUE)) {
$values[] = $default_value;
}
$possible_values = array_diff($possible_values, $values);
while ((count($possible_values) > 0) && count($values) < $minItems) {
$values = array_unique(array_merge($values, [array_shift($possible_values)]));
}
}
}
......@@ -46,23 +46,8 @@ class EnumListPropType extends PropTypePluginBase {
* {@inheritdoc}
*/
public static function normalize(mixed $value, ?array $definition = NULL): mixed {
$value = parent::normalize($value, $definition);
if ($value === NULL) {
return [];
}
if (!is_array($value)) {
$value = [$value];
}
if (!is_array($definition)) {
return $value;
}
$definition_items = $definition['items'] ?? [];
$value = array_map(function ($item) use ($definition_items) {
return EnumPropType::normalize($item, $definition_items);
}, $value);
return array_filter($value, function ($item) {
return $item !== NULL;
});
$definition_items = (!is_array($definition)) ? [] : ($definition['items'] ?? []);
return static::normalizeEnumListSize(static::normalizeEnumValues($value, $definition_items['enum'] ?? []), $definition, FALSE);
}
}
......@@ -42,30 +42,12 @@ class EnumPropType extends PropTypePluginBase {
* {@inheritdoc}
*/
public static function normalize(mixed $value, ?array $definition = NULL): mixed {
// @todo Change the autogenerated stub
$value = parent::normalize($value, $definition);
if (!is_array($definition)) {
return $value;
}
$enum = $definition['enum'] ?? [];
// First get the enum array.
$enum = (!is_array($definition)) ? [] : ($definition['enum'] ?? []);
if (!is_array($enum)) {
$enum = [];
}
// We try to match first without casting.
if (in_array($value, $enum, TRUE)) {
return $value;
}
// We try to cast the value and retry to match.
$value = static::convertValueToEnumType($value, $enum);
if (in_array($value, $enum, TRUE)) {
return $value;
}
// Fall back to default value (if defined)
if (isset($definition['default'])) {
return $definition['default'];
}
return NULL;
return static::normalizeEnumValue($value, $enum) ?? static::enumDefaultValue($definition);
}
}
......@@ -53,9 +53,9 @@ class EnumSetPropType extends PropTypePluginBase {
* {@inheritdoc}
*/
public static function normalize(mixed $value, ?array $definition = NULL): mixed {
$value = parent::normalize($value, $definition);
$value = EnumListPropType::normalize($value, $definition);
return is_array($value) ? array_unique($value) : [];
$definition_items = (!is_array($definition)) ? [] : ($definition['items'] ?? []);
$value = array_unique(static::normalizeEnumValues($value, $definition_items['enum'] ?? []));
return static::normalizeEnumListSize($value, $definition, TRUE);
}
}
......@@ -289,7 +289,7 @@ checkboxes_1:
source_id: checkboxes
source:
value:
B: B
D: D
entity:
body:
value: 'value_text_1'
......@@ -297,11 +297,11 @@ checkboxes_1:
props:
enum_list:
same:
B: "B"
D: "D"
assertSession:
elementExists:
- [ 'css', '.ui-patterns-test-component' ]
- [ 'xpath', "//div[contains(@class, 'ui-patterns-test-component')]//div[contains(@class, 'ui-patterns-props-enum_list')]//span[contains(text(), 'B')]" ]
- [ 'xpath', "//div[contains(@class, 'ui-patterns-test-component')]//div[contains(@class, 'ui-patterns-props-enum_list')]//span[contains(text(), 'D')]" ]
elementsCount:
- [ 'xpath', "//div[@class='ui-patterns-props-enum_list']//span", 1 ]
checkboxes_2:
......@@ -313,7 +313,7 @@ checkboxes_2:
source:
value:
A: A
B: B
E: E
entity:
body:
value: 'value_text_1'
......@@ -322,12 +322,12 @@ checkboxes_2:
enum_list:
same:
A: A
B: B
E: E
assertSession:
elementExists:
- [ 'css', '.ui-patterns-test-component' ]
- [ 'xpath', "//div[contains(@class, 'ui-patterns-test-component')]//div[contains(@class, 'ui-patterns-props-enum_list')]//span[contains(text(), 'A')]" ]
- [ 'xpath', "//div[contains(@class, 'ui-patterns-test-component')]//div[contains(@class, 'ui-patterns-props-enum_list')]//span[contains(text(), 'B')]" ]
- [ 'xpath', "//div[contains(@class, 'ui-patterns-test-component')]//div[contains(@class, 'ui-patterns-props-enum_list')]//span[contains(text(), 'E')]" ]
elementsCount:
- [ 'xpath', "//div[@class='ui-patterns-props-enum_list']//span", 2 ]
......@@ -483,19 +483,19 @@ list_textarea_1:
list_string:
source_id: list_textarea
source:
value: "A\r\nB"
value: "A\r\nF"
entity: {}
output:
props:
list_string:
same:
- 'A'
- 'B'
- 'F'
assertSession:
elementExists:
- [ 'css', '.ui-patterns-test-component' ]
- [ 'xpath', "//div[contains(@class, 'ui-patterns-test-component')]//div[contains(@class, 'ui-patterns-props-list_string')]//span[contains(text(), 'A')]" ]
- [ 'xpath', "//div[contains(@class, 'ui-patterns-test-component')]//div[contains(@class, 'ui-patterns-props-list_string')]//span[contains(text(), 'B')]" ]
- [ 'xpath', "//div[contains(@class, 'ui-patterns-test-component')]//div[contains(@class, 'ui-patterns-props-list_string')]//span[contains(text(), 'F')]" ]
elementsCount:
- [ 'xpath', "//div[@class='ui-patterns-props-list_string']//span", 2 ]
list_textarea_2:
......
......@@ -44,9 +44,17 @@ props:
enum:
- A
- B
- C
- D
- E
- F
'meta:enum':
A: 'Label A'
B: 'Label B'
C: 'Label C'
D: 'Label D'
E: 'Label E'
F: 'Label F'
enum_list_multiple:
title: "Enum List"
type: array
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment