PHP dynamic navigation menu active styling - php

I want to create a dynamic menu in PHP and based on what page they are on the menu will have different styling. I have this but it's not how I want it to be :(
This is the array I have, containing info from the database
Array(
[Home] => Array
(
[url] => Home
[name] => Home
[is_home] => 1
)
[About] => Array
(
[url] => About
[name] => About
[is_home] => 0
)
[Contact] => Array
(
[url] => Contact.php
[name] => Contact
[is_home] => 0
)
)
This is what I currently have,
if(isset($_GET["p"])) {
if(in_array($page_name, $navigation[$page_name])) {
$navigation[$page_name]["name"] = "<span>{$navigation[$page_name]["name"]}</span>";
}
}
foreach ($navigation as $nav) {
echo "<li>{$nav["name"]}</li>";
}
This is how the page_name variable looks
$page_name = current(explode(".", ucfirst(strtolower($_GET["p"]))));
As you can see this inserts the span tags in the navigation menu name so this works but that's not how I want it to be. I want to add class="active" the the list item that is the current page. I just don't know how to do it
I hope you understand what I mean and sorry for any messy indentation that occurred when pasting the code in here.
//Edit
The fetch and array code
$mysql->query("SELECT `page_name`, `is_home` FROM `pages` ORDER BY `order` ASC");
$navigation_items = array();
while ($mysql->fetch($row)){
$navigation_items[] = array(
"url" => $row["page_name"],
"name" => current(explode(".", $row["page_name"])),
"is_home" => $row["is_home"]
);
}
return $navigation_items;

First of all the array you provided is reformatted which means you changed the indexes into page names which isn't necessary.
This is how you can achieve what you want:
<?php
$menu = $Db->fetchAll("SELECT * FROM `menu`"); //or whatever method you're using to get data from the database.
$current = null;
if(isset($_GET['p'])) {
$current = current(explode(".", ucfirst(strtolower($_GET["p"]))));
}
$navigation = '';
for($i=0;$i<count($menu);$i++) {
$url = ucfirst(strtolower($menu[$i]['url']));
if($current == $url)
$class = ' class="active"';
else
$class = '';
$name = '<span'.$class.'>'.$menu[$i]['name'].'</span>';
$navigation .= "<li><a href='{$url}'>{$name}</a></li>";
}
?>

Related

Why does my code only return partial results? array_push not working for first element

So I'm returning an array of arrays returned from an MySQLi query, as you can see it pulls distinct categories from my layers database and then returns each layer associated with that category.
The results are only returning some results and not all when the code using print_r returns all the layers.
Where am I going wrong?
https://api.adameastwood.com/v1/TEST/logger.php -> results of print_r and foreach loop
$conn = new mysqli($sqlParams['host'], $sqlParams['username'],
$sqlParams['password'], $sqlParams['database']);
$Query = "SELECT DISTINCT `Category` FROM `layers` WHERE `enabled` = 1
ORDER BY `Category` ASC";
$menuCategories = [];
if ($result = $conn->query($Query))
{
while ($categoryRow = $result->fetch_row()){
foreach($categoryRow as $key => $value)
{
$layers = $conn->query("SELECT * FROM `layers` WHERE enabled = 1 AND Category = '$value' ORDER BY LayerName ASC");
while ($layerDetails = $layers->fetch_array()){
$menuItems = array([
'LCategory' => $layerDetails['Category'],
'LayerCode' => $layerDetails['LayerCode'],
'LayerName' => $layerDetails['LayerName'],
]);
foreach($menuItems as $item){
print_r($item);
$item = array('LayerDetails' => $item);
array_push($menuCategories['menuItem'][$value], $item);
foreach($item as $items => $itemValue)
array_push($menuCategories['menuItem'][$value][$itemValue], $itemValue);
}
}
}
}
echo "\n\n";
Array
(
[LCategory] => Council Assets
[LayerCode] => RBC/AL
[LayerName] => Available Land
)
Array
(
[LCategory] => Council Assets
[LayerCode] => RBC/COL
[LayerName] => Council Owned Land
)
Array
(
[LCategory] => Planning
[LayerCode] => DC/CA
[LayerName] => Conservation Areas
)
Array
(
[LCategory] => Planning
[LayerCode] => DC/LB
[LayerName] => Listed Buildings
)
Array
(
[LCategory] => Planning
[LayerCode] => DC/PA
[LayerName] => Planning Applications
)
Array
(
[LCategory] => Planning
[LayerCode] => DC/TPO
[LayerName] => Tree Preservation Orders
)
{
"menuItem": {
"Council Assets": [
{
"LayerDetails": {
"LCategory": "Council Assets",
"LayerCode": "RBC\/COL",
"LayerName": "Council Owned Land"
}
}
],
"Planning": [
{
"LayerDetails": {
"LCategory": "Planning",
"LayerCode": "DC\/LB",
"LayerName": "Listed Buildings"
}
},
{
"LayerDetails": {
"LCategory": "Planning",
"LayerCode": "DC\/PA",
"LayerName": "Planning Applications"
}
},
{
"LayerDetails": {
"LCategory": "Planning",
"LayerCode": "DC\/TPO",
"LayerName": "Tree Preservation Orders"
}
}
]
}
}
Your code has lot of "not-good-practice" behavior - but let address your issue:
Notice that array-push raise warning when null is given and not array (and you never init empty array in key menuItem or the category names). However, it does create an array after the command is sent - therefor, only the first element is left out.
Change you array_push to [] as $menuCategories['menuItem'][$value][] = $item; to make it work as you intend (change both array_push)

Array return, enumerat or other solution?

I'm having trouble identifying each row of this array ... would it be possible to enumerate or otherwise be able to pull a specific array field?
My code is:
<?php
/*
Generic function to fetch all input tags (name and value) on a page
Useful when writing automatic login bots/scrapers
*/
function get_input_tags($html)
{
$post_data = array();
// a new dom object
$dom = new DomDocument;
//load the html into the object
$dom->loadHTML($html);
//discard white space
$dom->preserveWhiteSpace = false;
//all input tags as a list
$input_tags = $dom->getElementsByTagName('input');
//get all rows from the table
for ($i = 0; $i < $input_tags->length; $i++)
{
if( is_object($input_tags->item($i)) )
{
$name = $value = '';
$name_o = $input_tags->item($i)->attributes->getNamedItem('name');
if(is_object($name_o))
{
$name = $name_o->value;
$value_o = $input_tags->item($i)->attributes->getNamedItem('value');
if(is_object($value_o))
{
$value = $input_tags->item($i)->attributes->getNamedItem('value')->value;
}
$post_data[$name] = $value;
}
}
}
return $post_data;
}
/*
Usage
*/
error_reporting(~E_WARNING);
$html = file_get_contents("https://secure.donman.net.au/client/ozchild/Donate.aspx");
echo "<pre>";
print_r(get_input_tags($html));
echo "</pre>";
?>
Generate the result
[radInMemDiscloseAmount] => No
[txtInMemOfAddress] =>
[txtInMemOfSuburb] =>
[txtInMemOfState] =>
[txtInMemOfPostCode] =>
[txtInHonorOfName] =>
[txtInHonorOfAddress] =>
[txtInHonorOfSuburb] =>
[txtInHonorOfState] =>
[txtInHonorOfPostCode] =>
[HonorEventType] => gf_other_choice
[HonorEventTypeOtherText] => Other
how can I have something like this?
[0][radInMemDiscloseAmount] => No
[1][txtInMemOfAddress] =>
[2][txtInMemOfSuburb] =>
[3][txtInMemOfState] =>
[4][txtInMemOfPostCode] =>
[5][txtInHonorOfName] =>
[6][txtInHonorOfAddress] =>
[7][txtInHonorOfSuburb] =>
[8][txtInHonorOfState] =>
[9][txtInHonorOfPostCode] =>
[10][HonorEventType] => gf_other_choice
[11][HonorEventTypeOtherText] => Other
how can I have something like this? or some way to identify array rows?
I'm having trouble identifying each row of this array ... would it be possible to enumerate or otherwise be able to pull a specific array field?

Parsing multi nested child in XML in PHP

Firstly first I am a beginner with PHP. Especially when i have to deal with XML Parsing , I am having a struggle with it right now, lots of xml. Hours and hours already I tried solving it and its already giving me a headache.
Here the XML :
<v1:product>
<v1:data>
<v1:account_id>5637</v1:account_id>
<v1:account_name>John Doe</v1:account_name>
<v1:product_id>f4dc8300-1f13-11e8-bfa43d4d9ee60f6b</v1:product_id>
<v1:product_name>Product Test</v1:product_name>
<v1:product_desc>
<v1:name>Arc</v1:name>
<v1:unit>boxes</v1:unit>
<v1:value>10</v1:value>
</v1:product_desc>
<v1:product_desc>
<v1:name>Birg</v1:name>
<v1:unit>kilos</v1:unit>
<v1:value>2</v1:value>
</v1:product_desc>
<v1:product_desc>
<v1:name>Cyitha</v1:name>
<v1:unit>Minutes</v1:unit>
<v1:value>30</v1:value>
</v1:product_desc>
<v1:offer>
<v1:offer_id>3575374</v1:offer_id>
<v1:offer_name>Flash</v1:offer_name>
</v1:offer>
</v1:data>
<v1:data>
<v1:account_id>5892</v1:account_id>
<v1:account_name>John Doe</v1:account_name>
<v1:product_id>jsad2sdx-asd2-983j</v1:product_id>
<v1:product_name>Product Test 2</v1:product_name>
<v1:product_desc>
<v1:name>Arc</v1:name>
<v1:unit>boxes</v1:unit>
<v1:value>2</v1:value>
</v1:product_desc>
<v1:product_desc>
<v1:name>Birg</v1:name>
<v1:unit>kilos</v1:unit>
<v1:value>10</v1:value>
</v1:product_desc>
<v1:product_desc>
<v1:name>Cyitha</v1:name>
<v1:unit>Minutes</v1:unit>
<v1:value>99</v1:value>
</v1:product_desc>
<v1:offer>
<v1:offer_id>3575374</v1:offer_id>
<v1:offer_name>Flash</v1:offer_name>
</v1:offer>
</v1:data>
</v1:product>
and this is what i have in PHP
$objGetEmAll = new DOMDocument();
$objGetEmAll->loadXML($theXML);
$datas = $objGetEmAll->getElementsByTagName('data');
$responseValue = array();
foreach($datas as $data) //each element of DATA
{
$dataValue = array();
if($data->childNodes->length)
{
foreach($data->childNodes as $i)
{
$dataValue[$i->nodeName] = $i->nodeValue;
}
}
$responseValue[] = $dataValue;
}
but still fail when i want to extract value dynamically inside product_desc tag. I want to change XML above into an array which is like below
Array
(
[0] => Array
(
[v1:account_id] => 5637
[v1:account_name] => adsfafds
[v1:product_id] => 124asd
[v1:product_name] => HALO
[v1:product_desc] => Array
(
[0] => Array
(
[v1:name] => A
[v1:unit] => BOXes
[v1:value] => 7
)
[1] => Array
(
[v1:name] => B
[v1:unit] => mins
[v1:value] => 1000
)
[2] => Array
(
[v1:name] => C
[v1:unit] => call
[v1:value] => 700
)
[3] => Array
(
[v1:name] => D
[v1:unit] => GB
[v1:value] => 4
)
)
[v1:offer] => Array
(
[v1:offer_id] => 3575374
[v1:offer_name] => Flash
)
)
)
I know maybe this is the easy one, but for me who just joined programming in these last month, this is confusing. Links or helps are welcome
Use this
$objGetEmAll = new DOMDocument();
$objGetEmAll->loadXML($theXML);
$datas = $objGetEmAll->getElementsByTagName('data');
$responseValue = array();
foreach($datas as $data) //each element of DATA
{
$dataValue = array();
$product_desc_counter = 0;
$offer_counter = 0;
if($data->childNodes->length)
{
foreach($data->childNodes as $i) {
// for v1:product_desc group case :1
if($i->nodeName == 'v1:product_desc' ){
foreach($i->childNodes as $p) {
$dataValue[$i->nodeName][ $product_desc_counter][$p->nodeName] = $p->nodeValue;
}
$product_desc_counter ++;
} else if($i->nodeName == 'v1:offer' ) // for offer group case:2
{
foreach($i->childNodes as $p) {
$dataValue[$i->nodeName][ $offer_counter][$p->nodeName] = $p->nodeValue;
}
$offer_counter ++;
}
else // case:3
$dataValue[$i->nodeName] = $i->nodeValue;
}
}
$responseValue[] = $dataValue;
}
In the above lines we loop over all data nodes then check if it has any nodes if it doesn't( like for items account_name, product_id ..) we simply store it's nodeValue in our result array ie. in $responseValue. If it has any child (v1:product_desc,v1:offer ie case:1 or 2) we again loop over its children and append them to combination of corresponding key and the corresponding loop counter ( $product_desc_counter or $offer_counter ) .It might be hard at first to understand (specially array indexes) but after fiddling with it for a while you will grasp it.

What's wrong with this php foreach code? (merged array)

$db = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
$items = 'SELECT items FROM menus';
$itemLink = 'SELECT itemLink FROM menus';
$itemQuery = $db->query($items);
$linkQuery = $db->query($itemLink);
$fetchItem = $itemQuery->fetch(PDO::FETCH_ASSOC);
$fetchLink = $linkQuery->fetch(PDO::FETCH_ASSOC);
$merged = array_merge($fetchItem,$fetchLink);
foreach($merged as $key=>$value){
echo "${key} => ${value} <br />";
}
This is what it looks like in the database:
items |itemLink
----------------------
Kill Bill|Kill Bill link
Preman |Preman link
So, the expected output, or at least what I thought must be this:
items => Kill Bill
items => Preman
itemLink => Kill Bill Link
itemLink => Preman Link
But the resulted output from the code is this:
items => Kill Bill
itemLink => Kill Bill Link
It's missing the other items and itemLink
So, how do I achieve the output that I want?
$fetchItem = $itemQuery->fetch(PDO::FETCH_ASSOC);
$fetchLink = $linkQuery->fetch(PDO::FETCH_ASSOC);
This only fetches the first row of each resultset. You need fetchAll:
$fetchItem = $itemQuery->fetchAll(PDO::FETCH_ASSOC);
$fetchLink = $linkQuery->fetchAll(PDO::FETCH_ASSOC);
and adjust the rest of your code.
foreach($merged as $entry) {
foreach( $entry as $key => $value ) {
echo "${key} => ${value} <br />";
}
}
EDIT:
The call of fetch only retrieved the first row of the resultset, whereas fetchAll parses the complete resultset into an Array. So the Objects look like this afterwards:
Array(
[0] => { 'items' => 'Kill Bill' },
[1] => { 'items' => 'Preman' }
)
Array(
[0] => { 'itemLink' => 'Kill Bill' },
[1] => { 'itemLink' => 'Preman' }
)
array_merge concatenate both arrays to the following:
Array(
[0] => { 'items' => 'Kill Bill' },
[1] => { 'items' => 'Preman' },
[2] => { 'itemLink' => 'Kill Bill' },
[3] => { 'itemLink' => 'Preman' }
)
So we now have a two dimensional array. To traverse the values we need first to select each $entry, which is done in the outer foreach and can afterwards access the key/value structure in the inner foreach.
As pointed out in the other comment: If you want to preserve the connection between itemsand itemLink, you should change the query in the first place to
SELECT items, itemLink FROM menus
You can use simple array_combine() function to do what you are trying to do now.
$merged = array_combine($fetchItem, $fetchLink);
This will make all the item from $fetchItem as keys to the item from $fetchLink.

Most efficient way to replace empty values in an array

Is there a better way of doing this PHP code? What I'm doing is looping through the array and replacing the "title" field if it's blank.
if($result)
{
$count = 0;
foreach($result as $result_row)
{
if( !$result_row["title"] )
{
$result[$count]["title"] = "untitled";
}
$count++;
}
}
Where $result is an array with data like this:
Array
(
[0] => Array
(
[title] => sdsdsdsd
[body] => ssdsd
)
[1] => Array
(
[title] => sdssdsfds
[body] => sdsdsd
)
)
I'm not an experienced PHP developer, but I guess that the way I've proposed above isn't the most efficient?
Thanks
if($result) {
foreach($result as $index=>$result_row) {
if( !$result_row["title"] ) {
$result[$index]["title"] = "untitled";
}
}
}
You don't need to count it. It's efficient.
if ($result)
{
foreach($result as &$result_row)
{
if(!$result_row['title'])
{
$result_row['title'] = 'untitled';
}
}
}
Also, you may want to use something other than a boolean cast to check the existence of a title in case some young punk director releases a movie called 0.
You could do something like if (trim($result_row['title']) == '')
Mixing in a little more to #Luke's answer...
if($result) {
foreach($result as &$result_row) { // <--- Add & here
if($result_row['title'] == '') {
$result_row['title'] = 'untitled';
}
}
}
The key is the & before $result_row in the foreach statement. This make it a foreach by reference. Without that, the value of $result_row is a copy, not the original. Your loop will finish and do all the processing but it won't be kept.
The only way to get more efficient is to look at where the data comes from. If you're retrieving it from a database, could you potentially save each record with an "untitled" value as the default so you don't need to go back and put in the value later?
Another alternative could be json_encode + str_replace() and then json_decode():
$data = array
(
0 => array
(
'title' => '',
'body' => 'empty',
),
1 => array
(
'title' => 'set',
'body' => 'not-empty',
),
);
$data = json_encode($data); // [{"title":"","body":"empty"},{"title":"set","body":"not-empty"}]
$data = json_decode(str_replace('"title":""', '"title":"untitled"', $data), true);
As a one-liner:
$data = json_decode(str_replace('"title":""', '"title":"untitled"', json_encode($data)), true);
Output:
Array
(
[0] => Array
(
[title] => untitled
[body] => empty
)
[1] => Array
(
[title] => set
[body] => not-empty
)
)
I'm not sure if this is more efficient (I doubt it, but you can benchmark it), but at least it's a different way of doing the same and should work fine - you have to care about multi-dimensional arrays if you use the title index elsewhere thought.
Perhaps array_walk_recursive:
<?php
$myArr = array (array("title" => "sdsdsdsd", "body" => "ssdsd"),
array("title" => "", "body" => "sdsdsd") );
array_walk_recursive($myArr, "convertTitle");
var_dump($myArr);
function convertTitle(&$item, $key) {
if ($key=='title' && empty($item)) {$item = "untitled";}
}
?>
If you want sweet and short, try this one
$result = array(
array(
'title' => 'foo',
'body' => 'bar'
),
array(
'body' => 'baz'
),
array(
'body' => 'qux'
),
);
foreach($result as &$entry) if (empty($entry['title'])) {
$entry['title'] = 'no val';
}
var_dump($records);
the empty() will do the job, see the doc http://www.php.net/manual/en/function.empty.php

Categories