У меня есть набор записей из MySQL, который возвращает идентификаторы категорий и их значения для заданных объектов. Например:
+-----------+-------------+----------------+
| object_id | category_id | category_value |
+-----------+-------------+----------------+
| 1 | 2 | VEGETARIAN |
| 1 | 3 | MATARÓ |
| 1 | 5 | MARCO POLO |
| 1 | 5 | JOHN DOE |
| 2 | 2 | VEGETARIAN |
| 2 | 3 | MATARÓ |
| 2 | 5 | JOHN DOE |
+-----------+-------------+----------------+
Имея это, мне понадобится следующий результирующий ассоциативный массив в PHP:
// They are arrays, so more than one object_id can be in the same category tree (and the object_id can be repeated across categories)
$final_array['VEGETARIAN']['MATARÓ']['MARCO POLO'] = array(1);
$final_array['VEGETARIAN']['MATARÓ']['JOHN DOE'] = array(1, 2);
Запрос сначала упорядочивает результаты object_id
а затем, по category_id
с установленным пользователем порядком. Итак, это было бы как ORDER BY object_id ASC, FIELD(category_id, usercat1, usercat2, usercat3)
(который в этом случае будет FIELD(category_id, 2, 3, 5)
,
У меня есть цикл, который проходит каждый набор, и я пытаюсь сохранить временную переменную для хранения уровней массива, потому что они могут изменяться (не всегда будет 3 уровня), так что-то вроде:
$temporary_array['VEGETARIAN'] = array();
$temporary_array = $temporary_array['VEGETARIAN'];
// And then, on the next iteration
$temporary_array['MATARÓ'] = array();
$temporary_array = $temporary_array['MATARÓ'];
// Now, $temporary_array would be equal to $temporary_array['VEGETARIAN']['MATARÓ'];
Таким образом, я могу создать главный ключ на основе новый значение категории, которое будет храниться как дочерний элемент родительского массива и получать все иерархическое дерево. Каждый уровень должен включать в себя все следующие.
Я пытался объявить это глобально и передать по ссылке, но, похоже, это не работает.
Есть ли способ добиться этого в PHP? Как бы вы сделали, чтобы получить желаемый результат?
РЕДАКТИРОВАТЬ:
Я был ближе к тому, чтобы изменить порядок категорий в обратном порядке, поэтому сначала я получаю последнюю категорию (ту, в которой нет других категорий) и иду вверх по массиву, что-то вроде этого:
// Long story very short, would be like
$final_array['new_category_value'] = $old_final_array;
И продолжай идти за каждым предметом. Когда я меняю object_id
тогда я сделаю:
array_merge_recursive($final_array, $actual_object_array);
Однако я до сих пор не могу получить желаемый результат.
Спасибо за ваше время и комментарии!
Предполагая, что вы можете обращаться к своим данным SQL как к ассоциативному массиву, и что значение «1» — это object_id (вместо «true / false 0/1 и т. Д.»), Что-то вроде этого:
$sth = $dbh->prepare("SELECT ......"); //Your SQL Here
$sth->execute();
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
Строки $ должны содержать что-то вроде этого:
$rows = array(
array(
"object_id" => 1,
"category_id" => 2,
"category_value" => "VEGETARIAN"),
array(
"object_id" => 1,
"category_id" => 3,
"category_value" => "MATARÓ"),
array(
"object_id" => 1,
"category_id" => 5,
"category_value" => "MARCO POLO"),
array(
"object_id" => 1,
"category_id" => 5,
"category_value" => "JOHN DOE")
);
С этого момента вы можете перебирать строки. То, что происходит с отдельной строкой, зависит от строки перед ней, поэтому сохраните и обновите переменную, содержащую ее, чтобы к ней можно было получить доступ в этом цикле
//Define your final array
$final_array = array();
//Store a reference to the last row in order to get the last category checked
$lastRow=null;
//Store reference to the last potential parent
$lastParent=&$final_array;
//Store a reference to the last entry - either an array or the object id
$lastEntry = null;//Loop over all returned rows
foreach($rows as $row) {
//If first time around loop, $lastRow will be null
//If $lastRow is not null, but matches this row's category_id, we should add to the same parent
if($lastRow===null || $lastRow['category_id']===$row['category_id']){
$lastParent[$row['category_value']] = $row['object_id'];
$lastEntry = &$lastParent[$row['category_value']];
//Note - Do not change last parent here
}
//lastCategoryId does not match this row's category ID and is not null, we must change the
// last entry to be an array and add this entry to it.
else {
$lastParent = &$lastEntry;
$lastParent = array($row['category_value'] => $row['object_id']);
$lastEntry = &$lastParent[$row['category_value']];
}//Loop complete, update the last row
$lastRow=$row;
}
Теперь вы можете проверить звонок print_r($final_array);
который возвращает:
Array
(
[VEGETARIAN] => Array
(
[MATARÓ] => Array
(
[MARCO POLO] => 1
[JOHN DOE] => 1
)
)
)
Других решений пока нет …