Recursive php menu - php

I have been searching around for some time but cannot seem to find an answer to my problem.
I have a deep nested array that I need to turn into a nested menu.
https://gist.github.com/anonymous/98e0dcf4f2aef40a1da6
I would like it to end up as something like the following.
https://gist.github.com/anonymous/a0dd4c7d047f11a5ce82
class foo {
function NavigationBuild($routes, $child = false) {
if ($child) {
foreach($routes as $route = > $row) {
if (is_array($row['children'])) {
$output. = self::NavigationBuild($row['children'], true);
} else {
$output. = "<li>".$val['route']."MEEEEE</li>";
}
}
} else {
$output. = '<ul>';
foreach($routes as $route = > $row) {
if (!strlen($row['parent'])) {
$output. = "<li>".$route."</li>";
}
foreach($row['children'] as $key = > $val) {
if (is_array($val['children'])) {
$output. = self::NavigationBuild($val['children'], true);
} else {
$output. = "<li>".$val['route']."MEEEEE</li>";
}
}
}
$output. = '</ul>';
}
return $output;
}
}

Figured it out - seems some sleep was needed.
Thanks to all USEFUL input

Related

output and call array from class function (rollingcurl)

Excuse my English, please.
I use Rollingcurl to crawl various pages.
Rollingcurl: https://github.com/LionsAd/rolling-curl
My class:
<?php
class Imdb
{
private $release;
public function __construct()
{
$this->release = "";
}
// SEARCH
public static function most_popular($response, $info)
{
$doc = new DOMDocument();
libxml_use_internal_errors(true); //disable libxml errors
if (!empty($response)) {
//if any html is actually returned
$doc->loadHTML($response);
libxml_clear_errors(); //remove errors for yucky html
$xpath = new DOMXPath($doc);
//get all the h2's with an id
$row = $xpath->query("//div[contains(#class, 'lister-item-image') and contains(#class, 'float-left')]/a/#href");
$nexts = $xpath->query("//a[contains(#class, 'lister-page-next') and contains(#class, 'next-page')]");
$names = $xpath->query('//img[#class="loadlate"]');
// NEXT URL - ONE TIME
$Count = 0;
$next_url = "";
foreach ($nexts as $next) {
$Count++;
if ($Count == 1) {
/*echo "Next URL: " . $next->getAttribute('href') . "<br/>";*/
$next_link = $next->getAttribute('href');
}
}
// RELEASE NAME
$rls_name = "";
foreach ($names as $name) {
$rls_name .= $name->getAttribute('alt');
}
// IMDB TT0000000 RLEASE
if ($row->length > 0) {
$link = "";
foreach ($row as $row) {
$tt_info .= #get_match('/tt\\d{7}/is', $doc->saveHtml($row), 0);
}
}
}
$array = array(
$next_link,
$rls_name,
$tt_info,
);
return ($array);
}
}
Output/Return:
$array = array(
$next_link,
$rls_name,
$tt_info,
);
return ($array);
Call:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
function get_match($regex, $content, $pos = 1)
{
/* do your job */
preg_match($regex, $content, $matches);
/* return our result */
return $matches[intval($pos)];
}
require "RollingCurl.php";
require "imdb_class.php";
$imdb = new Imdb;
if (isset($_GET['action']) || isset($_POST['action'])) {
$action = (isset($_GET['action'])) ? $_GET['action'] : $_POST['action'];
} else {
$action = "";
}
echo " 2222<br /><br />";
if ($action == "most_popular") {
$popular = '&num_votes=1000,&production_status=released&groups=top_1000&sort=moviemeter,asc&count=40&start=1';
if (isset($_GET['date'])) {
$link = "https://www.imdb.com/search/title?title_type=feature,tv_movie&release_date=,".$_GET['date'].$popular;
} else {
$link = "https://www.imdb.com/search/title?title_type=feature,tv_movie&release_date=,2018".$popular;
}
$urls = array($link);
$rc = new RollingCurl([$imdb, 'most_popular']); //[$imdb, 'most_popular']
$rc->window_size = 20;
foreach ($urls as $url) {
$request = new RollingCurlRequest($url);
$rc->add($request);
}
$stream = $rc->execute();
}
If I output everything as "echo" in the class, everything is also displayed. However, I want to call everything individually.
If I now try to output it like this, it doesn't work.
$stream[0]
$stream[1]
$stream[3]
Does anyone have any idea how this might work?
Thank you very much in advance.
RollingCurl doesn't do anything with the return value of the callback, and doesn't return it to the caller. $rc->execute() just returns true when there's a callback function. If you want to save anything, you need to do it in the callback function itself.
You should make most_popular a non-static function, and give it a property $results that you initialize to [] in the constructor.. Then it can do:
$this->results[] = $array;
After you do
$rc->execute();
you can do:
foreach ($imdb->results as $result) {
echo "Release name: $result[1]<br>TT Info: $result[2]<br>";
}
It would be better if you put the data you extracted from the document in arrays rather than concatenated strings, e.g.
$this->$rls_names = [];
foreach ($names as $name) {
$this->$rls_names[] = $name->getAttribute('alt');
}
$this->$tt_infos = [];
foreach ($rows as $row) {
$this->$tt_infos[] = #get_match('/tt\\d{7}/is', $doc->saveHtml($row), 0);
}
$this->next_link = $next[0]->getAttribute('href'); // no need for a loop to get the first element of an array

PHP - recursive function foreach

I would to create a recursive function in order to retrieve data from an array and to organize then.
However I have some difficulties to create the right logic. The principle must be apply to any sub level until it ends or nothing is found.
I want to prevent this kind of code by repeating a foreach inside a foreach...:
$cats = get_categories($args);
$categories = array();
foreach($cats as $cat){
$parent = $cat->category_parent;
if ($parent) {
$categories['child'][$parent][$cat->cat_ID] = $cat->name;
} else {
$categories['parent'][$cat->cat_ID] = $cat->name;
}
}
}
if (isset($categories['parent']) && !empty($categories['parent'])) {
foreach($categories['parent'] as $id => $cat){
$new_cats[$id]['title'] = $cat;
if (isset($categories['child'][$id])) {
foreach($categories['child'][$id] as $child_id => $child_cat){
$new_cats[$child_id]['title'] = $child_cat;
$new_cats[$child_id]['parent_id'] = $id;
if (isset($categories['child'][$child_id])) {
foreach($categories['child'][$child_id] as $sub_child_id => $sub_child_cat){
$new_cats[$sub_child_id]['title'] = $sub_child_cat;
$new_cats[$sub_child_id]['parent_id'] = $child_id;
}
}
}
}
}
}
}
May be this code help you to get idea for formatting your desired array format.
<?php
// Main function
function BuildArr($arr)
{
$formattedArr = array();
if(!empty($arr))
{
foreach($arr as $val)
{
if($val['has_children'])
{
$returnArr = SubBuildArr($val['children']); // call recursive function
if(!empty($rs))
{
$formattedArr[] = $returnArr;
}
}
else
{
$formattedArr[] = $val;
}
}
}
return $formattedArr;
}
// Recursive Function( Build child )
function SubBuildArr($arr)
{
$sub_fortmattedArr = array();
if(!empty($arr))
{
foreach($arr as $val)
{
if($val['has_children'])
{
$response = SubBuildArr($val['children']); // call recursive
if(!empty($response))
{
$sub_fortmattedArr[] = $response;
}
}
else
{
$sub_fortmattedArr[] = $arr;
}
}
return $sub_fortmattedArr;
}
}
?>
I use this code for my previous project for generating categories that upto n-th level

Faster way of doing this?

I have the following code, but it runs the foreach loop one at a time. Is there a way of making them all run at once?
foreach($json['orders']['cnr_output_ship_to_header'] as $header)
{
$orders_array[] = $header;
$guests_array[] = $header['guests']['cnr_output_guest_detail'];
$items_array[] = $header['items']['cnr_output_item_detail'];
}
foreach($guests_array as $guests)
{
pdo_insert('cnr_output_guest_detail', (array)$guests);
}
foreach($items_array as $items)
{
pdo_insert('cnr_output_item_detail', (array)$items);
}
foreach($orders_array as $orders)
{
pdo_insert('cnr_output_ship_to_header', (array)$orders);
}
This should work just fine
foreach ( $json['orders']['cnr_output_ship_to_header'] as $header ) {
pdo_insert('cnr_output_guest_detail', (array) $header['guests']['cnr_output_guest_detail']);
pdo_insert('cnr_output_item_detail', (array) $header['items']['cnr_output_item_detail']);
pdo_insert('cnr_output_ship_to_header', (array) $header);
}
why not this:
foreach($json['orders']['cnr_output_ship_to_header'] as $header) {
//$orders_array[] = $header;
pdo_insert('cnr_output_ship_to_header', (array)$header);
//$guests_array[] = $header['guests']['cnr_output_guest_detail'];
pdo_insert('cnr_output_guest_detail', (array)$header['guests']['cnr_output_guest_detail']);
//$items_array[] = $header['items']['cnr_output_item_detail'];
pdo_insert('cnr_output_item_detail', (array)$header['items']['cnr_output_item_detail']);
}

drupal: getting nodeautoterm node ids from taxonomy ids

I'm using drupal's NAT module and need to get the nid from the term id.
Here's what I tried:
foreach ( (array)nat_get_nids($termid) as $natid ) {
$NatName = $natid->name;
}
print $natid;
This does not work.
Node auto term's get nid function is like this:
function nat_get_nids($tids, $get_nodes = FALSE) {
static $nid_cache = NULL;
static $node_cache = NULL;
$return = array();
// Keep processing to a minimum for empty tid arrays.
if (!empty($tids)) {
// Sort tid array to ensure that the cache_string never suffers from order
// issues.
sort($tids);
$cache_string = implode('+', $tids);
if ($get_nodes) {
if (isset($node_cache[$cache_string])) {
return $node_cache[$cache_string];
}
elseif (isset($nid_cache[$cache_string])) {
// If the nid cache stores the same string, node_load() each nid and
// return them.
$return = array();
foreach (array_keys($nid_cache[$cache_string]) as $nid) {
$return[$nid] = node_load($nid);
}
$node_cache[$cache_string] = $return;
return $return;
}
}
else {
if (isset($nid_cache[$cache_string])) {
return $nid_cache[$cache_string];
}
elseif (isset($node_cache[$cache_string])) {
// If the node cache stores the same string, retrieve only the nids and
// return them.
foreach ($node_cache[$cache_string] as $nid => $node) {
$return[$nid] = $node->name;
}
// Cache extracted results.
$nid_cache[$cache_string] = $return;
return $return;
}
}
// Results have not been cached.
$tids = implode(', ', $tids);
$result = db_query("SELECT n.nid, t.name FROM {nat} n INNER JOIN {term_data} t USING (tid) WHERE n.tid IN (". db_placeholders($tids) .")", $tids);
while ($node = db_fetch_object($result)) {
if ($get_nodes) {
$return[$node->nid] = node_load($node->nid);
}
else {
$return[$node->nid] = $node->name;
}
}
if ($get_nodes) {
$node_cache[$cache_string] = $return;
}
else {
$nid_cache[$cache_string] = $return;
}
}
return $return;
}
Thanks in advance!
Edit: Try based on the first answer:
foreach (nat_get_nids($termid) as $nid => $node_name) {
}
print $node_name;
It looks like nat_get_nids is returning an associative array, so your for loop should look like
foreach (nat_get_nids($termid) as $nid => $node_name) {
...
}
$nids = nat_get_nids(array($termid));

PHP Warning Help?

I keep getting the following warning listed below on line 3.
Warning: Invalid argument supplied for foreach()
Here is the php code.
function dyn_menu($parent_array, $sub_array, $qs_val = "menu", $main_id = "nav", $sub_id = "subnav", $extra_style = "foldout") {
$menu = "<ul id=\"".$main_id."\">\n";
foreach ($parent_array as $pkey => $pval) {
if (!empty($pval['count'])) {
$menu .= " <li><a class=\"".$extra_style."\" href=\"".$pval['link']."?".$qs_val."=".$pkey."\">".$pval['label']."</a></li>\n";
} else {
$menu .= " <li>".$pval['label']."</li>\n";
}
if (!empty($_REQUEST[$qs_val])) {
$menu .= "<ul id=\"".$sub_id."\">\n";
foreach ($sub_array as $sval) {
if ($pkey == $_REQUEST[$qs_val] && $pkey == $sval['parent']) {
$menu .= "<li>".$sval['label']."</li>\n";
}
}
$menu .= "</ul>\n";
}
}
$menu .= "</ul>\n";
return $menu;
}
Here is the whole code I'm working on.
$mysqli = new mysqli("localhost", "root", "", "sitename");
$dbc = mysqli_query($mysqli,"SELECT id, label, link_url, parent_id FROM dyn_menu ORDER BY parent_id, id ASC");
if (!$dbc) {
// There was an error...do something about it here...
print mysqli_error();
}
while ($obj = mysqli_fetch_assoc($dbc)) {
if (empty($obj['parent_id'])) {
echo $parent_menu . $obj['id']['label'] = $obj['label'];
echo $parent_menu . $obj['id']['link'] = $obj['link_url'];
} else {
echo $sub_menu . $obj['id']['parent'] = $obj['parent_id'];
echo $sub_menu . $obj['id']['label'] = $obj['label'];
echo $sub_menu . $obj['id']['link'] = $obj['link_url'];
echo $parent_menu . $obj['parent_id']++;
}
}
mysqli_free_result($dbc);
function dyn_menu($parent_array, $sub_array, $qs_val = "menu", $main_id = "nav", $sub_id = "subnav", $extra_style = "foldout") {
$menu = "<ul id=\"".$main_id."\">\n";
foreach ($parent_array as $pkey => $pval) {
if (!empty($pval['count'])) {
$menu .= " <li><a class=\"".$extra_style."\" href=\"".$pval['link']."?".$qs_val."=".$pkey."\">".$pval['label']."</a></li>\n";
} else {
$menu .= " <li>".$pval['label']."</li>\n";
}
if (!empty($_REQUEST[$qs_val])) {
$menu .= "<ul id=\"".$sub_id."\">\n";
foreach ($sub_array as $sval) {
if ($pkey == $_REQUEST[$qs_val] && $pkey == $sval['parent']) {
$menu .= "<li>".$sval['label']."</li>\n";
}
}
$menu .= "</ul>\n";
}
}
$menu .= "</ul>\n";
return $menu;
}
function rebuild_link($link, $parent_var, $parent_val) {
$link_parts = explode("?", $link);
$base_var = "?".$parent_var."=".$parent_val;
if (!empty($link_parts[1])) {
$link_parts[1] = str_replace("&", "##", $link_parts[1]);
$parts = explode("##", $link_parts[1]);
$newParts = array();
foreach ($parts as $val) {
$val_parts = explode("=", $val);
if ($val_parts[0] != $parent_var) {
array_push($newParts, $val);
}
}
if (count($newParts) != 0) {
$qs = "&".implode("&", $newParts);
}
return $link_parts[0].$base_var.$qs;
} else {
return $link_parts[0].$base_var;
}
}
echo dyn_menu($parent_menu, $sub_menu, "menu", "nav", "subnav");
It's telling you that $parent_array isn't an array.
If you post the code that calls this function, we can tell you more.
Are you sure $parent_array is actually an array? Try checking it with is_array first (perhaps returning an empty string to represent the menu or whatever - adapt to your needs):
if (!is_array($parent_array)) {
return "";
}
This error happens when you supply not an array into forearch. Try print_r() first argument of every foreach
If you change your function signature to include type hinting (only works for arrays and objects), you'll be sure that your function gets what it needs:
function dyn_menu(array $parent_array, array $sub_array, //etc.)
And you should get an error message that pinpoints the caller of the function, which is where the problem really is.
It looks like you were expecting to build $parent_array in that while loop at the beginning. Instead it's just echoing stuff.
The lines like:
echo $parent_menu . $obj['id']['label'] = $obj['label'];
Should probably be like:
$menu['label'] = $obj['label'];
Then at the end (inside) of the loop add something like:
$parent_menu[$obj['id']] = $menu;
So you build the array you're using in dyn_menu.
In any case, the while loop looks like your problem. It's not building $parent_menu from the data.

Categories