Я пытаюсь построить сплющенный массив, который сохраняет метаданные из довольно сложного массива, исходящего из представления в моем проекте CodeIgniter. Эти метаданные - это такие вещи, как идентификатор, глубина и родительский узел.PHP: создание списка смежности через рекурсивную итерацию
Данные получены из библиотеки JavaScript запросов, которая позволяет пользователю создавать правила, которые будут использоваться в бизнес-логике. Мне нужно сохранить эти данные, и модель, с которой я столкнулся, чтобы представить древовидный характер этих правил, - это список смежности.
Это то, что у меня есть, и оно действительно работает в большинстве случаев, но оно уродливое, оно изготовлено из жвачки с пузырьками и клейкой лентой, а «большинство» случаев - это не «все» случаи. После прочтения документов SPL я подозреваю, что RecursiveIteratorIterator может быть более подходящим для проблемы.
Извините за длинную ветку, но я уверен, что мой подход отстой. Любой совет?
Здесь вход (например, места я предпочел бы не быть), образец изображение, показывающее его в действии тоже:
stdClass Object
(
[condition] => OR
[rules] => Array
(
[0] => stdClass Object
(
[id] => Any
[field] => Any
[type] => string
[input] => select
[operator] => not equal
[value] => Any
)
[1] => stdClass Object
(
[condition] => AND
[rules] => Array
(
[0] => stdClass Object
(
[id] => Place
[field] => Place
[type] => string
[input] => select
[operator] => equal
[value] => France
)
[1] => stdClass Object
(
[id] => Month
[field] => Month
[type] => string
[input] => select
[operator] => equal
[value] => January
)
)
)
[2] => stdClass Object
(
[condition] => AND
[rules] => Array
(
[0] => stdClass Object
(
[id] => Place
[field] => Place
[type] => string
[input] => select
[operator] => equal
[value] => Rio
)
[1] => stdClass Object
(
[id] => Month
[field] => Month
[type] => string
[input] => select
[operator] => equal
[value] => August
)
)
)
[3] => stdClass Object
(
[condition] => AND
[rules] => Array
(
[0] => stdClass Object
(
[id] => Place
[field] => Place
[type] => string
[input] => select
[operator] => equal
[value] => Liberia
)
[1] => stdClass Object
(
[id] => Month
[field] => Month
[type] => string
[input] => select
[operator] => equal
[value] => July
)
[2] => stdClass Object
(
[condition] => OR
[rules] => Array
(
[0] => stdClass Object
(
[id] => Year
[field] => Year
[type] => string
[input] => select
[operator] => equal
[value] => 2014
)
[1] => stdClass Object
(
[id] => Year
[field] => Year
[type] => string
[input] => select
[operator] => equal
[value] => 2015
)
)
)
)
)
)
)
Здесь требуемый выход за настойчивость. (См. Значения в крайнем правом углу каждой записи для важных бит метаданных).
Array
(
stdClass Object ([id] => Any [field] => Any [type] => string [input] => select [operator] => not equal [value] => Any [condition] => OR [subgroup] => 0 [parent_subgroup] =>)
stdClass Object ([id] => Place [field] => Place [type] => string [input] => select [operator] => equal [value] => France) [condition] => AND [subgroup] => 1 [parent_subgroup] => 0)
stdClass Object ([id] => Month [field] => Month [type] => string [input] => select [operator] => equal [value] => January [condition] => AND [subgroup] => 1 [parent_subgroup] => 0)
stdClass Object ([id] => Place [field] => Place [type] => string [input] => select [operator] => equal [value] => Rio [condition] => AND [subgroup] => 2 [parent_subgroup] => 0)
stdClass Object ([id] => Month [field] => Month [type] => string [input] => select [operator] => equal [value] => August[condition] => AND [subgroup] => 2 [parent_subgroup] => 0)
stdClass Object ([id] => Place [field] => Place [type] => string [input] => select [operator] => equal [value] => Liberia [condition] => AND [subgroup] => 3 [parent_subgroup] => 0)
stdClass Object ([id] => Month [field] => Month [type] => string [input] => select [operator] => equal [value] => July[condition] => AND [subgroup] => 3 [parent_subgroup] => 0)
stdClass Object ([id] => Year [field] => Year [type] => string [input] => select [operator] => equal [value] => 2014 [condition] => OR [subgroup] => 4 [parent_subgroup] => 3)
stdClass Object ([id] => Year [field] => Year [type] => string [input] => select [operator] => equal [value] => 2015 [condition] => OR [subgroup] => 4 [parent_subgroup] => 3)
)
Примечание: анализирует это правильно. Проблемы возникли бы, если бы я изменил порядок подгрупп 2 и 3, так как подгруппа группы 3, имеющая правила (Год = 2014 ИЛИ Год = 2015), имеет другой уровень гнездования и сильно нарушает мою рекурсию.
Вот мой код:
function deserialize_criteria_group($criteria, $subgroup = null) {
$array = array();
if ($subgroup == null) {
$first_run = true;
$subgroup = 0;
$condition = $criteria->condition;
$criteria = $criteria->rules;
}
foreach ($criteria as $rule) {
if ($rule->rules) {
$subgroup++;
$children = $this->deserialize_criteria_group($rule->rules, $subgroup);
foreach($children as $child) {
if ($child->condition == null) {
$child->condition = $rule->condition;
}
if ($child->parent_subgroup == null) {
$child->parent_subgroup = $first_run ? 0 : $subgroup - 1;
}
array_push($array, $child);
}
} else {
$rule->condition = $condition;
$rule->subgroup = $subgroup;
$rule->parent_subgroup = null;
array_push($array, $rule);
}
}
if ($first_run) {
//Ensure a root node exists, if not stub one out.
$criteria_group = json_decode(json_encode($array), true);
$root_encountered = $criteria_group[0]['subgroup'] > 0 ? false : true;
if (!$root_encountered) {
$root = array( 'subgroup' => 0,
'parent_subgroup' => null,
'condition' => $condition);
array_unshift($criteria_group, $root);
array_unshift($array, $root);
}
//Ensure the ALM is not broken.
$subgroup = 0;
foreach($criteria_group as $c) {
if($c['subgroup'] > $subgroup + 1) {
$msg = "Bad Order. Halting execution.";
print $msg;
log_message('error', $msg);
log_message('debug', 'expected: ' . $subgroup . ' actual: ' . $c['subgroup']);
log_message('debug', print_r($criteria_group, true));
die;
}
$subgroup = $c['subgroup'];
}
}
return $array;
}