Eloquent using foreach inside each function - php

I want to exchange image order(Data retrieved from angularjs/ui-sortable, so the $newImgOrder array is representing the new order.)
(array) $newImgOrder = ['test.jpeg', 'another.jpeg'];
Images::select('url')->where('project_id', '=', $args['id'])->get()
->each(function($img) use (&$newImgOrder) {
foreach ($newImgOrder as $item) {
$img->url = $item;
$img->save();
}
});
* UPDATED = RIGHT WAY FOR THE PERFORMING THIS ACTION *
Thanks #Devon
Removed foreach + select()
(array) $newImgOrder = ['test.jpeg', 'another.jpeg'];
Images::where('project_id', '=', $args['id'])->get()
->each(function($img) use (&$newImgOrder) {
$img->url = array_shift($item);
$img->save();
}
});
Here is a quick demonstration for what i want to do:
Table state before the action
+---------+-------------+--------------+
| id | project_id | url |
+---------+-------------+--------------+
| 1 | 15 | another.jpeg |
+---------+-------------+--------------+
| 2 | 15 | test.jpeg |
+---------+-------------+--------------+
Expected results =
+---------+-------------+--------------+
| id | project_id | url |
+---------+-------------+--------------+
| 1 | 15 | test.jpeg |
+---------+-------------+--------------+
| 2 | 15 | another.jpeg |
+---------+-------------+--------------+
Actual results =
+---------+-------------+--------------+
| id | project_id | url |
+---------+-------------+--------------+
| 1 | 15 | another.jpeg |
+---------+-------------+--------------+
| 2 | 15 | another.jpeg |
+---------+-------------+--------------+
What's the problem with that iteration. I tried with double foreach but i got the same results... Am i something missing out? Any help would be very appreciated. Thanks.

For each image, your code is looping through $newImageOrder and saving the url for that image. Hence, you're performing two saves for every image, which is clearly not what you want.
There is no reason for the inner foreach loop. If you're certain the number of elements in $newImageOrder will match the number of rows from your query and since you're passing $newImageOrder as a reference to the closure, you could make use of shift:
each(function($img) use (&$newImgOrder) {
$img->url = array_shift($newImgOrder);
$img->save();
});
This will shift the first element off of the array and return it, meaning you'll be removing and using the first element of $newImgOrder for each iteration.
Keep in mind, this is a mutable change. $newImgOrder is mutated by the closure. If this is not what you want, you may want to use a running count for the offset instead.

Related

Using Multidimensional array in Laravel 8 Blade

I am trying to get a status count of some processes and tasks just like a to-do list tasks count.
My current database look like this SQL Database Structure
+----+---------+------------+-------------+---------+------------+---------------------+---------------------+
| id | user_id | list_id | name | records | status | created_at | updated_at |
+----+---------+------------+-------------+---------+------------+---------------------+---------------------+
| 1 | 1 | 8Kwvf8ikcV | 10 mails | 19 | On-Hold | 2021-03-11 07:56:17 | 2021-03-11 07:56:17 |
| 2 | 1 | a0pJRv4Zfc | temp_emails | 884 | On-Hold | 2021-03-11 08:02:13 | 2021-03-11 08:02:13 |
| 3 | 1 | xrgZZkrLFA | 10 mails | 19 | Processing | 2021-03-11 08:06:37 | 2021-03-11 08:06:37 |
| 4 | 1 | lDOX8p2sgU | 10 mails | 19 | Completed | 2021-03-11 08:53:51 | 2021-03-11 08:53:51 |
+----+---------+------------+-------------+---------+------------+---------------------+---------------------+
I am using
return $listStats = ListName::select([
DB::raw("status"),
DB::raw("COUNT(status) as count")
])->where('user_id', Auth::id())
->groupBy('status')
->get();
Query to get the database and its count.
Current laravel out put is showing as
[{"status":"Completed","count":1},{"status":"On-Hold","count":2},{"status":"Processing","count":1}]
My question is how can I get the count of completed status without using foreach loop?
Do I need to change my query? or can I simply use $listStats['Completed']['count'] ?
A foreach will be run at some point unless you use a join in the query to give an order and force a result with all possible status.
One easy solution would be
$StatCount[ //make sure to list all possible statuses here
"Completed" => 0,
"Processing" => 0,
"On-Hold" => 0,
];
foreach ($listStats as $listStat) {
$StatCount[$listStat->status] = $listStat->count
}
Now you can access your status counts like this $statCount['Completed']
Counting is a pretty lightweight job and it can be done on the fly easily. Instead of creating an extra query to count the records, collect the records and count them in Blade. It's a better idea because you will fetch the tasks anyway and no need to query them twice.
// In controller
$user = User::where('id', Auth::id())->with(['tasks' => function($query) {
$query->groupBy('status')
}])->get();
return view('viewName')->with(['user', $user]);
// In Blade
$user->tasks->Completed->count();

SQL query returns one row too few

SOLUTION: Make sure you don't 'use up' any $responses->fetch_assoc()s before the while loop.
I performed mysqli_fetch_array($responses);.
In php I have this sql query (simplified for your convenience, but the problem remains)
$sql = "SELECT id, content FROM responses ORDER BY RAND()";
$responses = $conn->query($sql);
where the responses table looks like this:
+----+----------+--------+------+
| id | content | userId | part |
+----+----------+--------+------+
| 4 | peewee | 31 | 1 |
| 5 | tallinn | 31 | 1 |
| 6 | dewey | 31 | 1 |
| 7 | stanford | 31 | 1 |
+----+----------+--------+------+
That doesn't format properly so all you need to know is that the id and content rows are different for each entry while the rest is the same for each.
The problem is, when I do a while loop on $responses like so:
while ($row = $responses->fetch_assoc()) {
$responseId = $row["id"];
$content = $row["content"];
echo " id: ".$responseId;
echo " content: ".$content;
}
I always get 1 record fewer than there are. In this case, since there are 4 rows, I would only see 3 echoed. However, it is not always the same 3, nor are they in the same order. If I remove the ORDER BY RAND() clause, then it is always the first record which is left out.
Thanks in advance
Cheers

Query to group by the contents of the field

I need help to make query to group by content of field. I have the following Database:
+----+--------------+-----------------+------------------------------+
| id | depart_kode | depart_task | value |
+----+--------------+-----------------+------------------------------+
| 1 | 001 | Create Profil | Some Value |
| 2 | 001.12 | Create Profil | Some Value |
| 3 | 001.452 | Create Profil | Some Value |
| 4 | 002.914 | Create Profil | Some Value |
| 5 | 002 | Create Profil | Some Value |
| 6 | 003 | Create Profil | Some Value |
+----+--------------+-----------------+------------------------------+
I need to make a query where I group by depart_kode and I should print by the first 3 digits like this in format json
"001":[
{
"depart_kode":"001,
and other
},
{
"depart_kode":"001.12"
},
],
"002":[
{
"depart_kode":"002"
}
]
something like that, most importantly they will be grouped in an array based on the first 3 numbers like 001.
and json just an example, which I want to split into an array based on the first 3 digits
Something like this?
$departs = [];
foreach ($sqlRows as $row) {
$departKey = substr($row['depart_kode'], 0, 3);
if (!array_key_exists($departKey, $departs)) {
$departs[$departKey] = [];
}
$departs[$departKey][] = $row['depart_kode'];
}
Working example.
references
substr - get a specific part of a string (first 3 chars in our example)
array_key_exists - checks if the key in an array exists

Laravel orderBy with same value result keep changing

I've try to sort my result within the updated_at value. Because I seed the value all the updated_at value is same:
// Amount Table
-----------------------------------------------------
| id | amount | updated_at |
+----------+--------------------+-------------------+
| 1 | 232319 |2016-02-02 13:17:29|
| 2 | 232319 |2016-02-02 13:17:29|
| 3 | 100000 |2016-02-02 13:17:29|
| 4 | 231111 |2016-02-02 13:17:29|
| 5 | 12345 |2016-02-02 13:17:29|
+----------+--------------------+-------------------+
The problem is everytime I query :
$lists = Amount::orderBy('updated_at', 'DESC')->lists('id')->toArray();
I expect the result to be like this: [1,2,3,4,5] but it appear the result is sometime like that but sometime [2,3,1,4,5]. it keep randoming the result.
As far as i know, yes i can put another orderBy statement to the query, but isn't it suppose to be default it will order by the id?
Thanks
You are only ordering by updated_at which appear to all have the same value. If you want consistency, include a second column
$lists = Amount::orderBy('updated_at', 'DESC')->orderBy('id', 'ASC')->lists('id')->toArray();

Finding a specific row in a PropelCollection

I have two tables. One for orders, and for their prefs. The tables look like this:
Order:
+----------+---------------+------------+
| orderID | orderNumber | clientID |
+----------+---------------+------------+
| 1 | abc123 | 2 |
| 2 | orderX | 7 |
| 3 | Joe9 | 2 |
| 4 | Order4 | 2 |
+----------+---------------+------------+
OrderPref
+----------+----------+-------------+
| orderID | prefID | prefValue |
+----------+----------+-------------+
| 1 | 1 | $100 |
| 1 | 2 | 123 |
| 1 | 3 | $35 |
| 2 | 1 | $600 |
| 2 | 2 | 876 |
| 2 | 3 | $44 |
+----------+----------+-------------+
What I want to is for each order, get the prefValue for a specific prefID. Currently, this is what I am doing:
$orders = OrdersQuery::create()->filterByClientID(2)->find();
foreach($orders as $o){
$prefs = $o->getOrderPrefs();
foreach($prefs as $p){
if($p->getPrefID() === 2){
echo $p->getPrefValue();
break;
}
}
}
This works, but there needs to be a better way to get the one row I want for each order without looping through all the prefs.
I know this doesn't work, but is there something like this?
$orders = OrdersQuery::create()->filterByClientID(2)->find();
foreach($orders as $o){
// This obviously doesn't work, so is there a short way to do this?
echo $o->getOrderPrefs()->filterByPrefID(2)->getPrefValue();
}
I was reading the docs and found a ->search() method, but I don't know how to use it.
$orders = OrdersQuery::create()->filterByClientID(2)->find();
foreach($orders as $o){
// How can I search for the row with the prefID I want?
echo $o->getOrderPrefs()->search()->getPrefValue();
}
Looking at some old Propel stuff I've written, I'm guessing something like:
$prefValue = OrdersQuery::create()->
joinOrderPref()->
where('OrderPref.prefID = ?', $prefId)->
filterByClientID($clientId)->
select('OrderPref.prefValue')->
find()
;
The issue is that you need to get a specific column (reference).
For these chainable queries, my view is that an auto-completing editor is pretty much mandatory - remembering the syntax is nigh-on impossible without it.
$prefValues = OrdersQuery::create()
->filterByClientId(2)
->joinOrderPref()
->withColumn('OrderPref.PrefValue', 'theValue')
// row above fetches ONLY the needed column from joined table and
// gives 'theValue' alias to it
->select('theValue')
->find();
With this you don't need to do any foreaches in PHP or do it in two steps.
About the ->select() part - it's there only to not get the fully bloated/hydrated object, but actually only an array (PropelArrayCollection to be precise) with the prefValue data you need.
I didn't test this live though, some syntax issues may arise.

Categories