I have a string from which I need to get an associative array. I can freely modify the string to look like an array, but I still can't get an array out of it.
I tried explode, json, etc.
$string = $row->id . ',' . $row->title . ',';
// 1,Home,3,Services,6,Service 1,7,Service 2,2,Products
example
public function Menu($parent = null) {
$query = $this->menuManager->getPublicMenus()->where('parent', null)->order('sort_order');
if ($this->menuManager->getPublicMenus()->count() > 0) {
$menu = '';
foreach ($query as $row) {
$menu .= $row->id . ',' . $row->title . ',';
$menu .= $this->Menu($row->id);
}
return $menu;
}
}
I need output:
array
1 => "Home"
3 => "Services"
6 => "Service 1"
7 => "Service 2"
2 => "Products"
In case you HAVE TO use the string.
$input = '1,Home,3,Services,6,Service 1,7,Service 2,2,Products';
$keysAndValues = explode(',', $input);
$result = [];
$count = count($keysAndValues);
for ($i = 0; $i < $count; $i+=2) {
$key = $keysAndValues[$i];
$value = $keysAndValues[$i+1];
$result[$key] = $value;
}
Working example.
output
array(5) {
[1]=>
string(4) "Home"
[3]=>
string(8) "Services"
[6]=>
string(9) "Service 1"
[7]=>
string(9) "Service 2"
[2]=>
string(8) "Products"
}
I see you added an example. To get the array, its much cleaner to do this in your Menu method:
$menu = [];
foreach ($query as $row) {
$menu[$row->id] = [
'title' => $row->title,
'children' => $this->Menu($row->id)
];
}
return $menu;
Related
I'm working on processing data returned from a form but because I've had to manually assign ids to the select dropdowns (so that I can attach a help button to the headings) I can't find an example to work from.
The array being returned looks like this:
[10]=>
string(1) "0"
[11]=>
string(1) "0"
[12]=>
string(1) "0"
[20]=>
string(1) "0"
[21]=>
string(1) "0"
[22]=>
string(1) "0"
["comments"]=>
string(0) ""
["submitbutton"]=>
string(12) "Save changes"
What I need to do is group all that start with a unique number (i.e. 1,2...) and ignore the comments and submitbutton elements.
In other words, I want it to look like this:
id = 1
criteria0 = 0
criteria1 = 0
criteria2 = 0
id = 2
criteria0 = 0
criteria1 = 0
criteria2 = 0
Think I would just use a delimiter, eg:
In the form
foreach (array(1,2) as $id) {
foreach (array(1,2,3) as $criteria) {
$key = $id . '_' . $criteria;
$options[$key] = "Your description for id $id, criteria $criteria";
}
}
$attributes = array('multiple' => 'multiple', 'size' => 10);
$form->addElement('select', 'criteria', get_string('criteria', 'component'), $options, $attributes);
Then in the results
$formdata = $mform->get_data();
...
$results = array();
foreach ($formdata->criteria[$key] as $key => $value) {
list($id, $criteria) = explode('_', $key);
$results[$id][$criteria] = $value;
}
Also for reference, Moodle has a selectgroups field type. You will still need to use a unique key but you can group the options.
foreach (array(1,2) as $groupid) {
foreach (array(1,2,3) as $criteria) {
$key = $groupid . '_' . $criteria;
// Use a group.
$options[$groupid][$key] = "Your description for id $groupid, criteria $criteria";
}
}
$attributes = array('multiple' => 'multiple', 'size' => 10);
// Use selectgroups.
$form->addElement('selectgroups', 'criteria', get_string('criteria', 'component'), $options, $attributes);
$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);
}
}
Here is my code.
I am trying to get inspect link for steam item. I have tried to use preg_replace but no luck either.
$API_link = sprintf("http://steamcommunity.com/id/*steamid*/inventory/json/730/2?trading=1");
$json = file_get_contents($API_link);
$json_output = json_decode($json);
$result = $json_output;
$link = array();
$id = array();
foreach($result->rgDescriptions AS $item){
$empty = array();
$newstring = $item->actions[0]->link;
if($newstring == NULL){
continue;
} else {
$empty['link'] = $newstring;
array_push($link, $empty);
}
}
foreach($result->rgInventory AS $inventory){
$empty = array();
if($inventory->instanceid == 0){
continue;
} else {
$empty['id'] = $inventory->id;
array_push($id, $empty);
}
}
$array = array_merge($id, $link);
foreach($array AS $final){
$assetid = "%assetid%";
echo str_replace($assetid, $final['id'], $final['link']);
}
}
But its not working. Please see if you can help.
As I can see you have array of arrays:
// bracket squares equivalent of array() keyword PHP >=v5.4
// here is
// $link = array(['link'=>'url'],['link'=>'url'])
// $id = array(['id'=>'id'],['id'=>'id'])
// result will be:
// array(['link']=>'url'],['link'=>'url'],['id'=>'id'],['id'=>'id'])
$array = array_merge($id, $link);
foreach($array AS $final){
// here is the first $final
// array('link'=>'url')
$assetid = "%assetid%";
// but here is we try to get
// 'id' and 'link'
echo str_replace($assetid, $final['id'], $final['link']);
}
I think it's some kind of mistake.
Ok, some test script:
<?php
$a = array( array('link'=>'hello1'), array('link'=>'hello2'));
$b = array( array('id'=>'id0'), array('id'=>'id1'));
$c = array_merge($a, $b);
var_dump($c);
result:
array(4) {
[0] =>
array(1) {
'link' =>
string(6) "hello1"
}
[1] =>
array(1) {
'link' =>
string(6) "hello2"
}
[2] =>
array(1) {
'id' =>
string(3) "id0"
}
[3] =>
array(1) {
'id' =>
string(3) "id1"
}
}
array_merge doesn't mix your associative arrays between them nether all nor particular item (I hope I explain it correct)
of course
foreach ($c as $item) {
var_dump($item);
}
will enumerate all the items one by one
array(1) {
'link' =>
string(6) "hello1"
}
array(1) {
'link' =>
string(6) "hello2"
}
array(1) {
'id' =>
string(3) "id0"
}
array(1) {
'id' =>
string(3) "id1"
}
and there is no array that has both of them (link and id) in the item
This script can't associate link and id properly, cause some of links can be skipped by continue, some of id also can be skipped. And it will be just a random list of available information. You can stuck in the next situation:
- $links has first 10 links
- $id has 3,4,5,7,9,11
It's just a list. Even if you have only this pure info (no other details), you can't properly associate it between of them by using shown source.
Here is minimum 1 simple solutions:
don't skip, don't merge, just add an empty array, and your final loop will be like this:
$assetid = "%assetid%";
for ($link as $key=>$final) {
if (count($final) && count($id[$key])) {
echo str_replace($assetid, $id[$key]['id'], $final['link']);
} else {
// some of needed arguments absent
}
}
Description not enough. Maybe try dump some variables?
foreach($array AS $final){
$assetid = "%assetid%";
//Check what is in $final
var_dump($final);
echo str_replace($assetid, $final['id'], $final['link']);
}
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.
My function receives a array as parameter:
array(6) {
[0]=>
string(7) "usuario"
[1]=>
string(4) "john"
[2]=>
string(5) "senha"
[3]=>
string(40) "7c4a8d09ca3762af61e59520943dc26494f8941b"
[4]=>
string(9) "pessoa_id"
[5]=>
string(1) "2"
}
What I need:
SELECT * FROM (`funcionarios`) WHERE `usuario` = 'john' AND `senha` = '7c4a8d09ca3762af61e59520943dc26494f8941b' AND `pessoa_id` = '2'
I need to create a WHERE with it, I'm using CodeIgniter and I came to this stupid but working solution:
foreach($params as $x) {
if($pos%2==0)
$chave = $x;
else
$valor = $x;
$pos++;
if($pos%2==0)
$this->db->where($chave, $valor);
}
I'm trying to find something more user friendly because there will be another person using this code.
What is the best way to do this?
I think this it the best way if you can't change that array. IF you can, do so now, because it's really inelegant
$data = array(
"usuario" => "john",
"senha" => "7c4a8d09ca3762af61e59520943dc26494f8941b",
"pessoa_id" => 2
);
foreach($params as $x => $y) {
$this->db->where($x, $y);
}
If you can change the format of the array, just use an associative array. For example:
array(
"usuario" => "john" //etc.
);
Then you can take advantage of the key function in PHP to avoid your even index checking in the loop, or even change your loop to:
foreach ($params as $key => $value)
$query = "SELECT * FROM `funcionarios` WHERE ";
$wheres = array();
foreach ($paramas as $key => $val) {
$wheres[] = "`$key`='$val'";
}
$query .= implode(' AND ', $wheres); // $query is now "SELECT * FROM `funcionarios` WHERE `myKey`='myValue' AND `otherkey`='otherval'";
That should work
Generate a new proper associative array from the original. Then it's much easier.
$arr = array("key1", "value1", "key2", "value2", "key3", "value3");
$newArr = array();
for ($i = 0; $i < count($arr); $i += 2) {
$newArr[$arr[$i]] = $arr[$i + 1];
}
Then using foreach you can build your query.