add data on a array query result - php

I have the function below in my model which return an array of data. I want to make another operation on each row and add the result to array of data before to return it.
function get_all_annonce()
{
$this->db->select(" * from annonce");
$this->db->order_by("annonce.DATEDEBUTANNONCE","asc");
$q=$this->db->get();
if($q->num_rows()>0)
{
foreach($q->result() as $row)
{
$data[]=$row;
//I try to add another result
$experience=$this->get_experience($row->NUMUSER);
$data['experience']=$experience;
}
return $data;
}
}
But I have an error when I try to access to $experience or $row->'experience' in my view. How can I fix it ?

The $data variable is defined in the wrong scope. You defined it inside the foreach loop but you try to return it after. Try adding $data = Array(); above the foreach.

In addition to the answer above.
First you have unnecessary assignments, you can do it in one line.
2nd - when you use [] - it will create index automatically and the row will be added as an array to that index. You get a multidimensional array( 0 => result 1, 1 => result 2 etc).
If you want to add the 'experience' key to the result, you cannot add it directly to data.
You get an array that will have keys 0,1,2,3,4 ... 'experience' as last key - each time it is overwritten.
One way would be to use a variable for key (or use for loop instead):
$i = 0;
foreach($q->result() as $row)
{
$data[$i]=$row;
$data[$i]['experience'] = $this->get_experience($row->NUMUSER);
}
If you used only [] for both, it would assign different key for each one every iteration.

Related

Is there a faster way to compare multiple arrays in PHP?

I have a slow performance issue in comparing multiple arrays.
The algorithm that I've made is:
I'll be looping first the arrays by foreach
foreach($branches as $index => $branch) {
if (!$identical) {
continue;
}
// Basically this $permissions will be fetching data from the database.
$permissions = $this->get()
->where('user_id', $userId)
->where('branch_id', $userBranchId)
->sortBy('permission_id')
->pluck(['permission_id']);
// if index = 0 then I'll initialize the temporary variable (ARRAY) $initial otherwise I'll compare two variable (ARRAY)
if ($index === 0) {
$initial = $permissions;
} else {
if ($initial != $permissions) {
$identical = false;
}
}
}
So to compare multiple arrays, I use only this if condition and comparative symbol (==). But I'm thinking if
Don't query database in loop, you can use array_column to export branches array to columns "userId" and "userBranchId"
finaly build query using "whereIn"
I agree with #thaiha, you could reduce your queries to just one, and after make the comparison of the arrays. For example in Mysql you could do something like.
select * from `permissions` where (`user_id `, `branch_id `) in (('1', '2'), ('2', '4'));
then for comparing the arrays, you could do your loop, or use one of the php functions to compare arrays like array_diff is you are expecting all to match a specific set of permission. Or something like that.
Instead of looping array. I suggest that use eager loading instead.
Branch model
public function permissions(){
return $this->hasMany('App\Permission', 'foreign_key', 'local_key');
}
and in your controller
Branch::with('permissions')->where($condition)->get();
Read document here: https://laravel.com/docs/6.x/eloquent-relationships

Laravel collection for loops and mappings

I am trying to refactor my code, and remove a for loop.
$result = [];
foreach ($data as $language) {
$result[$language->{$key}] = $language->{$column};
}
This became:
$result = $data->map(function($language) use ($key, $column){
return [$language->{$key} => $language->{$column}];
});
But now instead of:
[
"key":"value",
"key":"value"
]
I am getting
[
{
"key":"value"
},
{
"key":"value"
}
]
Why doesn't it map like an array?
Please refer this URL
For Example:
$emailLookup = $employees->reduce(function ($emailLookup, $employee) {
$emailLookup[$employee['email']] = $employee['name'];
return $emailLookup;
}, []);
Gives you result like:
const emailLookup = {
'john#example.com': 'John',
'jane#example.com': 'Jane',
'dave#example.com': 'Dave',
};
In your case do like:
$result = $data->reduce(function($language, $a){
$language[$a['any_you_want']] = $a['any_you_want'];
return $language;
}, []);
Hope this helps you!
You probably needed to mapWithKeys:
$result = $data->mapWithKeys(function($language) use ($key, $column){
return [$language->{$key} => $language->{$column}];
});
The method has been available since Laravel 5.3
According to the docs:
The mapWithKeys method iterates through the collection and passes each value to the given callback. The callback should return an associative array containing a single key / value pair:
For your simple use case, pluck() is the method you're looking for. It will build a new collection using one column of an existing array. You can also pass in a second field that will be used to key the new collection.
So, in your case, the data column you're selecting is $column, and the column to use as the key for the new collection is $key. Your code would be:
$result = $data->pluck($column, $key);
This says "give me a collection of all of the $column data, and key it by the $key data".
If you want the plain array instead of the collection, just call all() on the result:
$result = $data->pluck($column, $key)->all();
If you need to "pluck" more than one column of data, you will need to use the mapWithKeys() method already mentioned.
Here in loop you need to use as key value pair
$result = [];
foreach ($data as $key => $language) {
$result[$key] = $language;
}

getting only one data from laravel collection seems difficult

I don't get this, I have a collection of items.
The collection contains in this case one and only one item at index 1 as it was filtered from a bigger collection.
The point is how do I get the only piece of data I need without having to reset the values of the index and then accessing at index 0 ??
This is a case where I will always have only ONE item in the collection but the index at could be different so I can't use the [0] index by default.
//returns all items with 'item_color_id" = 1
$item = Item::where(//some constraints);
$filtered = $item->filter(function ($i) {
return $i->item_color_id == 1;
});
if (count($filtered)) {
//need to access a single data inside the collection
// like for example 'item_brand_id'
//I can do it like this:
$filtered = $filtered->values();
$item_brand_id = $filtered[0]['item_brand_id'];
//but what sense does it have?? how can we access 'item_brand_id'
//from $filtered without resetting the indexes?
}
it doesn't make any sense to me that we don't have a method to access the data directly, or if we have it I missed it.
For example I coould use max() or min() on $filtered like this:
$max_brand_id = $filtered->max('item_brand_id');
It doesn't make any sense to find the max id in this case I know, but it shows that we can find the data in one passage.
I tried only('item_brand_id); but that returns empty while the data is there.
You still have eloquent collection so you can do just call first() function
$item_brand_id = $filtered->first()->item_brand_id;
filter() is used when you want a collection of matching elements, even if that only results in one element.
If you know that you only want one element that matches a truth test, use first() instead. It has the same signature.
Item::where(...)->get()->first(function ($item) {
return $item->item_color_id == 1;
})->get('item_brand_id');
You could change your database query to just return one element. If the result is always just one, there is no need to load an entire collection.
$item = Item::where(/*some constraints*/)->where('item_color_id', 1)->first();
if (isset($item))
echo $item->item_brand_id;

Laravel - Get variable from a DB Transaction Closure

I am working with a Laravel 5 LAMP stack, and I am trying to process a CSV import with a database transaction. Code looks like this:
// Should contain any messages to pass back to the user
$results = [];
// Contains the total records inserted
$total = 0;
DB::transaction(function() use($csv_file, $results, $total) {
// Some Code ...
$total++;
$results[] = 'Row 10 has some weird data...';
});
return view('plan.import')
->with('results', $results)
->with('total', $total);
At the end of that, my records are imported, but my $total and $results are still empty, since they are outside the scope of the closure. I know they are being altered inside the function, because I've stepped through it, and seen them change. I just can't figure how to get them out of that transaction and return them to the user. Can anyone please help with this?
You may replace the following line:
DB::transaction(function() use($csv_file, $results, $total)
with this:
DB::transaction(function() use($csv_file, &$results, &$total)
So the changes made inside the function will reflect in the variables because & creates a reference of the variable (Passes the variable reference) instead of passing them by value. Check Passing by Reference Manual.
Alternatively, you can return the variables from inside the closure like:
$array = DB::transaction(function() use($csv_file, $results, $total) {
// Some Code ...
$total++;
$results[] = 'Row 10 has some weird data...';
return compact('total', 'results');
});
Then use it like:
return view('plan.import')
->with('results', $array['results'])
->with('total', $array['total']);

PHP, foreach doesnt return an array but array_map with same code returns an array

I want the foreach to return arrays but it just returns a single array. But the array_map with same code does.
What is the correct way of getting the arrays out of the foreach.
Why does foreach behaves differently than array_map.
Inside the file (userdata.php)
Reme:Reme1991#jourrapide.com
george bush:GeorgeBush#gmail.com
obama:obama#gmail.com
Using array_map
function registered_users(){
$file_user = file('userdata.php');
return array_map(function($user){
return explode(':',$user);
},$file_user);
} //returns the exploded array correctly.
Using foreach
function registered_users(){
$file_user = file('userdata.php');
foreach ($file_user as $user) {
return explode(':',$user);
}
}// returns Array ( [0] => Reme [1] => Reme1991#jourrapide.com )
Because array_map() iterates over all elements in the array.... the foreach() would do the same except that your return is jumping out of it on the first iteration.
function registered_users(){
$users = [];
$file_user = file('userdata.php');
foreach ($file_user as $user) {
$users[] = explode(':',$user);
}
return $users;
}
EDIT
In response to your question "Why doesn't a return from array_map terminate the iteration?"
Because array_map() is a function that loops/iterates every element in the array, executing a "callback" function against each element. Your return is in the "callback" function, which acts on one individual array element at a time, and is called multiple times by array_map(), once for each element of the array in turn.
The return in your "callback" is simply returning a modified value for that one individual element (the current element in the array_map() loop) to the array_map() function.... it's telling array_map() what the new element value should be.
The array_map() function itself can't be interrupted: it will then continue iterating over the next element, sending that in turn to the "callback" function until it has done so for every element in the array.

Categories