Laravel hasMany relationship, limit with query - php

Scenario:
On a hasMany relationship, using the with function (for eager loading), I want to limit the results from each of the rows within (instead of the total).
I am following this tutorial (as I think it's the only way to achieve what I need from what I've read on SO) - https://softonsofa.com/tweaking-eloquent-relations-how-to-get-n-related-models-per-parent/
I have a Model - Room that hasMany Reviews.
Room Model:
class Room extends Scopes\BaseModel
public function reviews()
{
return $this->hasMany('App\Review');
}
public function latestReviews()
{
return $this->reviews()->latest()->nPerGroup('room_id', 1);
}
Scopes/BaseModel.php:
Direct copy from the website's tutorial, but with the namespace of namespace App\Scopes;
Controller using the with function:
class Room extends Scopes\BaseModel
$rooms = Room::where('room_types_id', $specialism_id)
->with('latestReviews')
->get();
Error:
RelationNotFoundException in RelationNotFoundException.php line 20:
Call to undefined relationship [latestReviews] on model [App\Room].

There are 2 ways of doing this. the first one is more like:
Room::with(['reviews' => function ($q) {
$q->where('*CONDITION IF NEEDED*')->orderBy('created_at', 'desc')->take(1);
}])->where('room_types_id', $specialism_id)->get();
The second way is using accessors.
public function getLatestReviewAttribute(){
return Review::where('room_id', $this->attributes['id'])->orderBy('created_at','desc')->take(1)->get();
}
and you can access it on your view by using $room->latest_review->review_column_name;
While on your controller you can just do Room::all();;

Related

Sort on the number of related (hasMany) documents

I have 2 collections.
Vehicles and Views.
I would like to bring back a list of vehicles sorted by the number of views.
My Vehicle class
class Vehicle extends Moloquent {
protected $dates = ['date_assigned'];
public function associated_views()
{
return $this->hasMany('App\Collections\View');
}
}
And my View class
class View extends Moloquent {
public function associated_vehicle()
{
return $this->belongsTo('App\Collections\Vehicle');
}
}
I can get the count of the views after the fact, with $vehicle->associated_views->count(), but this doesn't enable me to sort on the field before pulling back every single record. Is this possible?
Use withCount():
Vehicle::withCount('views')->latest('views_count')->get()
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models
https://laravel.com/docs/5.5/eloquent-relationships#counting-related-models

Laravel polymorphic relationship 0 results

I have a polymorphic relationship with Laravel.
My polymorphic relationship is Message->messageable becoming either Group or Chat.
Going from Message->messageable will give me the proper result(e.g the group or chat the message is associated with).
Going from example Group::first()->with('messages')->get() will return an empty messages array.
My db tables for message are
messageable_id
messageable_type
My model methods are as follows
class Message extends Model
{
public function messageable(){
return $this->morphTo();
}
^works as intended
class Group extends Model
{
function messages(){
return $this->morphMany('Message','messageable');
}
class Chat extends Model
{
public function messages(){
return $this->morphMany('Message','messageable');
These return empty.
example data used:
1
Any ideas?
You relationships are incorrect. You need to reference the full class namespace, not just the class name itself. E.g.
class Group extends Model
{
public function messages()
{
return $this->morphMany(\App\Models\Message::class', 'messageable');
}
}
Forgot to include namespaces in my Database messageable_type.
Changed from Group to App\Group.

Laravel 5.4 orderBy on morphTo relation

I am trying to order the results of a morphTo relation in Laravel 5.4. The below example does not work. Adding an orderBy method on other relations ( eg hasMany() ) does work.
class OrderLineItem extends Model
{
public function eventtable()
{
return $this->morphTo()->orderBy('date');
}
}
I have been able to order the result set after the query, by using sortBy on the collection. But would be good to order the results in the query. The date col is always available in the polymorphic related tables.
class OrderLineItem extends Model
{
public function eventtable()
{
return $this->morphTo()->orderBy('date','Desc');
//or you can use
//return $this->morphTo()->latest('date');
}
}

Laravel 5.3 Polymorphic many to many - how to get all the related rows regardless of their table sorted by pivot column?

I have a model Page and many models called SomethingSection - they're connected through a polymorphic m-m realtionship and the pivot has an additional column 'position'.
I need to write a relationship (or accessor maybe?) on the Page model that will return a collection of all connected Sections, regardless of their model (read: table).
My models:
class Page extends Model {
public function introSections()
{
return $this->morphedByMany(IntroSection::class, 'pagable');
}
public function anotherSections()
{
return $this->morphedByMany(AnotherSection::class, 'pagable');
}
}
class IntroSection extends Model {
public function pages()
{
return $this->morphToMany(Page::class, 'pagable');
}
}
class AnotherSection extends Model {
public function pages()
{
return $this->morphToMany(Page::class, 'pagable');
}
}
The pivot column looks like this:
pagables
-page_id
-pagable_id
-pagable_type
-position
I'm looking for a way to call a method/attribute on the Page model and get all the connected sections in a single collection, sorted too. What would be a good way to go about this?
I understand that the connected sections do not have the same interface, but in my case that's not a problem at all (in terms of what I will do with the data).
I also understand that relationships perform a separate query (for each relationship), so getting all of them with 1 query is impossible (also different interfaces would be a problem here). And for the same reason the sorting will need to be done on the collection level, not in query.
How could I make this as maintainable as possible and preferably with as small a performance hit as possible.
Thanks in advance.
You can use withPivot() method after your relationship to get the pivot columns with relation like this:
class Page extends Model {
public function introSections()
{
return $this->morphedByMany(\HIT\Models\Sections\IntroSection::class, 'pagable')
->withPivot(['position']);
}
public function anotherSections()
{
return $this->morphedByMany(AnotherSection::class, 'pagable');
}
}
class IntroSection extends Model {
public function pages()
{
return $this->morphToMany(Page::class, 'pagable')
->withPivot(['position']);
}
}
and you can use collection's sortBy to sort the collection by using sortBy() method like this:
$sorted_collection = IntroSection::pages->sortBy('pagables.position');
UPDATE:
You can use collection's combine() method to get all the relationships like this, add this method inside your Page Class:
public function getAllSections()
{
return $this->introSections->combine($this->anotherSections-toArray())
->sortBy('pagables.position'):
}
Hope this helps!

Laravel 5.2 relationship with pivot table

my tables:
every part contain many of card.
every card belong to many of part.
now,using laravel eloquent model how can fetch all card for a part without add more column to database
You need to define your relationships like below:
class Part extends Model
{
public function cards()
{
return $this->belongsToMany('App\Cards', 'user_cards');
}
}
Then you can fetch all the cards for a part like below:
$cards = Part::with('cards')->find($part_id);
Part::whereHas('cards', function($query) use ($cardId){
$query->where('id', $cardId);
})->get();
And your model relation should contain like this, for Part.php
public function cards(){
return $this->belongsToMany('App\Card');
}
And for Card.php
public function parts(){
return $this->belongsToMany('App\Part');
}

Categories