Associative array change key values - php

I have the following code to iterate through json array and change the value in the array.
<?php
$json='[{"type":"dropdown","label":"Is the property tenanted ?","req":0,"choices":[{"label":"Yes","sel":0,"notification":0,"subOptions":[{"NoteLabel":"Real Estate Agency ?","NoteValue":"","reqNote":"1"},{"NoteLabel":"Agents Mobile Number:","NoteValue":"","reqNote":"1"},{"NoteLabel":"Agents Email:","NoteValue":"","reqNote":"0"},{"PhotoLabel":"Attach a photo","PhotoValues":"","reqPhoto":"1"},{"NoteLabel":"Tenants Contact Number:","NoteValue":"","reqNote":"0"}]},{"label":"No","sel":1,"notification":0,"subOptions":[{"NoteLabel":"Clients Contact Number:","NoteValue":"","reqNote":"1"},{"PhotoLabel":"Attach a photo","PhotoValues":"","reqPhoto":"1"}]},{"label":"N\/A","sel":0,"notification":0,"subOptions":[]}]}]';
echo $json."<br/>";
echo "<br/><br/><br/>****************<br/><br/><br/>";
$json=json_decode($json,true);
foreach($json as $kSub => $vSub)
{
if( in_array($vSub['type'], ["dropdown"]))
{
if($vSub['label']=="Is the property tenanted ?")
{
$choices=&$vSub['choices'];
foreach($choices as $keyChoice=>&$valChoice)
{
if($valChoice['label']=="Yes")
{
$subOptions=&$valChoice['subOptions'];
foreach($subOptions as $kop=>&$Opval)
{
foreach($Opval as $kn=>&$vn)
{
if($kn=="NoteLabel")
{
if($vn=="Real Estate Agency ?")
{
$subOptions[$kop]['NoteValue']="DOMAIN";
}
}
}
}
}
}
}
}
}
echo json_encode($json)."<br/>";
I want to change the NoteValue inside subOptions array if the conditions are met. I am not sure whether I am doing it right or not, but the value is not changing. Please help me to sort out what I am doing wrong! I was also wondering whether I can reduce the number of code lines to get the result?

You need to use &vSub to make it a reference variable.
You can shorten the code by getting rid of the last loop, and just access the NoteLabel index directly. You can also combine the first two tests with &&. And you don't need any of the index variables in your foreach loops.
foreach($json as &$vSub)
{
if($vSub['type'] == "dropdown" && $vSub['label']=="Is the property tenanted ?")
{
$choices=&$vSub['choices'];
foreach($choices as &$valChoice)
{
if($valChoice['label']=="Yes")
{
$subOptions=&$valChoice['subOptions'];
foreach($subOptions as &$Opval)
{
if (isset($Opval['NoteLabel']) && $Opval['NoteLabel'] == "Real Estate Agency ?")
{
$Opval['NoteValue']="DOMAIN";
}
}
}
}
}
}

Related

While loop on multi-dimensional array

So I have a function that currently has a foreach and it works amazing, but I'm being forced to change it to a while loop:
PLEASE NOTE: The developers at my company don't want to use the foreach and they think that a while loop would be more efficient, but I'm not understanding how that would be executed, so I need some help.
So I have the following function ($post_blocks is an array of arrays):
public function parse_block_data(string $block_name, string $selector, $post_id)
{
if (!has_blocks($post_id)) {
return false;
}
$post_blocks = parse_blocks(get_the_content('', false, $post_id));
foreach ($post_blocks as $block) {
if ($block_name != $block['blockName']) {
continue;
}
if (!isset($block['attrs']['id'])) {
return false;
}
if (isset($block['attrs']['data'][$selector])) {
return $block['attrs']['data'][$selector];
} else {
break;
}
}
return false;
}
It uses the parameters to build up an array as shown below:
Output
So I started building a while loop inside the function, but I'm clueless on how to achieve it without using a foreach or if it's even possible, so I replaced the foreach with:
// I get the 9 counts of $post_blocks correctly.
$block = 0;
while ($block < count($post_blocks))
// If the $block_name doesn't match `blockName` value inside the multi-dimensional array, then continue iterating until the end and then return false.
// If ['attrs']['id'] is not set, return false.
// At last, if we have a blockName and a ID and the selector is set, return ['attrs']['data'][$selector]
}
All help will be appreciated! It makes no sense to me, but if someone can assist, I'd be forever grateful!
It's basically the same as your foreach loop, you just set the iteration variable by indexing the array, and increment the index manually.
$block_num = 0;
while ($block_num < count($post_blocks)) {
$block = $post_blocks[$block_num];
if ($block_name == $block['blockName']) {
if (!isset($block['attrs']['id'])) {
return false;
}
if (isset($block['attrs']['data'][$selector])) {
return $block['attrs']['data'][$selector];
} else {
break;
}
}
$block_num++;
}
I'm not sure why your colleagues think this is preferable.
If there's a company coding style they want you to follow, why don't you ask them what it should be?

php foreach iteration over object property array not incrementing the value

Please help! I have been staring at this for too long. I have a property of an object that is an array of objects. I want to pass in an object to a method of the parent object and search through that array property for a match, and if one is found return the index. Otherwise, I need it to return -1. For some reason, it is not iterating. If I echo out what should be the $order->product property (where the index is pointing during the loop), it is unchanging. I have dumped the array and I know it contains different values. I can show you a big var dump, but I figured I would first ask if there is a simple error or something else that is obvious to you that I have missed.
public function getItemIndex($prod) {
if (isset($this->orders)){
foreach($this->orders as $key => $order) {
if ($order->product == $prod) { //if I echo this $order->product to the screen, it is unchanging
return $key;
} else { return -1; }
}
}
else {
return -1;
}
}
If anyone has any ideas, I am open to discuss and post more information as needed. Thank you for your time.
You are ALWAYS returning a value on the first iteration, either the $key or -1. Try removing the else statement that you currently have. This will allow you to fully iterate over the entire array.
public function getItemIndex($prod) {
if (isset($this->orders)){
foreach($this->orders as $key => $order) {
if ($order->product == $prod) { //if I echo this $order->product to the screen, it is unchanging
return $key;
}
}
}
return -1;
}
This will ONLY return -1 once it has iterated over everything and found nothing to match. It will still return $key if it finds a match.

PHP - Apply operations to descendant arrays regardless of parent arrays

In a multidimensional array, I'm trying to select all descendant arrays with a certain key, no matter what their parent arrays are. I know the following syntax doesn't work, but hopefully it will help illustrate what I'm trying to accomplish:
<?php
foreach ($array[*][*]['descendant'] as $descendent) {
// do stuff
}
?>
Similarly, I need to figure out whether sibling arrays do not contain this array key. Something like this (again, I know the syntax is horribly wrong):
<?php
foreach ($array[*][*]['descendant'] < 1 as $descendent) {
// do stuff
}
?>
If there are always 3-dimensional array, you can use nested loop:
foreach($array as $lv1) {
foreach($lv1 as $lv2) {
foreach($lv2['descendant'] as $descendent) {
// do stuff
}
}
}
If you want to support unlimited number of dimension, you can use this ugly code
function drill($arr) {
if (isset($arr) && is_array($arr)) {
foreach($arr as $key => $value) {
if ($key == 'descendant') {
foreach($value as $descendent) {
// do stuff here
}
} else {
drill($value);
}
}
}
}
drill($array);

PHP if() state keeps evaluating to true even though it isn't

I'm having the toughest time figuring out this problem and I can't seem to find the answer.
Here's what I'm trying to do: I have different nav menus on my website depending on the section. I've already pre-built the different variations and on each page declare $linkbox_array, which is the array of links for my nav menu on that page. On certain pages I display horizontally and on others vertically. When vertical, I need a disclaimer to be added to the bottom of the stacked link boxes.
So my function is trying to say this: if the $linkbox_array is $general_linkboxes and the $bodyClass is "withSidebar", then echo out a disclaimer after array item 2. Otherwise, just echo out the array items.
So this is what I've written (forgive me if it sucks, I'm new to this):
function display_linkboxes($array) {
if ($linkbox_array == $general_linkboxes && $bodyClass = "withSidebar") {
foreach ($array as $linkbox) {
if ($linkbox == $array[2]) {
echo $linkbox;
global $general_disclaimer;
echo $general_disclaimer;
} else {
echo $linkbox;
}
}
} else {
foreach ($array as $linkbox) {
echo $linkbox;
}
}
}
The problem is that it keeps spitting out the $general_disclaimer even when the two conditions aren't true. I tried to deconstruct the function and figure out where I was going wrong and I realized my if statement always evaluates to true even if I put in jibberish. For example:
function display_linkboxes($array) {
if ($linkbox_array == $askjfdalfjk) {
foreach ($array as $linkbox) {
echo $linkbox;
}
}
}
This evaluates to true and displays the links even though $askjfdalfjk doesn't exist. Then I have the opposite problem below. This won't display the links even though the if statement should evaluate to true:
function display_linkboxes($array) {
if ($bodyClass == "withSidebar") {
foreach ($array as $linkbox) {
echo $linkbox;
}
}
}
What in the world am I doing wrong?!?! Any help is greatly appreciated!
In your code:
function display_linkboxes($array) {
if ($linkbox_array == $general_linkboxes && $bodyClass = "withSidebar") {
...
$linkbox_array, $general_linkboxes, and $bodyClass are not in scope for this function, which means they are both equal to each other in that neither of them exists. You need to either pass them as variables to the function (recommended), or change your code to the following:
function display_linkboxes($array) {
global $linkbox_array, $general_linkboxes, $bodyClass;
if ($linkbox_array == $general_linkboxes && $bodyClass == "withSidebar") {
...
I've edited this answer to include the = -> == fix on $bodyClass
Probably you set $linkbox_array outside of your function, then your function doesn't knoew it, unless you ...
function display_linkboxes($array) {
global $linkbox_array; // <------ now the variable exists within the function.
if ($linkbox_array == $askjfdalfjk) {
foreach ($array as $linkbox) {
echo $linkbox;
}
}
}
Same with $bodyClass
Your if conditional just needs a bit of refactoring:
if(($linkbox_array == $general_linkboxes) && ($bodyClass == "withSidebar")) {}
A single '=' is an assignment operation and will always evaluate to true.
A == is the conditional equals operation you were looking for.
Furthermore if you are checking for array equality and order matters to you then you should use the '===' operator which checks not just for the same elements but also the same order
Lastly you have a scoping issue - if your linkbox array is evaluating as equal to a null variable then it hasn't been defined. You can use the print_r() operation to check this. If the array is defined outside the function then you should pass it to the function as a parameter.

PHP - scope perseverance - Codeigniter

My question stems from a model I am writing to construct queries from predefined search objects that contain 'criteria', each search has a property $search->criteria that is an array of criteria objects....
Criteria (
"name" => "name", //name of given field to be searched
"expr" => "expr", //could be "<=" ">=" "="
"s_value" => "value" //value to be searched with
)
and the part of my search function that is adding the proper where statements to the query...
if(count($criteria)) {
foreach($criteria as $crit) {
$this->{$crit['name']}($crit['s_value'],$crit['expr']);
}
}
And now finally the function that loop is calling, 'name' here corresponds with whatever the criteria object has set as $criteria['name']....
function name($value,$expr = '=') {
$this->db->where('specific_field_name '.$expr,$value);
}
Now for the question..
I want to create a variable inside 'name' that will persist beyond a single execution, so for instance, if I have 2 criteria with the same name and it executes twice, I want to maintain a variable in it's scope for multiple executions.
EDIT
What I WANT to do. I have multple functions like this that all need their own counters.
function name($value,$expr = '=') {
if(isset($count))
$this->db->or_where('specific_field_name '.$expr,$value);
$count++;
}
else {
$count = 1;
$this->db->where('specific_field_name '.$expr,$value);
}
}
Ideas?
SOLUTION
if(count($criteria)) {
$criteria_count = array()
foreach($criteria as $crit) {
if(isset($criteria_count[$crit['name']])) {
$criteria_count[$crit['name']]++;
}
else {
$criteria_count[$crit['name']] = 1;
}
$this->{$crit['name']}($crit['s_value'],$crit['expr'],$criteria_count[$crit['name']]);
}
}
Changed the main search function to maintain a $criteria_count array with the names as keys and passing the count down to the specific functions.
You could use the global statement if you really want to do it this way.
Edit: here is how I might pass count into name and keep track of it that way.
At beginning of search function: $count = 0;
if(count($criteria)) {
foreach($criteria as $crit) {
$count = $this->{$crit['name']}($crit['s_value'],$crit['expr'],$count);
}
}
And then the name function:
function name($value,$expr = '=',$count) {
if($count > 0)
$this->db->or_where('specific_field_name '.$expr,$value);
$count++;
}
else {
$count = 1;
$this->db->where('specific_field_name '.$expr,$value);
}
return $count;
}

Categories