hasManyThrough relationship in Laravel 5.8 - laravel-5

I have the following struct:
Order
id
Order_Products
id
order_id
product_id
Products
id
Im trying to use hasManyTrough (https://laravel.com/docs/5.8/eloquent-relationships#has-many-through).
I have something like
class Order extends Model{
...
public function products()
{
return $this->hasManyThrough('App\Product', 'App\OrderProduct', 'product_id', 'id', 'order_id', 'id');
}
...
}
I can not make it work. I'm confused, can someone help me.

In this case you need to use belongsToMany relation.
A little bit about Has Many Through.
Tables:
Product
id
Order
id
product_id
Order_Category
id
order_id
in this case you can get Order Categories for Product
class Product {
// ...
order_categories() {
return $this->hasManyThrough('App\Post', 'App\User');
}
// ...
}
Laravel doing something like this.
$orderIds = Order::query()
->where('product_id', $product->id)
->get(['id'])
->pluck('id');
$orderCategories = OrderCategory::query()
->whereIn('order_id', $orderIds)
->get();

Thanks to Tim Lewis, I needed belongsToMany, cause order_products is pivot table. Something like this.
public function products()
{
return $this->belongsToMany('App\Product', 'order_products', 'order_id', 'product_id');
}

Related

How to get product name from pivot table using laravel?

I am trying to get product name from pivot table but unfortunately i have no idea how can i get product name from pivot table please help me thanks.
Product Model
public function category()
{
return $this->belongsToMany('App\ProductCategory', 'product_category', 'product_id', 'mf_product_category_id');
}
productcategory model
public function products()
{
return $this->belongsToMany('App\Product', 'product_category', 'mf_product_category_id', 'product_id');
}
controller
public function getproduct(Request $request)
{
// getting category Id
$categoryId = $request->category;
// getting product Id
$name = trim($request->product);
$productId = Product::where('name', $name)->pluck('id');
$getProductcategory = ProductCategoryCount::whereIn('mf_product_category_id', $categoryId)->whereIn('product_id', $productId)->get();
return $getProductcategory;
// return response()->json($getproduct);
}
As stated in laravel doc, you can retrieve pivot table extra data using withPivot on the relationship.
Define category in the Product Model
public function category()
{
return $this->belongsToMany('App\ProductCategory', 'product_category', 'product_id', 'mf_product_category_id')
->withPivot('Your_extra_data_on_pivot_table');
}
And by querying products, you can get category (which I suggest to be categories). You can retrieve it like this $products->first()->pivot->{name of_your_extra_data_on_pivot_table}
It is more optimized if you eager load this relationship.

Laravel apply where clause to belongsToMany query using with() method

I have a products table with brand_id, and a category_products table with, product_id and category_id.
My Products model :
class Product extends Model
{
public function categories() {
return $this->belongsToMany(Category::class)->withTimestamps();
}
}
My Brands Model :
class Brand extends Model
{
public function products() {
return $this->hasMany(Product::class)->with(['categories']);
}
}
My question is, How can I fetch the products from a Brand instance that belongs to certain category?
$brand = App\Brand::find(1);
/*
I want to be able to do something in the likes of :
*/
$brand->products_which_are_under_this_category
Remove with(['categories']) method from inside products() and write a query like that.
$brand->products()->with(['categories' => function ($query) {
$query->where('category_id', CATEGORY_ID);
}])->get();
hope this can help.

belongsToMany with multiple forieng key in Laravel

By default, laravel support two foreing_key in a pivot table. And both attach and detach methods work properly. But in case we have triple foreign key in a pivot table, what is the proper way to retrieve and insert data to the pivot table.
Tables
Orders:
id bill_number
Products
id name
Colors
id name
order_details:
id order_id product_id color_id price
My Models:
class Order extends Model
{
public function client() {
return $this->belongsTo('App\Client');
}
public function items() {
return $this->belongsToMany('App\Product', 'order_items');
}
}
class Product extends Model
{
//
public function orders() {
return $this->belongsToMany('App\Order', 'order_items');
}
}
class Color extends Model
{
//
public function orders() {
return $this->belongsToMany('App\Order', 'order_items');
}
}
Now I want to get or insert order_items with the following attribute:
order_id product_id color_id price
1 1 1 800
Products:
Shirt
Pant
Jacket
Color:
Gray
White
Black
Now I want to list all items of order with product name, color and price;
If I want to insert an order of shirt with black color and price of 800, how should I figure it out? And Also If I list all order items with color and prices which method should I use?
You could use an intermediate table model. Then you can define your relationship with color on that model.
A little bit "hacky" but you can use withPivot and wherePivot.
class Product extends Model
{
public function orders() {
return $this->belongsToMany('App\Order', 'order_items')->withPivot('color_id', 'price');
}
}
Then you may insert a new record like this:
$product->orders()->attach($orderId, ['color_id' => 1, 'price' => 800]);
And query it with:
$products = Product::whereHas('orders', function ($query) {
$query->where('color_id', '=', 1);
})->get();
I would use a double pivot table using a same order_id for order_product and order_color. Another solution is using a Polymorphic Relationship https://laravel.com/docs/5.8/eloquent-relationships#polymorphic-relationships
I finally made it with sql join as bellow:
class Order extends Model
{
public function items() {
return $this->belongsToMany('App\Product', 'order_details')->withPivot('id', 'price')
->join('colors', 'order_details.color_id', '=', 'colors.id')
->select('products.*', 'colors.name as color_name');
}
}

Laravel: One to Many to Many, retrieve distinct() values

Laravel 4 Project, using Eloquent ORM.
I have three tables: customers, orders and products (+ 1 pivot table order_product). Customers are linked one-to-many to Orders. Orders are linked many-to-many to Products.
Customers 1-->N Orders N<-->N Products
I would like to have a method on Customer model that retrieves a list of products that customer is buying.
To better understand this, assume products are consumable.
For example Customer #1 can place:
Order #1 for Products A, B and C;
Order #2 for Products A, C and D;
Order #3 for Products C and E;
...and the result I want to retrieve is a Collection with Products A, B, C, D and E.
Models are (pseudo-coded on the fly):
class Product extends Eloquent {
public function orders()
{
return $this->belongsToMany('Order');
}
}
class Orders extends Eloquent {
public function customer()
{
return $this->belongsTo('Customer', 'customer_id');
}
public function products()
{
return $this->belongsToMany('Product');
}
}
class Customers extends Eloquent {
public function orders()
{
return $this->hasMany('Orders', 'customer_id');
}
public function products()
{
// What to put here ???
}
}
Thanks to #deczo's answer, I was able to put up a single query method to retrieve items:
public function items()
{
$query = DB::table('items')->select('items.*')
->join('item_order', 'item_order.component_id', '=', 'items.id')
->leftJoin('orders', 'item_order.order_id', '=', 'orders.id')
->leftJoin('customers', 'customers.id' , '=', 'orders.customer_id')
->where('customers.id', $this->id)
->distinct()
->orderBy('items.id');
$eloquent = new Illuminate\Database\Eloquent\Builder( $query );
$eloquent->setModel( new Item );
return $eloquent->get();
}
This is a Many-to-Many relationship, but with the Orders table as the pivot table.
class Customers extends Eloquent {
public function orders()
{
return $this->hasMany('Orders', 'customer_id');
}
public function products()
{
return $this->belongsToMany('Products', 'orders', 'customer_id', 'product_id');
}
}
I've included the last two parameters, but if you follow the singular_id pattern they can be left out.
It's possible to receive distinct Product models like this:
public function products()
{
return $this->belongsToMany('Products', 'orders', 'customer_id', 'product_id')
->distinct();
}
#deczo's answer probably works fine, and is probably a lot more performant as all the data reduction is done in the database itself, but here's a 'pure Laravel' way that's undoubtedly more readable:
use Illuminate\Database\Eloquent\Collection;
class Customer extends Eloquent
{
...
public function products()
{
$products = new Collection;
foreach ($this->orders as $order) {
$products = $products->merge($order->products);
}
return $products;
}
}
Note that this method will not act like normal relationship methods - to get the resulting collection you call the method (i.e. $products = $customer->products();) and you can't access it as a property like you can with relationships (i.e. you can't do $products = $customer->products;).
Also, I'm kinda going on my understanding of the Illuminate\Database\Eloquent\Collection#merge() method here that it automatically does a DISTINCT-like thing. If not, you'll have to do a $collection->unique() kinda thing.
I can't think of easy relation method for this one, but here's a workaround:
$productsIds = DB::table('customers')
->leftJoin('orders', 'orders.customer_id', '=', 'customers.id')
->join('order_item', 'order_item.order_id', '=', 'orders.id')
->leftJoin('items', 'order_item.item_id' , '=', 'items.id')
->distinct()
->get(['items.id']);
$productsIds = array_fetch($productsIds, 'id');
$productsCollection = Product::whereIn('id', $productsIds);

Laravel 4 eloquent

Is there any way I can do this with eloquent?
$orders = Customer::with('orders','orders.shop')->where('orders.shop.location','=','Japan')->get()
Customers, orders and shop are tables where 1 customer has many orders and each order has one shop only.
Location is a column in the shop table
I keep getting an error stating orders.shop.location is a column not found.
Anyone can help? Thanks in advance.
You need to defined relationship in your model classes.
Customer model:
public function orders()
{
return $this->hasMany('Order');
}
Order model:
public function customer()
{
return $this->belongsTo('Customer');
}
Then if you want orders of a special customer you just have to do :
$orders = Customer::find($id)->orders;
Or find the user attatched to an order:
$user = Order::find($id)->user;
You can also use the same kind of relation between your Shop and Order model and do something like this:
$orders = Order::with(array('shop' => function($query)
{
$query->where('location', '=', 'japan');
}))->get();
Which should give you all orders for a shop located in japan.
More informations about this type of request:
http://laravel.com/docs/eloquent#eager-loading
in CostumerModel you need set a relationship (One To Many):
public function order()
{
return $this->hasMany('OrderModel', 'foreign_key_in_orderTable');
}
in OrderModel too:
public function costumer()
{
return $this->belongsTo('CostumerModel', 'foreign_key_in_orderTable');
}
then in OrderModel one more relationship with Shop (One To One):
public function shop()
{
return $this->hasOne('ShopModel', 'foreign_key');
}
Now in ShopModel (One To One):
public function order()
{
return $this->belongsTo('OrderModel', 'local_key');
}
query:
$orders = Customer::with('costumer', 'shop')->where('location','=','Japan')->get();

Resources