Can't display data in view from model in Laravel - php

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');
}
}

Related

How to use hasMany which has belongsTo in the child

I have database relation like below
I want to get shop data with their products which each product has their category. If we define it using Eloquent ORM in Laravel, shop hasMany products belongsTo productCategory.
I can get the data of shop with their products using hasMany, but I can't get the productCategory of each products. Does anyone know how to get the productCategory of each product?
Shop model:
class Shop extends Model
{
public function products() {
return $this->hasMany('App\Product');
}
}
Procuct model:
class Product extends Model
{
public function shop() {
return $this->belongsTo('App\Shop');
}
public function category() {
return $this->belongsTo('App\ProductCategory');
}
}
Product category model:
class ProductCategory extends Model
{
public function products() {
return $this->hasMany('App\Product');
}
}
Shop controller to get the data:
class ShopController extends Controller
{
public function show(Shop $shop)
{
$products = $shop->products()->get();
return view('pages.shop-detail.index')->with('shop', $shop)->with('products', $products);
}
}
On One To Many (Inverse) Relationships:
Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with a _ followed by the name of the primary key column. However, if the foreign key on the Product model is not category_id, you should pass the custom key name as the second argument to the belongsTo method:
class Product extends Model
{
public function category() {
return $this->belongsTo('App\ProductCategory', 'product_category_id');
}
}
Then in the view, loop over shop products an show the name of the product and the name of the product category:
<h3>Shop: {{ $shop->name }}</h3>
#foreach ($shop->products as $product)
<p>Product: {{ $product->name }}</p>
<small>Category: {{ $product->category->name }}</small>
#endforeach
But...
Doing the query in the way you had it in the question you'll have an N + 1 problem when you loop on products in the view.
Avoid the model binding in your controller to eager load the relationships and return just the shop, the products and category will be eager loaded on the Shop object:
class ShopController extends Controller
{
public function show($id)
{
$shop = Shop::with('products', 'products.category')->find($id);
return view('pages.shop-detail.index')->with('shop', $shop);
}
}

Is it possible to relate a table on a pivot one with eloquent ORM?

These are my tables many-to-many:
products and suppliers, however I need to relate the pivot(product_supplier) to a table called payment_supplier.
Product model
public function suppliers(){
return $this->belongsToMany('App\Supplier');
}
Supplier model
public function products(){
return $this->belongsToMany('App\Product');
}
but I need to relate pivot product_supplier to payment_supplier table just like described on the diagram
In this case, you could use a pivot model.
# Product Model
public function suppliers() {
return $this->belongsToMany(Supplier::class)->using(ProductSupplier::class);
}
# Supplier Model
public function products(){
return $this->belongsToMany(Product::class)->using(ProductSupplier::class);
}
# ProductSupplier Pivot Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class ProductSupplier extends Pivot
{
public function payment_supplier()
{
return $this->hasMany(PaymentSupplier::class);
}
}
However, doing it like this has a big problem: You CANNOT eager load a pivot's relationships. Not without an override (or a package).
The other way to go about it is using hasManyThrough
# Product Model
public function suppliers()
{
return $this->belongsToMany(Supplier::class)->using(ProductSupplier::class);
}
public function payment_suppliers()
{
return $this->hasManyThrough(PaymentSupplier::class, ProductSupplier::class);
}
# Supplier Model
public function products()
{
return $this->belongsToMany(Product::class)->using(ProductSupplier::class);
}
public function payment_suppliers()
{
return $this->hasManyThrough(PaymentSupplier::class, ProductSupplier::class);
}
This gives you every PaymentSupplier for a single Supplier/Product, so you'll need to apply some kind of filtering.

Laravel Eloquent 5 Tables

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!

Laravel 5.1 - Join through multiple tables

I have the following tables:
Customer
id
Order
id
customer_id
Order_notes
order_id
note_id
Notes
id
If I want to get all order notes for a customer so I can do the following, how can I do it? Is there way to define a relationship in my model that goes through multiple pivot tables to join a customer to order notes?
#if($customer->order_notes->count() > 0)
#foreach($customer->order_notes as $note)
// output note
#endforeach
#endif
Create these relationships on your models.
class Customer extends Model
{
public function orders()
{
return $this->hasMany(Order::class);
}
public function order_notes()
{
// have not tried this yet
// but I believe this is what you wanted
return $this->hasManyThrough(Note::class, Order::class, 'customer_id', 'id');
}
}
class Order extends Model
{
public function notes()
{
return $this->belongsToMany(Note::class, 'order_notes', 'order_id', 'note_id');
}
}
class Note extends Model
{
}
You can get the relationships using this query:
$customer = Customer::with('orders.notes')->find(1);
What about 'belongsToMany' ?
E.g. something like
$customer->belongsToMany('OrderNote', 'orders', 'customer_id', 'id');
Of course, it'll not work directly, if you want to get order object also (but maybe you can use withPivot)
In the end I just did the following:
class Customer extends Model
{
public function order_notes()
{
return $this->hasManyThrough('App\Order_note', 'App\Order');
}
}
class Order_note extends Model
{
public function order()
{
return $this->belongsTo('App\Order');
}
public function note()
{
return $this->belongsTo('App\Note')->orderBy('notes.id','desc');
}
}
Then access the notes like so:
#foreach($customer->order_notes as $note)
echo $note->note->text;
#endforeach

Laravel Eloquent for sale-product-customer relationship

So using Laravel 4, I have a Sales table that has a many to many relationship with a Products table, and it also has a one to many relation with a Customers table.
I set up my models as follows:
class Sale extends Eloquent {
...
public function products(){
return $this->belongsToMany('Product');
}
public function customers(){
return $this->belongsTo('Customer');
}
}
class Product extends Eloquent {
...
public function sales(){
return $this->belongsToMany('Sale');
}
}
class Customer extends Eloquent {
...
public function sales(){
return $this->hasMany('Sale');
}
}
What I want to do is return the data of all sales, including the data of each product included in each sale and the data of the customer that bought it.
In my SalesController I'm using eager loading to query my data like this:
public function index()
{
return Sale::with('products', 'customers')->get();
}
It returns an object with the Sale data, the Product data, but the Customer data is null.
How can I achieve this using Eloquent (or a custom query)?
EDIT
This is the object string it returns:
[{"id":1,"customer_id":1,"date":"2013-11-21","status":1,"created_at":"0000-00-00 00:00:00","updated_at":"0000-00-00 00:00:00","products":[{"id":1,"name":"Monitor","price":50,"status":1,"created_at":"0000-00-00 00:00:00","updated_at":"0000-00-00 00:00:00","pivot":{"sale_id":1,"product_id":1,"custom_price":25,"order":1}}],"customers":null}]
Try changing your customers relationship to singular:
class Sale extends Eloquent {
...
public function products(){
return $this->belongsToMany('Product');
}
public function customer(){ // <- here
return $this->belongsTo('Customer');
}
}
(Moved from comments to answer)

Categories