Converting Query Builder to Eloquent in Laravel - php

I have a user table, and a review table.
In my review table, there's a "star_rating" column.
I can get the average "star_rating" score for a user with the following query:
$star_rating = Review::where('artist_id', $user->id)->avg('star_rating');
However, this doesn't work too well when I'm printing out a bunch of users in blade (I want to show their average star_rating next to their names).
That's why I'd like to have a function in my User.php model that I can call to get a user's average star rating.
public function getAvgStarRating() {
return $this-> // logic goes here //;
}

Add this relation in your User model:
public function reviews()
{
return $this->hasMany(Review::class, 'artist_id', 'id');
}
Then add this method to get average of star ratings
public function getAvgStarRating()
{
return $this->reivews->avg('star_rating');
}
And if you need to display a group of user's rating, first eager load their reviews (it is more efficient)
$users = User::with('reviews')->get();
Then
foreach($users as $user) {
$user->getAvgStarRating();
}

Related

How to retrieve records from a table based on many to many relationship using eloquent in Laravel?

I have Three Models: Nationality, Nationality_Opportunity, Opportunity.
The Tables :
-------------------------------------------------------------------
nationalities | nationality_opportunities | opportunities
--------------------------------------------------------------------
id nationality_id id
name opportunity_id name
In Opportunity Model:
public function nationalities(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
{
return $this->belongsToMany(Nationality::class,'nationality_opportunities','opportunity_id','nationality_id');
}
In Nationality Model:
public function opportunities()
{
return $this->belongsToMany(Opportunity::class,'nationality_opportunities','opportunity_id','nationality_id');
}
-What do I want to do ?
I want to retrieve the opportunities records based on their selected nationalities which are sent as an array of ids through the request, so I want to check these ids in the pivot table in order to get their related opportunities records and display them in a Vue js component.
Scope Filter in Opportunity Model:
public function scopeWithFilters($query)
{
return $query->when(count(request()->input('categories', [])), function ($query) {
$query->whereIn('opp_cat_id', request()->input('categories'));
})->when(count(request()->input('nationalities',[])),function ($query){
$query->whereIn('nationalities.nationality_id', request()->input('nationalities'));
});
}
The parameter: nationalities = [1,2,3,5] .
Properties function in api controller:
public function opportunities()
{
$opportunities = Opportunity::withFilters()->get();
return PublicOpportunityResource::collection($opportunities);
}
Your Query is correct but you need to change the way you return the day please follow
$nationalities = [1,2,3,5]; //for temperory ids you can change it
$data= Nationality::with('opportunities')->whereIn('id', $nationalities)->get();
//return it as below
return response()->json($nationalities);
You can simply fetch opportunities with the code below
$nationalities = Nationality::with('opportunities')->whereIn('id', request()->input('nationalities'))->get();
And then you can access the opportunities by iterating over $nationalities or for the first row you can use $nationalities->first()->opportunities, not sure why you're using when in the callback function.
As per the edit you can make this query for your desired result
$nationalities = request()->input('nationalities');
$opportunities = Opportunity::with(['nationalities' => fn($q) => $q->whereIn('nationality_id', $nationalities)])->get();

Fetch multiple tables through hasManyThrough Laravel Eloquent

Database
I'm kind of new to databases and I made this small database, but I have problems fetching data from it.
Im trying to get all the racers from the logged in user, and it works properly, but if I enter $pigeons = $user->racer I only get back the racer table. I would like to know the attributes of the racers from the pigeons table aswell. I've made it work with query builder left joining the tables but I'm not sure why I set up this relationship if I can't use Laravel inner method.
In the User model I have these relationships:
public function pigeons(){
return $this->hasMany('App\Pigeon');
}
public function racers(){
return $this->hasManyThrough('App\Racer', 'App\Pigeon');
}
This is the Pigeon model:
public function user(){
return $this->belongsTo('App\User');
}
public function racer(){
return $this->hasMany('App\Racer');
}
}
And this is the Event model:
public function race(){
return $this->hasOne('App\Race');
}
public function racers(){
return $this->hasMany('App\Racer');
}
And this is what my EventsController looks like with the working alternative method and the commented not working.
public function upcoming(){
$id = auth()->user()->id;
$user = User::find($id);
$pigeons = DB::table('racers')->leftJoin('pigeons', 'racers.pigeon_id', '=', 'pigeons.id')->where('pigeons.user_id', '=', $id)->get();
//$pigeons = $user->racers;
return view('events.upcoming')->with('pigeons', $pigeons);
}
This is what I get with $user->racers or $user->racers()->get():
[{"id":1,"pigeon_id":14,"user_id":4,"event_id":1,"position":0,"created_at":null,"updated_at":null},{"id":2,"pigeon_id":15,"user_id":4,"event_id":1,"position":0,"created_at":null,"updated_at":null},{"id":3,"pigeon_id":16,"user_id":4,"event_id":1,"position":0,"created_at":null,"updated_at":null}]
And this is what I want to get, its not correct either since I should get id:1 but I want to pass to view these additional datas aswell like gender, color, ability (but they are in pigeons table not in racers).
[{"id":14,"pigeon_id":14,"user_id":4,"event_id":1,"position":0,"created_at":"2018-09-27 10:01:04","updated_at":"2018-09-27
10:01:04","gender":"hen","color":"blue","ability":38},{"id":15,"pigeon_id":15,"user_id":4,"event_id":1,"position":0,"created_at":"2018-09-27 10:01:04","updated_at":"2018-09-27
10:01:04","gender":"hen","color":"blue","ability":48},{"id":16,"pigeon_id":16,"user_id":4,"event_id":1,"position":0,"created_at":"2018-09-27 10:01:04","updated_at":"2018-09-27
10:01:04","gender":"cock","color":"blue","ability":11}]
To get the pigeons, what you would have to do is $pigeons = $user->racers()->get();. You can see an example of this in Laravel's official documentation https://laravel.com/docs/5.5/eloquent-relationships#introduction.

Eloquent query not working

I have a many to many relationship between users and categories. In a third table, I have a field called category_id to reference what category each record belongs to. I am setting up a system where by once a user logs in, I want them to see records that has category_id of the categories they've selected when registering.
My code is shown below
I have this relationship setup in users model,
public function categories()
{
return $this->belongsToMany('App\Category');
}
and also this
public function userCats()
{
return $this->categories()->get();
}
in the categories table i have this relationship setup
public function users()
{
return $this->belongsToMany('App\User');
}
in my 3rd Table controller i have the following code
if(Auth::check()){
$servo = Jumong::postOnly()->whereIn('category_id', Auth::user()->userCats())->get();
} else {
$servo = Jumong::all()->where('type','P');
}
dd($servo);
The problem is that the below part,
Auth::user()->userCats()
It returns only the last 2 records in Jumong table and there are more than that.
If I replace it with an array, it will return the right results.
Any ideas on what I am missing?
It doesn't work because whereIn expects an array of ids whereas
Auth::user()->userCats() returns a collection of categories.
You can still doing something like.
Auth::user()->categories->pluck('id')

One to many relationship in laravel extracting the latest timestamp

I have a one to many relationships in the database, and I am trying to extract the latest. The table names are notification and alertFrequency, they have models for each. I want to write a query that will get me the latest time stamp associated to a specific website in the notifications table. The alertFequency table has only 2 columns namely notification_id and created_at. the following are my model notification modl
class Notification extends Model
{
protected $fillable = ['id','website_url','email','slack_channel','check_frequency','alert_frequency','speed_frequency','active'];
public function statuses(){
return $this->belongsToMany('App\Status')->withPivot('values')->withTimestamps();
}
public function alertFrequencies(){
return $this->hasMany('App\AlertFrequency');
}
// trail versions
public function alert(){
$items = AlertFrequency::select('alertFrequencies.created_at')//Any column you want to fetch
->join('notifications', 'notifications.id', '=', 'alertFrequencies.notification_id')
->orderBy('alertFrequencies.created_at','desc')
->first();
if($items == null){
return null;
}
return $items->created_at->toDateTimeString();
class AlertFrequency extends Model{
protected $table = 'alertFrequencies';
public function notification(){
return $this->belongsTo('App\Notification');
}
}
inside the notification model i wrote a function that is expected to extract the data(i.e the latest time stamp of a specific website in the notification table) more over the notification_id is a foreign key in the alertFrequency table. the alert function is as follows
public function alert(){
$alert_timestamp = AlertFrequency::with('notification')->select('created_at')->orderBy('created_at','desc')->first();
//$alert_timestamp=$alert_timestamp->created_at->toDateTimeString();
if($alert_timestamp==null){
return false;
}
return $alert_timestamp;
}
it is returnning created_at time stamp but not the latset related to a specific website. i would apperciate your help?
in the database i have two websites added one at 12:18 and the second ata 12:24..... sorry i dont know how i can post the database here.
Directly You can not apply orderBy() on relation you need to use join()
Just try this. Hope it helps
$alert_timestamp = AlertFrequency::select('alertFrequencies.created_at')//Any column you want to fetch
->join('notification', 'notification.notification_id', '=', 'alertFrequencies.notification_id')
->orderBy('alertFrequencies.created_at','desc')
->get();

Laravel Object queries - 3 tables

I have three tables like this:
**Users**
id
**Posts**
id
user_id
**Favorites**
id
user_id
post_id
Currently, I made it so when I query my posts for display, it pulls all the related user data who created the post with that row which is great! But what I'm trying to do now is also add to see if the user Authorized (Logged in) has favorited the post (row) so I can display to that they already favorited it. I don't want to re-query for every post (i think its called the N+1 problem?). I'm using Laravel4
Post model
class Post extends Eloquent{
public function user(){
return $this->belongsTo('User');
}
User model
public function posts(){
return $this->hasMany('Post');
}
PostsController
public function index()
{
$posts = Post::with('user')->paginate(25);
return View::make('index', compact('posts'));
}
Step 1. Add favorites relationship in Post model.
public function favorites() {
return $this->hasMany('Favorite');
}
When querying the Model.
$auth_user_id = Auth::user()->id;
$posts = Post::with(array('user', 'favorites' => function($query) use ($auth_user_id){
$query->where('user_id', '=', $auth_user_id);
}))->get();
For more information refer to the eager load constraints,
http://laravel.com/docs/eloquent#eager-loading
Adding a many-to-many relationship using the favorites table as pivot would be one approach.
Add favorites relationship in User model:
public function favorites() {
return $this->belongsToMany('Post', 'favorites');
}
You should then be able to get all favorites by simply accessing
Auth::user()->favorites
To find whether the current post is a favorite, use
$isFavorite = Auth::user()->favorites->has($post->id);

Categories