How to setup laravel relationship - php

I'm using Larvel 5.3 and I have four tables I wish to set up relations with.
- Users
- Orders
- Products
- Brands
An order belongs to a user and a user has many orders.
A product belongs to many orders and additionally, to one brand.
A brand has many products.
I'm trying to find a way to get a user's order, with the products AND the brand of the products.
User.php
public function orders(){
return $this->hasMany('App\Order');
}
Order.php
public function user() {
return $this->belongsTo('App\User');
}
public function products(){
return $this->hasMany('App\Product');
}
Product.php
public function orders() {
return $this->belongsToMany('App\Orders');
}
public function brand(){
return $this->belongsTo('App\Brand');
}
Brand.php
public function products() {
return $this->hasMany('App\Flavour');
}
I wish to get back an array containing the users orders, along with each orders products and the products' brand.
Could anyone advise?

First, Products and Orders have a many to many relationship.
public function products(){
return $this->belongsToMany('App\Product');
}
Get a user's order first. Because users have many orders, you need to specify which order you want to view the products list from.
$order = $user->orders->first();
Then get all products and their brand
foreach($order->products) ...
For your super array, you can try Eager Loading
$arr = User::with('orders.products.brand')->get(); //Not tested

Related

Laravel PIVOT table with extra fields

I've the following structure in my database.
users
--
id
...
products
--
id
...
licenses (pivot table with some extra informations these data are grabbed via API)
--
user_id
product_id
license_key
license_type
url
purchased_at (datetime)
supported_until (datetime)
...
And here are codes in my model:
# User has many licenses
# User has many products through licenses
User
// User has many licenses.
public function licenses()
{
return $this->hasMany(License::class);
}
// User has many products
// Expected: products
// Outcome: not getting
public function products()
{
return $this->belongsToMany(Product::class, 'licenses', 'user_id', 'product_id')
->using(License::class);
}
Product Model.
# Product has many licenses
Product
public function licenses()
{
return $this-hasMany(License::class);
}
License Model
# License belongs to an user.
# License belongs to a product.
License
public function user()
{
return $this->belongsTo(User::class);
}
public function product()
{
return $this->belongsTo(Product::class);
}
Route
// These class namespaces are imported and all the necessary middlewares are applied.
Route::get('/my-products', [ProductController::class, 'index']);
And in product controller
ProductController
public function index()
{
$user = Auth::user();
// This doesn't get any products. Which is what I want to use.
$products = $user->products;
// This works but I want to display more efficiently and using less DB query.
$licenses = $user->licenses;
$products = [];
foreach ($licenses as $license) {
array_push( $products, $license->product)
}
// Get unique products of an user through licenses relation.
$products = collect($products)->unique();
}
I'm not getting any products from the licenses relation when using $user->products
I want to paginate the products if there are more than 5 products in a page and reduce extra layer of database queries and model loading. Please suggest some better way.
I would suggest to perform a separate single query for products that belongs to user via license as
$products = Product::whereHas('licenses.user', function (Builder $query) use($user) {
$query->where('id', $user->id);
})->paginate(5);
or
$products = Product::whereHas('licenses', function (Builder $query) use($user) {
$query->where('user_id', $user->id);
})->paginate(5);
This way you don't have to loop through all data to extract products from lazy loaded relation and no need for unique action also

How can i make a relationship between my three Models where Distributor and Product model are directly connected with the Distributorproduct Model

Distributor Table - id
Product Table - id
Distributorprocuct Table - distributor_id, product_id
Distributor Model -
public function product() { return $this->hasMany(Distributorproduct::class); }
Product Model -
public function distributor() { return $this->hasMany(Distributorproduct::class); }
Distributorproduct Model -
public function distributor() { return $this->belongsTo(Distributor::class); }
public function product() { return $this->belongsTo(Product::class); }
If I write $product->distributor then it gives me all the details of distributorproduct but i need the details of distributor not distributorproduct .
If i write $distributor->product then it gives me all the details of distributorproduct but i need the details of product not distributorproduct .
Thanks in advance...
It is not clear to me what is the relationship between Product, DistributorProduct and Distributor, but I think what you want is to specify a different kind of relationship between Distributor and Product (and Product -> Distributor).
In your Distributor modal class you can try defining your product method like this:
public function product() {
return $this->hasOneThrough(Product::class, Distributorproduct::class);
}
and the distributor method in the Product modal class like this:
public function distributor() {
return $this->hasOneThrough(Distributor::class, Distributorproduct::class);
}
But your mileage may vary, this kind of relationship is ok only if a Product has a single distributor (likely), and a distributor has a single Product (unlikely I guess).
The Laravel docs have a pretty good documentation about relationships. Looks especially at the Has One Through and the Has Many Through paragraphs.

Laravel: How to count data in database?

I want to make a list of students to know how many products each student buys. I have two tables : Member and Orders. In Orders table have column member_id and product_id. I want to count how many products each student buys. I can get list of student but i can't count how many products each student buys.
public function index()
{
$students = Member::getStudents();
$order = Order::where('member_id', $students->id)->count();
return view('admin.student.index', compact('students'));
}
But it appears an error:
Property [id] does not exist on this collection instance.
function getStudents()
public static function getStudents()
{
$members = Member::where('member_type_id', BaseModel::$student)->get();
for ($idxMember = 0; $idxMember < count($members); $idxMember++) {
if ( $members[$idxMember]->user_id ) {
$members[$idxMember]->username = User::find($members[$idxMember]->user_id)->username;
}
}
return $members;
}
I think it is because you get a collection on id.
so you should foreach your collection and get specific ids.
public function index() {
$students = Member::getStudents();
foreach($students as $student ) {
$order = Order::where('member_id', $student->id)->count();
}
return view('admin.student.index', compact('students'));
}
I suggest to use relationships in Database. It would be more easy and simple.
In orders table, there is a column called member_id which reference to id column in members table. (Keep attention to singular plural usage)
Refer Laravel Documentation for foreign key design and implementation.
You need 2 models, Member and Order. You should define the relationship as below.
Since this is One To Many Relationship,
In Member Model,
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Member extends Model
{
/**
* Get the orders for the member.
*/
public function orders()
{
return $this->hasMany('App\Order');
}
}
?>
In Order Model,
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
/**
* Get the member that owns the order.
*/
public function member()
{
return $this->belongsTo('App\Member');
}
}
?>
Now you can get order count per user using this code.
Member::find(MEMBER_ID)->orders->count();
This will return order count of the selected member.
Please refer the Laravel Documentation here.
Relationships | One To Many | One To Many (Inverse)
You can achieve this by simply using laravel relationship
In order to do this please follow below steps
First, create two relation in members model
public function orders()
{
return $this->hasMany('App\Models\Order', 'member_id', 'id);
}
Then retrieve the students details with orders
public function getStudents()
{
return Member::where('member_type_id', BaseModel::$student)->withCount('orders)->get();
}
Hope this helps
Thank you.
Sharing solution with explanation.
Objects are
Member (Student is also a member. But the Type is different)
Order (One order can have multiple products)
Product (Product will allocate with Orders and Members can place Orders)
Now If you are using Laravel. So the best way is to use Eloquent Relationships.
Model Member :
1 Define Query Scope
public function scopeStudents($query)
{
return $query->where('member_type_id', 1);
}
2 Define One to Many relation between Order and Member (One Student can have multiple orders. And I hope that other members can also have orders. So i am going to relate direct Member to Order)
public function orders()
{
return $this->hasMany('App\Order');
}
and
public function products()
{
return $this->hasManyThrough('App\Product', 'App\Order');
}
Model Order :
1 Define relation with Member Model for One to Many
public function member()
{
return $this->belongsTo('App\Member');
}
2 Define one to many between Order and Product
public function products()
{
return $this->hasMany('App\Product');
}
Model Product :
1 Define Order Product Relation
public function order()
{
return $this->belongsTo('App\Order');
}
Now the Model work is done. Only data fetching is remaining. Tell me in comments if you think below code is less and useful and easy to understand.
Controller Member :
1 Index Function :
// this will fetch all students with their orders and products
$data = Member::students()->with('orders', 'products')->get();
// this will fetch all students with their orders and order's products
$data = Member::students()->with('orders.products')->get();
// this will fetch all students with their orders count and products count
$data = Member::students()->withCount('orders', 'products')->get();

Laravel Collection of Multiple relation items

I have a User that has many Shops, And a Shop has many Products
Now I'm wondering, Is there a way that I can get a Collection of all products for this User.
Without having to loop through the shops he has.
Current method, Which returns a Collection of Shops with Products instead of a Collection of Products
$products = \Auth::user()->shops()->with('products')->get();
You'll want to define a HasManyThrough relation
class User extends Model
{
...
public function products()
{
return $this->hasManyThrough('App\Product', 'App\Shop');
}
...
}
You can get all the products from multiple shops by using the pluck method.
public function products()
{
return $this->shops->pluck('products');
}
public function shops()
{
return $this->belongsToMany(Shop::class);
}
($this being an instance of your user model)
And on your shops model you must have a Laravel relationship to products
public function products()
{
return $this->belongsToMany(Product::class);
}

Eloquent query not working

I have a many to many relationship between users and categories. In a third table, I have a field called category_id to reference what category each record belongs to. I am setting up a system where by once a user logs in, I want them to see records that has category_id of the categories they've selected when registering.
My code is shown below
I have this relationship setup in users model,
public function categories()
{
return $this->belongsToMany('App\Category');
}
and also this
public function userCats()
{
return $this->categories()->get();
}
in the categories table i have this relationship setup
public function users()
{
return $this->belongsToMany('App\User');
}
in my 3rd Table controller i have the following code
if(Auth::check()){
$servo = Jumong::postOnly()->whereIn('category_id', Auth::user()->userCats())->get();
} else {
$servo = Jumong::all()->where('type','P');
}
dd($servo);
The problem is that the below part,
Auth::user()->userCats()
It returns only the last 2 records in Jumong table and there are more than that.
If I replace it with an array, it will return the right results.
Any ideas on what I am missing?
It doesn't work because whereIn expects an array of ids whereas
Auth::user()->userCats() returns a collection of categories.
You can still doing something like.
Auth::user()->categories->pluck('id')

Categories