recursive function inside for loop - php

I m trying to create html in the controller instead of js.
There is an array with unknown depth of arrays.
$tree = $repo->childrenHierarchy();
and a function who reads the array and returns a string of html with values from array elements.
public function recursive($tree) {
$html = "";
foreach ($tree as $t) {
$html = $html . '<li> <span><i class="fa fa-lg fa-minus-circle"></i>' . $t['title'] . '</span>';
if ($t['__children'] != null) {
$html = $html . '<ul>';
$this->recursive($t['__children']);
$html = $html . '</ul>';
} else {
$html = $html . '</li>';
}
return $html;
}
My problem is that i cant hold the total string because everytime the function calls itself the var html is initialised, need to hold the string something like global but cant figure how.

After looking at this a little more, I don't think it really looks like a problem that the $html is initialized in the recursive calls. It seems to me that it actually should start as empty for the children. But it doesn't look like you're appending the children to the $html string you already have going. I think you need
$this->recursive($t['__children']);
to be instead
$html .= $this->recursive($t['__children']);

there shouldnt be anything wrong with just storing that value in class property while action ?
public $html = "";
public function recursive($tree) {
foreach ($tree as $t) {
$this->html = $this->html . '<li> <span><i class="fa fa-lg fa-minus-circle"></i>' . $t['title'] . '</span>';
if ($t['__children'] != null) {
$this->html = $this->html . '<ul>';
$this->recursive($t['__children']);
$this->html = $this->html . '</ul>';
} else {
$this->html = $this->html . '</li>';
}
return $this->html;
}

Related

Show to show php object um html modal

I'm trying to show a object in a html modal. Since I don't know the structure beforehand, and the child properties can also be objects or arrays, a simple recursive function seemed to be the way to go, but Im not sure. I have this:
<?php
class LogHelper extends Helper
{
public function warningLogError($body_error)
{
$data = [];
$html = '';
$html .= "<div name='bodyErrosr' class = 'form-group'>";
$html .= "<div class = 'alert alert-warning' role = 'alert'>";
if (!empty($body_error)) {
foreach($body_error as $key => $value) {
$html .= "<li><b>" . $key . "= " . $value. "</b></li>";
}
} else {
$html .= "<li><b>" . 'Error!' . "</b></li>";
}
$html .= "</ul>";
$html .= "</div>";
$html .= "</div>";
return $html;
}
}
But I don't know the structure beforehand, sometimes I receive an object inside object multiple times. How is the best way to do this?
Have a look at: https://packagist.org/packages/symfony/var-dumper
This also handles circular references (where print_r/vardump fail)

PHP foreach $output variation?

I need a little help on getting a rule in to output something else if a certain variable is called.
To break it down I have the following listed:
private $zebra_moto_symbol = array
( "ES400", "MC9500", "MC9200", "MC9190", "MC9094", "MC9090", "MC9097", "MC9060",;
and using this code it pulls the models into the page in a list:
public function manufacturer_models_list() {
$manu_name = $this->manufacturer_name;
$output = "<ul>";
sort($this->$manu_name);
foreach($this->$manu_name as $model) {
$output .= "<li>" . "" . $model . "</li>";
}
$output .= "</ul>";
$output .= "<p class=\"clear\"></p>";
$output .= "Arrange A Repair";
return $output;
}
On all but two of these, I need it display the repair.php link, however on two these need to be different. What would I need to input to make this happen?
Thanks in advance (sorry, this one stumped me).
:)
You can use a switch statement for this.
<?
public function manufacturer_models_list() {
$manu_name = $this->manufacturer_name;
$output = "<ul>";
sort($this->$manu_name);
foreach ($this->$manu_name as $model) {
switch($model) {
//Output NOT repair.php on this list of strings
case "ES400":
case "MC9500":
$output .= "<li>DIFFERENT OUTPUT</a></li>";
break;
//default is the action that happens if none of the previous conditions are met
default:
$output .= "<li>" . "" . $model . "</li>";
break;
}
}
$output .= "</ul>";
$output .= "<p class=\"clear\"></p>";
$output .= "Arrange A Repair";
return $output;
}
?>
Read more about Switch Statements
If I understood correctly, what you want is to have a different output on certain values.
I would think about have another array to hold the values that you want a different output and you can do something like this:
$different_output_array = ['ES400', 'MC9500']; # you can add new elements any time
and just modify your function to something like this:
public function manufacturer_models_list() {
$manu_name = $this->manufacturer_name;
$output = "<ul>";
sort($this->$manu_name);
foreach($this->$manu_name as $model) {
if(in_array($model,$different_output_array))
{
$output .= "<li>" . "" . $model . "</li>";
}
else
{
$output .= "<li>" . "" . $model . "</li>";
}
}
$output .= "</ul>";
$output .= "<p class=\"clear\"></p>";
$output .= "Arrange A Repair";
return $output;
}
Hope this can help.

Loop through two DOMNodeLists at once using DOMDocument class

I got an error saying
Object of class DOMNodeList could not be converted to string on line
This is the line which contains the error:
$output .= '<li><a target="_blank" href="' . $postURL . '">' .
$title->nodeValue . '</a></li>';
DOM
My code:
$postTitle = $xpath->query("//tr/td[#class='row1'][3]//span[1]/text()");
$postURL = $xpath->query("//tr/td[#class='row1'][3]//a/#href");
$output = '<ul>';
foreach ($postTitle as $title) {
$output .= '<li><a target="_blank" href="' . $postURL . '">' . $title->nodeValue . '</a></li>';
}
$output .= '</ul>';
echo $output;
How can I resolve the error?
You're fetching two independent node list from the DOM, iterate the first and try to use the second one inside the loop as a string. A DOMNodeList can not be cast to string (in PHP) so you get an error. Node lists can be cast to string in Xpath however.
You need to iterate the location path that is the same for booth list (//tr/td[#class='row1'][3]) and get the $title and $url inside the loop for each of the td elements.
$posts = $xpath->evaluate("//tr/td[#class='row1'][3]");
$output = '<ul>';
foreach ($posts as $post) {
$title = $xpath->evaluate("string(.//span[1])", $post);
$url = $xpath->evaluate("string(.//a/#href)", $post);
$output .= sprintf(
'<li><a target="_blank" href="%s">%s</a></li>',
htmlspecialchars($url),
htmlspecialchars($title)
);
}
$output .= '</ul>';
echo $output;

Variable data behaving strangely inside a function

I am working on a CodeIgniter application.
A part of the nav menu for my application is generated from using session data. Since, I have to print the same thing at a number of places, I wrote a function to do the printing. The file which creates the menu is given below. The function print_roles_assigned() is used a number of times in this file.
$roles_assigned = $this->session->userdata('roles_assigned');
function print_roles_assigned() {
$output = '';
if ($roles_assigned)
{
foreach ($roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
The code given above didn't work. Out of any options, I resorted to using a $GLOBAL. An issue like this has never happened with me before and I am not sure if the use of $GLOBAL is appropriate. The new code is given below:
$GLOBALS['roles_assigned'] = $this->session->userdata('roles_assigned'); // Change made here
function print_roles_assigned() {
$output = '';
$roles_assigned = $GLOBALS['roles_assigned']; // Using the global variable inside function
if ($roles_assigned)
{
foreach ($roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
I would like to know:
Why my initial code failed to work?
Is the use of $GLOBAL appropriate?
What can be an alternate method to fix this issue?
The initial code failed because your $roles_assigned in not injected. Parameterise the function to "function print_roles_assigned($roles_assigned) { .. } " to access the $roles_assigned variable.
Why my initial code failed to work?
Each function has what is called variable scope. Variables declared outside of the function are not accessible from within the function unless they are passed in as parameters, are members of a class that the function is a member of, or are explicitly declared to be global.
There are three different ways to do this, take your pick.
The easiest way to do this is to just pass the function in as a parameter I.E.
$roles_assigned = $this->session->userdata('roles_assigned');
function print_roles_assigned($roles_assigned) {
$output = '';
if ($roles_assigned)
{
foreach ($roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
Another option is to make $roles_assigned a member of the class, I.E.
$this->roles_assigned = $this->session->userdata('roles_assigned');
function print_roles_assigned() {
$output = '';
if ($this->roles_assigned)
{
foreach ($this->roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
The other option (not recommended) is to use the global keyword I.E.
$roles_assigned = $this->session->userdata('roles_assigned');
function print_roles_assigned() {
global $roles_assigned;
$output = '';
if ($roles_assigned)
{
foreach ($roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
This sounds like a scope issue. Try using $this->roles_assigned for your reference to that array.
IMO, it's not good-practise to use GLOBAL in this way.

My nested anchor tags won't nest?

I'm trying to build my site's navigation using recursion and I can't seem to get the <div> tags to nest properly. I'm not even sure if this code is the path I should go down, but It's a start. The desired output:
<div class="parent">1</div>
<div class="child">
1.1
1.2
1.3
</div>
<div class="parent">2</div>
<div class="child">
2.1
2.2
2.3
</div>
Here is my database:
Here's the code I'm trying to get working: (THIS CODE NEEDS A LOT OF WORK)
/* here's the call */
$this->buildNav($array,NULL,false);
private function buildNav($array,$parent,$loop)
{
$html = '';
$class = ($loop) ? 'child' : 'parent';
$tag = '<div>%s</div>';
$child = false;
foreach($array as $item)
{
if($item['parent']===$parent)
{
$child = true;
$html .= '<div>'.$item['category_name'];
$html .= $this->buildNav($array,$item['category_id'],true);
$html .= '</div>';
$html .= ''.$item['category_name'].'';
}
if(!$child)
{
$tag = '';
}
}
return sprintf($tag,$html);
}
UPDATE
Per shapeshifter's advice I went away from recursion and just called a function to get the children ... beautiful idea ;) Here's the code:
private function buildNav($array,$parent)
{
$html = '';
foreach($array as $item)
{
if($item['parent'] === NULL)
{
$html .= '<div class="parent">'.$item['category_name'].'</div>';
$html .= '<div class="child">'.$this->getChildren($array,$item['category_id']).'</div>';
}
}
return $html;
}
private function getChildren($array,$parent)
{
$html = '';
foreach($array as $item)
{
if($item['parent']===$parent)
{
$html .= ''.$item['category_name'].'';
}
}
return $html;
}
Thanks again to the others who provided such profound alternatives and or direction ;)

Categories