I am having problems echoing array data from a nested array, my array (for a single order) looks like this...
Array
(
[buyer_name] => Mr Smith
[buyer_phone] => 01234 567890
[buyer_email] => mygreatemail#fakeemail.com
[items] => Array
(
[0] => Array
(
[quantity] => 3
[item_title] => title 1
[custom_label] => JD3433
[item_variation] => Variation detail for title 1
[price] => £8.00
)
[1] => Array
(
[quantity] => 1
[item_title] => title 2
[custom_label] => JD5544
[item_variation] => Variation detail for title 2
[price] => £7.00
)
)
)
Generated from this code...
function readCSV($csvFile)
{
$output = [];
$fileHandle = fopen($csvFile, 'r');
$header = fgetcsv($fileHandle);
while (!feof($fileHandle)) {
$fileRow = fgetcsv($fileHandle, 1024);
$orderId = $fileRow[0];
// skip this row if it's empty (the first field contains no id)
if (empty($orderId)) {
continue;
}
/*
$fileRow[3] is "Buyer name", the first field that's present in one type of row
(the one containing common properties of the order). By checking if it's empty,
we identify the contents of the row - not empty means order row with common
properties, empty means item row with specific item properties.
*/
if (!empty($fileRow[3])) {
// no need to repeat the id inside the array - it's already stored in the key
$output[$orderId] = [
'sales_record' => $fileRow[0],
'order_number' => $fileRow[1],
'buyer_username' => $fileRow[2],
'buyer_name' => $fileRow[3],
// here you can continue explicitly adding any property you need
];
} else {
// add a new item entry
$output[$orderId]['items'][] = [
'item_number' => $fileRow[20],
'item_title' => $fileRow[21],
'quantity' => $fileRow[24],
'price' => $fileRow[25],
// here you can continue explicitly adding any property you need
];
}
}
fclose($fileHandle);
return $output;
}
I can echo individual main array data without issue using..
foreach($csv as $order) {
echo "Sales Record: "; echo $order[sales_record];
}
But having problems trying to echo nested array data.
I have read many similar questions on here and tried..
foreach($csv[$orderId]['items'] as $orderitems) {
echo $orderitems; echo "<br>";
}
with no luck, what am I doing wrong, please?
EDIT TO ADD...
If I can't echo the array in that way then this would result in me using lots of "if" statements (there could be 100+ items in an order) and the below is just for an example for "title", I'd have to repeat several hundred times for each item in the nested array, there must be a better way to achieve this??
if ($order[items][0][item_title] != "") { echo $order[items][0][item_title]; echo "<br>"; } else {}
if ($order[items][1][item_title] != "") { echo $order[items][1][item_title]; echo "<br>"; } else {}
if ($order[items][2][item_title] != "") { echo $order[items][2][item_title]; echo "<br>"; } else {}
//and so on
First, array-keys must be in Quotation marks:
no: $order[items][0][item_title]
yes: $order['items'][0]['item_title']
Normally your PHP version throws a warning:
Warning: Use of undefined constant item_title - assumed 'item_title' (this will throw an Error in a future version of PHP)
You can iterate over the array:
foreach($order['items'] as $item) {
echo $item['item_title']."<br/>";
}
If you have a nested array (array of orders and each order has an array of items) you can nest the foreach.
$orders = readCSV('filename.csv');
foreach ($orders as $orderId=>$order) {
foreach($order['items'] as $item) {
if (!empty($item['item_title'])) echo $item['item_title']."<br/>";
}
}
. concat two strings. You don't Need two echo-commands.
Pay attention to the wording, that makes the code more readable.
foreach (<plural> as <singular>)
Related
When accessing the script I am writing, you pass the category path to it when accessing the page. The script then compares the data to an array of actual categories, or a branch, that should be associated with that category.
I am setting the parents and all of its children into a tree and then going down the branch and comparing the data to ensure the customer is using a correct url. Here's a quick example of how the code works:
// Customer is accessing from site.com/store/some-cat/some-othercat
// We pass those variables with the htaccess to script.php?var=$1,$2
// We then explode that to make an array on $var[0] and $var[1]
$categoryMap = explode(",", $_GET['var']);
$categoryID = array();
$categoryInfoMap = array();
foreach ($categoryMap as $a) {
$categoryIDs[] = trim($a);
}
$getCategoryInfo = $db->fn->query("SELECT * FROM store_category");
....
// Inside while loop...
$categoryInfoMap[] = $db->result[]; // stored whole results as array
// End of the while loop
$masterKey = $mainClass->findKeyInDbArray($categoryInfoMap, 'c.path', $categoryMap[0]);
if ((isset($masterKey) && $masterKey === "0") || !empty($masterKey)) {
$thisId = $categoryInfoMap[$masterKey]['c.id'];
$thisPath = $categoryInfoMap[$masterKey]['c.path'];
$thisName = $categoryInfoMap[$masterKey]['c.name'];
$tree = $mainClass->buildTree($categoryInfoMap);
$children = $tree['children'][$thisId];
$childrenItems = "";
foreach ($categoryIDs as $cid) {
// One of the categories entered doesnt exist at all so we redirect,
// else we will go through them and make sure theyre apart of the branch
if (!$mainClass->recursive_array_search($cid, $tree)) {
... redirect them somewhere and die()
} else {
if (!$mainClass->recursive_array_search($cid, $children)) {
... redirect them somewhere and die()
} else {
!!!!!!!!!!!!============!!!!!!!!!!!!!!
THIS IS THE IMPORTANT PART HERE
!!!!!!!!!!!!============!!!!!!!!!!!!!!
}
}
}
}
... Rest of the script which works for now
Here is the functions used in the code above
public function findKeyInDbArray($products, $field, $value) {
foreach($products as $key => $product) {
if ($product[$field] === $value) {
return "$key";
}
}
return NULL;
}
public function buildTree($arr) {
$tree = array(
'children' => array()
);
$index = array(0=>&$tree);
foreach ($arr as $key => $val) {
$parent = &$index[$val['c.parentcatid']];
$node = $val;
$parent['children'][$val['c.id']] = $node;
$index[$val['c.id']] = &$parent['children'][$val['c.id']];
}
return $tree;
}
public function recursive_array_search($needle,$haystack) {
foreach($haystack as $key=>$value) {
$current_key=$key;
if($needle===$value OR (is_array($value) && $this->recursive_array_search($needle,$value) !== false)) {
return $current_key;
}
}
return false;
}
And here's an example of the tree array, from the parent node down. Shorted for visibility reasons
Array(
[c.id] => 1
[c.name] => Radios
[c.path] => radios
[c.parentcatid] => 0
[children] => (
[2] => (
[0] => 2
....
[children] => (
[3] => (
[c.id] => 3
....
[c.parentcatid] => 2
),
[4] => (
[c.id] => 4
....
[c.parentcatid] => 2
)
)
)
......
[10] => (
[0] => 10
....
[c.parentcatid] => 1
)
)
SO onto the good bits
Right now the code is working to prove that the branches have matching variables from their tree. If the item path, which is the variable we are using to compare to the url $var matches, then it will continue and work. so if in the branch the following values exist:
array(c.path => 'foo'),
array(c.path => 'bar')
And I visit the script as site.com/store/foo/bar then everything works great. If i visit the site as site.com/store/foo/notBar then it will fail, as the notBar variable is not a member of this branch. That's perfect right? Everything should work! Except it doesn't and for a good reason.
The issue here
If the item matches in the branch then it has passed the check and it's the end of the check. Not if the item is passed in the wrong order, such as site.com/store/bar/foo, then it still technically has good variables in it, but it should NOT pass since the structure is not in the order its coming down the parent array. Likewise, if another branch farther up the tree, lets say barwithNoChildren exists, i can swap foo or bar out with it and still pass, even though nothing should be there.
Hopefully you guy understand what I am asking, and can help suggest ways around this. I've been wracking my brain on this system for the last couple of days and since they want fancy urls for seo and other reasons, it's been a lot more difficult than I planned. Thanks for any suggestions!
A tree structure is not really helpful for this purpose. You should be thinking about how to create a data structure that makes it easy for you to match the input. Since your category input describes a branch of the tree, the best thing to do is build an array that you can use to match those branch descriptions to your categories efficiently.
Let's build an array where the keys are the paths for each category as described by their slugs, and the values are the category IDs. We can then immediately identify the matching category, or fail if the path is not in the array.
This breadcrumb-like structure is another pattern that is commonly used with categories. Along with the tree and flat id map, you can do pretty much anything you need. The key takeaway is to think about creating different structures with your data to accomplish different tasks. It's usually more efficient and less error prone to create a new structure that's easy to work with than it is to create complex logic to try and work with an existing structure that doesn't lend itself to the task at hand.
<?php
//Mock category records, would come from the DB in the real world
$categoryRecords = [
['id' => 1, 'title' => 'Radios', 'slug' => 'radios', 'parent_id' => 0],
['id' => 2, 'title' => 'Accessories', 'slug' => 'misc', 'parent_id' => 1],
['id' => 3, 'title' => 'Motorola', 'slug' => 'motorola', 'parent_id' => 1],
['id' => 4, 'title' => 'Handheld', 'slug' => 'handheld', 'parent_id' => 3],
['id' => 5, 'title' => 'Mobile', 'slug' => 'mobile', 'parent_id' => 3]
];
//Create an array that maps parent IDs to primary keys
$idMap = [];
foreach ($categoryRecords as $currRecord)
{
$idMap[$currRecord['id']] = $currRecord;
}
//Traverse the flat array and build the path lines
$paths = [];
$categoryIds = array_keys($idMap);
foreach ($categoryIds as $currLeafId)
{
$currCategoryId = $currLeafId;
$currLine = [];
do
{
$currLine[] = $idMap[$currCategoryId]['slug'];
$currCategoryId = $idMap[$currCategoryId]['parent_id'];
} while ($currCategoryId != 0);
$currLine = array_reverse($currLine);
$currPath = implode('/', $currLine);
$paths[$currPath] = $currLeafId;
}
//Join your input - $_GET['var'] in your example
$inputPath = implode('/', ['radios', 'motorola', 'handheld']);
//Now you can see if the incoming path matched a category
if(array_key_exists($inputPath, $paths))
{
$category = $categoryRecords[$paths[$inputPath]];
echo 'Matched category: '.$category['title'].PHP_EOL;
}
else
{
echo 'Invalid category path';
}
I am struggling with what would appear to be a pretty straight forward task. I have looked at and tried all kinds of functions and suggestion on SO hoping that maybe there is something simple and functional out there. Nothing I tried gives me the logic to do the restructuring.
I have a long complex array. However very much simplified the logic problem I am trying to solve generically is as follows:
$cost_type = Array
(
0 => "ISP2",
1 => "ISP3",
2 => "ISP4"
);
$supplier_name = Array
(
0 => "NAME-A",
1 => "NAME-B",
2 => "NAME-C"
);
$propertyid = Array
(
0 => "property1",
1 => "property2",
2 => "property2"
);
and I need to convert it to the following set of arrays (noting the concatenation of the two arrays with a common property id.....
$property1
(
array['charges']
[0] =>IPS2
array ['names']
[0] =>NAME-A
)
$property2
(
array['charges']
[0] ->IPS3
[1] =>IPS4
array['names']
[0] =>NAME-B
[1] =>NAME-c
)
I have tried everything over the course of the last few hours and a simple solution totally evades me.
If you can join the three arrays as you say in comments above this code will generate the look you want.
I loop through the array with property and keep key as the key to find names and charges in the other subarrays.
$cost_type = Array
(
0 => "ISP2",
1 => "ISP3",
2 => "ISP4"
);
$supplier_name =Array
(
0 => "NAME-A",
1 => "NAME-B",
2 => "NAME-C"
);
$propertyid = Array
(
0 => "property1",
1 => "property2",
2 => "property2"
);
$arr[] = $cost_type;
$arr[] = $supplier_name;
$arr[] = $propertyid;
$result = array();
Foreach($arr[2] as $key => $prop){
$result[$prop]["charges"][] =$arr[0][$key];
$result[$prop]["names"][] = $arr[1][$key];
}
Var_dump($result);
https://3v4l.org/EilvE
The following code converts the original array in the expected result:
$res = array();
foreach($arr[2] as $k => $foo){ // foreach property
if(!isset($res[$foo])){ // add property if not yet in list
$res[$foo] = array(
'charges' => array($arr[0][$k]),
'names' => array($arr[1][$k])
);
}else{ // add new value to already existing property
$res[$foo]['charges'][] = $arr[0][$k];
$res[$foo]['names'][] = $arr[1][$k];
}
}
Check it out here: https://eval.in/904473
Of course, it assumes a bunch on things about the data, but it should work for any number of items.
And if you need the property in another variable, just access it with $res['name of it].
Run this code you will get smiler result as you want :
$twodimantion=array();
$properties=array('property1','property2','property3');
$charges=array('ISP2','ISP3','ISP4');
$names=array('NAME-A','NAME-B','NAME-C');
foreach ($properties as $key => $property) {
$twodimantion['charge'][$key]=$charges[$key];
$twodimantion['names'][$key]=$names[$key];
$twoarray[$property]=$twodimantion;
}
echo '<pre>';
print_r($twoarray);
echo '</pre>';
I can't say I completely follow what you are trying to do, but I think this may be part of the way there for you.
When trying to restructure data in PHP, it's often helpful to create a empty array (or other data structure) to store the new data in first. Then you find a way to loop over your initial data structure that allows you to insert items into your reformatted structure in the right sequence.
<?php
$properties = []; // Array to hold final result
// Loop over your initial inputs
foreach ($groupsOfValues as $groupName => $groupValues) {
$temp = []; // Array to hold each groupings reformatted data
// Loop over the items in one of the inputs
for ($i=0; $i<count($group) && $i<count($properties)+1; $i++) {
if (!is_array($temp[$groupName])) {
$temp[$groupName] = [];
}
$temp[$groupName][] = $group[$i];
}
$properties[] = $temp;
}
I am getting a response from database in array like this:
Array ( [mage_form_post_status] => draft [mage_form_post_type] => post [mage_form_post_permission] => public [mage_form_post_author] => 1 [mage_form_post_redirect] => 0 )
Array ( [mage_form_post_status] => draft [mage_form_post_type] => post [mage_form_post_permission] => public [mage_form_post_author] => 1 [mage_form_post_redirect] => 88 )
Array ( [mage_gym_name] => Fanna - test [mage_your_name] => John )
What I am trying to achieve is to display mage_gym_name value only.
I have succeed to display it with this code:
foreach($gym_titles as $gym_title){
print_r(unserialize($gym_title));
echo '<br><br><br>';
}
Problem is that when there is no result, like in first two arrays I get 3 empty breaklines.
So I believe that I should wrap:
print_r(unserialize($gym_title));
echo '<br><br><br>';
In some kind of condition which should check if that current array contains that key name.
I have tried like this but it doesn't work:
foreach($gym_titles as $gym_title){
if (array_key_exists('mage_gym_name', $gym_title) {
echo "The 'first' element is in the array";
print_r(unserialize($gym_title));
echo '<br><br><br>';
} else {
echo 'no such element in this array';
}
}
You need to unserialize() before you check for the key:
foreach($gym_titles as $gym_title){
$result = unserialize($gym_title);
if(isset($result['mage_gym_name'])) {
echo "The 'first' element is in the array";
print_r($result);
echo '<br><br><br>';
} else {
echo 'no such element in this array';
}
}
I use isset(), feel free to use array_key_exists() if you must.
I am trying to return pull a value based on an attribute from an array, and it seems straight forward enough but I can't seem to nail down the correct way to accomplish this.
Here is the array I am trying to pull from:
[1] => InfoOptions Object
(
[description] => INFO
[optSequence] => 2
[eqpObject] => CUSTOMER NTWK ENG
[attribute] =>
[eqpValue] =>
[dlrSequence] => 10
)
[2] => InfoOptions Object
(
[description] =>
[optSequence] => 3
[eqpObject] => CUSTOMER TEST
[attribute] => CUSTOMER
[eqpValue] => Jon Doe
[dlrSequence] => 10
)
Here is what I have so far:
if (is_array($provisionCVResult->path->infoOptions-_InfoOptions)) {
foreach ($provisionCVResult->path->infoOptions ->InfoOptions as $cv_obj) {
$CVA = array();
$result = null;
foreach ($CV_obj as $value) {
if($value['attribute'] == 'CUSTOMER') {
$CVA["eqpValue"] = $cv_obj->eqpValue;
break;
}
}
$this->cvArrayDataList[] = $CVA;
}
}
Where am I going wrong?
If $provisionCVResult->path->InfoOptions is an array, it does not make sense to write $provisionCVResult->path->InfoOptions ->InfoOptions in the foreach
EDIT: I red in the comments that the array is $provisionCVResult->path->InfoOptions->InfoOptions
PHP is case sensitive so $cv_obj and $CV_obj are two different variables
The second foreach is not needed
So, assuming $provisionCVResult->path->InfoOptions->InfoOptions is returning an array of InfoOptions Object, I think you should do something like this:
if (is_array($provisionCVResult->path->InfoOptions->InfoOptions))
{
$result = null;
foreach($provisionCVResult->path->InfoOptions->InfoOptions as $cv_obj)
{
if($cv_obj->attribute == 'CUSTOMER')
{
$this->cvArrayDataList[] = array("eqpValue" => $cv_obj->eqpValue);
}
}
}
Having a quick look, try changing
$value['attribute'] == 'CUSTOMER'
To
$value->attribute == 'CUSTOMER'
As the element is an "InfoOptions object" and not an array.
Note I would also recommend using strict comparison, e.g '===' instead of '=='.
So I have a function that merges two arrays replacing "variables" that are in the $template array with values from the $marketArray. It's nice tight bit of code from some kind contributor's here. Now due to a new requirement I need to switch things a bit.
First I need to make it an array of arrays that essentially groups the stuff by market instead of one giant list in a single large array. Secondly I need the keys in the new arrays to be of the format market-counter
e.g. gb/en-1, gb/en-2 etc etc (this is so a JQuery gets an id it can use to determine where the results go later.
So I have entered a couple of new entries (marked //NEW) that would get the value for the market and started a counter. It's twisting my brain around the next step that hurts!
$marketArray is a multidimensional associative array of the markets like this (but a lot more markets!)
$markets = array(
array(market => 'se/sv', storeid => 'storeId=66', langid => 'langId=-14', storenumber => '109', prodid => '741586', artid => '22112334'),
array(market => 'at/de', storeid => 'storeId=82', langid => 'langId=-11', storenumber => '234', prodid => '374637', artid => '45678214')
);
$template is a bunch of url templates that need to be manipulated on a market by market basis (again shortened)
$template = array (
'/$market',
'/$market/catalog/',
'/$marketproducts/$artid',
'StockSearchForm?&productId=$prodid'
);
Here is the function
function urlBuilder($marketArray,$template) {
$urlstohit=array();
foreach ($marketArray as $m) {
$market = $m['market']; //NEW
$counter = 1; //NEW
foreach ($template as $t) {
$tt=$t;
foreach ($m as $k=>$v)
$tt=str_replace('$'.$k, $v, $tt);
$urlstohit[]=$tt;
}
}
return ($urlstohit);
}
so what I am trying to achieve is instead of one giant array like
$urlstohit (
[0] => '/se/sv/catalog/categories/',
[1] => '/se/sv/catalog/news/',
[2] => '/se/sv/catalog/categories/departments/',
[3] => '/se/sv/search/?query=giant'
[4] => '/at/de/catalog/categories/',
[5] => '/at/de/catalog/news/',
[6] => '/at/de/catalog/categories/departments/',
[7] => '/at/de/search/?query=giant'
)
a md-array grouped by market with the market-counter as keys
$urlstohit (
['se/sv'] => array(
['se/sv-1'] => '/se/sv/catalog/categories/',
['se/sv-2'] => '/se/sv/catalog/news/',
['se/sv-3'] => '/se/sv/catalog/categories/departments/',
['se/sv-4'] => '/se/sv/search/?query=giant'
),
['at/de'] => array(
['at/de-1'] => '/at/de/catalog/categories/',
['at/de-2'] => '/at/de/catalog/news/',
['at/de-3'] => '/at/de/catalog/categories/departments/',
['at/de-4'] => '/at/de/search/?query=giant'
)
)
Try this
function urlBuilder($marketArray,$template) {
$urlstohit=array();
foreach ($marketArray as $m) {
$market = $m['market'];
$counter = 1;
$urlstohit[$market] = array(); / ADDED
foreach ($template as $t) {
$tt=$t;
foreach ($m as $k=>$v)
$tt=str_replace('$'.$k, $v, $tt);
$urlstohit[$market][$market.'-'.$counter]=$tt; // EDITED
$counter++; // ADDED
}
}
} // ADDED
return ($urlstohit);
}
I've marked the lines I've added and edited (I think you were also missing a curly brace).