How to use where in laravel relationships? - laravel

I have a relationship on Orders and Customers.
a row from customers table :
customer_id
customer_name
customer_state
customer_city
1
Amin
Yazd
Yazd
a row from orders table :
order_id
customer_id
product_id
factor_id
1
1
3
4
Now I want order rows where customer_state is yazd.
Order.php
public function customer()
{
return $this->belongsToMany(Customer::class, 'orders', 'order_id', 'customer_id');
}
OrdersController.php
$state = "Yazd";
$reportItem = Order::whereHas("customer", function ($query) use ($state) {
$query->where('customer_state', $state)->get();
});
It doesn't work. How I can handle this?

What I understand from the given input you're not using the proper relation here:
The belongsToMany relation is used for many-to-many relations using an allocation table. But you are actually using a one-to-many relation => one customer can have many orders.
In this case you should use a belongsTo relation on Order Model or/and a hasMany relation on Customer Model:
// Order.php
public function customer() {
return $this->belongsTo(Customer::class)
}
// Customer.php
public function orders() {
return $this->hasMany(Order::class)
}

You have put get() at the wrong place. Change this
$reportItem = Order::whereHas("customer", function ($query) use ($state) {
$query->where('customer_state', $state)->get();
});
To
$reportItem = Order::whereHas("customer", function ($query) use ($state) {
$query->where('customer_state', $state);
})->get();
Learn more about laravel relations

Related

how to use a model function in scope in laravel?

I have two tables
1- Products
2- Discounts
I want to select all discounted products, but there is a problem, in Discount table there is no product_id, there is array of product id like : ["1","4","23"] which means this discount is used for products with id of 1 or 4 or 23.
I already created a function in my product model that defines if the product has discount or not and use it like :
$product->hasDiscount(); //returns 1 or 0
what I need actually?
I need an scope for my product model like below to use in my select query to get all discounted products:
public function scopeDiscounted($query)
{
return $query->where($this->hasDiscount() , '=' , 1);
// I know this code is wrong, I just want to explain the needed code result
}
Lets start by normalizing your data, create the following table and loop in a migration.
public function up()
{
Schema::create('discount_product', function (Blueprint $table) {
$table->unsignedInteger('discount_id');
$table->unsignedInteger('product_id');
// add foreign keys if you like
});
Discount::all()->each(function (Discount $discount) {
$productIds = json_encode($discount->productIds);
foreach ($productIds as $productId) {
$discount->saveMany(Product::whereIn('id', $productIds)->get());
}
});
}
To make this migration work, you have to create the relationships before running the migration. I was lazy using models in the migration, the best approach is to use the DB facade.
class Discount {
public function products()
{
return $this->belongsToMany(Product::class);
}
}
class Product {
public function discounts()
{
return $this->belongsToMany(Discount::class);
}
}
Now you should be able to get all discounted products and you could put this in your scope.
$discountedProducts = Product::whereHas('discounts', function ($query) {
$query->where('active', true);
$query->whereDate('expire_at', '>=', now())
})->get();

Select column from relations relation in laravel

I'm trying to do eager loading using with() method, I only want to get selected column from relations relation, how can I do that ? . I'm using polymorphic relation.
Draft::with(["user:id,username","article:id,locale","article.articleable:title"])->where([
["user_id",$user_id],
["is_suspended",1]
])->get();
Draft Model
public function article()
{
return $this->belongsTo("App\Models\Article");
}
Article Model
public function drafts()
{
return $this->hasMany("App\Models\Draft", "article_id", "id");
}
public function articleable()
{
return $this->morphTo();
}
other models which has polymorphic relation with Article model
public function articles()
{
return $this->morphMany("App\Models\Article", "articleable");
}
This has been fixed in Laravel 5.7.6: https://github.com/laravel/framework/pull/25662
In order for this to work, you also have to select the id column:
Draft::with('user:id,username', 'article:id,locale', 'article.articleable:id,title')
^^
->where([
['user_id', $user_id],
['is_suspended', 1]
])->get();

getting pivot columns in collection in laravel

how to return collection of eloquent models with pivot column? For example, there are M:N relationship between users and vats. I want to retrieve all users data( with vats and with pivot column (costOfDelivery) , which is in pivot table user_vat).
In my code I have:
$vats = Vat::whereHas('users', function($query) use ($user) {
$query->where('user_id', $user->id);
})->with('country')
->get();
but this return data from vats and country, not from pivot table "user_vat", how to retrieve also costOfDelivery?
To retrieve the data from pivot table, you must use pivot attribute
Something like this
foreach($users->roles as $role){
echo $role->pivot->created_at;
}
To return json, you can use the toJson() method like
$vat->toJson();
<?php
/**
* The model class with the belongsToMany user class relation.
*/
class Vat extends Model
{
public function user()
{
return $this->belongsToMany(\App\User::class)
->withPivot(['cost_of_delivery', /**Specific columns for the pivot.*/]);
}
}
<?php
/*
* Your query (which I think is a little bit complicated that it should be.
*/
$vats = Vat::whereHas('users', function($query) use ($user) {
$query->where('user_id', $user->id);
})->with(['country', 'users'])
->get();
I would use sth. like:
<?php
$user->load(['vats.country']);
$vats = $user->getRelationValue('vats');
And
$vats->first()->pivot->cost_of_delivery
should give you the cost of delivery of the first vat.

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