How can I convert a hierarchical tree to parent-child relationships? - php

At the moment, i'm creating a dynamic menu for my own CMS (practising) in PHP, but I don't know to save the data in my database.
Database structure:
menuitem_id
menu_id
menuitem_order
menuitem_name
menuitem_page_id
parent_menuitem_id
I do get this output as a hierarchical tree, but that isn't the desired format for storing it into my database:
Array
(
[0] => Array
(
[id] => 2
)
[1] => Array
(
[id] => 1
[children] => Array
(
[0] => Array
(
[id] => 3
[children] => Array
(
[0] => Array
(
[id] => 4
)
[1] => Array
(
[id] => 5
)
)
)
[1] => Array
(
[id] => 6
)
)
)
)
However, I want to convert this to a parent ID array with new fresh ID's (I will truncate the table and insert new data). Something like this:
Array
(
[0] => 0
[1] => 0
[2] => 2
[3] => 3
[4] => 3
[5] => 2
)
How can this be done?
Note: i have read this article, but I need the opposite code of it.

You need a recursive function:
function flattenHierarchicalArray($arr, $parentId = null) {
$items = array();
foreach ($arr as $item) {
$items[] = array('id' => $item['id'], 'parentId' = $parentId);
if (isset($item['children'])) $items = array_merge($items, flattenHierarchicalArray($item['children'], $item['id']));
}
return $items;
}

I think I have the solution combined with AlliterativeAlice's PHP code.
I'm using the Nestable plugin. That extension creates my hierarchical tree and sets it in a hidden field in my form (done by JavaScript). I updated this code to create new IDs by adding this code:
var nestable_update = function(e){
//added for updating old IDs
$(".dd-item").each(function(index){
$(this).data("id", index+1);
});
var list = e.length ? e : $(e.target),
output = list.data("output");
if (window.JSON) {
output.val(window.JSON.stringify(list.nestable("serialize")));
} else {
output.val("JSON browser support required for this demo.");
}
};
$(".dd").nestable({
maxDepth:5
}).on("change", nestable_update);
nestable_update($(".dd").data("output", $("#nestable_output")));
I used your PHP code for getting the parentID (many thanks to AlliterativeAlice, because it's more efficient than my original PHP code):
function flatten_hierarchical_tree($arr, $parent_id=0) {
$items = array();
foreach ($arr as $item) {
$items[] = array('id' => $item['id'], 'parent_id' => $parent_id);
if (isset($item['children'])) $items = array_merge($items, flatten_hierarchical_tree($item['children'], $item['id']));
}
return $items;
}

For those who are interested in my final code. It works for storing the data in the database and build it again into a hierarchical tree + a printable tree for HTML.
JavaScript code for the nestable plugin:
var nestable_update = function(e){
$(".dd-item").each(function(index){
$(this).data("id", index+1);
});
var list = e.length ? e : $(e.target),
output = list.data("output");
if (window.JSON) {
output.val(window.JSON.stringify(list.nestable("serialize")));
} else {
output.val("JSON browser support required for this demo.");
}
};
$(".dd").nestable({
maxDepth:5
}).on("change", nestable_update);
nestable_update($(".dd").data("output", $("#nestable_output")));
Database structure:
menuitem_id
menu_id
menuitem_order
menuitem_name
menuitem_page_id
parent_menuitem_id
PHP functions for building trees (format storing data in database + format getting data from database):
function create_flatten_hierarchical_tree($tree, $parent_id=0) {
$items = array();
foreach ($tree as $item) {
$items[] = array("id" => $item["id"], "parent_id" => $parent_id);
if (isset($item["children"])) $items = array_merge($items, create_flatten_hierarchical_tree($item["children"], $item["id"]));
}
return $items;
}
function create_hierarchical_tree($tree, $root=0) {
$return = array();
foreach($tree as $child => $parent) {
if($parent["parent_menuitem_id"] == $root) {
if(isset($tree[$child]["menuitem_id"]) === true){
$parent['children'] = create_hierarchical_tree($tree, $tree[$child]["menuitem_id"]);
}
unset($tree[$child]);
$return[] = $parent;
}
}
return empty($return) ? null : $return;
}
function print_hierarchical_tree($tree, $rows_pages) {
if(!is_null($tree) && count($tree) > 0) {
$return .= "<ol class='dd-list'>";
foreach($tree as $item){
$options = "";
foreach($rows_pages as $row_pages){
$selected = "";
if($row_pages["page_id"] == $item["menuitem_page_id"]){
$selected = "selected";
}
$options .= "<option value='".$row_pages["page_id"]."' $selected>".$row_pages["friendly_url"]."</option>";
}
$return .= "<li class='dd-item' data-id='".$item["menuitem_id"]."'><div class='dd-handle'>drag</div><div class='item_wrapper'><div class='item'><div class='item_title'>".$item["menuitem_name"]."</div></div><div class='item_sub'><div class='label_input'><label for='menuitem_name".$item["menuitem_id"]."'>Menuitem name</label><input type='text' id='menuitem_name".$item["menuitem_id"]."' name='menuitem_name[]' value='".$item["menuitem_name"]."' /></div><div class='label_input'><label for='page_link".$item["menuitem_id"]."'>Page link</label><label class='select'><select id='page_link".$item["menuitem_id"]."' name='menuitem_page_id[]'>".$options."</select></label></div> <a onClick='delete_menuitem(".$item["menuitem_id"].");' class='button red_bg delete'>Delete</a></div></div>";
$return .= print_hierarchical_tree($item["children"], $rows_pages);
$return .= "</li>";
}
$return .= "</ol>";
}
return empty($return) ? null : $return;
}
Core code of menu_edit.php page:
<?php
$stmt_menuitems = $dbh->prepare("SELECT * FROM inno_mw_thurs_menuitems mi WHERE mi.menu_id=:menu_id");
$stmt_menuitems->bindParam(":menu_id", $_GET["menu_id"]);
$stmt_menuitems->execute();
if (!empty($stmt_menuitems->rowCount())) {
?>
<div class="dd">
<?php
$result = $stmt_menuitems->fetchAll();
$tree = create_hierarchical_tree($result);
$stmt_pages = $dbh->prepare("SELECT * FROM inno_mw_thurs_pages");
$stmt_pages->execute();
$rows_pages = $stmt_pages->fetchAll();
$tree = print_hierarchical_tree($tree, $rows_pages);
echo $tree;
?>
</div>
<?php
}
Core code of menu_edit_process.php page:
if(isset($_POST["menu_id"])){
$menu_id = $_POST["menu_id"];
$nestable_output = json_decode($_POST["nestable_output"], true);
$parent_menuitem_ids_arr = create_flatten_hierarchical_tree($nestable_output);
$stmt = $dbh->prepare("TRUNCATE TABLE inno_mw_thurs_menuitems");
$stmt->execute();
$stmt = $dbh->prepare("INSERT INTO inno_mw_thurs_menuitems (menu_id, menuitem_order, menuitem_name, menuitem_page_id, parent_menuitem_id) VALUES (:menu_id, :menuitem_order, :menuitem_name, :menuitem_page_id, :parent_menuitem_id)");
$menuitem_order_arr = array();
foreach($_POST["menuitem_name"] as $f => $name){
$menuitem_name = $_POST["menuitem_name"][$f];
$menuitem_page_id = $_POST["menuitem_page_id"][$f];
$parent_menuitem_id = $parent_menuitem_ids_arr[$f]["parent_id"];
if(array_key_exists($parent_menuitem_id, $menuitem_order_arr) && $parent_menuitem_id != 0){
$menuitem_order_arr[$parent_menuitem_id] += 1;
}
else{
$menuitem_order_arr[$parent_menuitem_id] = 0;
}
$stmt->bindParam(":menu_id", $menu_id);
$stmt->bindParam(":menuitem_order", $menuitem_order_arr[$parent_menuitem_id]);
$stmt->bindParam(":menuitem_name", $menuitem_name);
$stmt->bindParam(":menuitem_page_id", $menuitem_page_id);
$stmt->bindParam(":parent_menuitem_id", $parent_menuitem_id);
$stmt->execute();
}
header("location: menus_list.php");
}
Please, feel free to improve this code.

Related

replace values of keys in json1 from Json2

I am very very new to php.. actually i am from java domain. But, i have to do some work in php for integration. My scenario is, i have one json array which will have 4 keys for ex:
one json --> {"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}.
I will be getting another JSON which ever edited from admin panel. for example if i updated any key, only that key will coming in the
second JSON --> for ex: {"blog_heading":"def"}
Now, i have to replace the value of second json to first json. example output for above scenario like I am very very new to php.. actually i am from java domain. But, i have to do some work in php for integration. My scenario is, i have one json array which will have 4 keys for ex:
output json --> {"id":7,"active":1,"blogId":"abc","blog_heading":"def"}.
So i am trying as below,
$id = json_decode($data_string);
$id2 = json_encode($post);
$id5 = json_decode($id2);
$id6 = array();
foreach ($id as $key => $value)
{
$log->debug($key . ': ' . $value);
if (array_key_exists($key, $id5->data)) {
$log->debug($key . 'element is in the array');
$log->debug($value . 'element is in the array');
//array_push($id5, "apple", "raspberry");
$id3 = array($key => $value);
$id3[$key] = $value;
$log->debug($id3);
}else{
$log->debug($key . 'element is not in the array');
}
}
$id7 = json_encode($id2);
$log->debug($id7);
id5 data is : $id5
DEBUG - 2017-06-05T02:26:20-04:00 - stdClass Object
(
[meta] => stdClass Object
(
[table] => story
[type] => item
)
[data] => stdClass Object
(
[id] => 7
[active] => 1
[blogId] => abc
[blog_heading] => xyz
)
)
==================
Log of $id :
stdClass Object
(
[active] => 1
[blog_heading] => def
[id] => 7
)
Please suggest me how can i achieve this... Anything i am doing wrong here
Please try that:
$j1 = '{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}';
$j2 = '{"blog_heading":"def"}';
$result = json_encode(
array_merge(
json_decode($j1, true),
json_decode($j2, true)
)
);
<?php
$json1='{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}';
$json2='{"blog_heading":"def"}';
$json1=json_decode($json1);
$json2=json_decode($json2);
foreach ($json1 as $key => $value) {
if($json2->$key){
$json1->$key=$json2->$key;
}
}
$json1=json_encode($json1);
$json2=json_encode($json2);
If you have only one element in array,Do like this
$a = json_decode('{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}',true);
$b = json_decode('{"blog_heading":"def"}',true);
$a['blog_heading'] = $b['blog_heading'];
print_r($a);
If you have multiple element like this :
$c = json_decode('[{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"},
{"id":8,"active":1,"blogId":"abc","blog_heading":"xyz"}]',true);
$d = json_decode('[{"blog_heading":"def"},{"blog_heading":"hello"}]',true);
$return = array();
for ($i=0; $i < count($c); $i++) {
$c[$i]['blog_heading'] = $d[$i]['blog_heading'];
$return[] = $c[$i];
}
print_r($return);
If you want to replace value by specific id
$c = json_decode('[{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"},
{"id":8,"active":1,"blogId":"abc","blog_heading":"xyz"}]',true);
$d = json_decode('[{"id":7,"blog_heading":"def"},{"id":9,"blog_heading":"hello"}]',true);
$return = array();
for ($i=0; $i < count($c); $i++) {
if($d[$i]['id'] == $c[$i]['id']) {
$c[$i]['blog_heading'] = $d[$i]['blog_heading'];
}
$return[] = $c[$i];
}
print_r($return);
Checking dynamic key value pair :
$c = json_decode('[{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"},
{"id":8,"active":1,"blogId":"abc","blog_heading":"xyz"}]',true);
$d = json_decode('[{"id":6,"blog_heading":"def"},{"id":9,"blog_heading":"hello"}]',true);
$return = array();
for ($i=0; $i < count($c); $i++) {
$result = array_intersect_key($c[$i], $d[$i]);
foreach ($result as $key => $value) {
$c[$i][$key] = $d[$i][$key];
}
$return[] = $c[$i];
}
print_r($return);
Check demo here

Not sure why my tree building function is returning an empty array?

I'm taking a flat array and creating a tree from it using the following function, but it always returns an empty array ($branch = array()) on this set of data.
public static function buildTree($activities, $parent = 0)
{
$branch = array();
foreach ($activities as $activity) {
if ($activity['in_reply_to'] == $parent) {
$children = self::buildTree($activities, $activity['activity_id']);
if ($children) {
$activity['children'] = $children;
}
$branch[] = $activity;
}
}
return $branch;
}
And here's the data set.
Array
(
[0] => Array
(
[activity_id] => 583069095760826322
[in_reply_to] => 583068167603269635
)
[1] => Array
(
[activity_id] => 583068167603269635
[in_reply_to] => 582781728499965991
)
)
in_reply_to references the activity_id.
So, you can see that 0 is actually a child of 1.
We don't have the data for the parent of 1, so that should just be ignored based on the function.
Anyway, this is always returning an empty array and I'm not sure why.
Your problem is not on the code but on your data, you don't have a root node with "in_reply_to" = 0
Try to execute your code with this data set:
$activities = array(
array("activity_id" => 583069095760826322, "in_reply_to" => 583068167603269635),
array("activity_id" => 583068167603269635, "in_reply_to" => 0)
);
Assuming your activity_id-field is auto incrementing r otherwise ordered, then you can find the lowest id inside your activities-array with this function and use it as the root.
public static function findLowestActivityID($activities)
{
$id = null;
foreach ($activities as $activity) {
if ($id === null || $id > $activity['activity_id']) {
$id = $activity['activity_id'];
}
}
return $id;
}
Example-Call:
$rootID = YourClassName::findLowestActivityID($activities);
$result = YourClassName::buildTree($activities, $rootID);

Category Hierarchy (PHP/MySQL) in Yii

I found this here: Category Hierarchy (PHP/MySQL)
And i want to display that code, but it is not working correctly.
I got the following Hierarchy:
-Airsoft
--Scopes
That's all. But the code is displaying:
-Airsoft
--Scopes (So far so good)
-Scopes <--- this one should not be here!
Here's the code:
public static function producten(){
$connection=Yii::app()->db; // assuming you have configured a "db" connection
$sql = 'SELECT id, parent, naam FROM categories ORDER BY naam';
$command=$connection->createCommand($sql);
$dataReader=$command->query();
$refs = array();
foreach ($dataReader as $row)
{
$ref = & $refs[$row['id']];
$ref['parent'] = $row['parent'];
$ref['naam'] = $row['naam'];
if ($row['parent'] == NULL)
{
$list[$row['id']] = & $ref;
}
else
{
$refs[$row['parent']]['children'][$row['id']] = & $ref;
}
}
function toUL(array $array)
{
$html = '<ul>' . PHP_EOL;
foreach ($array as $value)
{
$html .= '<li>' . $value['naam'];
if (!empty($value['children']))
{
$html .= toUL($value['children']);
}
$html .= '</li>' . PHP_EOL;
}
$html .= '</ul>' . PHP_EOL;
return $html;
}
print_r($refs);
echo toUL($refs);
}
The print_r() in there is displaying:
Array ( [1] => Array ( [parent] => [naam] => Airsoft [children] => Array ( [2] => Array ( [parent] => 1 [naam] => Scopes ) ) ) [2] => Array ( [parent] => 1 [naam] => Scopes ) )
Can somebody figure out what's wrong with the code and help me please?
You can try this:
$connection=Yii::app()->db; // assuming you have configured a "db" connection
$sql = 'SELECT id, parent, naam FROM categories ORDER BY naam';
$command=$connection->createCommand($sql);
$dataReader=$command->queryAll();
function createList($elements, $parentId = 0) {
$branch = array();
foreach ($elements as $element) {
if ($element['parent'] == $parentId) {
$children = createList($elements, $element['id']);
if ($children) {
$element['children'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
$list = createList($dataReader);
CVarDumper::dump($list, 5678, true);

PHP comparing 2 arrays of arrays

Hi All I have 2 arrays for example in PHP as seen below:
[users] => Array ( [0] => Array ( [username] => Timothy ) [1] => Array ( [username] => Frederic ) )
[users2] => Array ( [0] => Array ( [username] => Johnathon ) [1] => Array ( [username] => Frederic ) [] => Array ( [username] => Peter))
I am trying to compare the contents of each array against each other in order to put a html element, I tried using a nested foreach as seen below:
foreach($users as $user){
foreach ($users2 as $user2){
if($user['username'] == $user2['username']){
echo "<option value=' ".$user['username']."' selected = 'selected'>".$user['username']."</option>";
break;
} else{
echo "<option value=' ".$user['username']."'>".$user['username']."</option>";
}
}
}
my issue is that the items are being echoed more than once which is ruining my select element. Any ideas on how to compare the contents of each?
I want to achieve a list of each name eg:
-Timothy
-Frederic (this should be highlighted as it is in both arrays)
-Johnathon
- Peter
I would take it in a different way.
//Create user array one
$users = array();
$users[] = array('username'=>'Timothy');
$users[] = array('username'=>'Frederic');
//create user array 2
$users2 = array();
$users2[] = array('username'=>'Johnathon');
$users2[] = array('username'=>'Frederic');
$users2[] = array('username'=>'Peter');
$temp_array = array();
foreach($users as $key => $value) {
$temp_array[$value['username']] = '';
}
foreach($users2 as $key => $value) {
$temp_array[$value['username']] = array_key_exists($value['username'], $temp_array) ? 'DUPLICATE' : null;
}
echo '<select>';
foreach($temp_array as $key_value => $status) {
echo "<option value='{$key_value}' ".(($status == 'DUPLICATE') ? 'selected style="background-color: yellow;"' : '').">{$key_value}</option>";
}
echo '</select>';
I'll let the array take care of it self, if it shares the same key, it will merge, then just flag it with "duplicate".
If there is never any duplicates as you say in each array, the following works for me. This may look a bit complicated, but read through my comments.
You can copy the code and run it in it's own page to see if it works the way you want.
<?php
//Create user array one
$users = array();
$users[] = array('username'=>'Timothy');
$users[] = array('username'=>'Frederic');
//create user array 2
$users2 = array();
$users2[] = array('username'=>'Johnathon');
$users2[] = array('username'=>'Frederic');
$users2[] = array('username'=>'Peter');
//create a new array to combine all of the data, yes, there will be duplicates
$allData = array();
//add to allData array
foreach ($users as $user) {
$allData[] = $user['username'];
}
//add to allData array
foreach ($users2 as $user2) {
$allData[] = $user2['username'];
}
//create an array that will hold all of the duplicates
$dups = array();
//add any duplicates to the array
foreach(array_count_values($allData) as $val => $c) {
if($c > 1) $dups[] = $val;
}
//remove the duplicates from the allData array
$allData = array_unique($allData);
//echo out form
echo '<select>';
foreach ($allData as $user) {
if (in_array($user, $dups)) {
echo "<option value=' ".$user."' selected = 'selected'>".$user."</option>";
}
else {
echo "<option value=' ".$user."'>".$user."</option>";
}
}
echo '</select>';
?>
However, I'm not sure what your intentions are since IF you had "Peter" and "Frederic" in BOTH arrays, you are not going to get the form you want. But, this works for what you wanted.

how to pick different keys and values from 2 arrays in php and alter the same?

I have two array like
previous:
Array(
[name] => [asdfg]
[city] => [anand]
)
current:
Array(
[name] => [ud]
[state] => [anand]
)
Now i have to compare these two array and want to alter the changed current array key or values and wrap the elements like
Array(
[name] => [<span class='bold_view'> ud </span>]
[<span class='bold_view'> state </span>] => [anand]
)
$current['name']="<span class='bold_view'> ".$current['name']." </span>";
$current['<span class='bold_view'> state </span>']=$current['state'];
I have to say that it doesn't make much sense but here it is..
Copy this code and just execute : and see the view source (Ctrl+u)
<?php
$prev = array("name"=>"[asdfg]","city"=>"[anand]");
$curent = array("name"=>"[ud]","state"=>"[anand]");
$res = array();
foreach($prev as $key=>$val){
$res[$key] = $val;
if(array_key_exists($key,$curent)){
$res[$key] = "[<span class='bold_view'> ".$curent[$key]." </span>]";
}
if($new_key = array_search($val,$curent)){
unset($res[$key]);
$res["<span class='bold_view'> ".$new_key." </span>"] = $val;
}
}
print_r($res);
?>
$arr_pre = array(
"name"=>"asdfg",
"city"=>"anand",
"address" => "anand",
);
$arr_current= array(
"name"=>"ud",
"state"=>"anand",
"address" => "ananda"
);
$result = array_diff_assoc($arr_current,$arr_pre);
$count_curr = array_count_values($arr_current);
$count_old = array_count_values($arr_pre);
foreach ($result as $key => $value){
if(!array_key_exists($key,$arr_pre ))
{
$key_new = "<b>".$key."</b>";
if(!in_array($value,$arr_pre))
{
$val = "<b>".$value."</b>";
}
else if((isset($count_curr[$value]) != isset($count_old[$value])))
{
$val = "<b>".$value."</b>";
}
else
{
$val = $value;
}
unset($arr_current_info[$key]);
}
else {
$key_new = $key;
if(!in_array($value,$arr_pre))
{
$val = "<b>".$value."</b>";
}
else if((isset($count_curr[$value]) != isset($count_old[$value])))
{
$val = "<b>".$value."</b>";
}
else
{
$val = $value;
}
}
$arr_current_info[$key_new]=$val;
}
echo "<pre>";
print_r($arr_current_info);
I have done like this and i got perfect answer

Categories