Creating php arrays from sql queries - php

I'm trying to create an array of arrays so I can build a dynamic menu, but I'm getting lost amongst the code. My output looks like this:
$menu = Array (
[0] => Array (
[text] => Home
[class] => 875
[link] => //Home
[show_condition] => TRUE
[parent] => 0
)
[1] => Array (
[text] => About
[class] => 326
[link] => //About
[show_condition] => TRUE
[parent] => 0
)
etc
etc
etc
[339] => Array (
[text] => Planner
[class] => 921
[link] => //Planner
[show_condition] => TRUE
[parent] => 45
)
)
And the two functions which should build the menu are:
function build_menu ( $menu ) {
$out = '<div class="container4">' . "\n";
$out .= ' <div class="menu4">' . "\n";
$out .= "\n".'<ul>' . "\n";
for ( $i = 1; $i <= count ( $menu )-1; $i++ )
{
if ( is_array ( $menu [ $i ] ) ) {//must be by construction but let's keep the errors home
if ( $menu [ $i ] [ 'show_condition' ] && $menu [ $i ] [ 'parent' ] == 0 ) {//are we allowed to see this menu?
$out .= '<li class="' . $menu [ $i ] [ 'class' ] . '"><a href="' . $menu [ $i ] [ 'link' ] . '">';
$out .= $menu [ $i ] [ 'text' ];
$out .= '</a>';
$out .= get_childs ( $menu, $i );
$out .= '</li>' . "\n";
}
}
else {
die ( sprintf ( 'menu nr %s must be an array', $i ) );
}
}
$out .= '</ul>'."\n";
$out .= "\n\t" . '</div>';
return $out . "\n\t" . '</div>';
}
function get_childs ( $menu, $el_id ) {
$has_subcats = FALSE;
$out = '';
$out .= "\n".' <ul>' . "\n";
for ( $i = 1; $i <= count ( $menu )-1; $i++ )
{
if ( $menu [ $i ] [ 'show_condition' ] && $menu [ $i ] [ 'parent' ] == $el_id ) {//are we allowed to see this menu?
$has_subcats = TRUE;
$add_class = ( get_childs ( $menu, $i ) != FALSE ) ? ' subsubl' : '';
$out .= ' <li class="' . $menu [ $i ] [ 'class' ] . $add_class . '"><a href="' . $menu [ $i ] [ 'link' ] . '">';
$out .= $menu [ $i ] [ 'text' ];
$out .= '</a>';
$out .= get_childs ( $menu, $i );
$out .= '</li>' . "\n";
}
}
$out .= ' </ul>'."\n";
return ( $has_subcats ) ? $out : FALSE;
}
But the menu is refusing to show any submenu levels - it only displays top level. Any ideas?
Thanks!

Your code is almost there - you may want to change mysql_fetch_array to mysql_fetch_assoc, and you can convert values as returned into the appropriate types using functions like intval:
$menu = array();
$sql = "SELECT TabName as text, TabID as class, TabPath as link, IsVisible as show_condition, ParentId as parent FROM dnn_SMA_Tabs WHERE PortalID = 3 AND IsVisible = 'True' ORDER BY TabOrder ASC";
$result = mysql_query($sql);
$index = 1;
while($row = mysql_fetch_assoc($result)) {
$row['parent'] = intval($row['parent']);
$menu[$index] = $row;
$index++;
}
You'll need to convert show_condition to the appropriate type - how to do that probably depends on what column type IsVisible is.

i see your array has indexes from [0] to [399]
Array (
[0] => Array (
[text] => Home
[class] => 875
[link] => //Home
[show_condition] => TRUE
[parent] => 0
)
[1] => Array (
[text] => About
[class] => 326
[link] => //About
[show_condition] => TRUE
[parent] => 0
)
etc
etc
etc
[339] => Array (
[text] => Planner
[class] => 921
[link] => //Planner
[show_condition] => TRUE
[parent] => 45
) )
but you try to show items from [1] to [340]
for ( $i = 1; $i <= count ( $menu ); $i++ )
count($menu) returns 340 ([0]->[399])
Solution: for ( $i = 0; $i < count ( $menu ); $i++ )
start from 0 and go until 399 (strictly < 340)

I would do it in an other way: object oriented.
class Menu {
private $children = array();
private $name = '';
private $link = '';
private $class = '';
private $show = TRUE;
function __construct($name, $class, $link, $show = TRUE, $parent = null) {
$this->name = $name;
$this->link = $link;
$this->class = $class;
$this->show = $show;
if(!is_null($parent)) {
$parent->addChild($this);
}
}
function addChild(Menu $child) {
$this->children[] = $child;
}
// ... remaining getters (and probably setters)
}
Then you can build the menu like this:
$home = new Menu('Home', '875', '//Home');
$about = new Menu('About', '326', '//About');
//...
$planner = new Menu('Planner', '921', '//Planner', true, $home);
$menu = array($home, $about,...);
This is just one example. I am aware that this would mean you create 340 variables to hold your menu. With other setter and getter methods you can do it better, this is just a fast 'sketch'.
You can build the menu like this:
function build_menu ( $menu, $showContainer = false) {
$out = '';
if($showContainer) {
$out = '<div class="container4">' . "\n";
$out .= ' <div class="menu4">' . "\n";
}
if(!empty($menu)) {
$out .= '<ul>' . "\n";
for ($entry in $menu) {
if($entry->getShow()) {//are we allowed to see this menu?
$out .= '<li class="' . $entry->getClass() . '"><a href="' . $entry->getLink() . '">';
$out .= $entry->getText();
$out .= '</a>';
$out .= "\n" . build_menu($entry->getChildren());
$out .= '</li>' . "\n";
}
}
$out .= '</ul>'."\n";
}
if($showContainer) {
$out .= "\n\t" . '</div>';
$out .= "\n\t" . '</div>';
}
return $out;
}
I didn't test the code, but this is the idea behind it. If you have no experience with OOP and php have a look at the official documentation.
And also note that this requires PHP5.

Related

How to merge 3 arrays keeping their meta key?

I'm Getting some arrays from some wordpress custom fields:
$content = array(get_post_meta($postId, 'content'));
$media = array(get_post_meta($postId, 'media'));
$yt = array(get_post_meta($postId, 'youtube'));
I then need to have it printing in sequence, like:
media
content
LInk
Embed
And repeat the sequence for each value
media
content
LInk
Embed
For the sequence I'd use this:
echo '<ul>';
for ($i = 0; $i < count($all_array['media']); $i++) {
for ($j = 0; $j < count($all_array['content']); $j++) {
for ($k = 0; $k < count($all_array['youtube']); $k++) {
echo '<li>media->' . $all_array['media'][$i] . '</li>';
echo '<li>content->' . $all_array['content'][$j] . '</li>';
echo '<li>link->' . $all_array['link'][$k] . '</li>';
}
}
}
echo '</ul>';
But I'm doing something wrong with the merging of the 3 fields as if I do a var_dump before to run the for bit, like
echo '<pre>' . var_export($all_array, true) . '</pre>';
Then this is what I get and I cannot iterate as I wish:
array (
0 =>
array (
0 =>
array (
0 => '
brother
',
1 => '
Lorem
',
2 => '
End it
',
),
1 =>
array (
0 => '337',
1 => '339',
),
2 =>
array (
0 => 'https://www.youtube.com/watch?v=94q6fzbJUfg',
),
),
)
Literally the layout in html that I'm looking for is:
image
content
link
image
content
link
...
UPDATE
This how I am merging the arrays:
foreach ( $content as $idx => $val ) {
$all_array[] = [ $val, $media[$idx], $yt[$idx] ];
}
This is the associative array how it looks like:
Content:
array (
0 =>
array (
0 => '
brother
',
1 => '
Lorem
',
2 => '
End it
',
),
)
Media
array (
0 =>
array (
0 => '337',
1 => '339',
),
)
Youtube
array (
0 =>
array (
0 => 'https://www.youtube.com/watch?v=94q6fzbJUfg',
),
)
The way I've resolved it is first I calculate the tot. items within each array, then I get the array with max items and loop and add the items in sequence:
//GET CUSTOM FIELDS
$content = get_post_meta($post_to_edit->ID, 'content', false);
$media = get_post_meta($post_to_edit->ID, 'media', false);
$yt = get_post_meta($post_to_edit->ID, 'youtube', false);
$max = max(count($content), count($media), count($yt));
$combined = [];
//
// CREATE CUSTOM FIELDS UNIQUE ARRAY
for($i = 0; $i <= $max; $i++) {
if(isset($media[$i])) {
$combined[] = ["type" => "media", "value" => $media[$i]];
}
if(isset($content[$i])) {
$combined[] = ["type" => "content", "value" => $content[$i]];
}
if(isset($yt[$i])) {
$combined[] = ["type" => "youtube", "value" => $yt[$i]];
}
}
Finally I can loop:
foreach ($combined as $key => $val) {
if($val['type'] === "media") {
...
}
if($val['type'] === "content") {
...
You don't need to merge the arrays together. It will work fine in separate arrays. However, your for loops don't have the right logic. Try:
for ($i = 0; $i < count($media); $i++) {
for ($j = 0; $j < count($media[$i]); $j++) {
echo '<li>media->' . $media[$i][$j] . '</li>';
}
for ($j = 0; $j < count($content[$i]); $j++) {
echo '<li>content->' . $content[$i][$j] . '</li>';
}
for ($j = 0; $j < count($youtube[$i]); $j++) {
echo '<li>link->' . $youtube[$i][$j] . '</li>';
}
}

How can I foreach this array object?

I want to foreach the game name and info and each game must filter as platform_name.
$list = (object)[];
$list->egame =
[
(object)['platform_name'=>'TT', 'game'=>(object)[(object)['game_name'=>'game1', 'info'=>'test1'],(object)['game_name'=>'game2', 'info'=>'test2'],(object)['game_name'=>'game3', 'info'=>'test3']]],
(object)['platform_name'=>'TG', 'game'=>(object)[(object)['game_name'=>'game4', 'info'=>'test4'],(object)['game_name'=>'game5', 'info'=>'test5']]],
(object)['platform_name'=>'TBIN', 'game'=>(object)[(object)['game_name'=>'game6', 'info'=>'test6']]]
];
?>
Try this
$list = (object)[];
$list->egame =
[
(object)['platform_name' => 'TT', 'game' => (object)[(object)['game_name' => 'game1', 'info' => 'test1'], (object)['game_name' => 'game2', 'info' => 'test2'], (object)['game_name' => 'game3', 'info' => 'test3']]],
(object)['platform_name' => 'TG', 'game' => (object)[(object)['game_name' => 'game4', 'info' => 'test4'], (object)['game_name' => 'game5', 'info' => 'test5']]],
(object)['platform_name' => 'TBIN', 'game' => (object)[(object)['game_name' => 'game6', 'info' => 'test6']]]
];
$arr = (array)$list->egame;
for ($i = 0; $i < count($arr); $i++) {
foreach ($arr[$i] as $key => $value) {
$aa = (array)$arr[$i]->game;
foreach ($aa as $k => $v) {
echo $aa[$k]->game_name." ".$aa[$k]->info."<br/>";
}
echo "<br/>";
}
}
Here You go:
<?php
$list = (object)[];
$list->egame =
[
(object)['platform_name'=>'TT', 'game'=>(object)[(object)['game_name'=>'game1', 'info'=>'test1'],(object)['game_name'=>'game2', 'info'=>'test2'],(object)['game_name'=>'game3', 'info'=>'test3']]],
(object)['platform_name'=>'TG', 'game'=>(object)[(object)['game_name'=>'game4', 'info'=>'test4'],(object)['game_name'=>'game5', 'info'=>'test5']]],
(object)['platform_name'=>'TBIN', 'game'=>(object)[(object)['game_name'=>'game6', 'info'=>'test6']]]
];
foreach ( $list->egame as $eg ) {
foreach ( $eg->game as $game ) {
echo "game: " . $game->game_name . " info: " . $game->info . "<br>";
}
}
?>
Edit #1
Includes platform:
foreach ( $list->egame as $eg ) {
foreach ( $eg->game as $game ) {
echo "platform: " . $eg->platform_name . " game: " . $game->game_name . " info: " . $game->info . "<br>";
}
}

Echo multidimensional array in a html table

I am having a multidimensional array with same values like this,
[documents] => Array
(
[0] => Array
(
[doc_id] => 3
[doc_type] => driving_licence
[expiry_date] => 2015-11-26
[added_date] => 2015-11-16
)
[1] => Array
(
[doc_id] => 3
[doc_type] => driving_licence
[expiry_date] => 2015-11-26
[added_date] => 2015-11-16
)
)
So now I need to echo this array in a html table with single <tr>.
This is how I tried it :
foreach ($userData as $key => $value) {
$i=0;
foreach ($value['documents'] as $k => $v) {
$i++;
$html = "<tr>\n";
$html .= " <td class='center'>{$i}</td>";
$html .= " <td>{$v['doc_type']}</td>";
$html .= " <td>{$v['expiry_date']}</td>";
$html .= " <td>{$v['added_date']}</td>";
$html .= "</tr>\n";
echo $html;
}
}
But its repeating table <tr> with same values.
Can anybody tell me how to avoid this?
Thank you.
As requested, here is an example for you.
$userData = $input = array_map("unserialize", array_unique(array_map("serialize", $userData)));
foreach ($userData as $key => $value) {
$i=0;
foreach ($value['documents'] as $k => $v) {
$i++;
$html = "<tr>\n";
$html .= " <td class='center'>{$i}</td>";
$html .= " <td>{$v['doc_type']}</td>";
$html .= " <td>{$v['expiry_date']}</td>";
$html .= " <td>{$v['added_date']}</td>";
$html .= "</tr>\n";
echo $html;
}
}
That will give you a table with 1 <tr> row.
this is the way i would do what you are trying to do:
$movies = array
(
array('Office Space' , 'Comedy' , 'Mike Judge' ),
array('Matrix' , 'Action' , 'Andy / Larry Wachowski' ),
array('Lost In Translation' , 'Comedy / Drama' , 'Sofia Coppola' ),
array('A Beautiful Mind' , 'Drama' , 'Ron Howard' ),
array('Napoleon Dynamite' , 'Comedy' , 'Jared Hess' )
);
echo "<table border=\\"1\\">";
echo "<tr><th>Movies</th><th>Genre</th><th>Director</th></tr>";
for ( $row = 0; $row < count($movies); $row++ )
{
echo "<tr><td>";
for ( $column = 0; $column < count($movies); $column++ )
{
echo $movies[$row][$column] ;
}
echo "<td></tr>";
}

Loop through json array and group by key values

After json_decode I have the following Array :::
$json = Array ( [name] => Array ( [0] => Peter [1] => David ) [dep] => Array ( [0] => accounts [1] => sales ) [date] => Array ( [0] => 10/27/2015 [1] => 09/25/2015 ) );
How can I group the values by key so I get the following in a PHP foreach loop ? :::
<ul>
<li>Peter, accounts, 10/27/2015</li>
<li>David, sales, 09/25/2015</li>
</ul>
I've tried a similar foreach loop ( see below ) without the desired results, I'm able to print all the key & value's but I'm not able to group values by key eg. [1] :::
foreach($json as $row){
foreach($row as $key=>$val){
echo $key . ': ' . $val . '<br>';
}
}
Any assistance would be appreciated :::
You could use the following code to sort the list:
<?php
$json = [
"name" => ["Peter","David"],
"dep" => ["accounts", "sales"],
"date" => ["10/27/2015","09/25/2015"]
];
$final = [];
foreach($json as $section)
{
foreach($section as $key=>$info)
{
if(!isset($final[$key])) $final[$key] = "";
$final[$key] .= $info . ", ";
}
}
echo "<ul>";
foreach($final as $row)
{
echo "<li>" . substr($row, 0, strlen($row) - 2) . "</li>"; // -2 to remove the extra ", "
}
echo "</ul>";
?>
Result:
<ul>
<li>Peter, accounts, 10/27/2015</li>
<li>David, sales, 09/25/2015</li>
</ul>
Perhaps try something like this:
$arrayCount = count($json['name']);
$output = '<ul>';
for($i = 0; $i < $arrayCount; $i++) {
$output .= '<li>';
$output .= $json['name'][$i] . ', ';
$output .= $json['dep'][$i] . ', ';
$output .= $json['date'][$i];
$output .= '</li>';
}
$output .= '</ul>';
echo $output;
You would also be better off using an array format like this:
$json =
Array(
Array(
'name' => 'Peter',
'dep' => 'accounts',
'date' => '10/27/2015'
),
Array(
'name' => 'David',
'dep' => 'accounts',
'date' => '09/25/2015'
)
);
This is because you can create a easier to understand foreach loop like this:
$output = '<ul>';
foreach($json as $row) {
$output .= '<li>';
$output .= $row['name'] . ', ';
$output .= $row['dep'] . ', ';
$output .= $row['date'];
$output .= '</li>';
}
$output .= '</ul>';
echo $output;

Problem to generate nested ul lists using PHP

I am working on a front-end web app where a nested unordered list would be used for the jQuery plugin mcdropdown.
Here is the data structure from PHP: a nested array of arrays :
Array
(
[0] => Array
(
[fullpath] => ../foil/alphanumeric/
[depth] => 0
)
[1] => Array
(
[fullpath] => ../foil/alphanumeric/letters/
[depth] => 1
)
[2] => Array
(
[fullpath] => ../foil/alphanumeric/numbers/
[depth] => 1
)
[3] => Array
(
[fullpath] => ../foil/alphanumeric/numbers/symbols/
[depth] => 2
)
)
Basically, I took the excellent answer from this question on SO, modified it a bit :
global $fullpaths; // $fullpaths contains the above data structure in print_r
$result = '';
$currentDepth = -1;
while(!empty($fullpaths))
{
$currentNode = array_shift($fullpaths);
if($currentNode['depth'] > $currentDepth)
{
$result .='<ul>';
}
if($currentNode['depth'] < $currentDepth)
{
$result .=str_repeat('</ul>', $currentDepth - $currentNode['depth']);
}
$result .= '<li>'. $currentNode['fullpath'] .'</li>';
$currentDepth = $currentNode['depth'];
if(empty($fullpaths))
{
$result .= str_repeat('</ul>', 1 + $currentDepth);
}
}
print $result;
and got the following output:
<ul>
<li>../foil/alphanumeric/</li>
<ul>
<li>../foil/alphanumeric/letters/</li>
<li>../foil/alphanumeric/numbers/</li>
<ul>
<li>../foil/alphanumeric/numbers/symbols/</li>
</ul>
</ul>
</ul>
Which cannot be accepted by the mcdropdown jQuery plugin, it expects something like this:
<li rel="1">
'Alphanumeric'
<ul>
<li rel="2">'Letters'</li>
<li rel="3">'Numbers'
<ul>
<li rel="4">'Symbols'</li>
</ul>
</li>
</ul>
</li>
To be frank, I don't quite understand how the answer from that question works, I have been trying to modify that solution to cope with my situation, but still failed.
Any help and suggestion is much appropriated in advance.
If you already have the correct depth values, then you don't need recursion. I have a similar function that I use for <ul>-<li>-generation:
function ulli($newlevel, &$level, $UL="ul", $once=1) {
if ($level == $newlevel) {
echo "</li>\n";
}
while ($level<$newlevel) {
$level++;
echo "\n <$UL>\n";
}
while ($level>$newlevel) {
if ($once-->0) { echo "</li>\n"; }
$level--;
echo " </$UL>"
. ($level>0 ? "</li>" : "") . "\n"; // skip for final </ul> (level=0)
}
}
It needs a current $level variable for reference (=$currentDepth). And you pass it your depth as $newlevel. It however needs the first depth to be 1.
Basic usage is like:
$currentDepth=0;
foreach ($array as $_) {
ulli($_["depth"]+1, $currentDepth);
echo "<li>$_[path]";
}
ulli(0, $currentDepth);
Well, quirky. But it worked for me.
Does this code (indentation apart) produces the result you want?
$d = array(
0 => array(
'fullpath' => '../foil/alphanumeric/',
'depth' => 0
),
1 => array(
'fullpath' => '../foil/alphanumeric/letters/',
'depth' => 1
),
2 => array(
'fullpath' => '../foil/alphanumeric/numbers/',
'depth' => 1
),
3 => array(
'fullpath' => '../foil/alphanumeric/numbers/symbols/',
'depth' => 2
)
);
echo "<ul>\n";
$cdepth = 0; $rel = 1; $first = true; $veryfirst = true;
foreach($d as $e)
{
$mpath = "'" . ucfirst(basename($e['fullpath'])) ."'";
if ( $e['depth'] == $cdepth ) {
if ( $first && !$veryfirst) { echo "</li>\n";}
echo "<li rel=\"$rel\">", $mpath;
$rel++; $first = false; $veryfirst = false;
} else {
$depthdiff = $e['depth'] - $cdepth;
if ( $depthdiff < 0 ) {
for($i = 0; $i < -$depthdiff; $i++) {
echo "</ul>\n</li>\n";
}
} else {
for($i = 0; $i < $depthdiff; $i++) {
echo "\n<ul>\n";
$first = true;
// indeed buggy if $depthdiff > 1...
}
}
echo "<li rel=\"$rel\">", $mpath, "\n";
$rel++; $first = true;
}
$cdepth = $e['depth'];
}
for($i = 0; $i < $cdepth; $i++) {
echo "</ul>\n</li>\n";
}
echo "</ul>\n";
EDITED code: Still not perfect but you can work on it... :D

Categories