Converting PHP array in HTML list - php

I have the array below which I would like to output in a specific HTML list format.
My PHP array is as follow:
Array
(
[MAIN] => Master Product
[ID1] => Array
(
[0] => Product 1
)
[ID2] => Array
(
[0] => Product 2
[ID3] => Array
(
[0] => Product 3
)
[ID4] => Array
(
[0] => Product 4
)
)
)
The HTML list format I am looking for is as follows.
<ul id="treeview">
<li>Master Product
<ul>
<li>Product 1</li>
<li>Product 2
<ul>
<li>Product 3</li>
<li>Product 4</li>
</ul>
</li>
</ul>
</li>
</ul>
Any help would be appreciated.

Try this on for size:
function recurseTree($var){
$out = '<li>';
foreach($var as $v){
if(is_array($v)){
$out .= '<ul>'.recurseTree($v).'</ul>';
}else{
$out .= $v;
}
}
return $out.'</li>';
}
echo '<ul>'.recurseTree($yourDataArrayHere).'</ul>';

$data = array(); // your data
function toUL($data=false, $flatten=false){
$response = '<ul>';
if(false !== $data) {
foreach($data as $key=>$val) {
$response.= '<li>';
if(!is_array($val)) {
$response.= $val;
} else {
if(!$flatten){
$response.= toUL($val);
} else {
// pulls the sub array into the current list context
$response.= substr($response,0,strlen($response)-5) . toUL($val);
}
}
$response.= '</li>';
}
}
$response.= '</ul>';
return $response;
}
// Test #1 -- named values
echo toUL(array('a'=>'b','c'=>'d','e'=>array('f'=>'g')));
// Result #1
b
d
g
// Test #2 -- value lists
echo toUL(array('a','b','c',array('d','e','f')));
// Result #2
a
b
c
d
e
f

Inspired from this answer but where leaves are surounded by <li>
function recurseTree($var)
{
$out = '';
foreach ($var as $v) {
if (is_array($v)) {
$out .= '<ul>'.recurseTree($v).'</ul>';
} else {
$out .= '<li>'.$v.'</li>';
}
}
return $out;
}
And if you have associative array you can try this function:
function recurseTree($var)
{
$out = '';
foreach($var as $k => $v){
if (is_array($v)) {
$out .= '<dl>'.self::recurseTree($v).'</dl>';
} else {
$out .= '<dt>'.$k.'</dt>'.'<dd>'.$v.'</dd>';
}
}
return $out;
}

Related

Created alphabetical list in php [duplicate]

I have an array that already contains all it's values in alphabetical order:
Alligator
Alpha
Bear
Bees
Banana
Cat
Cougar
Now I just want to list the first letter each starts with above it like so:
A
---
Alligator
Alpha
B
---
Bear
Bees
Banana
C
---
Cat
Cougar
etc...
How can this be done?
The solution is to keep in a variable the first letter of the previously printed word, like:
$previous = null;
foreach($array as $value) {
$firstLetter = substr($value, 0, 1);
if($previous !== $firstLetter) echo "\n".$firstLetter."\n---\n\n";
$previous = $firstLetter;
echo $value."\n";
}
NB: if some entries start with a lower-case letter and others with upper-case letters, use the strcasecmp function in the test instead of !==.
here is another simple solution:-
$result = array();
foreach ($list as $item) {
$firstLetter = substr($item, 0, 1);
$result[$firstLetter][] = $item;
}
echo "<pre>"; print_r($result);
Output :-
Array (
[A] => Array
(
[0] => Alligator
[1] => Alpha
)
[B] => Array
(
[0] => Bear
[1] => Bees
[2] => Banana
)
[C] => Array
(
[0] => Cat
[1] => Cougar
)
)
Well i have three solutions.
1) Make another array containing all alphabets. Then use foreach to iterate through this array. And in nested foreach check for occurance of that letter through strpos method of php.
Here is rough code.
<?php
$alphabets = array ("A","B","C"....); //for all alphabtes
foreach($alphabets as $alphabet)
{
echo $alphabet;
foreach($myArray as $arr)
{
$pos = strpos($arr, $alphabet);
if($pos===flase)
{
//do nothing
}
else
{
echo $arr;
}
}
?>
2) second method have same logic as above. But here you dont need to make array for alphabets. You can get all alphabets this way.
<?php
foreach(range('a', 'z') as $letter) {
echo $letter;
}
?>
Php range method
3) Third solution also have same logic as above two. Here you can get alphabets by another way :)
for ($i=65; $i< =90; $i++) {
$x = chr($i);
print $x;
}
For HTML output:
<h3>A</h3>
<ol>
<li>
<em>tag count</em>
Animal
</li>
<li>
<em>tag count</em>
Aqua
</li>
<li>
<em>tag count</em>
Arthur
</li>
</ol>
<!-- if B not EXIST not show B -->
<h3>C</h3>
<ol>
<li>
<em>tag count</em>
Camel
</li>
<li>
<em>tag count</em>
Crazy
</li>
</ol>
<!-- etc -->
I change Artefact2 code and share for you
<?php $previous = null;
foreach ($dataProvider as $key => $tag) {
$firstLetter = strtoupper(substr($tag['name'], 0, 1));
if($previous !== $firstLetter) {
if($key != 0) {
echo '</ol>';
}?>
<h3 class="alpha">
<span><?php echo $firstLetter;?></span>
</h3>
<ol class="tags main">
<?php } ?>
<li class="tag">
<em><?php echo $tag['TagsCount']; ?></em>
<a href="<?php echo $tag['slug']; ?>">
<strong><?php echo ucfirst($tag['name']); ?></strong>
</a>
<span class="perc" style="width: 90px;"></span>
</li>
<?php if($key == count($dataProvider)-1) {
echo '</ol>';
}
$previous = $firstLetter;
}
?>
Best Regards www.Forum.iSYSTEMS.am
Iterate through the array and check if the current item starts with another letter than the previous one. If that's the case print your "A ---".
$currentLetter = '';
foreach ($list as $item) {
$firstLetter = substr($item, 0, 1);
if ($firstLetter !== $currentLetter) {
echo $firstLetter . "\n---\n";
$currentLetter = $firstLetter;
}
echo $item . "\n";
}
As Shivansh said above in his answer, I think that is correct way
$result = array();
foreach ($list as $item) {
$firstLetter = substr($item, 0, 1);
$result[$firstLetter][] = $item;
}
echo "<pre>"; print_r($result);
To Display the array generated by this code use
foreach ( $list as $key => $value ) {
//Do some thing with $key (A,B,C)
foreach ($value as $var){
//Do some thing with $var (Array of A, B ,C)
}
}

Looping into a multidimensional array with PHP

I've got this array:
Array
(
[0] => Array
(
[name] => System
[order] => 1
[icon] => stats.svg
[0] => Array
(
[title] => Multilingual
)
[1] => Array
(
[title] => Coloring
)
[2] => Array
(
[title] => Team work
)
[3] => Array
(
[title] => Tutorials
)
)
)
I want to loop into this to show the section name and after all the features containing in the following array.
So, this is what I made:
foreach ($features as $feature => $info) {
echo '
'.$info['name'].'
<ul class="menu-vertical bullets">
';
foreach (array_values($info) as $i => $key) {
echo '
<li>'.$key['title'].'</li>
';
}
echo '
</ul>
';
}
It works except for the first third <li> where I have the first char of name, order and icon value.
Do you know why ?
Thanks.
array_values return value of array so for info values is name, order, icon, 0, 1, ...
Your values foreach is wrong if you just want print title you can use:
foreach ($features as $feature => $info) {
echo '
'.$info['name'].'
<ul class="menu-vertical bullets">
';
//Remove some keys from info array
$removeKeys = array('name', 'order', 'icon');
$arr = $info;
foreach($removeKeys as $key) {
unset($arr[$key]);
}
foreach (array_values($arr) as $i => $key) {
echo '
<li>'.$key['title'].'</li>
';
}
echo '
</ul>
';
}
In php, array_values means all the values of the array. So array_values($info) is array($info['name'], $info['order'], $info['icon'], $info[0], $info[1], $info[2], $info[3])
in your example, you can skip the non-integer keys of the $info to get your titles:
<?php
$features = array();
$info = array();
$info['name'] = 'System';
$info['order'] = 1;
$info['icon'] = 'stats.svg';
$info[] = array('title'=>'Multilingual');
$info[] = array('title'=>'Coloring');
$features[] = $info;
foreach ($features as $feature => $info) {
echo $info['name'] . PHP_EOL;
echo '<ul class="menu-vertical bullets">' . PHP_EOL;
foreach ($info as $k => $item) {
if(!is_int($k)) continue;
echo '<li>' . $item['title'] . '</li>' . PHP_EOL;
}
echo '</ul>' . PHP_EOL;
}
BUT, your original data structure is not well designed and hard to use. For a better design, you can consider the following code, move your items to a sub array of $info:
<?php
$features = array();
$info = array();
$info['name'] = 'System';
$info['order'] = 1;
$info['icon'] = 'stats.svg';
$info['items'] = array();
$info['items'][] = array('title'=>'Multilingual');
$info['items'][] = array('title'=>'Coloring');
$features[] = $info;
foreach ($features as $feature => $info) {
echo $info['name'] . PHP_EOL;
echo '<ul class="menu-vertical bullets">' . PHP_EOL;
foreach ($info['items'] as $item) {
echo '<li>' . $item['title'] . '</li>' . PHP_EOL;
}
echo '</ul>' . PHP_EOL;
}
Sample output of the two demos:
System
<ul class="menu-vertical bullets">
<li>Multilingual</li>
<li>Coloring</li>
</ul>
It works except for the first third li where I have the first char of name, order and icon value. Do you know why ?
Why you see first chars of the values of 'name', 'order', 'icon'? Let see how PHP works.
Take the first loop as an example: foreach (array_values($info) as $i => $key)
Then $i == 0, $key == 'System'
We know that $key[0] == 'S', $key[1] == 'y', $key[2] == 's', etc.
Then you try to access $key['title'], but the string 'title' is not valid as a string offset, so it is converted to an integer by PHP: intval('title') == 0.
Then $key['title'] == $key[intval('title')] == 'S'
That's what you see.
array_value() returns the values of the array, here you will get the value of the array $info and what I understand is that is not what you need. See details for array_value().
You can check if the key for the $info is an integer. if yes, echo the title. Give this a try.
foreach ($features as $feature => $info) {
echo $info['name'].'<ul class="menu-vertical bullets">';
foreach ($info as $key => $value) {
if (is_int($key)) {
echo '<li>'.$key['title'].'</li>';
}
}
echo '</ul>';
}

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);

adding a parents parameter to a recursive element

I'm building a menu and i need to have the parents keys on my generated sub items
The function looks like this:
function get_menu($tagmenu){
$menu="";
$count=0;
foreach ($tagmenu as $key => $value) {
$is_active=false;
$class="";
if(isset($_GET["tagsearch"])){
if($key == $_GET["tagsearch"]){
$is_aktive=true;
};
};
$menu.= "<ul>";
$sub="";
if(is_array($value)){
if (count($value)>0) {
$sub.= "<div class='submenu'>";
$sub.=get_menu($value);
$sub.= "</div>";
}
}
$li= "<li class='menuitem'><a href='?tagsearch=".$key."'>".$key."</a>";
if (strpos($sub,"'menuitem active'")!==false || $is_active ) {
$li=str_replace("'menuitem'", "'menuitem active'", $li);
}
$menu.=$li.$sub;
$menu.= "</li>";
$menu.= "</ul>";
}
return $menu;
}
And this is the array;
Array(
[fotografie] => Array(
[schwarzweiss] => Array(
[street] => Array()
)
)
)
Is it possible with this stucture to add all keys of the parent array to the link?
At the end it should look like
Yes, it is. You need to add second parameter to recursive function, in which you pass current string.
function get_menu($tagmenu, $shortcut = array())
{
$menu="";
$count=0;
foreach ($tagmenu as $key => $value)
{
$shortcut[] = $key;
$is_active=false;
$class="";
if(isset($_GET["tagsearch"]))
{
if($key == $_GET["tagsearch"])
{
$is_aktive=true;
};
};
$menu.= "<ul>";
$sub="";
if(is_array($value))
{
if (count($value)>0)
{
$sub.= "<div class='submenu'>";
$sub.=get_menu($value, $shortcut);
$sub.= "</div>";
}
}
$li= "<li class='menuitem'>".$key."";
if (strpos($sub,"'menuitem active'")!==false || $is_active )
{
$li=str_replace("'menuitem'", "'menuitem active'", $li);
}
$menu.=$li.$sub;
$menu.= "</li>";
$menu.= "</ul>";
}
return $menu;
}
echo get_menu(
array(
'fotografie' => array(
'schwarzweiss' => array(
'street' => array()
)
)
)
);
You have had already href attribute on the link, so I've used class attr to show you the example.
Demo: http://sandbox.onlinephpfunctions.com/code/184eaa428de75511eda1ffee8f8ad08b82a03919

Nested lists using PHP's iterator?

I'm trying to display this kind of array:
$nodes = array(
1 => array(
'title' => 'NodeLvl1',
'children' => array(),
),
2 => array(
'title' => 'NodeLvl1',
'children' => array(
1 => array(
'title' => 'NodeLvl2',
'children' => array(),
),
2 => array(
'title' => 'NodeLvl2',
'children' => array(
1 => array(
'title' => 'NodeLvl3',
'children' => array(),
),
2 => array(
'title' => 'NodeLvl3',
'children' => array(),
),
),
),
),
),
3 => array(
'title' => 'NodeLvl1',
'children' => array(),
),
);
like this:
<ul>
<li>
NodeLvl1
</li>
<li>
NodeLvl1
<ul>
<li>NodeLv2</li>
...
</ul>
</li>
...
Basically a nested list taking into account the "children" property. So far I've come up with this:
class It extends RecursiveIteratorIterator{
protected
$tab = "\t";
public function beginChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
}
public function endChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth())."\n</ul>";
}
public function nextElement(){
echo str_repeat($this->tab, $this->getDepth() + 1).'<li>';
}
}
$it = new It(new RecursiveArrayIterator($nodes));
foreach($it as $key => $item)
echo $item;
Which doesn't work quite right: I get each item wrapped between <ul>s and I don't know how can I close <li>s...
Any ideas on how to make this work? Also is it possible to get all the array properties (the actual element), instead of just the "title" property inside my foreach() loop? And can this be done with objects instead of arrays?
Do you need a class iterator for this? You could do this with just a simple function...
function arrayToListHTML($array, $level = 0) {
static $tab = "\t";
if (empty($array)) return;
$tabs = str_repeat($tab, $level * 2);
$result = "{$tabs}<ul>\n";
foreach ($array as $i => $node):
$result .= "{$tabs}{$tab}<li>\n{$tabs}{$tab}{$tab}{$node['title']}\n".arrayToListHTML($node['children'], $level + 1)."{$tabs}{$tab}</li>\n";
endforeach;
$result .= "{$tabs}</ul>\n";
return $result;
}
Which will produce this output:
<ul>
<li>
NodeLvl1
</li>
<li>
NodeLvl1
<ul>
<li>
NodeLvl2
</li>
<li>
NodeLvl2
<ul>
<li>
NodeLvl3
</li>
<li>
NodeLvl3
</li>
</ul>
</li>
</ul>
</li>
<li>
NodeLvl1
</li>
</ul>
This covers what you've shown us, but I'm not sure what you mean by other properties. Are there more properties in each array other than title and children?
Instead of trying to use your class like an array in foreach() consider using your class to perform the function. For instance, the following code will output correctly but the function is performed inside the class.
class It extends RecursiveIteratorIterator{
protected
$tab = "\t";
public function beginChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
}
public function endChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth)."\n</ul>";
}
public function nextElement(){
echo str_repeat($this->tab, $this->getDepth())."<li>".$this->current()."</li>\n";
}
}
$it = new It(new RecursiveArrayIterator($nodes));
foreach($it as $key => $item)
//echo $item;
//it will be better to write a function inside your custom iterator class to handle iterations
?>
You can use RecursiveCachingIterator to do what you want. Here is an example, (source: https://github.com/cballou/PHP-SPL-Iterator-Interface-Examples/blob/master/recursive-caching-iterator.php)
<?php
// example navigation array
$nav = array(
'Home' => '/home',
'Fake' => array(
'Double Fake' => array(
'Nested Double Fake' => '/fake/double/nested',
'Doubly Nested Double Fake' => '/fake/double/doubly'
),
'Triple Fake' => '/fake/tripe'
),
'Products' => array(
'Product 1' => '/products/1',
'Product 2' => '/products/2',
'Product 3' => '/products/3',
'Nested Product' => array(
'Nested 1' => '/products/nested/1',
'Nested 2' => '/products/nested/2'
)
),
'Company' => '/company',
'Privacy Policy' => '/privacy-policy'
);
class NavBuilder extends RecursiveIteratorIterator {
// stores the previous depth
private $_depth = 0;
// stores the current iteration's depth
private $_curDepth = 0;
// store the iterator
protected $_it;
/**
* Constructor.
*
* #access public
* #param Traversable $it
* #param int $mode
* #param int $flags
*/
public function __construct(Traversable $it, $mode = RecursiveIteratorIterator::SELF_FIRST, $flags = 0)
{
parent::__construct($it, $mode, $flags);
// store the caching iterator
$this->_it = $it;
}
/**
* Override the return values.
*
* #access public
*/
public function current()
{
// the return output string
$output = '';
// set the current depth
$this->_curDepth = parent::getDepth();
// store the difference in depths
$diff = abs($this->_curDepth - $this->_depth);
// get the name and url of the nav item
$name = parent::key();
$url = parent::current();
// close previous nested levels
if ($this->_curDepth < $this->_depth) {
$output .= str_repeat('</ul></li>', $diff);
}
// check if we have the last nav item
if ($this->hasNext()) {
$output .= '<li>' . $name . '';
} else {
$output .= '<li class="last">' . $name . '';
}
// either add a subnav or close the list item
if ($this->hasChildren()) {
$output .= '<ul>';
} else {
$output .= '</li>';
}
// cache the depth
$this->_depth = $this->_curDepth;
// return the output ( we could've also overridden current())
return $output;
}
}
?>
Usage
<?php
try {
// generate the recursive caching iterator
$it = new RecursiveCachingIterator(new RecursiveArrayIterator($nav));
// build the navigation with the iterator
$it = new NavBuilder($it, RecursiveIteratorIterator::SELF_FIRST);
// display the resulting navigation
echo '<ul id="nav">' . PHP_EOL;
foreach ($it as $value) {
echo $value . "\n";
}
echo '</ul>' . PHP_EOL;
} catch (Exception $e) {
var_dump($e); die;
}
?>
First let me explain few things to you. Your array has two pattens
One with numeric indexes
One with string indexes, with title and children which has be parsed differently
I think a recursive function plays very nice role on this part, rather than complex logics. And our recursive function has to be able to handle both patterns separately.
Here is my version of the function you could use with explanation
function arraytolist(Array $array) { //ensure what you receive is array
if(count($array)) { //only if it has some items
//In case the array has `title` index we encountered out PATTERN 2
if(isset($array['title'])) {
$o = "<li>";
$o .= $array['title']; //simply add the title
$o .= arraytolist($array['children']); //and pass the children to this function to verify again
$o .= "</li>";
} else { //if its a normal array, //PATTERN 1
$o = "<ul>";
foreach($array as $value) {
$n = "";
if(is_array($value)) { //in case its an array again,
//send it to this very same function so that it will return as output again
$n .= arraytolist($value);
} else {
$n .= "<li>$value</li>";
}
$o .= strlen($n) ? $n : ""; //if $n has something use it otherwise not
}
$o .= "</ul>"; //lets close the ul
}
return $o;
}
}
Some Advantage of this function
No iteration level
As long as its an array and has item, keeps on building them
Power of simple logic in PHP
I would opt for a simple recursive function that flattens the array into the text/html format:
function arrToList( $arr, $embedded = false ) {
$output = array();
if ( $embedded ) $output[] = '<li>';
$output[] = '<ul>';
foreach ( $arr as $key => $values ) {
$output[] = '<li>'.$values['title'].'</li>';
if ( $values['children'] ) {
$output[] = arrToList( $values['children'], true );
}
}
$output[] = '</ul>';
if ( $embedded ) $output[] = '</li>';
return implode(PHP_EOL, $output);
}
Output from using your input:
NodeLvl1
NodeLvl1
NodeLvl2
NodeLvl2
NodeLvl3
NodeLvl3
NodeLvl1
or the actual code:
<ul>
<li>NodeLvl1</li>
<li>NodeLvl1</li>
<li>
<ul>
<li>NodeLvl2</li>
<li>NodeLvl2</li>
<li>
<ul>
<li>NodeLvl3</li>
<li>NodeLvl3</li>
</ul>
</li>
</ul>
</li>
<li>NodeLvl1</li>
</ul>
Cheers

Categories