Laravel group by foreign key - php

I have three models
Project
Category
Drawing
The relationship between them is as follows
Drawing belongs to a category
Drawing also belongs to a project
Drawing table:
id
name
project_id
category_id
Project Table :
id
name
Category Table :
id
name
I want to print all the drawings of a particular project grouped by category name like so :
CATEGORY X
* Drawing 1
* Drawing 2
CATEGORY Y
* Drawing 3
* Drawing 4
I do not want to print a category if there is no drawing for this particular project in it.
this is what im stuck at :
Project->drawings()->groupBy('category_id');
Thank you in advance

To get the output you want, it'd be easier to come at the problem from the direction of categories.
The following will find all categories, with drawings belonging to the specified $projectId, but only those categories that actually have one or more drawings.
$projectId = 123;
$projectScope = function ($query) use ($projectId) {
return $query->where('project_id', $projectId)
});
$categories = Category::with(['drawings' => $projectScope])
->whereHas('drawings', $projectScope)
->get();

You can do it like
$categories = Category::whereIn('id',$project->drawings()
->groupBy('category_id')
->pluck('category_id')
)->get();
Now, Iterate over $categories like
#foreach($categories as $category)
// display category name as {{$category->name}}
#foreach($category->drawings() as $drawing)
// display drawings as {{$drawing->name}}
#endforeach
#endfoeach
Hope you understand.

Related

How to display related products through pivot table?

I want to display related item which is in same category.
Here is my 3 table structure
food item table
:
"food_item_id",
"name" ,
"image" ,
food item category table :
"food_item_category_id"
"name"
pivot table
id,
food_item_id
food_item_category_id
FooItem model:
public function foodItemCategory() {
return $this->belongsToMany(FoodItemCategory::class, 'food_items_have_categories', 'food_item_id', 'food_item_category_id')
->withPivot('food_item_id', 'food_item_category_id')
->withTimestamps();
}
Food Category Model:
public function foodItem() {
return $this->belongsToMany(FoodItem::class, 'food_items_have_categories', 'food_item_category_id', 'food_item_id')
->withPivot('food_item_id', 'food_item_category_id')
->withTimestamps();
}
I want to get all food items from a specific category. Suppose a user clicks on a food item which Id is 1 and It is belongs to category ID 2. Now I want to show more food items which is in the category ID 2. I want to display that in my view blade.
Now, how can I display the related products in view which is in the same category?
As your relation is many to many, you can do this:
$food = FoodItem::find(1);
$categories = $food->foodItemCategory;
$items = [];
foreach($categories as $category) {
$items[$category->id] = $category->foodItem;
}
then you can pass $items to your blade template.

Laravel gather data by relational id

In my application, I have a posts table, categories tables and category_post table as a post and category have a many to many relationship.
I want to get all posts with their attached categories, but also group them together as on my frontend I want to be a loop over an object and show a list like this,
Cooking
Post Number 1
Post Number 3
Post Number 4
Music
Post Number 2
Post Number 5
Languages
Post Number 6
Post Number 7
I know in my controller I can do this,
$posts = Post::with('categories')->get();
But I don't how to groupBy a relational attribute or if I can structure the returned data in such a way that I can loop over it to form the list below.
you can get the data from db and then group them the way you want:
$posts = Post::with('categories')->get();
$result = $posts->groupBy([
'categories',
function ($item) {
return $item['category_name'];
},
], $preserveKeys = true);
more details about grouping by relation fields in:
https://laravel.com/docs/7.x/collections#method-groupby
As per given your table: posts and categories tables are the main tables and category_post table is a pivot table which contains the relation between posts and categories table :
So, Your relation should be posts->category_post->categories
$posts = Posts::with('category_post')->get();
$grouped = $posts->groupBy('category_post.category_id');
The category_post also related to the categories table for categories data.
In category model you cam setup and belongsToMany relation like the following
function posts()
{
return $this->beongsToMany(Post::class, 'category_post', 'category_id', 'post_id');
}
Then do as Arun A S suggested.

What query can i use to get subcategories for each category?

I am using this query to get the children of each category
$this['children'] = Cat::first()->children;
But it only gets the subcategories of of the first category and the same subcategories appear for all other categories. Any ideas on how t fix this?
Model relation
public function children(){
return $this->hasMany(static::class,'parent_id','id');
Table structure
category table
id
cat_title
parent_id
nest_right
nest_left
nest_depth
slug
parent_id = 0(category)
parent_id > 0(subcategory)
To get sub-categories of each category you first need to get the id of each category and use it in you query. (e.g. in a foreach loop)
$this['children'] = Cat::find($id)->children;
If you need to get all the categories with their related subcategories at the same time you need to eager load:
$allCatsWithTheirChildren = Cat::with('children')->all();

How to write query to get result form multiple tables in laravel

I am doing project in laravel. There are two tables "categories" and "subcategories". "subcategories" table have categoryid as a foreign key.
I want to fetch categoryname from categories table and subcategoryid,subcategoryname from subcategories table where categoryid = $categoryid.
Here is something what I did. $cat contains many categoryid's but, from this I got only subcategories details,
foreach($cat as $categoryid){
$subcategories[] = Subcategory::where('categoryid', '=', $categoryid)->get();
}
I am not getting how to do this,please help.

Laravel accessor to convert category ids to category titles

Thanks for taking the time to help.
I am building a blog in which I can associate categories. I'm saving the associated cats in the blog table by id.
Eg: category_blog_id = 1, 3, 9
I want to retrieve the categories by there title so thought the best approach was to write an accessor on the blog model.
Could someone point me in the right direction with this?
Should I add use CategoryBlog to the model and then explode the category_blog_id and run a foreach ver it?
That is what I have been trying, but it isn't working quite right yet and I wondered if there is a better, more Laravel-y way to do this?
Many thanks.
Actually, the relation between Post and Category could be many-to-many because a Category can has multiple posts under it and also a Post could be in more than one Category. So, if this is the case then you should create three tables like:
Table - posts:
id | post_title | post_slug | post_content | Others...
Table - categories:
id | category_title | category_slug | Others...
Table - category_post (Pivot table/ maintains relation between posts and categories):
id | category_id | post_id
Then you need two Models as Post and Category:
// Post model
class Post extends Eloquent {
public function categories() {
return $this->belongsToMany('Category');
}
}
// Category model
class Category extends Eloquent {
public function posts() {
return $this->belongsToMany('Post');
}
}
Create categories using something like this:
category::create(array(...)); // Input::all() (Mass Assignment)
Also you may create a Category using:
$category = new category;
$category->category_title = Input::get('category_title');
$category->category_slug = Input::get('category_slug');
// other fields (if have any)
$category->save();
Now create Post and attach categories:
$post = new Post; // Assume that, this is the first post so id would be 1
$post->title = 'My Post'; // Input::get('post_title');
$post->slug = 'mypost'; // Input::get('post_slug');
// Assign other values like post_content etc then
$post->save();
Once the Post is saved then:
// Attach two categories with this post using category id
$post->categories()->sync(array(1, 2)); // These (1, 2) are category ids
So, now you have a Post and this Post belongs to to categories, in other words, this post has been created under two categories by syncing the the post and categories, you are actually making a relation between the post and two categories and these relational data will be saved in category_post table so according to this example you category_post table will contain something like this:
id | category_id | post_id
----------------------------
1 | 1 | 1
2 | 2 | 1
Now you may query using Post model to get all the posts with categories like this:
$posts = Post::with('categories')->get();
Also find a single post by id with categories related to it using something like this:
$post = Post::with('categories')->find(1);
You may access the related categories using this:
$post->categories->get(0); // first category from the collection
$post->categories->get(1); // second category from the collection
If you pass the collection of Post models to your view like this;
$posts = Post::with('categories')->get();
return View::make('post.index')->with('posts', $posts);
Then in the view you may loop all posts and categories like this:
#foreach($posts as $post)
{{ $post->post_title }}
{{ $post->post_content }}
#foreach($post->categories as $category)
{{ $category->title }}
#endforeach
#endforeach
You may also use the Category model like:
// Get all categories with related posts
$categories = Category::with('posts')->get();
// Get a category using it's id with related posts
$category = Category::with('posts')->find(2); // Category id 2
This is the basic idea, read the manual (Eloquent ORM) for more.
Don't ever store delimited values in the database! Instead introduce a many-to-many (pivot) table blog_category in addition to blogs and categories tables. It will allow you to normally maintain and query your data using the means that relational database gives you (e.g. JOINs).
The schema for such table may look like something this:
CREATE TABLE blog_category
(
blog_id INT UNSIGNED NOT NULL,
category_id INT UNSIGNED NOT NULL,
PRIMARY KEY (blog_id, category_id),
FOREIGN KEY (blog_id) REFERENCES blogs (id),
FOREIGN KEY (category_id) REFERENCES categories (id)
);
A Laravel migration for such table may look like
class CreateBlogCategoryTable extends Migration {
public function up() {
Schema::create('blog_category', function(Blueprint $table)
{
$table->integer('blog_id')->unsigned();
$table->integer('category_id')->unsigned();
$table->foreign('blog_id')->references('id')->on('blogs');
$table->foreign('category_id')->references('id')->on('categories');
$table->primary(['blog_id', 'category_id']);
});
}
public function down() {
Schema::drop('blog_category');
}
}
Laravel Eloquent supports many-to-many relationships out of the box:
In Blog model
class Blog extends Eloquent {
public function categories() {
return $this->belongsToMany('Category');
}
}
and in Category model
class Category extends Eloquent {
public function blogs() {
return $this->belongsToMany('Blog');
}
}
Now you can access blogs through categories
$blogs = Category::find(1)->blogs();
or categories to which a specific blog belongs
$categories = Blog::find(1)->categories();

Categories