Template Engine refactoring - php

$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);
}
}

Related

How can I print all children of a specific array that I detect via URL parameter?

This is my array:
array(1) {
["farm"]=>
array(1) {
["animals"]=>
array(1) {
[horses]=>
array(4) {
["fred"]=>
string(4) "fred"
["sam"]=>
string(4) "sam"
["alan"]=>
string(4) "alan"
["john"]=>
string(4) "john"
}
}
}
}
And this is my URL
mypage.php?id=2&dir=animals
I would like to print the children of my URL parameter dir(In this case:animals)
This is the way I try to do it:
foreach($array as $sub) {
if ($_GET['dir'] == $sub){
$result = array_merge($result, $sub);
echo $result;
}
}
My result: An empty page.
The result I wish: horses
Your array:
$arr = array("farm" =>
array("animals"=>
array("horses" =>
array("fred" => "fred",
"sam" => "sam",
"alan" => "alan",
"john" => "john")
)
)
);
Here we go, i make a recursive function for searching the value.
This function not work if you search for fred and their siblings.
$search = 'horses';
get_values($arr);
function get_values($arr){
global $search;
foreach($arr as $key => $value){
if($key == $search){
if(is_array($value)){
echo join(", ", array_keys($value));
}
else{
echo $value;
}
}else{
get_values($value);
}
}
}
Output:
fred, sam, alan, john
Your $array has a farm key and that farm only contains your dir animals.
If everything is in farm you can do like this:
if(!empty($_GET['dir'])) {
$result = array_merge($result, $array['form'][$_GET['dir']]
}
print_r($result);
I don't know what $result contains initially, but you can adapt if this is not the case or just echo $array['form'][$_GET['dir']] if you don't have multiple items in $result

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.

Different array structures and breaking of foreach

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

php count+array_filter multiple values within a multi dimensional array [duplicate]

This question already has answers here:
array_count_values() with objects as values
(3 answers)
Closed 6 months ago.
How can I prevent duplicating the same block of code for each value that I want to search for?
I want to create a new array ($result) by counting for specific values within another multi-dimensional array ($data).
$result = array();
$result['Insulin'] = count(array_filter($data,function ($entry) {
return ($entry['choice'] == 'Insulin');
}
)
);
$result['TZD'] = count(array_filter($data,function ($entry) {
return ($entry['choice'] == 'TZD');
}
)
);
$result['SGLT-2'] = count(array_filter($data,function ($entry) {
return ($entry['choice'] == 'SGLT-2');
}
)
);
$data array example:
array(2) {
[0]=>
array(9) {
["breakout_id"]=>
string(1) "1"
["case_id"]=>
string(1) "1"
["stage_id"]=>
string(1) "1"
["chart_id"]=>
string(1) "1"
["user_id"]=>
string(2) "10"
["region"]=>
string(6) "Sweden"
["choice"]=>
string(7) "Insulin"
["switched_choice"]=>
NULL
["keep"]=>
string(1) "1"
}
[1]=>
array(9) {
["breakout_id"]=>
string(1) "1"
["case_id"]=>
string(1) "1"
["stage_id"]=>
string(1) "1"
["chart_id"]=>
string(1) "1"
["user_id"]=>
string(1) "7"
["region"]=>
string(6) "Sweden"
["choice"]=>
string(7) "Insulin"
["switched_choice"]=>
NULL
["keep"]=>
string(1) "1"
}
}
You may convert your anonymous function into a closure with the use keyword. Pass in a string variable for the value you want to match.
// Array of strings to match and use as output keys
$keys = array('Insulin','TZD','SGLT-2');
// Output array
$result = array();
// Loop over array of keys and call the count(array_filter())
// returning the result to $result[$key]
foreach ($keys as $key) {
// Pass $key to the closure
$result[$key] = count(array_filter($data,function ($entry) use ($key) {
return ($entry['choice'] == $key);
}));
}
Converting your var_dump() to an array and running this against it, the output is:
Array
(
[Insulin] => 2
[TZD] => 0
[SGLT-2] => 0
)
You can simplify it with array_count_values() as well:
$result2 = array_count_values(array_map(function($d) {
return $d['choice'];
}, $data));
print_r($result2);
Array
(
[Insulin] => 2
)
If you need zero counts for the missing ones, you may use array_merge():
// Start with an array of zeroed values
$desired = array('Insulin'=>0, 'TZD'=>0, 'SGLT-2'=>0);
// Merge it with the results from above
print_r(array_merge($desired, $result2));
Array
(
[Insulin] => 2
[TZD] => 0
[SGLT-2] => 0
)
Not the most efficient algorithm in terms of memory, but you can map each choice onto a new array and then use array_count_values():
$result = array_count_values(array_map(function($item) {
return $item['choice'];
}, $data));
Since 5.5 you can simplify it a little more by using array_column():
$result = array_count_values(array_column($data, 'choice'));
You can simplify your code easily if counting is your only goal :
$result = array();
foreach ($data AS $row) {
if (!isset($result[$row['choice']])) {
$result[$row['choice']] = 1;
} else {
$result[$row['choice']]++;
}
}
If you want to count only specific choices, you can change the above code into something like this :
$result = array();
$keys = array('Insulin', 'TZD', 'SGLT-2');
foreach ($data AS $row) {
if (!in_array($row['choice'], $keys)) {
continue;
}
if (!isset($result[$row['choice']])) {
$result[$row['choice']] = 1;
} else {
$result[$row['choice']]++;
}
}

parse, filter and display multi-level json using php

Completely new to JSON and am tasked with filtering/sorting a remote JSON using php and embedding formatted results into a CMS.
The data structure looks like this:
"Categories":[
{
"Name":"Americas",
"ID":"12345",
"Countries":[
{
"Name":"Argentina",
"Partners":[
{
"Country":"Argentina",
"ID":"4321",
"LogoUrl":"logo1.jpg",
"Title":"Company A",
"AddressBlock":"123 Main Street",
"Phone":"444-555-1212",
"TollFree":"",
"Email":"info#CompanyA.com",
"Url":"http://www.CompanyA.com/",
"IsVisible":true,
"IsDistributor":false
}
]
},
{
"Name":"Brazil",
"Partners":[
{
"Country":"Brazil",
"ID":"5432",
"LogoUrl":"logo2.jpg",
"Title":"Company B",
"AddressBlock":"54 Center Street",
"Phone":"234-567-3600",
"TollFree":"",
"Email":"info#CompanyB.com",
"Url":"http://www.CompanyB.com",
"IsVisible":true,
"IsDistributor":false
},
"Name":"Canada",
"Partners":[
{
"Country":"Canada",
"ID":"Company C",
"LogoUrl":"logo3.Company C",
"AddressBlock":"1 Mll Road Floor 27\r\nCanton, ON",
"Phone":"555-66-7777",
"TollFree":"",
"Email":"info#CompanyC.com",
"Url":"http://www.CompanyC.com",
"IsVisible":true,
"IsDistributor":false
},
]
}
]
}
]
Ideally I would like to store the key/value pairs in an array and then print them out as a list sorted alphabetically. Each Country could have multiple entries and those set to "IsVisible:false" would need to be hidden.
I did some searching here and I could get to the data source but the array is not
'exploded' or looped through its dimensions by php and get this returned:
Categories:Array
using this code:
$string = file_get_contents("https://myURL.securekey");
foreach ($json_a as $key => $value)
{
foreach($value as $v)
{
echo $v." ";
}
}
Any help would be GREATLY appreciated.
Thanks!
Edited: So by using the below:
$string = file_get_contents('https://secure.json');
$json = json_decode($string, true);
foreach($json as $fieldIndex => $fields) {
foreach($fields as $valueIndex => $envelope) {
foreach($envelope as $valueEntry) {
foreach($valueEntry as $key => $value) {
if ($key == "Name") {
echo $value;
}
printf("%d - %d - %s: '%s'\n", $key, $value);
$build[$valueIndex][$key]=$value;
}
}
}
}
var_dump($build);
I get the following output:
0 - 0 - 0: 'Array' 0 - 0 - 1: 'Array' 0 - 0 - 2: 'Array' 0 - 0 - 3: 'Array' 0 - 0 - 4: 'Array' 0 - 0 - 5: 'Array' array(1) { [0]=> array(6) { [0]=> array(2) { ["Name"]=> string(9) "Argentina" ["Partners"]=> array(1) { [0]=> array(11) { ["Country"]=> string(9) "Argentina" ["ID"]=> string(36) "4d93" ["LogoUrl"]=> string(52) "http://www.aaa.com/images/partners/aaa.jpg" ["Title"]=> string(14) "Company S.A." ["AddressBlock"]=> string(118) "Main Street - Dock 8 12435- Anytown USA" ["Phone"]=> string(17) "(444) 123-4567" ["TollFree"]=> string(0) "" ["Email"]=> string(28) "info#aaa.com" ["Url"]=> string(35) "http://www.aaaa.com/" ["IsVisible"]=> bool(true) ["IsDistributor"]=> bool(false) } } }
But still unsure as to how to reference the specific name/values to echo them where needed. I assume maybe something like:
if ($key == "Title") {
echo "Title: " . $key . "<br />";
} esleif ($key == "Country") {
echo $value;
}
but am stuck on a) where to place it in the loop so it actually grabs the values at the right level and b) the syntax (which must be off because I can still only see anything with a var_dump at the end rather than echo out the values from within the loop.

Categories