Querying on a pivot table using Model::query in Livewire - laravel

I have been using this table package lately, MedicOneSystems/livewire-datatables and I cannot seem to grab information from pivot tables.
public function builder()
{
return $this->model::query();
}
This is in their base livewire controller, then you can create your own controller by using some of the functions they offer you.
My problem is that once I enter a workbook(Workbook) I need to get the stations that are stored in a pivot table(StationWorkbook) and then go further and take the station(Station) names and everything else from the station table. I am able to get either all the stations, or just the pivot or just the workbook, but I cannot seem to be able to go through them
This is what I have tried so far in my controller.
public function builder()
{
return $this->current_workbook->stations->query();
}
Method Illuminate\Database\Eloquent\Collection::query does not exist
public function builder()
{
return Station::query();
}
public function builder()
{
return StationWorkbook::query();
}
public function builder()
{
return Workbook::query();
}
public function builder()
{
return Workbook::query()->where('id', $this->workbook)->stations;
}
Property [stations] does not exist on the Eloquent builder instance.
None of these was able to return the stations of the workbook.

You are trying to access the collection stations on the Eloquent QueryBuilder - that won't work until after you use get(), which you cannot do with this package, since it expects a QueryBuilder instance.
I'm not entirely sure what you need here, but if you need the station that belongs to that Workbook, then you need to return the querybuilder of the Stations model.
If we assume that you have defined a workbook relation on your Station model, then you can use whereHas() - which can be called on the querybuilder - to limit the data you need. I'm assuming that $this->workbook is the ID, and not the full instance of the model (if its the model, you need to use $this->workbook->id).
public function builder()
{
return Station::whereHas('workbook', function($query) {
return $query->where('id', $this->workbook);
});
}
You can also eager-load the workbook in that query by adding with(). Eager-loading means that Laravel will retrieve the stations joined with the workbook, so that you can access the data of both without extra queries required.
public function builder()
{
return Station::with('workbook')->whereHas('workbook', function($query) {
return $query->where('id', $this->workbook);
});
}

Related

Laravel Eloquent 'withCount' function on multiple joined tables

I have multiple hasMany relations where I want the row count only for the last table.
Users can register for workshops at a specific date and time, so the relations look like 'Workshop' -> hasMany 'Date' -> hasMany 'TimeSlot' -> hasMany 'Registration'.
//Workshop Model
public function workshop_dates(){
return $this->hasMany(WorkshopDate::class);
}
//Date Model
public function workshops(){
return $this->belongsTo(Workshop::class);
}
public function workshop_times(){
return $this->hasMany(WorkshopTime::class);
}
//Time Model
public function workshop_dates(){
return $this->belongsTo(WorkshopDate::class);
}
public function registrations(){
return $this->hasMany(Registration::class);
}
//Registration Model
public function workshop_times(){
return $this->belongsTo(WorkshopTime::class, 'workshop_time_id','id');
}
In my controller I fetch all workshops with all related dates and timelots, but I don't want the user to download all the registration data. I only want them to download the number of registrations for each timeslot.
I tried with the 'withCount' function:
return Workshop::with('workshop_dates.workshop_times.registrations')->withCount('registrations')
But this gave me the error 'Call to undefined method App\Workshop::registrations()'
So I created this method in Workshop.php, with the extended version of hasManyThrough:
public function registrations(){
return $this->hasManyDeep(Registration::class, [WorkshopDate::class,WorkshopTime::class]);
}
However, now I get the total number of registrations per workshop in stead of per timeslot.
I'm a laravel beginner and searching for a solution for many hours. All help is appreciated!
You can add the withCount() on relationship with a closure like this:
Workshop::with(['workshop_dates.workshop_times' => function($q) {
$q->withCount('registrations');
}, 'workshop_dates.workshop_times.registrations'])
->get()
Otherwise, something like this approach https://stackoverflow.com/a/41166325/4705339

Laravel 5.8 local query scope with pivot table, return the related models

I have Services that have a many-to-many relationship to People as contacts, connected by a services_contacts pivot table and I'm attempting to create a local scope query on the Service model to return the primaryContacts():
public function scopePrimaryContacts($query)
{
$pivot = $this->contacts()->getTable();
return $query->whereHas('contacts', function ($q) use ($pivot) {
return $q->where("{$pivot}.is_primary", true);
});
}
This returns the services, where I need it to return the people that are related as is_primary on the pivot table itself. I'd like to be able to call $this->primaryContacts on my Service model, like I can call $this->contacts to get any/all contacts. Any ideas where to go from here? Here are the relationships... contacts on the Service model:
public function contacts()
{
return $this->belongsToMany(Person::class, 'services_contacts', 'service_uuid', 'person_uuid')
->withPivot('is_primary', 'is_active', 'contact_type_uuid')
->withTimestamps();
}
And services on the Person model:
public function services()
{
return $this->belongsToMany(Service::class, 'services_contacts', 'person_uuid', 'service_uuid');
}
I wouldn't make this a scope, I'd make a second relationship function but with some additional params.
Service Model
public function primaryContact()
{
return $this->belongsToMany(Person::class, 'services_contacts', 'service_uuid', 'person_uuid')
->wherePivot('is_primary', true)
->wherePivot('is_active', true);
}

Getting data from two separate models in laravel

I wanted to get data which is related to an id and I used the find($id) method to get those data, now I wanna get data from two tables which have one to many relationship.
How can I get data which is related to the same id from two table?
I try to this way but it hasn't worked:
public function show($id)
{
$post=Clients::find($id);
return view('pet.shw',['post'=>$post,'pets'=>$post->pets]);
}
Why you dont use with() I have simple solution but maybe not best solution:
Post::with('pets')->where('id',$id)->first();
Maybe below code is work to i dont test it:
Post::with('pets')->find($id);
Of course you should have comments method in your Post Object:
public function pets(){
return $this->hasMany(Pet::class);
}
hope help
You need to first define a relationship between your Client model and Pet model
So, in App\Client, you would have the following relationship:
public function pets()
{
return $this->hasMany(Pet::class);
}
and in App\Pet, you would have the following relationship:
public function client()
{
return $this->belongsTo(Client::class)
}
You should then be able to do this in your Controller:
public function show($id)
{
$post = Client::with('pets')->find($id);
return view('pet.shw')
->withPost($post);
}
and accesses your relationship like this in the pet.shw view:
foreach($post->pets as $pet) {}
For more information read about Eloquent Relationships

Merging results from belongsToMany and belongsTo relationships in Eloquent

In my Image model I have two relationships with my Article model, one many-to-many and one one-to-many:
public function articlesAlbums()
{
return $this->belongsToMany('Article', 'article_image', 'image_id', 'article_id')->publishedFilter();
}
public function articleThumb()
{
return $this->hasMany('Article')->publishedFilter();
}
I merge the results from these to get all images used by Article:
public function getArticlesAllAttribute()
{
return $this->articlesAlbums->merge($this->articleThumb);
}
In my Article model I have two relationships with my Image model:
public function images()
{
return $this->belongsToMany('Image', 'article_image', 'article_id', 'image_id');
}
public function thumbnail()
{
return $this->belongsTo('Image', 'image_id');
}
I would like to merge these as well, same way I do in my Image model:
public function getImagesAllAttribute()
{
return $this->images->merge($this->thumbnail);
}
But that doesn't work, it seems to be because my thumbnail relationship is belongsTo, not hasMany. So maybe it's not a collection. When I try I get an exception:
Call to a member function getKey() on a non-object
I've tried converting it to a collection with:
new Collection($this->thumbnail)
but get an error saying:
__construct() must be of the type array, object given
How can I merge $this->images and $this->thumbnail in my Article model to get the same results that I do in my Image model? Meaning that the results are merged with no duplicates.
Many thanks.
Update:
Since Razor made me realized that $this->thumbnail did not in fact return a collection, but rather a single object it made me rethink if merge was really the proper function to use.
return $this->images->merge($this->thumbnail()->get());
This seemed to cause a lot of unnecessary queries, even though I was eager loading.
So I ended up doing this instead:
public function getImagesAllAttribute()
{
$imagesAll = $this->images;
if ( ! is_null($this->thumbnail)) $imagesAll->add($this->thumbnail);
return $imagesAll->unique();
}
It drastically reduced the number of queries, and the result is the same.
$this->thumbnail is the same as $this->thumbnail()->first(), to get a collection, you may try:
public function getImagesAllAttribute()
{
return $this->images->merge($this->thumbnail()->get());
}

Returning counts of a relationship model in Laravel

I have a model for user and annotations along with a pivot table user_like for storing annotations liked by user. The annotation table is also associated with another model (ranges) through hasMany relationship. I am trying to return all annotations along with its user, ranges and total number of likes.
The code below works for user, ranges and even likes. But, I am only interested in returning the count of likes and not the actual values (i.e. list of users liking the annotation). Is there a way to include just the counts for one of the models from the relations?
Eloquent query:
$annotations = Annotation::with('ranges')
->with('likes')
->with('author')
->where('document_id', $docid)->get()->toArray();
The model:
class Annotation extends Eloquent {
public function ranges()
{
return $this->hasMany('Range');
}
public function author()
{
return $this->belongsTo('User', 'user_id');
}
public function likes()
{
return $this->belongsToMany('User', 'annotation_like');
}
public function countOfLikes()
{
return $this->likes()->count();
}
}
If you want to retrieve count for multiple annotations using eager loading then you need the following 'helper' relation setup:
public function countLikesRelation()
{
return $this->belongsTo('User','annonation_like')->selectRaw('annotation_like, count(*) as count')->groupBy('annotation_like');
}
// then you can access it as such:
$annotations= Annotation::with('countLikesRelation')->get();
$annotations->first()->countLikesRelation->count;
// to make it easier, we create an accessor to the count attribute
public function getLikesCountAttribute()
{
return $this->countLikesRelation->count;
}
//And then, simply use
$annotations->first()->sectionsCount;

Resources