I have 5 tables.
Users
Categories
Products
Product_categories
Order Details
A user purchases an an item and in my order details table I store the quantities etc.
I wanted to return all items that are of the main category = 'Testing' via the user.
$user = Auth::user();
return $user->items();
I have the following relationship on my user model.
public function items()
{
return $this->hasMany('App\OrderDetail','user_id')->selectRaw('item_description,count(quantity) as count')->where('item_description','<>','Carriage')->groupBy('item_id')->get();
}
I know I've not associated the the categories table here but I'm wondering how I would pull all the users order details where item category is "testing". The item can be related to many categories hence the product_categories table.
I'm not after someone writing the answer I'd like to know where I start to look at linking these via the model?
Would I be right in saying I have to do a function within my model relation?
According to your requirements & structure, your table should be structured like this:
users
id
name
...
categories
id
name
...
products
id
name
cost
...
category_product
id
category_id
product_id
order_details
id
user_id
cost
...
product_order_detail
id
product_id
order_detail_id
Your models should be structured like this:
class User extends Model
{
public function orderDetails()
{
return $this->hasMany(OrderDetail::class);
}
}
class Product extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class, 'category_product');
}
public function orderDetails()
{
return $this->belongsToMany(Order::class, 'product_order_detail');
}
}
class Category extends Model
{
public function product()
{
return $this->belongsToMany(Product::class, 'category_product');
}
}
class OrderDetail extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function products()
{
return $this->belongsToMany(Product::class, 'product_order_detail');
}
}
and to fetch all the items / products who belongs to the category named Testing and belongs to the user, who've ordered it:
$items = Product::whereHas('categories', function($q) {
$q->where('name', '=', 'Testing');
})->whereHas('orderDetails', function($q) use($user) {
$q->whereHas('user', function($q) use($user) {
$q->where('id', $user->id);
});
})->get();
Hope this helps!
Related
Considering this table
Services Table
id
company_id
category_id
1
2
4
2
4
6
And this model
CategoryModel.php
public function companies():Attribute
{
return new Attribute(
get: fn () => CompanyModel::whereHas('services', function ($q) {
$q->where('category_id', $this->id);
}),
);
}
Considering that the services table holds both company_id and category_id columns what would be the best approach to query companies relationship that have services under the current category (The companies table does not have a category_id column), my current implemetation is not optimal as it does not allow me to perform any relationship constrains.
EDIT
Each company offers multiple services and each service belongs to a single category.
I also have a reviews table (related to each service) with a rating column
The above query worked efficiently until I needed to constrain/order categories based on the reviews table.
CategoryModel.php
public function scopeHasReviews($query)
{
$query->whereHas('companies', fn ($q) => $q->whereHas('reviews'));
}
This ofcourse will not work since there is no relationship.
Using Attribute in this context is dangerous, because it can lead to N+1 problems. This is a usual many-to-many relationship, so it needs to be implemented in models:
Category.php
public function companies(): BelongsToMany
{
return $this->belongsToMany(Company::class, 'services');
}
Company.php
public function categories(): BelongsToMany
{
return $this->belongsToMany(Category::class, 'services');
}
Further, since it is not clear exactly what problem must be solved - I will write an example with sorting by number of reviews:
Review.php
public function scopeWhereRawService(Builder $query, string $service): Builder
{
return $query->whereRaw('service_id = ' . $service);
}
Company.php
public function reviews(): HasManyThrough
{
return $this->hasManyThrough(Review::class, Service::class);
}
public function categories(): BelongsToMany
{
return $this->belongsToMany(Category::class, 'services');
}
public function categoriesOrderedByReviews(): BelongsToMany
{
return $this->categories()->withCount([
'reviews as reviews_count' => fn(Builder $q) => $q->whereRawService('services.id')
])->orderByDesc('reviews_count');
}
Category.php
public function reviews(): HasManyThrough
{
return $this->hasManyThrough(Review::class, Service::class);
}
public function companies(): BelongsToMany
{
return $this->belongsToMany(Company::class, 'services');
}
public function companiesOrderedByReviews(): BelongsToMany
{
return $this->companies()->withCount([
'reviews as reviews_count' => fn(Builder $q) => $q->whereRawService('services.id')
])->orderByDesc('reviews_count');
}
I have a problem with a many to many relationship and the translations of the terms.
I have 4 tables:
products
- id, price, whatever
products_lang
- id, product_id, lang, product_name
accessori
- id, active
accessori_lang
- id, accessori_id, lang, accessori_name
I'm trying to assign accessories to products with an intermediate table named:
accessori_products
this is the model for Product:
class Product extends Model {
protected $table = 'products';
public function productsLang () {
return $this->hasMany('App\ProductLng', 'products_id')->where('lang','=',App::getLocale());
}
public function productsLangAll() {
return $this->hasMany('App\ProductLng', 'products_id');
}
public function accessori() {
return $this->belongsToMany('App\Accessori', 'accessori_products');
}
}
this is the model for productLng:
class ProductLng extends Model {
protected $table = 'products_lng';
public function products() {
return $this->belongsTo('App\Product', 'products_id', 'id');
}
}
Then I have the model for Accessori:
class Accessori extends Model {
protected $table = 'accessori';
public function accessoriLang() {
return $this->hasMany('App\AccessoriLng')->where('lang','=',App::getLocale());
}
public function accessoriLangAll() {
return $this->hasMany('App\AccessoriLng');
}
public function accessoriProducts() {
return $this->belongsToMany('App\Products', 'accessori_products', 'accessori_id', 'products_id');
}
}
And the model for AccessoriLng:
class accessoriLng extends Model {
protected $table = 'accessori_lng';
public function accessori() {
return $this->belongsTo('App\Accessori', 'accessori_id', 'id');
}
}
I get the results by this:
$products = Product::has('accessori')->with([
'productsLang ',
'accessori' => function ($accessori){
$accessori->with([
'accessoriLang'
]);
}
])->get();
return $products;
but I want to get only the active accessories something like where accessori.active = 1 but I really don't know where to put it. I've tried in different way but I'm stuck on it by 2 days.
IIRC you don't need a model for the intermediate table on your many to many relationships.
If you want to return Products where Accessori is active you can use whereHas on the Product model.
$prod = Product::whereHas('accessori', function($query) {
$query->where('active', 1);
})->get();
Where the $query param will be running on the Accessori model.
You can do the inverse as well with Accessori to Product.
$acessoris = Accessori::where('active', 1)->whereHas('accessoriProduct')->with(['accessoriLang', 'accessoriProducts.productsLang'])->get();
I have a problem with related models.
There are three models. User, PostType (music, animals) and Post.
A user can select the posttypes he wants to see. So I created a pivot-table posttype_user.
Now I can save the selected postTypes binded to a user.
// User model
public function postTypes()
{
return $this->belongsToMany(PostType::class);
}
// PostType model
public function users()
{
return $this->belongsToMany(User::class);
}
The Post model has a foreign key with postType_id. And this relationships in the models:
// Post model
public function postType()
{
return $this->belongsTo(PostType::class);
}
// PostType model
public function post()
{
return $this->hasMany(Post::class);
}
Now I want to receive all Posts (of the selected posTypes) from the current user (Auth::user()).
But I don't know how. Does anyone have an idea?
You can use nested whereHas():
Post::whereHas('postType', function($q) {
$q->whereHas('users', function($q) {
$q->where('id', auth()->id());
});
})->get();
Or you can do this:
$postTypeIds = auth()->user()->postTypes()->pluck('id');
$posts = Post::whereIn('post_type_id', $postTypeIds)->get();
In my project I have orders which have many products and customers who have many orders. I am confused because I want to get all orders that a certain customer has and the products of each order. I messed up something somewhere and I am not sure if I set my relationships correctly. Here is my products table:
Here is my customers table:
And here is my orders table:
Here are my models:
Product:
class Product extends Model
{
public function orders()
{
return $this->belongsToMany('App\Order');
}
}
Order:
class Order extends Model
{
public function products()
{
return $this->hasMany('App\Product', 'id');
}
public function customer()
{
return $this->belongsTo('App\Customer');
}
}
Customer:
class Customer extends Model
{
public function orders()
{
return $this->hasMany('App\Order', 'id');
}
}
I get all customers from my database with App\Customer::all() in my CustomersController and pass the data in my customers.blade.php.
<h1>Customers:</h1>
#foreach($customers as $customer)
<h3>{{$customer->name}}</h3>
#foreach($customer->orders as $order)
<p>Order ID: {{$order->id}}</p>
#foreach($order->products as $product)
<p>Product title: {{$product->title}}</p>
#endforeach
#endforeach
<hr>
#endforeach
Here is the output:
If someone could explain why it doesn't output everything and give some advice if this is the way to go with the relationships, I would be very thankful.
Your products should belong to an order, rather than have a many-to-many relationship.
class Product extends Model
{
public function orders()
{
return $this->belongsTo('App\Order');
}
}
I found a solution by making a pivot table for products and orders called products_orders which holds the product_id and the order_id and making a many to many relationship between Product and Order. That is because an order may have multiple products and products may exist in multiple orders.
My pivot table products_orders:
class Product extends Model
{
public function orders()
{
return $this->belongsToMany('App\Order');
}
}
class Order extends Model
{
public function products()
{
return $this->belongsToMany('App\Product', 'products_orders');
}
public function customer()
{
return $this->belongsTo('App\Customer');
}
}
I made a one to many relationship (customer_id in orders table) for Customer and Order and now everything works fine.
class Customer extends Model
{
public function orders()
{
return $this->hasMany('App\Order');
}
}
I have three tables: users, items and user_items. A user has many items and a item belongs to many users.
**Users**
id
username
password
**Items**
id
name
**User_items**
id
user_id
item_id
Models:
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items', 'item_id', 'user_id');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id');
}
}
I need to select all items table, print it and highlight rows which belongs to specific user id=1.
Selection highlighted output:
What is the right way to do it (in laravel style)?
You can use it like this
public function user_items()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id')->withPivot('id');
}
Like this you can access values of third table.
Some useful links-
http://www.developed.be/2013/08/30/laravel-4-pivot-table-example-attach-and-detach/
http://vegibit.com/many-to-many-relationships-in-laravel/
http://laravel.com/docs/4.2/eloquent
You can do it like this way...
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items', 'item_id', 'user_id')->withPivot('id');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id')->withPivot('id');
}
}
From controller..
$user_id = 2;
Item::with(['users'=>function($q) use ($user_id){$q->where('user_id',$user_id);}])->get();
In view at the time of listing a row you can highlight the row just use a condition as each item->users is blank or not.