Get Average from Polymorphic Relation - laravel

I am both trying to get the review counts and the average review ratings.
I have tables:
Tables:
id
.....
Chairs:
id
.....
Reviews:
id
rating
reviewable_id
reviewable_type
class Review extends Model {
public function reviewable() {
return $this->morphTo();
}
}
class Tables extends Model {
public function reviews() {
return $this->morphMany('App\Review', 'reviewable');
}
public function avg_rating() {
return $this->reviews()
->selectRaw('avg(rating) as avgRating, review_id')
->groupBy('review_id');
}
}
I've tried:
Table::with(['avg_rating'])->withCount('reviews')->where(function($q) use ($regex_terms, $terms){
$q->where('name', 'REGEXP', $regex_terms);
})->get();
But get "Unknown column 'review_id' in 'field list'" or attempting it with variations of "hasmany" yielded only an empty array or an array with the reviews. Just wonder what the best way to accomplish this is or if I'd have to loop through the reviews and calculate manually or a second raw query
I have this but not sure if it is efficient or best practice within Eloquent:
$tables->each(function ($table) {
$table->review_average = DB::table('reviews')
->select(DB::raw("ROUND( avg(rating), 2) as avg"))
->where("reviewable_id", "=", $table->id)->first()->avg;
});

Apparently, I was using Lumen based on the Laravel 6 framework, so it had been throwing a "method not found" error when I tried "withAvg" before. But after searching for that method, I saw that it required a higher version of Laravel. So, updating to Laravel/Lumen 8 allowed me to use the "withAvg" function.
So now my query builder statement looks like:
Table::with(['avg_rating'])->withCount('reviews')->withAvg("reviews", "rating")->where(function($q) use ($regex_terms, $terms){
$q->where('name', 'REGEXP', $regex_terms);
})->get();

Related

Eloquent Removing Columns

I'm having a really strange issue with my eloquent query. I have a table called Calls which I am joining to Contacts and Companies. I am trying to reference the column calls.id but it has been replaced with the id for Companies.
Here is my query:
$calls=DB::table('calls')
->leftJoin('contacts','calls.contact_id','=','contacts.id')
->leftJoin('companies','calls.company_id','=','companies.id')
->where('completed','=',false)
->orderBy('call_on','asc')
->get();
return $calls;
I have seen on Github that this seems to be a known bug but no-one has put forward a workaround.
Can anyone point me in the right direction?
The most direction solution to your immediate question is to add a select to your Eloquent query:
$calls=DB::select('calls.* from calls')
->leftJoin('contacts','calls.contact_id','=','contacts.id')
->leftJoin('companies','calls.company_id','=','companies.id')
->where('completed','=',false)
->orderBy('call_on','asc')
->get();
return $calls;
Instead of the default select *, explicitly dictate what is returned. However, this can be done a lot more cleanly with Eloquent using models:
Calls::whereHas('companies', function (Builder $query) {
$query->where('completed', false);
})->orderBy('call_on', 'asc')->get();
In order for this to work you need to setup the relationship on the model level:
// App\Calls model:
public function companies() {
return $this->belongsTo(App\Companies::class);
}
// App\Companies model:
public function calls() {
return $this->hasMany(App\Calls::class);
}

How to retrieve multiple relations with multiple tables in laravel eloquent

I'm using Laravel 5.8 to build a babysitting site. I have 4 tables with different relationships as below:
please see this image
The relationships are:
Babysitter->hasMany(session)
Sessions->hasOne(Review)
Sessions->hasOne(Kids)
Sessions->hasOne(Babysitter)
Sessions->hasOne(Parent)
I want to achieve 2 things:
First one
I want to show this result when listing all babysitters. I'm showing this information for each babysitter:
plsease see this image
See here what I couldn't achieve
plsease see this image
This is my code
Sitters::where('Status', 'active')->where('Verified', 1)->get();
Second one
Also, I've tried to show kids name with parent review as shown here:
plsease see this image
This is what i'm using
Sessions::select('Reviews.*', 'Sessions.Parent_id')->join('Reviews', 'Reviews.Session_id', '=', 'Sessions.id')->with('owner')->where('Trainer_id', session('user')->Id)->where('Status', '=', 'complete')->with('owner')->orderBy('Sessions.id', 'DESC')->get();
Here is Session.php Model
public function owner(){
return $this->belongsTo('App\Models\Parents', 'Parent_id');
}
As discussed change the relations:
Babysitter->hasMany(sesstion)
Sessions->hasOne(Review)
Sessions->belongsTo(Kids)
Sessions->belongsTo(Babysitter)
Sessions->belongsTo(Parent)
First one
in Babysitter.php declare the following attributes
class Babysitter extends Model
{
public function reviews()
{
$this->hasManyThrough(Review::class, Session::class);
}
public function getAverageReviewAttribute()
{
return $this->reviews()->avg('Rating');
}
}
Then you just need to call it on the model instance.
$babysitter = Babysitter::first();
return $babysitter->average_review;
Second one
Just use the relation
$babysitter = BabySitter::with(['sessions' => public function ($session) {
$session->with(['review','parent','kids']);
})->where('trainer_id', '=', session('user')->Id) //did not understand this condition
->first();
This assumes you have parent, kids and review relation declared on Session::class. (change the names if needed)
After a few days of searching & testing, this is what worked for me:
Inside (Sitters) Model, put this relation
public function sessions()
{
return $this->hasMany(Sessions::class, 'sitter_id')
->withCount('reviews')
->withCount(['reviews as review_avg' => function($query){
$query->select(DB::raw('AVG(Rating)'));
}]);
}
Also, inside (Sessions) Model, put this relation
public function reviews()
{
return $this->hasOne(Reviews::class, 'Session_id');
}
Now you query like this
return $sitters = Sitters::with('sessions')->get();
I hope this can help someone :)

Laravel eloquent get data from two tables

Laravel Eloquent Query builder problem
Hello I have a problem when I am trying to get all the rows where slug = $slug.
I will explain in more details:
I have two tables, cards and card_categories.
cards has category_id.
card_categories has slug.
What I need is a query which returns all the cards which contents the slugs.
For example I made this:
$cards = Card::leftJoin('card_categories', 'cards.id', '=', 'card_categories.id')
->select('cards.*', 'card_categories.*')
->where('card_categories.slug', $slug)
->paginate(5);
But what happens is that just return 1 row per category.
I don't know what is wrong.
Many thanks.
I think I understand what you mean, from your explanation I would imagine your card model is as follows.
class Card extends Model {
protected $table = 'cards';
public function category()
{
return $this->belongsTo(Category::class)
}
}
In which case, you should just be able to do this:
$cards = Card::whereHas('category', function ($query) use ($slug) {
$query->where('slug', $slug);
})->paginate(5);
That will select all of the cards that has the category id of the given slug.

Laravel / Eloquent: Search for rows by value in polymorphed table

I'm stuck at the moment and hope someone can give me a hand. I'm using a polymorphic relation and want to search my database for rows that fulfill conditions in the "parent" and the "child" table.
To get concrete, one small example. Given the following structure I e.g. want to look for a property with price "600" and rooms "3". Is there a way to do that with eloquent?
Tables
Table properties (parent)
id
price
details_type [can be "Apartment" or "Parcel"]
details_id
Table apartments (child)
id
rooms
Table parcels (child)
id
... (does not have a "rooms" column)
Relationships
Class Property
public function details() {
return $this->morphTo();
}
Classes Apartment + Parcel
public function property() {
return $this->morphMany('Property', 'details')
}
What I tried
A lot, really. But somehow I'm always doing something wrong or missing something. The solutions that, in my opinion should work are either:
Property::with(array('details' => function($query) {
$query->where('rooms', 3);
}));
or
Property::with('details')
->whereHas('details', function($query) {
$query->where('rooms', '=', '3');
});
But in both cases I get the following FatalError.:
Class name must be a valid object or a string
Has anyone of you already had a similar problem? Thank you very much for any kind of hint.
Let's start with your naming convention:
public function detail() // It relates to a single object
{
return $this->morphTo();
}
And
public function properties() // It relates to several objects
{
return $this->morphMany('Property', 'details')
}
Then you would be able to do this:
$properties = Property::whereHas('details', function($q)
{
$q->where('rooms', '=', '3');
})
->where('price', '=', 600)
->get();
Please note that this will never return a Parcel, since there isn't a parcel with a room.

Laravel 3 Eloquent ORM usage

I have the following code which works but doesn't seem to follow the laravel eloquent way:
Article::left_join('images', 'articles.id', '=', 'images.article_id')
->join('article_category', 'articles.id', '=', 'article_category.article_id')
->where('article_category.category_id', '=', $category_id)
->get();
I have 4 tables; articles and categories which have a many to many relationship with each other, a pivot table article_category table which holds the article id and category id and an image table which has one to one relationship with an article.
I setup my models as:
class Category extends Eloquent {
public static function get_articles($category_id) {
return static::find($category_id)->has_many_and_belongs_to('Article');
}
class Article extends Eloquent {
public function categories() {
return $this->has_many_and_belongs_to('Category');
}
public function image() {
return $this->has_one('Image');
}
However I can't seem to get all three bits of info together. I can do:
Category::get_articles($current_category)->get();
To get all articles in a given category but I can't seem to get the image for the article, there seems to be nothing I can chain onto? Unless I'm doing it incorrectly? Is there a trick I'm missing?
I even tried the stripped down version from the docs:
foreach (Article::with('image')->get() as $article) {
echo $article->image->foo;
}
However I get an error: Trying to get property of non-object, even though var_dump shows $article->image is an object! Weird.
Thanks
If you have not setup a model for the image table, do that. The ORM needs the model there so it knows what 'Image' refers to.
Can you get the category information using the ::with method or is that troublesome too?

Resources