PHP array loop and format - php

I am very new to PHP, learning fast but not fast enough! I am also learning Laravel 5.1.
I am trying to build a HTML select list array from an Eloquent query output, in the correct format for form builder (Form::select).
I have the following call to Eloquent to pull the data:
// Get list of States for address select
$states = State::all()->toArray();
It returns the following array:
array:8 [▼
0 => array:2 [▼
"id" => "1"
"state" => "ACT"
]
1 => array:2 [▼
"id" => "2"
"state" => "NSW"
]
...
];
I want to loop through it and generate the following output:
array = [
'' => 'State', <-- This is the default for the select list
'1' => 'ACT',
'2' => 'NSW',
...
];
I am using Laravel 5.1, so I am using the included array_add() function in my helper.
I call my function like this:
$states = create_select_list($states, 'State');
I next want to format the output so it is ready for the Form::select statement. I have tried the code below (as the final try from a few iterations!) but unsuccessfully.
function create_select_list($data, $default)
{
// Declare array and set up default select item
$container = ['' => $default];
// Loop through data entries and build select list array
foreach($data as list($entry, list($key, $value))) {
$container = array_add($container, $key, $value);
}
// Return the select list array
return $container;
}
All help or suggestions are appreciated!

This answer is not about loop fix. I think previous comment should help you.
Just another idea. You can try use array_map instead foreach for this case.
For example:
$states = ['' => 'State'];
array_map(function($item) use (&$states) {
$states[$item['id']] = $item['state'];
}, State::all()->toArray());

Loop like below:
foreach($data as $key => $keyArr ) {
$container = array_add($container, $keyArr['id'], $keyArr['state']);
}

You don't need to use list() in your foreach loop, instead try:
foreach($data as $key => $value) {
$container = array_add($container, $key, $value);
}
The PHP documentation gives a good overview of what list() actually does.

Related

Get value of dynamic sub-array, in multidimensional array

Not sure if my question is clear, but here's what I'm trying to achieve. Let’s say I have a multidimensional array like so:
$arr['client1']**['dog']['Jack']**
$arr['client2']['cat']['Stacy']
How can I get the second portion of the array (between **), knowing it can be anything. For client 3, it could be a crocodile. For Client 4, it could be a car.
So I'm looking to "build" the structure of the array, dynamically. Something like so:
$arr['client1']{partBetweenThe**InTheExemple}
{partBetweenThe**InTheExemple} would be constructed "on the fly" (hence, the dynamically).
EDIT: Hopefully some clarifications...
The array changes every time. Basically, I'm building an addon to poll any API on the web. The data structure I'm getting can be anything. So what I need to do is build the key combination "on the fly", with variables.
In the exemple above, my variable would be something like $query = ['dog']['Jack'] and to get the value, I would poll it like so (from a logistic perspective, I know this doesn't work):
$arr['client1'][$query] or $arr['client1']$query or $arr['client1']{$query}
You can define the query as an array with each level as an element. Then we can iterate through that and check if we find a matching key in the response:
function findInArray(array $query, array $data)
{
foreach ($query as $key) {
if (!array_key_exists($key, $data)) {
// The key was not found, abort and return null
return null;
}
// Since the key was found, move to next level
$data =& $data[$key];
}
return $data;
}
// Example response
$response = [
'client1' => [
'dog' => [
'Jack' => 'Some value',
],
]
];
// Define the query as an array
$query = ['dog', 'Jack'];
$result = findInArray($query, $response['client1']);
Demo: https://3v4l.org/WjXTn
Edit:
So since the array's structure can't be changed this will return the client if the structure remains ['client']['animal']['name'].
$clients = [
'client1' => [
'dog' => [
'Jack' => []
]
],
'client2' => [
'cat' => [
'Stacy' => []
]
]
];
$animal = 'dog';
$name = 'Jack';
foreach ($clients as $client => $options) {
if (
array_key_exists($animal, $options) &&
array_key_exists($name, $options[$animal])
) {
echo $client;
break;
}
}

how to process my array to be associative on first two levels and on third to have simple value

I'm trying to construct an array where there only strings and the array would look like this
key->key->value
To explain it I attached two screenshots below.
I start with this:
After my code below I'm 90% there, yet there is an array in value on the third level instead of simple value.
Here is some code:
$theme = ThemeHandler::with('sections.settings')->find($activeTheme);
$themeSettings = $theme->sections;
$themeSettings = collect($themeSettings->toArray());
// dd($themeSettings);
$themeSections = [];
foreach ($themeSettings as $key => $value) {
$settings = collect($value['settings']);
$settings = $settings->mapToGroups(function ($item) {
return [$item['key'] => $item['value']];
});
$themeSections[$value['key']] = $settings->toArray();
}
dd($themeSections);
I would like to end up with this structure
key->key->value
and not
key->key->single_element_array->value
I'm not sure how I end up with an array at the bottom level when I do this
return [$item['key'] => $item['value']];
inside the mapToGroups, which is a function found here: https://laravel.com/docs/5.8/collections#method-maptogroups
Maybe I misunderstand how mapToGroups work. Anybody has an idea how to get key->key->value structure output?
Use mapWithKeys() instead of mapToGroups().
You're getting an array instead of the simple value you expect because the value is a group, albeit a group with only one member.
mapToGroups() groups all the values with the same key, but mapWithKeys() will assign a single value to each key.
You can see in the examples in the collection documentation, mapToGroups() produces a result like this:
[
'Sales' => ['John Doe', 'Jane Doe'],
'Marketing' => ['Johnny Doe'],
]
And mapWithKeys() result is like this:
[
'john#example.com' => 'John',
'jane#example.com' => 'Jane',
]

Multidimensional array loop with array search

I realize there are a number of questions about multidimensional arrays and foreach loops, and I have spent hours reading through them and trying to get my own loop to work -- without success. If the solution is a duplicate, I'll remove my question (or link to another if that is preferred).
Now, the challenge:
Using an array of returned MYSQL results. The results are from multiple joined tables in an associative array. Now I need to convert it to the multidimensional array I need.
I've got most of it working, but my issue is looping through and adding new items to the right place in the array.
Here's some code:
//example of how array is setup in the way I want, this part works.
foreach($results as $i => $a):
//some other code is here, see below.
$items[$i] = [
"id" => $a['id'],
"itemid" => $a['itemid'],
"name" => $a['name'],
"def" => $a['def'],
"class" => $a['class'],
"timeline" => $a['timeline'],
"files" => [
[0] => [
"id" => $a['fileid'],
"name" => $a['filename'],
"path" => $a['filepath'],
"type" => $a['filetype']
]
],
"tags" => [
[0] => [
"id" => $a['tagid'],
"name" => $a['tagname']
]
]
];
endforeach;
Then I've tried a number of ways to loop through in order to only add to the 'tags' or 'files' if the item 'id' is the same as the last. Here is the current code in my editor, not working:
//inside foreach loop, before above code
if($items[$i-1]['id'] == $a['id']):
//it is the same item, works to here.
if(in_array($a['filename'], $items[$i-1], FALSE)):
//add to files array for last item
$items[$i-1]['files'][] = [
"id" => $a['fileid'],
"name" => $a['filename'],
"path" => $a['filepath'],
"type" => $a['filetype']
];
elseif(in_array($a['tagname'], $items[$i-1], FALSE)):
//add to tags array for last item
$items[$i-1]['tags'][] = [
"id" => $a['tagid'],
"name" => $a['tagname']
];
endif;
else:// else it does the code above
As you can see, my most recent attempt was to use in_array, which I now realize doesn't work on multidimensional arrays. My issue is that I can't figure out how to determine if its a new file or new tag for the same item.
Ultimately, I want an array of 'items' which have multiple 'files' and 'tags.' I'm going to json_encode and use it with JS afterwards.
Any advice on how to get this working or optimize it, would be greatly appreciated.
P.S. As I mentioned above, I know this question has been asked before -- though I wasn't able to get their solutions working for me. I'll remove this question if the solution is a duplicate (as in, it's not really helpful to others). Thank you for any help, it is greatly appreciated!
Don't use "autoincrementing" array indices as they easily get messed up. Use your database id since it's already there:
//example of how array is setup in the way I want, this part works.
foreach($results as $i => $a):
$items[$a['id']] = [ // THIS CHANGED.
"id" => $a['id'],
"itemid" => $a['itemid'],
...
Now, with any further result, you can easily check, if the id is already in your array:
if (isset($items[$a['id']])) {
// We had this id before, just add files/tags to it.
// Check first, if files subarray exists, if not: create it.
if (!isset($items[$a['id']]['files'])) {
$items[$a['id']]['files'] = array();
}
$items[$a['id']]['files'][] = array(...); // add the new file.
// Repeat for tags.
}
If your result could return the same file more than once for an id, you can check if the filename is already in there by using a search function:
$filename = $a['filename'];
if (!searchFilename($filename, $items[$a['id']]['files']) {
// Filename is not in there, yet.
// Add file info.
}
function searchFilename($id, $array) {
foreach ($array as $key => $val) {
if ($val['filename'] === $id) {
return true;
}
}
return false;
}
Same applies to tags in a similar way.
In the end, if you do not want the ids for index of $items, just call:
$items = array_values($items);

How do I modify this PHP code to return nested results

I want to get this as a single object because I work with a JObject on the frontend.
I got an array at the moment but I am unsure how i should modify it so it returns a single object instead.
This is the code:
$contacts = array();
while ($row = mysqli_fetch_array($stmt))
{
$contact = array("ID" => $row['ProduktID'],
"Name" => $row['ProduktNamn'],
"Number" => $row['ProduktPris']);
array_push($contacts, $contact);
}
echo json_encode($contacts, JSON_PRETTY_PRINT);
And the goal is for it to look something like this with "results" as well so I can reach the whole thing:
To wrap your array of contacts in an object with a single results property:
echo json_encode(array('results' => $contacts), JSON_PRETTY_PRINT);
You can use typecasting to convert an array to an object:
$object = (object) $array_name;
or manually convert it into an object
$object = object;
foreach($arr as $key => $value)
{
$object->$key = $value;
}
Like this? Keep in mind an object is different then an array and your question is rather confusing.
while ($row = mysqli_fetch_array($stmt)){
$contact[] = [
"ID" => $row['ProduktID'],
"Name" => $row['ProduktNamn'],
"Number" => $row['ProduktPris']
];
}
json_encode(['result' => $contact]); // Forget the JSON_PRETTY_PRINT.
Using this method [], it will use the first available numeric index starting with 0. This way you don't have to push an array.

How to replace an element in an array

I have a COLLECTION collflokks in MongoDB, sample Document is :-
{
"_id" : "b_8AUL",
"f_name" : "Pizza. Hut",
"f_lat" : "22.7523513",
"f_lng" : "75.9225847",
"c_uid" : "33",
"f_type" : NumberLong(3),
"members" : [
"42",
"43"
]
}
Within the "members" array , I want to add Arrays like {id:42,name:Mark} , {id:43,name:Hughes}
Currently i'm adding just ids(eg.42,43). I'm only concerned about the new data as it will have new ids .Please suggest.
Earlier I was using this code to push into the members Array:
$flokkCollection = 'collFlokks';
$flokkCollection->update(
array("_id" => $f_handle),
array('$push' => array("members" => $u_id))
);
Well if what you are asking here is "replacing your existing data" then you need to "loop" the results from the collection and "replace" the array content that exists with your new format.
There are likely smarter ways to approach this, but you are not really giving us all the required information in your question, so I can only answer in the basic terms.
Presuming you have:
$required = array(
array(array("id" => "42"), array("name" => "Mark")),
array(array("id" => "43"), array("name" => "Hughes"))
);
As input, then you do something like this:
function myMapper($v) {
return $v["id"];
}
$mapped = array_map("myMapper",$required);
foreach( $mapped as $value) {
$filtered = array_values(
array_filter($required,function($k) {
return $k["id"] == $value;
})
)[0];
collection.update(array(
array("members" => $value),
array('$set' => array(
"members.$" => $filtered
))
));
}
Which should use the positional $ operator to find the matched "position" of the array element by the value used in the "query" portion of the update statement, then in the "update" portion of that statement $set that current array index to the new value at the "filtered" content index from the original input array.
Outside of PHP. We call these inner elements "objects" and not "arrays" which is a PHP notation trait. Key/value things are "objects" and "lists" are "arrays".

Categories