How to join table with req->id - php

public function getTourDetail(Request $req)
{
//Get link detail
$tour = Tour::where('id',$req->id)->first();
//I want to take location.city of the location table
$detail = Tour::join('location','tour.id_location','=','location.id')
->whereColumn([
['tour.id_location','=','location.id']
])
->get(array(
'tour.id as id_tour',
'location.image',
'tour.name',
'tour.id_location',
'location.city'
));
return view('page.tour-detail',compact('tour','detail'));
}
I would like to be able to combine two query statements to get information from the location table ($ detail) like the id of the link request ($ tour).

Since you use models, you can use Eloquent relationships to load related data. First, define a relationship in the Tour model:
public function location()
{
return $this->belongsTo(Location::class, 'id_location')
}
Then load Tour and get related location:
$tour = Tour::find($req->id);
$relatedLocation = $tour->location;

First thing, if you are using model then using eloquent relationship will be a better idea to deal with the situation like yours. But if you want to join your table then this will be the way:
public function getTourDetail($id)
{
$tour = Tour::where('id',$id)->first();
//I want to take location.city of the location table
$detail = DB::table('location')
->join('tour','tour.id_location','=','location.id')
->select(
'tour.id as id_tour',
'location.image',
'tour.name',
'tour.id_location',
'location.city'
)->get();
return view('page.tour-detail',compact('tour','detail'));
}
Note: if you are getting id from submitted form then replace first portion of the code with:-
public function getTourDetail(Request $request)
{
$tour = Tour::where('id',$request->id)->first();

Related

What is the best way to select comments with user data and additional with Laravel?

Im trying to make list with comments, including data about user and his car, that are stored in another tables.
Controller contained such query:
Charging::available()
->with('some.ports', 'shares')
->find($id);
And I rewrote it to such:
Charging::available()
->with('some.ports', 'shares')
->with('chargingComments.user')
->with('chargingComments.car')
->find($id);
Thats how ChargingComments model looks like:
public function comments() {
return $this->belongsTo(\App\Models\Charging::class);
}
public function user() {
return $this->belongsTo(\App\Models\User::class);
}
public function car() {
// here 'id' is the row in the table with users cars
// 'car_id' is in the table with comments
return $this->hasOne(\App\Models\UserCar::class, 'id', 'car_id');
}
It returns me data about each comments` user and his car, but btw I have to somehow limit result to 10 rows. I tried to add
'user' => function($query) {
return $query->take(10);
}])
But it didnt work.
Im sure that should be the better way to write this code, but dont know how
try this
Charging::with('some.ports', 'shares')->with('chargingComments.user')->with('chargingComments.car')->find($id)->latest()->take(10)->get();

How to retrieve data from one table based on the calculation of another two table?

Suppose I have Three model named as Customer ,Invoice and Payment.
Invoice and Payment model looks like
id , customer_id, amount
I want to get only those customer whose
Invoice.sum(amount)>Payment.sum(amount) with these amount difference
I am currently retrieve like
$customers=Customer::get();
foreach($customers as $customer)
{
$pay=Payment::where('customer_id',$customer->id)->sum('amount');
$due=Invoice::where('customer_id',$customer->id)->sum('amount');
if($due>$pay){
// showing this customers
}
}
Is there any better way with eloquent join?
How Can I get In laravel eloquent ?
Have you set any relationship in the Model? A better eloquent query will look like this. You might need to adjust a bit
Customer::join('payment','customer.id','=','payment.customer_id')
->join('invoice','customer.id','=','invoice.customer_id')
->select(array('customer.*'),DB::raw("SUM(payment.amount) as payment_sum,SUM(invoice.amount) as invoice_sum"))
//->where('customer_id',$customer->id)
->groupBy('customer.id') //replace with anything that make sense for you.
->havingRaw('invoice_sum > payment_sum')
->get();
Try this
First, define the relationship in your Customer Model
public function payments()
{
return $this->hasMany(Payment::class); //based on your logic or structure
}
public function invoices()
{
return $this->hasMany(Invoice::class); //based on your logic or structure
}
Customer::with(['payments' => function($query) {
$query->sum('amount');
}])
->get();
or
$customers=Customer::with('payments','invoices')->get();
foreach($customers as $customer)
{
$pay = $customer->payments()->sum('amount');
$due = $customer->invoices()->sum('amount');
//other logic
}

Return belonging name with ID form Laravel, check for the type?

sorry for the title of this question but I am not sure how to ask it...
I am working on a project where I have two Models Trains and Cars, to this model I have a belonging Route.
I want to make a query and check if the routeable_type is App\Car than with the selected routeable_id to get the data from the Car. And if the routeable_type is Train then with the ID to get the data from the Tran.
So my models go like this:
Train:
class Train extends Model
{
public function routes()
{
return $this->morphMany('App\Route', 'routeable');
}
}
Car:
class Car extends Model
{
public function routes()
{
return $this->morphMany('App\Route', 'routeable');
}
}
Route:
class Route extends Model
{
public function routeable()
{
return $this->morphTo();
}
}
And the query I have at the moment is:
$data = Route::leftjoin('cars', 'cars.id', '=', 'routes.routeable_id')
->leftjoin('trains', 'trains.id', '=', 'routes.routeable_id')
->select('routes.id', 'cars.model AS carmodel', 'trains.model AS trainmodel', 'routeable_type', 'routes.created_at');
With this query if I have the same ID in cars and trains I get the data from both and all messes up. How do I check if routeable_type is Car ... do this, if routeable_type is Train .. do that?
Will something like this be possible in a 1 single query:
$data = Route::select('routes.id', 'routeable_type', 'routes.created_at');
if(routeable_type == 'Car'){
$data = $data->leftjoin('cars', 'cars.id', '=', 'routes.routeable_id')->select('routes.id', 'cars.model AS carmodel', 'routeable_type', 'routes.created_at');
}else{
$data = $data->leftjoin('trains', 'trains.id', '=', 'routes.routeable_id')->select('routes.id', 'trains.model AS trainmodel', 'routeable_type', 'routes.created_at');
}
Maybe this is what you are looking for?
DB::table('routes')
->leftJoin('cars', function ($join) {
$join->on('cars.id', '=', 'routes.routeable_id')
->where('routes.routeable_type', 'App\Car');
})
->leftJoin('trains', function ($join) {
$join->on('trains.id', '=', 'routes.routeable_id')
->where('routes.routeable_type', 'App\Train');
})
->select('routes.id', 'cars.model AS car_model', 'trains.model AS train_model', 'routes.routeable_type', 'routes.created_at');
->get();
I think you may want to follow the morphedByMany design.
https://laravel.com/docs/5.7/eloquent-relationships#many-to-many-polymorphic-relations
This was also a neat visual for the different relation types.
https://hackernoon.com/eloquent-relationships-cheat-sheet-5155498c209
I was faced with a similar issue though I failed to follow the correct design initially and was forced to query the many possible relations then wrote custom logic after to collect the relation types and ids then do another query and assign them back through iteration. It was ugly but worked... very similar to how Eloquent does things normally.
i don't have enough repo, so i can't comment. that's why i am putting as an answer.
You should use 2 different queries, for each model.
This will be better, code wise as well as performance wise. also if both models have similar fields you should merge them to 1 table and add a 'type' column.
and put non-similar fields in a 'meta' column.
( in my opinion )

Fetching has many relationship data Laravel and using avg function

I am using Laravel 5 with vue js. Basically i am fetching data using axios and trying to display on the webpage using vue js v-for directive.
i have tables in database like this:
ratings Table
id review_id rating
Then i have a
reviews table
id review
They have one to many relationship between. so here in my Review Model i have method
public function ratings()
{
return $this->hasMany('App\Rating')
->selectRaw('review_id,AVG(rating) AS average_rating')
->groupBy('review_id');
}
so here i want to fetch list of reviews with their average ratings. so in my controller i am doing this:
public function getAllReviews(Request $request)
{
$reviews = Review::with('ratings')->get();
return $reviews;
}
So i am getting result but the problem is every review doesnt have ratings record so it is returning null? maybe...
when i try to render in vue template it throws an error undefined because in our collection some reviews do not have ratings.
Now my question is: Can i do something like if there is no record in the ratings for a particular review is it possible to add an array with value 0?? so in my frontend it wont see as undefined.
I hope i am successful to explain i am trying.
Thank you.
You may do it this way:
public function getAllReviews(Request $request)
{
$reviews = Review::selectRaw('*, IFNULL((SELECT AVG(rating) FROM ratings where ratings.review_id = reviews.id), 0) as avg_rating')->get();
return $reviews;
}
I would suggest using the basic relationship and a modified withCount():
public function ratings() {
return $this->hasMany('App\Rating');
}
$reviews = Review::withCount(['ratings as average_rating' => function($query) {
$query->select(DB::raw('coalesce(avg(rating),0)'));
}])->get();
public function showProduct($id)
{
$data = Product::where('category_id',$id)
->selectRaw('*, IFNULL((SELECT AVG(value) FROM ratings where ratings.product_id = products.id), 0) as avg_rating')
->get();
return view('ecommerce.web.productsOfcategory',compact('data'));
}
$avgQuery = "IFNULL((SELECT AVG(ratings.rating) FROM ratings WHERE ratings.review_id = reviews.id),'No Ratings') as avg_rating";
$reviews = Review::query()->selectRaw("reviews.*, $avgQuery")->get();
//SQL Query
$sqlQuery = "select reviews.*, IFNULL((SELECT AVG(ratings.rating) FROM ratings where ratings.review_id= ratings.id), 'No ratings') as avg_rating FROM reviews";

laravel add conditions in belongsToMany relationshaip

In index controller i don't need any condition so data retrieves very clearly with all relational models.
$questions = Question::with('user','courses','subjects')->take(10)->orderBy("id","DESC")->get();
This return the question list with all related data like user courses and subject
But in courses controller when try to retrieve data with same and adding condition for course slug then its return error.
$questions = Question::with('user','courses','subjects')->where("slug",$course)->take(10)->orderBy("id","DESC")->get();
Because its adds this condition in question table query so there are no slug coloumn.
And When i retrieved with course class it return correct result but the subjects and users are missing
$questions = Course::with("question")->where("nick_name",$course)->orWhere("slug",$course)->orderBy("id","DESC")->take(10)->get();
Then how can i get all related data.
And the course model has
public function question(){
return $this->belongsToMany('App\Models\Question','university_questions')->take(10);
}
and question model have
public function courses(){
return $this->belongsToMany('App\Models\Course','course_questions');
}
public function subjects(){
return $this->belongsToMany('App\Models\Subject','subject_questions');
}
public function years(){
return $this->hasMany('App\Models\QuestionYear');
}
What is missing here please help.
if you want to get multiple relations you need to pass array,like this
$questions = Course::with([
'questions.user',
'questions.courses',
'questions.subjects'
])
->take(10)
->where("slug",$slug)
->orderBy("id","DESC")
->get();

Categories