Different array structures and breaking of foreach - php

I generate XML file from dynamic content but I get 2 array types to get images:
First array type is when there are more than 1 images, example:
array(1) {
["Images"]=>
array(3) {
[0]=>
array(2) {
["Url"]=>
string(57) "http://example.net/image1.jpg"
["Default"]=>
bool(true)
}
[1]=>
array(2) {
["Url"]=>
string(57) "http://example.net/image2.jpg"
["Default"]=>
bool(false)
}
[2]=>
array(2) {
["Url"]=>
string(57) "http://example.net/image3.jpg"
["Default"]=>
bool(false)
}
}
}
Second type is when I had only 1 image, example:
array(1) {
["Images"]=>
array(2) {
["Url"]=>
string(57) "http://example.net/image111.jpg"
["Default"]=>
bool(true)
}
}
How I can make second type to use type of first array, because when I looping these arrays with foreach there is a problem with content. Is there any function to fix this or something?!
Edit:
This is the foreach now and it works:
$productImages = $product->appendChild($this->_xmlDoc->createElement('ProductImages'));
if(isset($productInfo['ProductImages'])) {
foreach($productInfo['ProductImages']['Images'] as $image) {
if(!is_array($image) && is_string($image)) {
$productImage = $productImages->appendChild($this->_xmlDoc->createElement('ProductImage'));
$productImage->appendChild($this->_xmlDoc->createElement('ImagePath', $image));
}
if(isset($image['Url']) && is_array($image)) {
$productImage = $productImages->appendChild($this->_xmlDoc->createElement('ProductImage'));
$productImage->appendChild($this->_xmlDoc->createElement('ImagePath', $image['Url']));
}
}
}
This is how foreach looks 20 minutes after my question. So I'll vote for first answer, because its similar to my work around :)
Cheers,
Georgi!

I've encountered the same issue before with using a SOAP call. You don't need to change the structure of the array. You can simply change the behaviour of your foreach loop instead, using is_array. It checks if the variable is an array or not. Example, using your arrays:
$first_array = array(
"Images" => array(
array("Url" => "http://example.net/image1.jpg", "Default" => true),
array("Url" => "http://example.net/image2.jpg", "Default" => false),
array("Url" => "http://example.net/image3.jpg", "Default" => false)
)
);
$second_array = array(
"Images" => array(
"Url" => "http://example.net/image111.jpg",
"Default" => true
)
);
echo "Results on the first array:<br />";
foreach ($first_array["Images"] as $element) {
if (is_array($element)) {
foreach ($element as $value) {
echo $value . "<br />";
}
} else {
echo $element . "<br />";
}
}
echo "<br />";
echo "Result on the second array:<br />";
foreach ($second_array["Images"] as $element) {
if (is_array($element)) {
foreach ($element as $value) {
echo $value . "<br />";
}
} else {
echo $element . "<br />";
}
}
PHPFiddle Link: http://phpfiddle.org/main/code/4y8j-4jd1

Related

Template Engine refactoring

$global_models =
array(12) {
["page.login"]=>
string(1) "2"
["page.item.id"]=>
string(3) "new"
["page.content.title"]=>
string(0) ""
["page.trigger.date"]=>
string(0) ""
["page.trigger.url"]=>
string(0) ""
["page.trigger.admin_only"]=>
string(1) "N"
["page.content.body"]=>
string(0) ""
["page..ga"]=>
string(27) "GA1.2.1694644634.1491872034"
["prompt.message"]=>
string(0) ""
["prompt.error"]=>
string(0) ""
["page.tags"]=>
array(1) {
["name"]=>
array(2) {
[0]=>
string(2) "xx"
[1]=>
string(2) "yy"
}
}
["page.custom"]=>
array(2) {
["header"]=>
array(2) {
[0]=>
string(0) "1"
[1]=>
string(1) "a"
}
["value"]=>
array(2) {
[0]=>
string(0) "2"
[1]=>
string(1) "b"
}
}
}
Code:
foreach ($global_models as $var => $data) {
// when model data is an array
if (is_array($data)) {
// fetch for blocks and render loops
$forblocks = array();
preg_match_all('/(?<block>\[for:'.$var.'\](?<content>[\s\S]+)\[end:'.$var.'\])/ix', $view_output, $forblocks, PREG_SET_ORDER);
if (count($forblocks)) {
foreach ($forblocks as $foundForBlock) {
$foreach_data = '';
foreach ($data as $mykey => $row) {
// set model values within the loop, ex: blocks.x value
$block_content = $foundForBlock['content'];
foreach ($row as $subvar => $value) {
if (!is_array($value)) {
$block_content = str_replace('['.$var.'.'.$subvar.']', $value, $block_content);
//$block_content = str_replace('['.$var.'.'.$mykey.']', $value, $block_content);
}
}
// append the parsed new block (of for loop) as processed view to render (ifs and setters for example)
$foreach_data .= $this->process_view($controller, $block_content, $recursion_level + 1);
}
$view_output = str_replace($foundForBlock['block'], $foreach_data, $view_output);
}
}
} else {
// simple model, replace model with value ex: "[stats.x]" by "18"
$view_output = str_replace('['.$var.']', $data, $view_output);
}
}
Issue:
Key to value pair works
my blocks of data don't work...
$viewoutput =
"
[page.login]
"
should result in
"
2
"
This:
$viewoutput =
"
[for:page.custom]
[page.custom.header] - [page.custom.value]
[end:page.custom]
"
should result in
"
1 - 2
a - b
"
This:
$viewoutput =
"
[for:page.tags]
[page.tags.name]
[end:page.tags]
"
should result in
"
xx
yy
"
I've refactored my code about 20 times and each time I get a headache...!
Someone please help?
Thanks and viva la community! :)
I have tried my self best to get it done. I know this is not a generic solution but it will solve your current problem. You must use different function for using loop([for:page.custom]) and simple([page.login]) attribute. I have already went through this issue. I also solved one of my problem by this, Here you should define seperate function which will first decide which function will handle modification whether it is for loop or for simple. But for now i have fixed your issue with a single php function.
Try this code snippet here
<?php
ini_set('display_errors', 1);
$global_models = array(
"page.login" => "2",
"page.item.id" => "new",
"page.content.title" => "",
"page.trigger.date" => "",
"page.trigger.url" => "",
"page.trigger.admin_only" => "N",
"page.content.body" => "testing",
"page..ga" => "GA1.2.1694644634.1491872034",
"prompt.message" => "",
"prompt.error" => "",
"page.tags" =>
array(
"name" =>
array(
0 => "xx",
1 => "yy"
)
),
"page.custom" =>
array(
"header" =>
array(
0 => "1",
1 => "a",
),
"value" =>
array(
0 => "2",
1 => "b",
)
)
);
$viewoutput =
"
[page.content.body]
[for:page.custom]
[page.custom.header] - [page.custom.value]
[end:page.custom]
";
echo modify($viewoutput);
function modify($viewoutput)
{
$returnString="";
global $global_models;
$segments=explode("\n", $viewoutput);
$counter=0;
while(count($segments)>0)
{
$segment=$segments[$counter];
if (preg_match("/\[for:\K([\w\.]+)\]/", $segment,$matches))
{
unset($segments[$counter]);
$counter++;
$segment=$segments[$counter];
$pointer=0;
$data=array();
preg_match_all("/\.([\w]+)\]/", $segment,$segmentMatches);
for($x=0;$x<count($global_models[$matches[1]][$segmentMatches[1][0]]);$x++)
{
$newString=$segment;
foreach($segmentMatches[1] as $toReplace)
{
$newString= str_replace("[".$matches[1].".".$toReplace."]", $global_models[$matches[1]][$toReplace][$x], $newString);
}
$data[]=$newString;
}
}
elseif(preg_match("/\[end:\K([\w\.]+)\]/", $segment))
{
$returnString.= implode("\n", $data);
}
elseif(preg_match("/\[([\w\.]+)\]/", $segment,$matches1) && !preg_match("/\[for:\K([\w\.]+)\]/", $segment,$matches))
{
$returnString=$returnString.$global_models[$matches1[1]]."\n";
}
else
{
$returnString=$returnString.$segment."\n";
}
unset($segments[$counter]);
$counter++;
}
return $returnString;
}
Fixed myself...
// process shared models (variables)
foreach ($global_models as $var => $data) {
// when model data is an array
if (is_array($data)) {
// fetch for blocks and render loops
$forblocks = array();
preg_match_all('/(?<block>\[for:'.$var.'\](?<content>[\s\S]+)\[end:'.$var.'\])/ix', $view_output, $forblocks, PREG_SET_ORDER);
if (count($forblocks)) {
foreach ($forblocks as $foundForBlock) {
$block_content = array();
foreach ($data as $mykey => $row) {
//$foreach_data = '';
// set model values within the loop, ex: blocks.x value
foreach ($row as $subvar => $value) {
if (!isset($block_content[$subvar])) $block_content[$subvar] = $foundForBlock['content'];
if (!is_array($value)) {
if (is_numeric($subvar)) {
$block_content[$subvar] = str_replace('['.$var.'.'.$mykey.']', $value, $block_content[$subvar]);
}
}
}
// append the parsed new block (of for loop) as processed view to render (ifs and setters for example)
}
$block_content = implode("\n", $block_content);
$view_output = str_replace($foundForBlock['block'], $block_content, $view_output);
}
}
} else {
// simple model, replace model with value ex: "[stats.x]" by "18"
$view_output = str_replace('['.$var.']', $data, $view_output);
}
}

How to loop and get serialized values from database with php

I'm developing a pizza's restaurant ecommerce and now I'm trying to get the size (Familiar) and the ingredients (Pernil dol�, Bac�, Emmental) of a pizza that was ordered previously. The data I want to get (the italic values in this paragraph) becomes serialized from database:
a:4:{s:10:"attributes";a:2:{s:6:"Tamany";a:1:{i:3;s:8:"Familiar";}s:11:"Ingredients";a:3:{i:318;s:12:"Pernil dol�";i:270;s:5:"Bac�";i:294;s:8:"Emmental";}}s:9:"shippable";s:1:"0";s:4:"type";s:5:"pizza";s:6:"module";s:10:"uc_product";}array(4) { ["attributes"]=> array(2) { ["Tamany"]=> array(1) { [3]=> string(8) "Familiar" } ["Ingredients"]=> array(3) { [318]=> string(11) "Pernil dol�" [270]=> string(4) "Bac�" [294]=> string(8) "Emmental" } } ["shippable"]=> string(1) "0" ["type"]=> string(5) "pizza" ["module"]=> string(10) "uc_product" }
I discovered 'unserialized' php method and I tried this:
$attr = $row['data']; // data from database
$data = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $attr); // I did this because I get some errors...
After I did that, I got this multidimensional array (a bit more human readable):
array(4) { ["attributes"]=> array(2) { ["Tamany"]=> array(1) { [3]=> string(8) "Familiar" } ["Ingredients"]=> array(3) { [318]=> string(11) "Pernil dol�" [270]=> string(4) "Bac�" [294]=> string(8) "Emmental" } } ["shippable"]=> string(1) "0" ["type"]=> string(5) "pizza" ["module"]=> string(10) "uc_product" }
Next step was try to loop the resulting data with a foreach loop, like the following:
foreach($data['attributes'] as $item)
{
print '<ul>';
foreach($item as $value)
{
print_r('<li>' . $value . '</li>');
}
print '</ul>';
}
I'm a php beginner PHP developer and I can't figure out how can I loop this array in order to get the values I need. I'm getting this error:
Warning: Invalid argument supplied for foreach() in /home/my_host/public_html/dev.mysite.com/inc/file.php on line 79
Can anybody tell me how I have to loop this array to get the data?
Any help will be very, very appreciated.
Best regards,
I created this example for you. First I declared an array which believe mimics the array you have to parse. Then I looped through and outputed the contents of the array.
<?php
$array = array(
0 => array(
'0' => 'John Doe',
'1' => 'john#example.com'
),
1 => array(
'0' => 'Jane Doe',
'1' => 'jane#example.com'
),
);
foreach ($array as $key => $value) {
$thisArray = $array[$key];
print_r('<ul>');
foreach ($thisArray as $key2 => $value){
print_r('<li>'.$thisArray[$key2].'</li>');
}
print_r('</ul>');
}
?>
Finally, and based on the answer of #Gregory Hart, I reached my goal. This is the final code that makes it possible in my particular case:
$data = $row['data'];
$attrib = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $data);
$attr = unserialize($attrib);
foreach ($attr as $key => $value)
{
print_r('<ul>');
$thisArray = $attr[$key];
foreach ($thisArray as $key2 => $value2)
{
print_r('<li>' . $key2 . ': ');
$thisArray2 = $attr[$key][$key2];
foreach ($thisArray2 as $key3 => $value3)
{
if ($key2 == 'Tamany')
print_r('<span class="label label-warning">' . utf8_encode($thisArray2[$key3]) . '</span> ');
if ($key2 == 'Ingredients')
print_r('<span class="label label-success">' . utf8_encode($thisArray2[$key3]) . '</span> ');
if ($key2 == 'Salsa')
print_r('<span class="label label-primary">' . utf8_encode($thisArray2[$key3]) . '</span> ');
}
print '</li>';
}
print_r('</ul>');
}
Thanks for you help!
Try this logic:
$data_unserialize = unserialize($row->data);
foreach ($data_unserialize as $data_key => $data_value) {
if($data_key =='size')
{
$thisArray = $data_unserialize[$data_key ];
foreach ($thisArray as $key2 => $value2){
if($key2=='attributes')
{
switch ($value2)
{
case "Pernil dol�":
echo'Pernil dol �';
break;
case "Emmental":
echo'Emmental';
break;
default:
echo 'Nothing';
}
}
}
}
}
NB:- And remove the break; from switch statement to display all ingrediants.

Foreach loop working, but outputting "invalid argument"?

I hope to give enough information here, but I am confused as to why the foreach loop works, it gets each data and outputs it in an li but I am getting an invalid argument error?
Here is the result of the var_dump
array(1) { ["questions"]=>
array(2) { ["title"]=> string(5) "Keanu" [1]=>
array(1) { ["questionlist"]=> array(2) { [0]=>
array(1) {
["a-question"]=> string(1) "1" } [1]=> array(1) {
["a-question"]=> string(5) "civil" } } } } }
Here is my foreach statement
foreach($questions['questions'] as $key => $value){
foreach($value['questionlist'] as $key => $subquestion){ //line 119
echo '<li>'.$subquestion['a-question'].'</li>';
}
}
$questions is a variable used to get the data from the database like this.
$questions = $wpdb->get_row("SELECT * FROM $table_name ORDER BY id DESC LIMIT 1" , ARRAY_A);
The data comes from ajax, I modify the ajax $_POST like this before sending to the database.
// Add modifications
$questions['questions'] = $_POST['questions']['data'];
// DB data
$name = $wpdb->escape($questions['questions']['title']);
$data = $wpdb->escape(json_encode($questions));
Screenshot:
I am not sure why I am getting the invalid argument, I suspect its because the array may not be formatted properly, if you need any more information let me know.
A Solution: Thanks to #didierc
I used his code and modified it a bit to display my data in a loop, basically all I did was add another foreach.
foreach($questions['questions'] as $key => $value){
if(is_array($value) && isset($value[ 'questionlist'])){
foreach($value as $key => $subquestion){ //line 119
foreach ($subquestion as $key => $value){
// This loops all the ['a-question'] data
echo '<li>''.$value['a-question'].''</li>';
}
}
}
}
Try this:
foreach ($questions['questions'] as $key => $value) {
if (is_array($value) && isset($value[ 'questionlist'])) {
foreach ($value['questionlist'] as $subnum => $subquestion) {
foreach ($subquestion as $qtitle => $qanswer) {
With variable names hopefully explicit enough. That should get you started.
NB: The data is probably easier to understand when formatted as below:
array(1) {
["questions"]=> array(2) {
["title"] => string(5) "Keanu"
[1] => array(1) {
["questionlist"]=> array(2) {
[0]=> array(1) {
["a-question"]=> string(1) "1"
}
[1]=> array(1) {
["a-question"]=> string(5) "civil"
}
}
}
}
}

create php array using simpleXMLobject

I'm trying to get this array ($resdata) with object(SimpleXMLElement) into a php array:
$resdata =
array(59) {
[0]=> ...
[10]=> object(SimpleXMLElement)#294 (28) {
["reservation_id"]=> string(7) "8210614"
["event_id"]=> string(6) "279215"
["space_reservation"]=> array(2) {
[0]=> object(SimpleXMLElement)#344 (9) {
["space_id"]=> string(4) "3760"
["space_name"]=> string(9) "205"
["formal_name"]=> string(33) "Center" }
[1]=> object(SimpleXMLElement)#350 (9) {
["space_id"]=> string(4) "3769"
["space_name"]=> string(9) "207"
["formal_name"]=> string(32) "Right" } } }
}
I've tried:
$res = (array)$resdata;
$reservation = $res['reservation'];
$result = array();
foreach ($reservation as $key => $value){
$res = array($value);
$spid = $res[0]->space_reservation->space_id;
echo $value->event_id."<br />";
echo $spid."<br />";
}
This only outputs the first space_id and I need to get all the space_ids within "space_reservation" array. Not all records will have multiple space_ids. Any help pointing me in the right direction is appreciated. Not sure if I should use xpath but I need to re-write my foreach statement regardless.
I was hoping to be able to literally convert all references to "object(SimpleXMLElement)#_ (#)" to "array(#)"
[10]=> array (28) {
["reservation_id"]=> string(7) "8210614"
["event_id"]=> string(6) "279215"
["space_reservation"]=> array(2) {
[0]=> array (9) {
["space_id"]=> string(4) "3760"
["space_name"]=> string(9) "205"
["formal_name"]=> string(33) "Center" }
[1]=> array (9) {
["space_id"]=> string(4) "3769"
["space_name"]=> string(9) "207"
["formal_name"]=> string(32) "Right" } } }
}
the function in my cakephp 1.3 controller is this:
$xml = simplexml_load_string($string);
$this->data['events']= $xml->children();
$resdata = $this->data['events'];
$this->set('resdata',$resdata);
I think this should do what you are looking for:
foreach ($resdata as $res) {
echo $res->event_id . '<br />';
foreach ($res->space_reservation as $reservation) {
echo $reservation->space_id . '<br />';
}
}
Googled it and found a general solution for any SimpleXMLElement to array conversion:
function xml2array($xml) {
$arr = array();
foreach ($xml as $element) {
$tag = $element->getName();
$e = get_object_vars($element);
if (!empty($e)) {
$arr[$tag] = $element instanceof SimpleXMLElement ? xml2array($element) : $e;
}
else {
$arr[$tag] = trim($element);
}
}
return $arr;
}

Traverse non-numerical indexes of an array

Think I'm missing a basic concept. I want to generate html by traversing through a few different arrays of data. They don't use numbers as indexes so numerical looping doesn't work. I cant figure out how to use a foreach() here either. How can I traverse $price and $description when the indexes aren't numbers?
Sample:
$traverser= 0;
while($traverser < $number_of_records)
{
print $traverser . " - " . $price[$traverser] . "<br />";
print $description[$traverser];
$traverser++;
}
Partial Sample of the Array Structure:
object(phpQueryObject)#2799 (13) { ["documentID"]=> string(32) "1d62be942498df890cab4ccb78a007a2" ["document"]=> &object(DOMDocument)#3 (0) { } ["charset"]=> &string(5) "utf-8" ["documentWrapper"]=> &object(DOMDocumentWrapper)#2 (17) { ["document"]=> &object(DOMDocument)#3 (0) { } ["id"]=> string(32) "1d62be942498df890cab4ccb78a007a2" ["contentType"]=> string(9) "text/html" ["xpath"]=> &object(DOMXPath)#4 (0) { } ["uuid"]=> int(0) ["data"]=> array(0) { } ["dataNodes"]=> array(0) { } ["events"]=> array(0) { } ["eventsNodes"]=> array(0) { } ["eventsGlobal"]=> array(0) { } ["frames"]=> array(0) { } ["root"]=> &object(DOMElement)#5 (0) { } ["isDocumentFragment"]=> &bool(true) ["isXML"]=> bool(false) ["isXHTML"]=> bool(false) ["isHTML"]=> bool(true) ["charset"]=> &string(5) "utf-8" } ["xpath"]=> &object(DOMXPath)#4 (0) { } ["elements"]=> array(560) { [0]=> object(DOMElement)#2239 (0) { } [1]=> object(DOMElement)#2240 (0) { } [2]=> object(DOMElement)#2241 (0) { } [3]=> object(DOMElement)#2242 (0) { } [4]=> object(DOMElement)#2243 (0) { } [5]=> object(DOMElement)#2244 (0) { } [6]=> object(DOMElement)#2245 (0) { } [7]=> object(DOMElement)#2246 (0) { } [8]=> object(DOMElement)#2247 (0) { }
Since it looks like you need the array keys as well, since you're referencing multiple different arrays, you want the $a as $k => $v syntax for foreach:
foreach($description as $key => $desc)
{
print $key . " - " . $price[$key] . "<br />";
print $desc;
}
You can take your pic as to how you want to iterate them:
<?php
$ary = array( // demo array
'apple' => 'Apple',
'orange' => 'Orange',
'grape' => 'Grape'
);
// show the structure
var_dump($ary); echo "\r\n";
// use a foreach with the key and value
foreach ($ary as $key => $val)
printf("%s => %s\r\n", $key, $val);
echo "\r\n";
// just get the raw keys
$keys = array_keys($ary);
var_dump($keys); echo "\r\n";
output:
array(3) {
["apple"]=>
string(5) "Apple"
["orange"]=>
string(6) "Orange"
["grape"]=>
string(5) "Grape"
}
apple => Apple
orange => Orange
grape => Grape
array(3) {
[0]=>
string(5) "apple"
[1]=>
string(6) "orange"
[2]=>
string(5) "grape"
}
There's always array_map & array_walk.
I'm not sure I get the question, but it's really as simple as:
<?php
$array = array('foo', 'bar');
foreach ($array as $element) {
echo "{$element}\n";
}
This should output "foo" and "bar".

Categories