I'm in Pain because of this problem.
Problem
I have categories table which contains id, slug and parent_id.
lessons table which contains category_id (the child of a Category)
I want by Eloquent scope get all lessons posted by Category parent id
example:
parent category of id=1 have children categories of ids 3, 4 and 5.
Then retrieve Lessons under the parent category of id=1, so this must return the lessons of all of the childrens.
Categories table
public function parent()
{
return $this->belongsTo(self::class, 'parent_id');
}
public function lessons()
{
return $this->hasManyThrough(
\App\Lesson::class, \App\Category::class,
'parent_id', 'category_id', 'id'
);
}
//Pointless try
// public function scopeGetParent($query, $slug)
// {
// $query->where('slug', $slug)->first()->lessons;
// }
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
Lessons.php
return Lesson::recentLessons()
->byParentCategory($args['category'])
->simplePaginate($page)
->shuffle();
how can I construct scopeByParentCategory() function??
sorry for the fuzzy question! Spent 3 hours trying :(
update: I got this idea right after posting the question but still wanna know what do you think about it and if this the best way to handle it.
public function scopeByParentCategory($query, $slug)
{
$ids = [];
foreach (Category::where('slug', $slug)->first()->children as $value)
{
$ids[] = $value->id;
}
return $query->whereIn('category_id', $ids);
}
First put this code inside of your Category model:
public function scopeOfSlug($query, $slug)
{
$query->where('slug', $slug);
}
Then in your controller
return Category::ofSlug($args['category'])
->lessons
->simplePaginate($page)
->shuffle();
Related
I need get categories with products, only where products exists on category, I have code:
$categories = Category::with(['children.products', 'products'])->has('children.products')->orHas('products')->whereNull('parent_id')->whereId($category->id)->paginate(15);
But whereId = $category->id not working.. Why? I get category with other categories.. but I need get only certain category, where id = categoryId
Model category:
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
public function parent()
{
return $this->belongsTo(self::class, 'parent_id')->withoutGlobalScope('active');
}
public function products()
{
return $this->hasMany(Product::class);
}
You should combine has and orHas within enclosed function, something similar to below:
$query->where(function($query) {
$query->has('children.products');
$query->orHas('products');
});
Additionally, to above, I would recommend using "join" because "has" is a lot slower.
I have a page where i show products under their subcategory url's and in top of my page i want to print the subcategory title and subcategory image, how can I do that?
here is my function:
public function productsubcategory($slug, $subslug)
{
$products = Product::whereHas('subcategory', function($q) use($subslug){
$q->where('slug',$subslug);
})->paginate(12);
return view('frontend.subcategories', compact('products'));
}
and I show my products with foreach like #foreach($products as $product) ....
The best way you doing is One to Many relationship. Use ORM for that. You will get details here: https://laravel.com/docs/5.0/eloquent
In your Category.php Model
public function subcategories()
{
return $this->hasMany('App\Subcategory', 'category_id');
}
In you Subcategory.php Model
public function category()
{
return $this->belongsTo('App\Category', 'category_id');
}
public function products()
{
return $this->hasMany('App\Product', 'subcategory_id');
}
And your Product.php Model
public function subcategory()
{
return $this->belongsTo('App\Subcategory', 'subcategory_id');
}
And you will get subcategory list
$subcategories = Category::find($id)->subcategories;
And You get products
foreach($subcategories as $subCat)
{
//your code
}
And here is another link for One to Many relationship. If you read details it will help you. https://laravel.com/docs/5.5/eloquent-relationships
SOLVED
I added another query in my function so totally become like this:
public function productsubcategory($slug, $subslug)
{
$products = Product::whereHas('subcategory', function($q) use($subslug){
$q->where('slug',$subslug);
})->paginate(12);
$productss = Product::whereHas('subcategory', function($q) use($subslug){
$q->where('slug',$subslug);
})->first();
return view('frontend.subcategories', compact('products', 'productss'));
}
And here is how i show my subcategory info in their pages.
{{$productss->Subcategory->title}}
Hope this help others.
I'm showing all sub categories under main category. On each sub-category there is a counter of how many items are assigned there.
Main Category
- Sub Category (1)
- Sub Category (3)
- etc
Current problem is that one item can be published and unpublished. When the item is not published yet I don't want to show it on counter. Column in items table is published and accept 1 for published and 0 for unpublished.
This is what I have to show them on page
HomeController.php
$allCategories = Category::where('parent_id', 0)->has('children.item')
->with(['children'=> function($query){
$query->withCount('item');
}])
->get()
->each(function($parentCategory){
$parentCategory->item_count = $parentCategory->children->sum(function ($child) { return isset($child->item_count)?$child->item_count:0;});
});
My Item.php model
public function category()
{
return $this->belongsTo('App\Category');
}
My Category.php model
public function item()
{
return $this->hasMany('App\Item','category_id');
}
public function parent()
{
return $this->belongsTo('App\Category', 'id', 'parent_id');
}
public function children()
{
return $this->hasMany('App\Category', 'parent_id', 'id');
}
I've tried to directly add it to the query but doesn't make any difference
$query->withCount('item')->where('published', 1);
You have to add the where condition in the relationship function item of Category.php model.
Here is the code:
public function item()
{
return $this->hasMany('App\Item','category_id')->where('published', 1);
}
In my routes/web.php I have a route like this...
Route::get('/tags/{tag}', 'TagsController#show');
Then, inside TagsController because I have a post_tag pivot table that has been defined as a many-to-many relationship.
Tag.php...
public function posts(){
return $this->belongsToMany(Post::class);
}
public function getRouteKeyName(){
return 'name';
}
Post.php...
public function tags(){
return $this->belongsToMany(Tag::class);
}
I get the posts for a certain tag like this...
public function show(Tag $tag){
$posts = $tag->posts;
return view('posts.index', compact('posts','tag'));
}
Then, to sort the posts into newest first I can do this in index.blade.php...
#foreach ($posts->sortByDesc('created_at') as $post)
#include('posts.post')
#endforeach
This works fine, but I'm doing the re-ordering at collection level when I'd prefer to do it at query level.
From Eloquent: Relationships I can see that I can do something like this, which also works...
$user = App\User::find(1);
foreach ($user->roles as $role) {
//
}
But, something like this does not seem to work...
public function show($tag){
$posts = \App\Tag::find($tag);
return view('posts.index', compact('posts'));
}
My question is, how can I filter/order the data at a query level when using pivot tables?
To order your collection you must change
public function tags(){
return $this->belongsToMany(Tag::class);
}
to
public function tags(){
return $this->belongsToMany(Tag::class)->orderBy('created_at');
}
Extending #leli. 1337 answer
To order content without changing the relation created.
First, keep the original relation
class User
{
public function tags
{
return $this->belongsToMany(Tag::class);
}
}
Second, during query building do the following
//say you are doing query building
$users = User::with([
'tags' => function($query) {
$query->orderBy('tags.created_at','desc');
}
])->get();
With this, you can order the content of tags data and in query level also if needed you can add more where clauses to the tags table query builder.
I want to get all the books under a certain category. The category has many subjects and books are linked to subjects.
My code:
class BookCategory extends Model {
public function subjects() {
return $this->hasMany('BookSubject', 'category_id', 'id');
}
public function getBooksAttribute() {
return Books::whereHas('subjects', function ($query) {
return $query->join('book_category', 'book_category.id', '=', 'book_subject.subject_id')
->where('book_category.id', $this->id);
})->get();
}
}
and my Books model:
class Books extends Model {
public function subjects() {
return $this->belongsToMany('BookSubject', 'book_by_subject', 'book_id', 'subject_id');
}
}
If I do:
$cats = \App\Models\BookCategory::all();
foreach ($cats as $c) {
echo $c->books->count();
}
It's always returning 0 for all the rows. What I'm I doing wrong?
I believe the problem is in your subquery:
return $query->join('book_category', 'book_category.id', '=', 'book_subject.subject_id')
->where('book_category.id', $this->id);
I'm pretty sure book_subject.subject_id should be book_subject.category_id
Hard to tell without seeing your db schema.