Laravel: get children by parent slug - laravel-5

I have a Section and a Picture models, with a one-to-many relationship (Section can have many Pictures; Picture has only one Section)
I'm able to retrieve all Pictures given a Section id:
$section = '1';
$records = Picture::where('section_id', $section)->orderBy('position')->get();
What if I'd like to retrieve Picture by Section slug (or name)?
All these examples don't work:
$section = 'wedding';
$records = Picture::where('sections.slug', $section)->orderBy('position')->get(); // nope
$records = Picture::where($this->section()->slug, $section)->orderBy('position')->get(); // nope
I tried to search in Laravel docs, but I didn't get the case...
Thank you

For querying relations you should use whereHas function.
If your relation is named section() in Picture model then your query should be as:
$section = 'wedding';
$records = Picture::whereHas('section', function($q) use($section) {
$q->where('slug', $section);
})
->orderBy('position')
->get();
Docs

Related

$query->with() is working but $query->load() not working in Laravel

I have three models.
Section
Subject
Chapter
Section has many subjects and subject has many chapters.
I want to load a section with all its subjects and the subjects with all its chapters.
Here is the code I am trying:
$section = Section::find(1)->load(['subjects' => function ($query) {
$query->load('chapters');
}]);
This is not working. $query->load('chapters') this part gives me error. But if I try this code:
$section = Section::find(1)->load(['subjects' => function ($query) {
$query->with('chapters');
}]);
This is working. I have some issues with $query->with() so I want to use $query->load() instead. What should I do to use load() instead of with()>
Eloquent Query builder does not have a function called load(). But Eloquent Model does.
$section = Section::find(1)
->load(['subjects' => function ($query) { // in here you are calling load on a model (Section).
$query->load('chapters'); // in here you are calling load on a query builder instance.
}]);
when you want to load some relations after fetching a model, use load() function
when you want to load some relations while fetching models, use with() function
in your case you have already fetched the subject. So you can use load('subject'). But while you are loading subjects (you have not fetched the subjects yet), so you should call with('chapters')
EDIT
short version of your second approach
$section = Section::find(1)->load(['subjects.chapters');
If there is no special requirements to fetch the section alone, the better approach is load both subjects and chapters while fetching the section.
$section = Section::with('subjects.chapters')->find(1)
why not using:
$section = Section::query()->with('subjects.chapters')->find(1)
This will preload subjects with chapters and get you a fast result.

Counting data before sending to view in Laravel

I have two tables, products and product_images, now I want to show product which has at least one image.
In controller I have a simple function in ProductController to fetch all the products:
public function products(){
$allProducts = $this->product->paginate(15);
return view('frontend.pages.products',compact('allProducts'));
}
But, I want to send the products which has at least one image of each product.
What should I do to achieve that?
Edit:
I have created relationship between tables, now how can I get my desired answer?
I have written this in the Controller:
$allProducts = $this->product->whereHas('product_images', function ($query){
$query->where();
})->get();
Assuming table schema
product
-id
-name
product_image
-id
-product_id
-url //any columns you needed
$product_ids = DB::table('product')
->join('product_image','product_image.product_id','=','product.id')
->select('product.id','roduct.name')
->groupBy('product.id')
->get();
$product_count = count($product_ids);
Eloquent has this built in.
Example
// Retrieve all posts that have three or more comments...
$posts = App\Post::has('comments', '>=', 3)->get();
In your case
In your case you could change the $allProducts line to be
$allProducts = $this->product()->has('product_image', '>=', 1)->paginate(15);
I didn't test the code above.
See documentation for more information on this topic.
https://laravel.com/docs/6.x/eloquent-relationships#querying-relationship-existence
You can use selectRaw:
$products = Product::leftJoin('product_images',function ($join){
$join->on('products.product_id','=','product_images.product_id');
})->selectRaw("products.product_id i, count(product_images.id) c")
->groupBy('products.product_id')
->where('c','>=',3)
->get();
Getting answer querying realtionship:
The query will look like following:
$allProducts = $this->product->has('Images')->paginate(15);
But, make you sure you have created relation in Model like the following:
public function Images(){
return $this->hasMany('\App\Models\ProductImages');
}
I have used hasMany relationship because one product can have multiple images.

Access relation in forelse on the same model - laravel

i have a question about accessing relation in laravel model. I have category model which has relation to translation model and category model(same model/itself - one category can be displayed in other categories using pivot table CategoryToCategory):
category model:
public function childCategories(){
return $this->hasManyThrough('App\Models\Category',
'App\Models\CategoryToCategory',
'id_parent_category',
'id',
'id',
'id_category');
}
public function translation($locale = null)
{
if ($locale == null) {
$locale = \App::getLocale();
}
return $this->hasOne('App\Models\CategoryLanguage', 'id_category', 'id')->where('locale', '=', $locale);
}
Now i take current category + translation + child categories:
$category = Category::with('translation', 'childCategories')->active()->where('id', $id)->first();
And display all childs names:
#forelse($category->childCategories as $category)
{{ $category->translation->name }}
#endforelse
I works but each child category makes another query to get translation(it's not loaded for elements in forelse). So how to load relation "translation" in category model which is foreaching loaded relation?
I could query model CategoryToCategory to get all child categories + load translation for that model and result be the same:
$categories = CategoryToCategory::with('translation')->where('id_parent_category', $id)->get();
And there will be one query for translations. Still i'm curious about using first solution instead query categoryToCategory.
Any ideas?
Have a nice day!
To eager load a distant relationship you can use the dot notation like so:
$category = Category::with('translation', 'childCategories.translations')
->active()
->where('id', $id)
->first();
This is known as "nested eager loading" and is referenced in the docs here:
https://laravel.com/docs/5.8/eloquent-relationships#eager-loading

How to get all item same category with Eloquent

Hi all,
I'm building an application in Laravel, I want to get all item in an article category without using this Eloquent.
My code is
$info = Article::find($article_id);
$cate_info = $info->article_categories()->first();
if($cate_info){
$same = Article::with(['article_categories' => function ($query) use ($cate_info){
$query->where('articles_category.ID' ,$cate_info->ID);
}])->where('ID' ,'!=' ,$article_id)->get();
}
And I get all articles. How to solve.
Article and Article_Category is in many to many relationship.
Thanks.
If you want to have all the articles of a particular article_categories you can use whereHas method, now suppose you have name as a field column in categories table, so you can have something like this:
public function getData(Request $request)
{
$category = $request->categoryName;
// $category = 'ABC Category';
$articles = Article::whereHas('article_categories', function($query) use($category) {
$query->where('name', 'like', '%'.$category.'%');
})->get();
return response()->json(['articles' => $articles], 200);
}
Hope this helps.

whereHas with Eager Loading in Laravel

i have a question regarding whereHas in Laravel
public function index($category = null) {
$videos = Video::with(['content', 'content.categories' => function($query) use ($category) {
return $query->where('name', $category);
}])->paginate(10);
return view('frontend.videos')->with('videos', $videos);
}
Take that method, i have a Video model, the Video Model has a 1-to-1 relationship with the Content Model which in turn has a many-to-many relationship with the Categories Model
I need to get all videos where the which have a content with a category where the name matches whatever has been searched, is this possible? if so how?
I've figured it out, the final solution looks something like this, the eager loading will get me the Categories Model in the Subquery and i can simply use that and check against it.
$videos = Video::whereHas('content.categories', function($categories) use ($category) {
$categories->where('name', $category);
})->paginate(10);

Resources