PHP Laravel (->with) only 1 result - php

I have 2 models: TheSeries and TheEpisodes.
TheSeries has many TheEpisodes and TheEpisodes has one TheSeries.
I am trying to list all TheSeries and display latestEpisode in each, by using TheEpisodes.addDate.
The code I have right now is this:
$TheSeries = TheSeries::with('TheEpisodes');
What should I do to display only latest 1 episode for each TV serial?
EDIT
->take(1) and ->limit(1) do not work for TheEpisodes
EDIT (Latest Semi-Working Code)
$results = TheSeries::take(5)->with(['TheEpisodes' => function($q) {
$q->orderBy('addDate', 'desc');
}])->get()
This works, it returns the episodes in correct order but I am unable to limit the results to 1. This following codes don't work:
// Example 1
$results = TheSeries::take(5)->with(['TheEpisodes' => function($q) {
$q->orderBy('addDate', 'desc')->take(1);
}])->get()
// Example 2
$results = TheSeries::take(5)->with(['TheEpisodes' => function($q) {
$q->orderBy('addDate', 'desc')->limit(1);
}])->get()
// Example 3
$results = TheSeries::take(5)->with(['TheEpisodes' => function($q) {
$q->orderBy('addDate', 'desc')->first();
}])->get()
Those are the column names of the tables:
TheSeries - id, originalTitle, aliasTitle, description, imageURL, startingDate, endingDate, activeBool
TheEpisodes: id, seriesID, authorID, addDate, episodeVersion

Define a TheLatestEpisode hasOne relation on your TheSeries model:
class TheSeries extends Model
{
public function TheLatestEpisode()
{
return $this->hasOne(TheEpisode::class, 'seriesID')->orderBy('id', 'desc');
}
}
Then you can easily do:
$series = TheSeries::with('TheLatestEpisode')->get();

You can try it as:
$TheSeries = TheSeries::with(['TheEpisodes' => function($q) {
$q->orderBy('created_at', 'desc')->take(1);
}])
->get();
Or try with limit as:
$TheSeries = TheSeries::with(['TheEpisodes' => function($q) {
$q->orderBy('created_at', 'desc')->limit(1);
}])
->get();

$TheSeries = TheSeries::with(['TheEpisodes' => function($q) {
$q->orderBy('created_at', 'desc')->first();
}])
->get();
can't work?

Why don't you use the DB statement ?
DB::table('TheEpisodes')
->leftjoin('TheSeries','TheEpisodes.SeriesId','=','TheSeries.id')
->select('TheEpisodes.*','TheSeries.id as sId','TheSeries.name as sName',...)
->orderBy('TheEpisodes. addDate','desc')
->take(1)
->get();

You can try something like this in your TheSeries model: (it is easier)
public function getLatestEpisodeAttribute(){
$episode = TheEpisodes::where('series_id',$this->attributes['id'])
->latest()
->first();
if(!$episode){
return "no episodes for this Series";
}
return $episode;
}
On your controller just do the query normally without including anything related to TheSeries and you can access it values in your blade file like this:
//lets suppose there is a title attibute in the episodes
{{$TheSeries->latest_episode->title}}
//or a duration attribute
{{$TheSeries->latest_episode->duration}}

The best solution I found, was to create a one-to-one relationship with orderBy('addDate'), it works!!!
Reference: https://softonsofa.com/tweaking-eloquent-relations-how-to-get-latest-related-model/

$TheSeries = TheSeries::with('TheEpisodes')->first();
Or
$TheSeries = TheSeries::with('TheEpisodes')->firstOrFail();

Related

Get last records from relationship in Laravel

I have a one to many relation between Person and Visit tables like this:
public function visits()
{
return $this->hasMany('App\Models\Visit');
}
And want to get the persons who has a sickness_id of 1 in the relation like this:
$persons = Person::whereHas('visits', function ($query) {
$query->where('sickness_id', 1);
})->get();
And it works fine but I want to search just last visit of each person.
I mean if a person has two visits, one with sickness_id of 1 and other with sickness_id of 2, do not return this person because last visit is sickness_id of 2.
you can use hasOne relation for that:
public function lastVisit()
{
return $this->hasOne('App\Models\Visit')->latest();
}
then you can load it:
$persons = Person::whereHas('lastVisit', function ($query) {
$query->where('sickness_id', 1);
})->get();
I think the above answer is gonna work. Using addSelect, this might also work:
Person::addSelect('last_visit_id', Visit::select('id')
->whereColumn('person_id', 'persons.id')
->latest()
->limit(1)
)
->where('last_visit_id', 1)
->get();
$person = modelname::query()
->where(['sickness_id' => '1' ])
->select('visits')
->orderBy('id', 'DESC')
->first();

Laravel belongsToMany relation condition

I have created many-to-many relation using belongsToMany function:
class Doctor extends Model
{
...
public function categories()
{
return $this->belongsToMany('App\Category', 'doctors_to_categories', 'doctor_id', 'category_id');
}
...
}
Now I want to create query with many-to-many condition. In SQL in would be:
SELECT *
FROM `doctors`
JOIN `doctors_to_categories`
ON `doctors_to_categories`.`doctor_id` = `doctors`.`id`
WHERE `doctors_to_categories`.`category_id` = 1
I have tried to achieve this like:
$doctors = Doctor::with(['categories' => function($query) {
$query->where('category_id', '=', 1);
}])->get();
Or
$doctors = Doctor::with(['categories' => function($query) {
$query->where('categories.id', '=', 1);
}])->get();
But it is not working. Any ideas how it should be? Thanks for any help.
The with() function does not actually introduce a join in your query, it just loads the relation of all models as a second query. So the with() function couldn't possibly change the original result set.
What you are looking for is whereHas(). This will add a WHERE EXISTS clause to the existing query.
$doctors = Doctor::with('categories')->whereHas('categories', function ($query) {
$query->where('categories.id', 1);
})->get();
Using ->with() doesn't actually limit the results of the Doctor::...->get() query; it simply tells Laravel what to return in the relationships attribute. If you actually want to enforce returning only Doctors that have a category 1 relationship, you need to use whereHas():
$doctors = Doctor::whereHas('categories', function($query) {
$query->where('categories.id', '=', 1);
// `id` or `categories.id` should work, but `categories.id` is less ambigious
})->get();
You can add whereHas condition for this. Try code below:
$doctors = Doctor::with('categories')->whereHas('categories', function($query) {
$query->where('id', 1);
})->get();

OrderBY On model relationship eloquant on controller?

I am not able to find any perfect solution for it.
Controller:
$servicerequest = ServiceRequest::selectRaw('count(id) as totalservice,max(created_date) as last_service,service_provider_id,id,service_id,account_id,service_request,created_date')->with(['account' => function($first) use ($keyword) {
$first->select('id', 'restaurant_name')->orderBy('restaurant_name', 'DESC');
}])
->with(['serviceProvider' => function($query) use ($keyword) {
$query->select('id', 'company_name');
}])->groupBy('account_id')
->orderBy('company_name', 'DESC')
->paginate(100);
I need an order by on model relation table field and that effect on main table data. because it's and one to one relationship so no need to order by on the inside.
Like I need to the orderby whole on relations data.
Collection:
You must make join your relation table to used orderBy relation table.
You can try this code.
$servicerequest = ServiceRequest::selectRaw('count(id) as totalservice, max(created_date) as last_service,service_provider_id,id,service_id,account_id,service_request,created_date, SERVICEPROVIDERTABLE.company_name')
->join('serviceProvider', 'SERVICEPROVIDERTABLE.id', '=', 'SERVICEREQUESTTABLE.service_provider_id')
->with([
'account' => function ($first) use ($keyword) {
$first->select('id', 'restaurant_name')
->orderBy('restaurant_name', 'DESC');
}
])
//->with([
// 'serviceProvider' => function ($query) use ($keyword) {
// $query->select('id', 'company_name');
// }
//])
->groupBy('account_id')
->orderBy('SERVICEPROVIDERTABLE.company_name', 'DESC')
->paginate(100);
i hope this works.

How to fetch users not assigned to a particular role in Laravel [duplicate]

In Laravel we can setup relationships like so:
class User {
public function items()
{
return $this->belongsToMany('Item');
}
}
Allowing us to to get all items in a pivot table for a user:
Auth::user()->items();
However what if I want to get the opposite of that. And get all items the user DOES NOT have yet. So NOT in the pivot table.
Is there a simple way to do this?
Looking at the source code of the class Illuminate\Database\Eloquent\Builder, we have two methods in Laravel that does this: whereDoesntHave (opposite of whereHas) and doesntHave (opposite of has)
// SELECT * FROM users WHERE ((SELECT count(*) FROM roles WHERE user.role_id = roles.id AND id = 1) < 1) AND ...
User::whereDoesntHave('Role', function ($query) use($id) {
$query->whereId($id);
})
->get();
this works correctly for me!
For simple "Where not exists relationship", use this:
User::doesntHave('Role')->get();
Sorry, do not understand English. I used the google translator.
For simplicity and symmetry you could create a new method in the User model:
// User model
public function availableItems()
{
$ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
return \Item::whereNotIn('id', $ids)->get();
}
To use call:
Auth::user()->availableItems();
It's not that simple but usually the most efficient way is to use a subquery.
$items = Item::whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
})
->get();
If this was something I did often I would add it as a scope method to the Item model.
class Item extends Eloquent {
public function scopeWhereNotRelatedToUser($query, $user_id)
{
$query->whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
});
}
}
Then use that later like this.
$items = Item::whereNotRelatedToUser($user_id)->get();
How about left join?
Assuming the tables are users, items and item_user find all items not associated with the user 123:
DB::table('items')->leftJoin(
'item_user', function ($join) {
$join->on('items.id', '=', 'item_user.item_id')
->where('item_user.user_id', '=', 123);
})
->whereNull('item_user.item_id')
->get();
this should work for you
$someuser = Auth::user();
$someusers_items = $someuser->related()->lists('item_id');
$all_items = Item::all()->lists('id');
$someuser_doesnt_have_items = array_diff($all_items, $someusers_items);
Ended up writing a scope for this like so:
public function scopeAvail($query)
{
return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
}
And then call:
Items::avail()->get();
Works for now, but a bit messy. Would like to see something with a keyword like not:
Auth::user()->itemsNot();
Basically Eloquent is running the above query anyway, except with a = instead of a <>.
Maybe you can use:
DB::table('users')
->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Source: http://laravel.com/docs/4.2/queries#advanced-wheres
This code brings the items that have no relationship with the user.
$items = $this->item->whereDoesntHave('users')->get();

Laravel OrderBy Relationship count with pagination

I have many projects and each has many orders, some completed, some not.
I want to order them by the amount of completed orders like this:
$products = $products->orderBy(function($product) {
return $product->orders->where('status', 2)->count();
})->paginate(15);
I know the order call doesn't work like this but this is the best was show the problem. SortBy doesn't work because I want to use pagination.
Finally found a good solution for the problem:
$products = $products->join('orders', function ($join) {
$join->on('orders.product_id', '=', 'products.id')
->where('orders.status', '=', 2);
})
->groupBy('products.id')
->orderBy('count', $order)
->select((['products.*', DB::raw('COUNT(orders.product_id) as count')]))->paginate(50);
Try this if it works:
$categories = Prodcuts::with(array('orders' => function($query) {
$query->select(DB::raw('SELECT * count(status) WHERE status = 2 as count'))
$query->orderBy('MAX(count)')
}))->paginate(15);
return View::make('products.index', compact('categories'));
Note: This is not tested.
From 5.2 on wards you can use the withCount for counting relationship result.
In this case the
$products = $products->withCount(['orders' => function ($query) {
$query->where('status', 2);
}]);
Reference : https://laravel.com/docs/5.2/eloquent-relationships

Categories