Laravel sort by related table - php

I have a little complicated relationship and I also want to order my results using column in the other table, let's see:
$book = Book::where('id', '=', $id)->with([
'versions.titles' => function ($query) {
//I want to paginate table "titles"
$query->groupBy('titles.title')->paginate(15);
},
'versions.titles.numbers' => function ($query) {
// but I want to order it by "numbers.order_key"
$query->orderBy('numbers.order_key', 'asc')->get();
}])
->first();
Of course, this code doesn't work properly - titles column isn't sorted by numbers.order_key. Does anybody have any idea how to get it? I don't really want to use joins because of a complication of my relationships.
Update:
My models
Book:
-id
Title:
-id
Version:
-id
-book_id
titles_version:
-title_id
-version_id
Number:
-id
-book_id
-title_id
I want to obtain one nested record to paginate titles, e.g. $book->versions->titles->paginate(15), where titles have to be ordered by numbers.order_key.

Related

Laravel multiple select filter for categories, only get one select as output

In laravel 8, I am filtering blog articles by category. However when I select multiple categories in my select menu. I do get the proper request . for example: articles/category/?category_ids=3,4
But it will only output one selected filter. If I select 2 filters it just selects that next filter as if I only selected that one. (I also use Axios but the request is done proper, so its in my Controller)
Here is my code I tried:
$data['articles'] = Article::whereHas('categories', function ($query) use($category_ids){
$query->whereHas('category_id', '=', $category_ids)->where('premium',0);
;})->get();
I also tried:
$data['articles'] = Article::whereHas('categories', function ($query) use($category_ids){
$query->whereIn('category_id', [$category_ids])->where('premium',0);
;})->get();
So how do I get to query both or more category id's ?
I am using a pivot table:
Articles can have many Categories
Categories can have many Articles
I use article_category as a pivot table
When checking for relationship existence in many-to-many relations, the check is still to be done against the id in the categories table.
Try this
$category_ids = collect(explode(',', $request->category_ids))
->map(fn($i) => trim($i))
->all();
$data['articles'] => Article::whereHas('category', fn($query) =>
$query->whereIn('categories.id', $category_ids)
->where('categories.premium', 0)
)->get();
You can explode the categories and then make the query like this.
$categories = explode(',',$request->categories);
$data['articles'] = Article::whereHas('categories', function ($query) use($categories){
$query->whereIn('category_id', $categories)->where('premium',0);
})->get();

Laravel 5.7 - Many To Many Relation - Select Movies which have the provided array of Genre IDs

This is my controller code:
if ($request->genre && !$request->search) {
$genres = explode(',', $request->genre);
return Movie::with('genres')->whereHas('genres', function ($q) use ($genres) {
return $q->whereIn('id', $genres);
})->paginate(10);
}
My pivot table contains movie_id and genre_id. Both movies and genres tables do not contain reference of ID of each other.
I would need to select all movies from the table which have genres selected by the user.
For example, an array of id's = [1, 4, 9] and to select from pivot table movies that contain those genre ids.
Thanks in advance!
EDIT:
General problem was return inside callback and the way I handled data later on. Thanks for your answers, I appreciate it! :)
You did a wrong query, try the given query.
return Movie::with(['genres'])->whereHas('genres' ,function ($query) use ($genres){
$query->whereIn('id', $genres);
})->paginate(10);

Laravel mysql Inner join and also select a specific field from another table

I have the following query:
Ratings::join('users', 'movieratings.rated_by', '=', 'users.usr_id')
->where('rated_on', $movieId)
->orderBy('rated_at', 'desc')
->select('comment', 'rating', 'rated_as', 'rated_at', 'username')
->paginate(20);
This will get all the feedback ratings for a specific movie.
But I have another table which contains the total good and bad ratings for a specific movie movie, the only problem is that I cant get it to work to query that table as well at the same time.
If I do another query I would simply write: Movie::where('movie_id', $movieId)->select('total_good_ratings', 'total_bad_ratings')->get(); this would output eg "22, 15" but is it possible to only fetch two columns from a specific row then do a inner join between two tables and paginate the result?
thanks
You can do a leftJoin with the table that contains the good and bad ratings, where the join condition will be the id of the movie.
Ratings::join('users', 'movieratings.rated_by', '=', 'users.usr_id')
->leftJoin('movie', 'movie.id', '=', 'movieratings.rated_on')
->where('rated_on', $movieId)
->orderBy('rated_at', 'desc')
->select('comment', 'rating', 'rated_as', 'rated_at', 'username', 'total_good_ratings', 'total_bad_ratings')
->paginate(20);
I think you can try this:
Ratings::leftJoin('users', 'users.usr_id', '=', 'movieratings.rated_by')
->leftJoin('movie', 'movie.id', '=', 'movieratings.rated_on')
->where('movieratings.rated_on', $movieId)
->orderBy('movie.rated_at', 'desc')
->select('movieratings.comment', 'movieratings.rating', 'movieratings.rated_as', 'movie.rated_at', 'users.username', 'movieratings.total_good_ratings', 'movieratings.total_bad_ratings')
->paginate(20);
Hope this help for you !!!
In case this may be of help:
Assuming:
class Rating extends Model {
public users() {
$this->belongsTo(User::class, 'usr_id');
}
public movie() {
$this->belongsTo(Movie::class, 'rated_on'); //Name looks odd, it should be movie_id if you are following standard conventions
}
}
Then you can lazy/eaher load them:
$ratings = Ratings::with([ "movie" => function ($query) {
$q->select('total_good_ratings', 'total_bad_ratings');
}])->where('rated_on', $movieId)
->orderBy('rated_at', 'desc')
->select('comment', 'rating', 'rated_as', 'rated_at', 'username',"rated_on")
->paginate(20);
You can get the movie info via $ratings[X]->movie->total_good_ratings (in a loop that would be $rating->movie->total_good_ratings
A bit of critique though:
total_good_ratings looks like it's a derived attribute so it should not have been stored in the first place. It's appears to be a count of the good ratings.
You should use the standard conventions when naming columns and tables e.g. a foreign key is usually called <foreign table name in singular>_<foreign field name> example user_id or movie_id .

get table data base on pivot table in laravel

I have M:N relationship between tables handymen and categories. So, pivot table is category_handyman. How to fetch all handymen data, who have category_id=1 in pivot table? I wanted to do something like this: (but this doesnt work)
$handymen = Handyman::with('categories')
->where('category_id', 1)
->get();
You can use whereHas() method to filter on related records:
$handymen = Handyman::whereHas('categories', function($query) {
$query->whereId(1);
})->get();

Laravel 5 filter on pivot

I have two tables Candidates & Qualifications with a joining pivot table called Results.
What I want to do is select all candidates for this centre and filter them by a value in the pivot table.
So select all candidates from centre 1 where the pivot “status” = “REGISTERED”
I have tried numerous approaches and am currently with the one below but nothing is working.
$candidates = Candidate::where('batch_centre_id','=', $id)->with(array('qualification' => function($q)
{
$q->wherePivot('status','=', 'REGISTERED');
}))->get();
Any advice would be much appreciated
In Eloquent wherePivot method can only be loaded on a relation. The way you're doing it, you're calling it on qualifications relation, therefore you're fetching all candidates and then, for each of them, you're loading qualifications that have status=REGISTERED. That's why you're getting all candidates.
You could work around it by using Eloquent's whereHas() method that let's you filter the base model you're trying to fetch by attributes of some relation. In your case the following should work:
$candidates = Candidate::where('batch_centre_id','=', $id)
->whereHas('qualifications', function($q) {
$q->wherePivot('status','=', 'REGISTERED');
})->with('qualifications')->get();
This way you'll get only candidates that have a qualification with status=REGISTERED and all their qualifications. If you want to additionally filter loaded qualifications by status, add the constraint like you did in your code:
$candidates = Candidate::where('batch_centre_id','=', $id)
->whereHas('qualifications', function($q) {
$q->wherePivot('status','=', 'REGISTERED');
})->with(array('qualifications', function($q) {
$q->wherePivot('status','=', 'REGISTERED');
})->get();

Categories