fix sub-cats where also included on parent level and validation error for categories (caused by them being a real array with children and not an associate one)

This commit is contained in:
ralf 2024-08-25 10:18:29 +02:00
parent 891d69e14d
commit 761197737a

View File

@ -165,7 +165,7 @@ class Select extends Etemplate\Widget
($this->attrs['rows'] && strpos($this->attrs['options'], $this->attrs['rows']) !== 0 ? $this->attrs['rows'] . ',' . $this->attrs['options'] : $this->attrs['options']),
$false, $false, $value_in
);
$allowed = array_merge($allowed2, array_keys($type_options));
$allowed = array_merge($allowed2, self::optionValues($type_options));
// add option children's values too, "" is not read, therefore we cast to string
foreach($this->children as $child)
@ -323,6 +323,31 @@ class Select extends Etemplate\Widget
}
}
/**
* Get all values from an option array, which can be an associate array with values as key, or a "real" array or arrays with key "value"
*
* @param array|array[] $options incl. possible children
* @return string[]
*/
static function optionValues(array $options)
{
if (!$options || (function_exists('array_is_list') && !array_is_list($options)) ||
(!function_exists('array_is_list') && !isset($options[0]) && !isset($options[count($options) - 1])))
{
return array_keys($options);
}
$option2value = static function (array $option) use (&$option2value)
{
if (!empty($option['children']))
{
return array_merge((array)(string)$option['value'], ...array_map($option2value, $option['children']));
}
return [(string)$option['value']];
};
$values = array_merge(...array_map($option2value, $options));
return $values;
}
/**
* Fill type options in self::$request->sel_options to be used on the client
*
@ -725,7 +750,7 @@ class Select extends Etemplate\Widget
$globalCategories = ($globalCategories && strlen($globalCategories) > 1 ? $globalCategories : !$globalCategories);
// we cast $type4 (parent) to int, to get default of 0 if omitted
$cats = $categories->return_sorted_array(0, False, '', '', '', $globalCategories, (int)$parentCat, true) ?: [];
$cat2option = static function(array $cat) use (&$cat2option, $globalCategories, $categories)
$cat2option = static function(array $cat) use (&$cat2option, $globalCategories, $cats)
{
return array_filter([
'value' => $cat['id'],
@ -736,16 +761,28 @@ class Select extends Etemplate\Widget
'main' => (int)$cat['main'],
// if we have children, fetch and return them
'children' => empty($cat['children']) ? null :
array_map($cat2option, $categories->return_sorted_array(0, False, '', '', '', $globalCategories, (int)$cat['id'], true)?:[]),
array_values(array_map($cat2option, array_filter($cats, static function(array $child) use ($cat)
{
return $child['parent'] == $cat['id'];
}))),
//add different class per level to allow different styling for each category level:
'class' => "cat_level" . $cat['level'] . " cat_{$cat['id']}",
'icon' => !empty($cat['data']['icon']) ? \admin_categories::icon_url($cat['data']['icon']) : null,
// send cat-date too
]+(is_array($cat['data']) ? $cat['data'] : []));
};
$options = array_map($cat2option, $cats);
// filter out sub-categories, they get added as children above
$options = array_map($cat2option, array_values(array_filter($cats, static function(array $cat) use ($parentCat)
{
return $cat['parent'] == (int)$parentCat;
})));
// preserve unavailable cats (eg. private user-cats)
if (isset(self::$request) && $value && ($unavailable = array_diff(is_array($value) ? $value : explode(',',$value),array_keys($cats))))
if (isset(self::$request) && $value &&
($unavailable = array_diff(is_array($value) ? $value : explode(',',$value),
array_map(static function(array $cat)
{
return $cat['id'];
}, $cats))))
{
// unavailable cats need to be merged in again
$unavailable_name = $form_name . self::UNAVAILABLE_CAT_POSTFIX;