Php doesn't break in a recursive foreach loop - php

I have a recursive function like below.
public function findnodeintree($cats,$cat_id)
{
foreach($cats as $node)
{
if((int)$node['id'] == $cat_id)
{
echo "finded";
$finded = $node;
break;
}
else
{
if(is_array($node) && array_key_exists('children', $node)){
$this->findnodeintree($node['children'],$cat_id);
}
}
}
return $finded;
}
For Example
$node =$this->findnodeintree($category_Array, 169);
It gaves me
"founded"
A PHP Error was encountered
Severity: Notice
Message: Undefined variable: finded
Array Structure is like
[0] => Array
(
[id] => 0
[name] => MAIN CATEGORY
[depth] => 0
[lft] => 1
[rgt] => 296
[children] => Array
(
[0] => Array
(
[id] => 167
[name] => CAT 0
[depth] => 1
[lft] => 2
[rgt] => 17
[children] => Array
(
[0] => Array
(
[id] => 169
[name] => CAT 1
[depth] => 2
[lft] => 3
[rgt] => 4
)
[1] => Array
(
[id] => 170
[name] => CAT 2
[depth] => 2
[lft] => 5
[rgt] => 10
[children] => Array
(
[0] => Array
(
[id] => 171
[name] => CAT 5
[depth] => 3
[lft] => 6
[rgt] => 7
)
[1] => Array
(
[id] => 172
[name] => CAT 3
[depth] => 3
[lft] => 8
[rgt] => 9
)
)
)

To get the right value from recursion, your recursion call must not discard the return value. And since you want to walk back up the recursion tree as soon as you get a hit, and actually return the matching node, you have to break your loop at that point too.
Otherwise subsequent recursion calls overwrite your variable and the wrong node, false, or null is returned.
This should be what works:
public function findnodeintree($cats,$cat_id)
{
foreach($cats as $node)
{
if((int)$node['id'] == $cat_id){
return $node;
}
elseif(array_key_exists('children', $node)) {
$r = $this->findnodeintree($node['children'], $cat_id);
if($r !== null){
return $r;
}
}
}
return null;
}
Note: I removed the is_array because at that point $node has to be an array or throw an error at the first branch condition.

Change your recursion line to this:
$finded = $this->findnodeintree($node['children'],$cat_id);
You want to be able to get the line, if you recall the function, that line have to fill your variable, otherwise it will be filled in the last occuring situation but will never return the result to your first call.
Hence, $finded will be empty or non-existing in your first call.

The recursive call findnodeintree will go through certain loops will not "find" anything and yet they still return a variable $finded. Except that since in their loop it was never found, that variable is indeed not declared. Try this:
public function findnodeintree($cats,$cat_id)
{
$finded = NULL;
foreach($cats as $node)
{
if((int)$node['id'] == $cat_id)
{
echo "finded";
$finded = $node;
break;
}
else
{
if(is_array($node) && array_key_exists('children', $node)){
$this->findnodeintree($node['children'],$cat_id);
}
}
}
return $finded;
}

Related

select array value of an object in php

I'm just a beginner and would like to select a value of an array inside an object. I'm quite lost and don't know how to do.
ie : how to get de value of "thailande" inside this object ?
Forminator_Form_Entry_Model Object
(
[entry_id] => 42
[entry_type] => custom-forms
[form_id] => 24342
[is_spam] => 0
[date_created_sql] => 2020-07-02 11:42:21
[date_created] => 2 Juil 2020
[time_created] => 2 Juil 2020 # 11:42
[meta_data] => Array
(
[select-1] => Array
(
[id] => 87
[value] => thailande
)
[radio-1] => Array
(
[id] => 88
[value] => 1
)
[number-1] => Array
(
[id] => 89
[value] => 10
)
[_forminator_user_ip] => Array
(
[id] => 90
[value] => 84.101.156.169
)
)
[table_name:protected] => politis_5_frmt_form_entry
[table_meta_name:protected] => politis_5_frmt_form_entry_meta
)
thx a lot for your help.
It's fairly straightforward - you just go down the hierarchy one step at a time referencing the index you need.
So, assuming $obj in this example is an instance of Forminator_Form_Entry_Model then you would write
$obj->meta_data["select-1"]["value"]
which will point to the data you're looking for.
N.B. The ->index syntax is used to get properties of an object. the ["index"] syntax is used to get properties of an array.
You can try Callback Functions
function array_search_id($val_for_search, $array_data, $search_in_path='root') {
if(is_array($array_data) && count($array_data) > 0) { // if value has child
foreach($array_data as $key => $value) {
$paths_list = $search_in_path;
// Adding current key to search path
array_push($paths_list, $key);
if(is_array($value) && count($value) > 0) { // if value has child
$res = array_search_id($val_for_search, $value, $paths_list);//callback function
if ($res != null)
return $res;
}
else if($value == $val_for_search){
//if you wants path + result
return end($paths_list);
/*
//if you wants path
return join(" --> ", $paths_list);
*/
} //if value find in array return val
}
}
return null;
}
array_search_id('thailande', $your_array);

PHP Array: Twice if statement in a for

I'm having a difficult to finish a if statement twice.. The rest works fine but when I try to check in another subarray it doesn't work.
EDIT:
- The first if condition is to check the type of products
- The second if condition is to check the size attributes.
- Products: sweatshirt_crianca and sweatshirtc_crianca_capuz
- Sizes: 4_anos, 6_anos, 8_anos, 11_anos, 12_anos and 14_anos
Need to disable ( $this->enabled = false; ) Those sizes except 14_anos.
This is what I get from $order->products[$i]
Array
(
[qty] => 1
[name] => .Mr Mickey T-shirt
[model] =>
[image] => blusa-mr-mrs-blusao-sweat-camisolas-portugal.png
[tax] => 20
[tax_description] => IVA 23%
[price] => 10.8333
[final_price] => 16.6666
[weight] => 0.00
[id] => 1342{18}135{17}132{19}148
[attributes] => Array
(
[0] => Array
(
[option] => s_cor_produto
[value] => branco
[option_id] => 18
[value_id] => 135
[prefix] => +
[price] => 0.0000
)
[1] => Array
(
[option] => s_produto
[value] => sweatshirt_crianca
[option_id] => 17
[value_id] => 132
[prefix] => +
[price] => 5.8333
)
[2] => Array
(
[option] => s_tamanho_produto
[value] => 8_anos
[option_id] => 19
[value_id] => 148
[prefix] => +
[price] => 0.0000
)
)
)
Array
(
[qty] => 1
[name] => Adivinha quem vai ser mama shirt
[model] =>
[image] => adivinha-quem-vai-ser-mama-tshirt-gravida.png
[tax] => 20
[tax_description] => IVA 23%
[price] => 10.8333
[final_price] => 10.8333
[weight] => 0.00
[id] => 1860{20}157{18}139{17}128{19}152
[attributes] => Array
(
[0] => Array
(
[option] => s_cor_impressao
[value] => branco
[option_id] => 20
[value_id] => 157
[prefix] => +
[price] => 0.0000
)
[1] => Array
(
[option] => s_cor_produto
[value] => azul_royal
[option_id] => 18
[value_id] => 139
[prefix] => +
[price] => 0.0000
)
[2] => Array
(
[option] => s_produto
[value] => tshirt_mulher
[option_id] => 17
[value_id] => 128
[prefix] => +
[price] => 0.0000
)
[3] => Array
(
[option] => s_tamanho_produto
[value] => M
[option_id] => 19
[value_id] => 152
[prefix] => +
[price] => 0.0000
)
)
)
Sometimes it can contains 1 or 4 subarrays. This is cod payment from osCommerce, I'm trying to exclude specific products from this method based on the attributes of it.
This works fine in the first if statement to check the [value] but the lines that are commented the syntax is correct but it's not working. This is the code I got:
for ($i=0, $n=sizeof($order->products); $i<$n; $i++) {
if ($order->products[$i]['weight'] > '0.00') {
$this->enabled = false;
}
if ( (isset($order->products[$i]['attributes'])) && (sizeof($order->products[$i]['attributes']) > 0) ) {
for ($j=0, $n2=sizeof($order->products[$i]['attributes']); $j<$n2; $j++) {
if ( ($order->products[$i]['attributes'][$j]['option'] == 's_produto') && ($order->products[$i]['attributes'][$j]['value'] == 'sweatshirt_crianca') ) {
//if ( ($order->products[$i]['attributes'][$j]['option'] == 's_tamanho_produto') && ($order->products[$i]['attributes'][$j]['value'] == '14_anos') ) {
$this->enabled = false;
//}
}
else if ( ($order->products[$i]['attributes'][$j]['option'] == 's_produto') && ($order->products[$i]['attributes'][$j]['value'] == 'sweatshirtc_crianca_capuz') ) {
//if ( ($order->products[$i]['attributes'][$j]['option'] == 's_tamanho_produto') && ($order->products[$i]['attributes'][$j]['value'] != '14_anos') ) {
$this->enabled = false;
//}
}
}
}
}
Any solutions? Thanks.
The main problem with your code is that you want to test for different
array elements but you're doing it while iterating one by one. The code
inside the for loop will only see the current element on the
iteration. So when you nest the if statements, you're basically
testing if the current element is equal to something, and then if it
is you test if this very same element is equal to something else. This
logic will fail.
Since apparently only the option and value keys are important, I
suggest creating another array with those first. Then, you can access
all these properties at once -- and not only the current attribute
inside an iterator. For example, here is a simplified attributes array
for your last example in the question:
$attributes = [
s_cor_impressao => 'branco'
s_cor_produto => 'azul_royal'
s_produto => 'tshirt_mulher'
s_tamanho_produto => 'M'
];
To create this easily and also to simplify your code, I suggest using
the foreach ... as loop. Also, you don't need to check if the
array has items. If there are no items, simply the foreach won't be
executed at all. It is worth checking if it is set, like you did, if you
don't know in advance. But another way is to just skip directly to the
next iteration if it is not set with the continue control
structure.
foreach ($order->products as $product) {
if ($product['weight'] > 0)
$this->enabled = false;
if (!isset($product['attributes']) || !is_array($product['attributes']))
continue;
$attributes = [];
foreach ($products['attributes'] as $attr)
$attributes[ $attr['option'] ] = $attr['value'];
# [tests]
}
Now, in the tests mark above you can do your tests like:
if ($attr['s_produto'] == 'sweatshirt_crianca' &&
$attr['s_tamanho_produto'] == '14_anos') {
# do something
# $this->enabled = false;
} else if (...) {
# do something else
}
I would rewrite your loop using foreach to make it more readable and prone to less errors. Also, watch out for your comparisons (== vs. ===). Try it in this manner:
foreach ($order->products as $product) {
if ($product['weight'] > 0.00) {
$this->enabled = false;
}
if (!empty($product['attributes'])) {
foreach ($product['attributes'] as $attribute) {
if ($attribute['option'] === 's_produto') {
switch ($attribute['value']) {
case "sweatshirt_crianca" :
// .. do some code
break;
case "s_tamanho_produto" :
// .. do some code
break;
case "14_anos" :
// .. do some code
break;
case "something else" :
// .. do some code
break;
default:
break;
}
}
}
}
}
Sidyll beat me to it but I was thinking along similar lines:
// loop through each product
foreach ( $order->products as $prod )
{
if($prod['weight'] > '0.00')
{
$this->enabled = false;
}
if( isset($prod['attributes']) && is_array($prod['attributes']) )
{
$matching_product_type_found = false;
$matching_valid_size_found = false;
foreach ( $prod['attributes'] as $attr )
{
if ( $attr['option'] == 's_produto' &&
( $attr['value'] == 'sweatshirt_crianca' ||
$attr['value'] == 'sweatshirtc_crianca_capuz'
) )
{
$matching_product_type_found = true;
}
if ( $attr['option'] == 's_tamanho_produto' && $attr['value'] == '14_anos' )
{
$matching_valid_size_found = true;
}
}
if( $matching_product_type_found == true )
{
$this->enabled = $matching_valid_size_found;
}
}
}

If Key Value pair exists in multidimensional array.. How to?

I have a codeigniter shopping cart going and its "cart" array is the following:
Array (
[a87ff679a2f3e71d9181a67b7542122c] => Array
(
[rowid] => a87ff679a2f3e71d9181a67b7542122c
[id] => 4
[qty] => 1
[price] => 12.95
[name] => Maroon Choir Stole
[image] => 2353463627maroon_3.jpg
[custprod] => 0
[subtotal] => 12.95
)
[8f14e45fceea167a5a36dedd4bea2543] => Array
(
[rowid] => 8f14e45fceea167a5a36dedd4bea2543
[id] => 7
[qty] => 1
[price] => 12.95
[name] => Shiny Red Choir Stole
[image] => 2899638984red_vstole_1.jpg
[custprod] => 0
[subtotal] => 12.95
)
[eccbc87e4b5ce2fe28308fd9f2a7baf3] => Array
(
[rowid] => eccbc87e4b5ce2fe28308fd9f2a7baf3
[id] => 3
[qty] => 1
[price] => 14.95
[name] => Royal Blue Choir Stole
[image] => 1270984005royal_vstole.jpg
[custprod] => 1
[subtotal] => 14.95
)
)
My goal is to loop through this multidimensional array some how and if ANY product with the key value pair "custprod == 1" exists, then my checkout page will display one thing, and if no custom products are in the cart it displays another thing. Any help is appreciated. Thanks.
Rather than looping over it, you can check for the custprod key using array_key_exists. Or simply check to see if arr['custprod'] isset (both functions handle null differently).
$key = "custprod";
$arr = Array(
"custprod" => 1,
"someprop" => 23
);
if (array_key_exists($key, $arr) && 1 == $arr[$key]) {
// 'custprod' exists and is 1
}
function item_exists($cart, $custprod) {
foreach($cart as $item) {
if(array_key_exists("custprod", $item) && $item["custprod"] == $custprod) {
return true;
}
}
return false;
}
Now, you can use this function to check if product exist in stack:
if(item_exists($cart, 1)) {
// true
} else {
// false
}
You still need to loop the array to check it:
$cust_prod_found = false;
foreach($this->cart->contents() as $item){
if (array_key_exists("custprod", $item) && 1 == $item["custprod"]) {
$cust_prod_found = true; break;
}
}
if ($cust_prod_found) {
// display one thing
} else {
// display another thing
}

Needle search in array returns 0 if not found

I'm using this function to search the (highest) array key when a value of userid is found:
function array_search_value($needle,$haystack) {
foreach($haystack as $key => $value) {
if(in_array($needle, $value)) return $key;
}
}
My array looks like this (it's generated by a simple query):
Array
(
[0] => Array
(
[0] => 1
[userid] => 1
[1] => 2
[score1] => 2
[2] => 0
[score2] => 0
)
[1] => Array
(
[0] => 3
[userid] => 3
[1] => 2
[score1] => 2
[2] => 2
[score2] => 2
)
[2] => Array
(
[0] => 4
[userid] => 4
[1] => 1
[score1] => 1
[2] => 1
[score2] => 1
)
[3] =>
)
This code:
echo array_search_value(4, $r)
Returns 2, which is correct.
Looking for 1 gives 0, which is correct.
However, when I search for 2 (which can't be found), it returns 0.
This, off course, is not correct... What I want it to do is return nothing at all, not 0.
I've tried tweeking the function by adding "== true" but that won't work either.
Anyone know's how to fix this?
Thanks a lot!
when I search for 2 (which can't be found), it returns 0. This, off course, is not correct...
Looking at your provided array, it is correct. The value 2 appears in key 0:
[0] => Array
(
[0] => 1
[userid] => 1
[1] => 2 // here
[score1] => 2 // and here
[2] => 0
[score2] => 0
)
If you only want to look at the userid key, then you can't just use in_array(), but have to do such:
<?php
function array_search_value($needle,$haystack) {
foreach($haystack as $key => $value) {
if($value['userid'] === $needle) return $key;
}
return null; // not found
}
if (array_search_value(2, $r) === null) { /* doesn't happen */ }
When you search for 2 you will get 0 since you have $haystack[0][score1] = 2. You need to specify that you're looking for userid and not anything else.
foreach($haystack as $key => $value) {
if ($value['userid'] == $needle) {
return $key;
}
}

values not push on recursive array

Let me explain my problem. I try to generate an array of categories.
Here is my function.
private function recursiveCategoriesTree($id_parent, $level, $categories)
{
$tree = array();
foreach($categories as $categorie)
{
if($id_parent == $categorie['id_parent'])
{
$tree[$level][] = $categorie;
$this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories);
}
}
return $tree;
}
When I trace the loop with echo, everything seems to work, all the parent categories and girls are covered, but are not pushed into the array.
Here is the print_r of my categories
array(
[0] => Array
(
[id_category] => 4
[name] => Pièces détachées
[id_parent] => 1
)
[1] => Array
(
[id_category] => 5
[name] => Excavateur
[id_parent] => 4
)
[2] => Array
(
[id_category] => 6
[name] => série 100
[id_parent] => 5
)
[3] => Array
(
[id_category] => 7
[name] => above
[id_parent] => 6
)
[4] => Array
(
[id_category] => 8
[name] => système hydraulique
[id_parent] => 7
)
[5] => Array
(
[id_category] => 9
[name] => série 200
[id_parent] => 5
)
[6] => Array
(
[id_category] => 10
[name] => thru
[id_parent] => 6
)
[7] => Array
(
[id_category] => 11
[name] => Compaction
[id_parent] => 4
)
)
Here is the result of print_r generated
Array(
[0] => Array
(
[0] => Array
(
[id_category] => 5
[name] => Excavateur
[id_parent] => 4
)
[1] => Array
(
[id_category] => 11
[name] => Compaction
[id_parent] => 4
)
)
)
I call my function like that
$tree = $this->recursiveCategoriesTree(4, 0, $categories)
What is the problem ? thank you =)
Either get the return value from your recursive call and push that onto the array, or make a private property of the class called tree and push values onto that instead. You are not passing the variable $tree across recursive function calls.
E.g. if you do this it will work: (EDIT: Fixed... [again])
private $catTree = array();
private $catStartLevel = FALSE;
private function recursiveCategoriesTree($id_parent, $level, $categories) {
if ($this->catStartLevel !== FALSE) $this->catStartLevel = $level;
foreach($categories as $categorie) {
if($id_parent == $categorie['id_parent']) {
$this->catTree[$level][] = $categorie;
$this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories);
}
}
if ($this->catStartLevel === $level) {
$tree = $this->catTree;
$this->catTree = array();
$this->catStartLevel = FALSE;
}
return $tree;
}
...however this is not great, because you now have a 'pointless' private property in your class. You would be better to change you array structure, and catch the return values from $this->recursiveCategoriesTree()...
EDIT
Thinking about it, if you really want the array in that structure, you would probably be better to pass the variable to be populated with the array by reference:
private function recursiveCategoriesTree($id_parent, $level, $categories, &$tree) {
foreach($categories as $categorie) {
if($id_parent == $categorie['id_parent']) {
$tree[$level][] = $categorie;
$this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories, $tree);
}
}
}
...and then you would call it like this...
$myTree = array();
$obj->recursiveCategoriesTree($id_parent, $level, $categories, $myTree);
print_r($myTree);
recursiveCategoriesTree() returns the $tree, but you're not doing anything with that return value when you're calling the method recursively. You're only storing the $tree returned from the initial call to the method.
Perhaps you want something like this?
$categorie['children'] = $this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories);
You should first fetch all the childs of a category, and add them to its array, before appending the category to the tree. Kind of like this:
foreach($categories as $categorie)
{
$categorie['childs'] = $this->recursiveCategoriesTree($categorie['id_category'], ($level+1), $categories);
$tree[$level][] = $categorie;
}

Categories