Laravel 5: How to use 'where' or 'orderBy' using eloquent? - php

First things first, this is not a duplicate of Laravel 4: how to "order by" using Eloquent ORM
I have this model User, then I have this other model Idea. I'm writting a view with the details of the user, and I want to post all the ideas the user has suggested. Now, the ideas have a status, the first status is "DRAFT", that means only the user who posted the idea can review it, the idea should not be shown to other users looking at the profile.
Using eloquent I could do something like:
#foreach($user->idea as $idea)
...display details...
#endforeach
My problem is that this approach would cycle through all ideas AND in the order where they were introduced. I can add an #if to show only what I want, like
#foreach($user->idea as $idea)
#if($idea->status !='DRAFT')
...show the idea...
#endif
#endforeach
But I don't think it's the smart way to do it, I'd like to do something like
$ideas = $user->idea->where('status', '<>', 'DRAFT')
and then cycle through the $ideas variable, or at least, I'd like somtehing like
$ideas = $user->idea->orderBy('created_at', 'desc')
But I have no idea on how to do it.

You can do it like this:
$ideas = $user->idea()
->where('status', '<>', 'DRAFT')
->orderBy('created_at', 'desc')
->get();
When you use ->idea() it will start a query.
For more information about how to query a relationship: https://laravel.com/docs/5.7/eloquent-relationships#querying-relations

You can user where clause like this
DB::table('products_to_categories')
->where('categories_id', $id )
->update([
'categories_id' => $unassigned_cat_id
]);
and you can use orderBy clause like this
DB::table('products_to_categories')
->where('categories_id', $id )
->orderBy('subId','DESC');

Related

Is it possible to do orderBy() or orderBy() in Laravel?

Is it possible to do orderBy() or orderBy() in Laravel Eloquent? My current query only sorts the item.ItemID upon user clicking sort on the frontend but it won't sort item.Desc when the user clicks sort on the frontend.
I've tried putting these orderBy()s inside of a where() clause using a closure but that didn't work either. Does anyone know of a good way I could rectify this?
$this->model
->join('awards', 'item.ItemID', '=', 'awards.LinkID')
->join('opportunities', 'awards.AwardID', '=', 'branch.AwardID')
->groupBy('item.ItemID', 'item.Desc')
->orderBy('item.ItemID', $clickedDInventoryItemIdFlag ? 'DESC' : 'ASC')
->orderBy('item.Desc', $clickedDescriptionColumnFlag ? 'DESC' : 'ASC')
->select("item.ItemID", "item.Desc", "branch.OppID")
->get();
Ordering in SQL is cumulative, so you'll always be ordering by the first item, then the second. Instead you can manipulate the query based on a condition:
$this->model
->join('awards', 'item.ItemID', '=', 'awards.LinkID')
->join('opportunities', 'awards.AwardID', '=', 'branch.AwardID')
->groupBy('item.ItemID', 'item.Desc')
->when(
$clickedDescriptionColumnFlag, // condition
fn ($q) => $q->orderBy('item.Desc') // true
fn ($q) => $q->orderBy('item.ItemID') // false
)
->select("item.ItemID", "item.Desc", "branch.OppID")
->get();
I have to say though, whenever I see query builder joins happening like this, it's a big flag telling me that you likely don't understand model relationships. (And the fact that you used "Eloquent" in your title, despite there being no such code in the question!) I would strongly suggest looking into how Eloquent works; for all but the heaviest loads the increase in coding efficiency far outweighs the slight decrease in database query efficiency.
Until you call get() method it is all query builder since all chaining methods return self instance. So you can separate chain and use if block when needed:
$someModels = $this->SomeModel
->join('awards', 'item.ItemID', '=', 'awards.LinkID')
->join('opportunities', 'awards.AwardID', '=', 'branch.AwardID')
->groupBy('item.ItemID', 'item.Desc');
if ($condition) {
$someModels->orderBy('item.ItemID', $clickedDInventoryItemIdFlag ? 'DESC' : 'ASC')
} else {
$someModels->orderBy('item.Desc', $clickedDescriptionColumnFlag ? 'DESC' : 'ASC');
}
$someModels
->select("item.ItemID", "item.Desc", "branch.OppID")
->get();

How to pass an array from a query inside a foreach

I have the following query that will bring all Auth user friends :
$usrusrmembs = DB::table('usrusrs')
->where('accepted', 1)
->where('user_id', $u_id)
->orwhere('friend_id', $u_id)
->pluck('friend_id', 'user_id');
Next is a foreach to loop the ids received from the above query, get the posts of all Ids, and then sending the result to a blade :
foreach($usrusrmembs as $key => $val){
$rec_users = ($key == $u_id) ? $val : $key;
$f_usrs_psts = DB::table('posts')
->where('posts.user_id', $rec_users)
->get();
}
return view('updates', ['f_posts' => $f_usrs_psts] );
The output in the blade shows only posts of one friend , while ignores the others. I feel there is a problem in the posts query, where it only sends to the blade the last processed ID. If this is the problem, then how can I solve it ?
This is where Laravel really shines. Take advantage of the relationships and do this all in one query with eager loading. I don't know what your model relations are, but something like this:
$usrusrmembs = \App\UserUserModel::where('accepted', 1)
->where('user_id', $u_id)
->orwhere('friend_id', $u_id)
->with('posts')
->get();
If you want more control, you can use a combination of closures and whereHas, but this above should get you close. Then, in your view you can loop on the posts for each:
#foreach($usrusrmembs as $usr)
echo $usr-name // etc
#foreach ($usr->posts as $post)
echo $post->whatever
#endforeach
#endforeach
This is not going to give you exactly what you need, but the idea should help you to work through it and you can skip the whole n+1 issue by removing the foreach loop in your controller.

Laravel OrderBy Nested Collection

I'm using a Roles package (similar to entrust). I'm trying to sort my User::all() query on roles.id or roles.name
The following is all working
User::with('roles');
This returns a Collection, with a Roles relation that also is a collection.. Like this:
I'm trying to get all users, but ordered by their role ID.
I tried the following without success
maybe because 'roles' returns a collection? And not the first role?
return App\User::with(['roles' => function($query) {
$query->orderBy('roles.id', 'asc');
}])->get();
And this
return App\User::with('roles')->orderBy('roles.id','DESC')->get();
None of them are working. I'm stuck! Can someone point me in the right direction please?
You can take the help of joins like this:
App\User::join('roles', 'users.role_id', '=', 'roles.id')
->orderBy('roles.id', 'desc')
->get();
Hope this helps!
You can make accessor which contains role id or name that you want to sort by.
Assume that the accessor name is roleCode. Then App\User::all()->sortBy('roleCode') will work.
Here's the dirty trick using collections. There might be a better way to achieve this(using Paginator class, I guess). This solution is definitely a disaster for huge tables.
$roles = Role::with('users')->orderBy('id', 'DESC')->get();
$sortedByRoleId = collect();
$roles->each(function ($role) use($sorted) {
$sortedByRoleId->push($role->users);
});
$sortedByRoleId = $sortedByRoleId->flatten()->keyBy('id');
You can sort your relations by using the query builder:
notice the difference with your own example: I don't set roles.id but just id
$users = App\User::with(['roles' => function ($query) {
$query->orderBy('id', 'desc');
}])->get();
See the Official Laravel Docs on Constraining Eager Loading
f you want to order the result based on nested relation column, you must use a chain of joins:
$values = User::query()->leftJoin('model_has_roles', function ($join)
{
$join>on('model_has_roles.model_id', '=', 'users.id')
->where('model_has_roles.model_type', '=', 'app\Models\User');})
->leftJoin('roles', 'roles.id', '=', 'model_has_roles.role_id')
->orderBy('roles.id')->get();
please note that if you want to order by multiple columns you could add 'orderBy' clause as much as you want:
->orderBy('roles.name', 'DESC')->orderby('teams.roles', 'ASC') //... ext
check my answer here:
https://stackoverflow.com/a/61194625/10573560

Laravel: how to access record by id in view

In my controller I return a view with a ?collection $programs? from an eloquent query to the view.
Controller
$programs = ScheduledProgram::where('registration_start_date', '<=', $today)
return View::make('admin/register_users/show', compact(programs));
I wan to do something like this without it running a new query from the view...
VIEW
{{$program->find(id)}}
I know that $programs is a dataset that already has the record, but I don't know the way to access the element by ID this way.
How do I do this?
(sorry, seems like an obviously searchable question but my search terms aren't comming up with the answer)
in that case you need to make a #foreach in $programs to access the data. Like this:
#foreach($programs as $key => $value)
{{$value->id}}
#endforeach
If the return is only one line you can do this:
{{$programs[0]->id}}
1.You have to add the method get (converts the "dataset " in a Laravel collection) to iterate the collection.
$programs = ScheduledProgram::where('registration_start_date', '<=', $today)
->get()
2.If you want to get a single record:
ScheduledProgram::where('registration_start_date', '<=', $today)->where('id', 5)->get();

Passing external elements to the model in a select query with Eloquent

Trying to transform a query in raw mysql to the eloquent laravel queries. I am stuck on trying to get external elements (from other models) inside it...Mainly the "color" (that comes from the BookingStatus and creating the URL and putting it in as URL.
Could you help me out?
Here is the mysql query:
$booking = DB::table('bookings')
->select('bookings.id as id', 'booking_reference as description', 'booking_status as title', 'color', DB::raw('concat("http://127.0.0.1/blabla/public/profile/Calendar/detail/",bookings.id) as url'),'booking_date as start')
->join('booking_status','booking_status.id','=','bookings.bookingstatus_id')
->where('photographer_id', '=', $photographer->id)
->union(DB::table('bookings')
->select('bookings.id as id', 'booking_reference as description', 'booking_status as title', 'color',DB::raw('concat("http://127.0.0.1/KYMA/public/profile/Calendar/detail/",bookings.id) as url'),'booking_date as start')
->join('booking_status','booking_status.id','=','bookings.bookingstatus_id')
->where('user_client_id', '=', $user->id)
)
->get();
edited: And here is where I have gone so far
$booking_info = Booking::with('bookingStatus')
->where('photographer_id', $photographer->id)
->orWhere('user_client_id', $user->id)
->select(['id as id', 'booking_reference as description','booking_date as start', 'bookingstatus_id as title'])
->get();
I tried a few things with the color and read the docs of Laravel but I just can't get it right... How do I pass it in my select query ? If I simply add 'color' obviously it will not pick it up because it is in the attached array and not the "primary" one...
Thanks a lot for your help!!
///// EDIT /////
Here is a solution I found to be able to pass everything I want, I'm not using the model relations thought since couldn't understand how to pass their array values in my select request...
$booking_info = Booking::where('photographer_id', $photographer->id)
->orWhere('user_client_id', $user->id) //because he could be client of a shoot ;-)
->join('booking_status','booking_status.id','=','bookings.bookingstatus_id')
->join('shooting_types', 'shooting_types.id', '=', 'bookings.stype_id')
->join('users', 'users.id', '=', 'user_client_id')
->join('addresses', 'addresses.id', '=', 'users.address_id')
->select('bookings.id as id', 'first_name', 'phonenumber', 'booking_reference as description', 'stype_name as title', 'color', 'booking_date as start')
->get();
You could use:
$bookings = Booking::with('booking_status')
->where('photographer_id', $photographer->id)
->orWhere('user_client_id', $user->id)
->get();
of course you need to have status relationship between Booking and Status
And if you have color column in your BookingStatus model, you can access it now:
foreach ($bookings as $b) {
echo $b->booking_status->color;
}
Using Raw SQL is not suggested as long as Model core api can be invoked directly in controller by having related associations with other table. I would suggest to use Models core api with relations.
For Example
$bookings = Booking::with('booking_status')
->where('photographer_id', $photographer->id)
->get();
The above sample code is just an example of using laravel eloquent associations in controller. However, you will need to make changes in the above conditions as per your requirement.
Note: The above code will work only if you have defined associations in all relevant models. For example Booking model must have association "hasMany" with BookingStatus model and similarly BookingStatus model should have association "belongsTo" with Booking table. In this way you don't need to write custom queries.

Categories