Laravel: How to count data in database? - php

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();

Related

Laravel Multi BelongsTo RelationShip Merge with Eager Loading

Laravel version:7.0
reviews table (Model - Review) has id, product_type, product_id, rating columns.
product_type can be service, plugin, module and each value has own model App\Service, App\Plugin, App\Module. I could put model names directly in product_type but I prefer to use those values.
Here is Review model relationship.
public function plugin()
{
return $this->belongsTo(Plugin::class, "product_id")->withDefault();
}
public function module()
{
return $this->belongsTo(Module::class, "product_id")->withDefault();
}
public function service()
{
return $this->belongsTo(Service::class, "product_id")->withDefault();
}
public function getItem()
{
if($this->product_type=='module')
{
return $this->module;
}elseif($this->product_type=='service')
{
return $this->service;
}else {
return $this->plugin;
}
}
Now I want to get them with eager loading in Review Model as following:
$reviews = Review::with("getItem")->get();
Without Eager loading, I could use $review->getItem()->name // this returns name of product.
How can I get them with eager loading?
You could have implemented this easily as a polymorphic relationship. In your Reviews Model, you could do this:
Model Structure
App\Review.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
public function reviewable()
{
return $this->morphTo();
}
}
Then add reviews() method to your App\Service, App\Plugin and App\Module models
public function reviews()
{
return $this->morphMany('App\Review', 'reviewable');
}
Table Structure
You reviews table could look like this:
reviews
id - integer
body - text
reviewable_id - integer
reviewable_type - string
Note the reviewable_id and reviewable_type fields. The reviewable_id stores the id of the item reviewed and the reviewable_type stores the model related to the item.
Retrieving The Relationship
You may access the relationships via your models. For example, to access all of the reviews for a service, we can use the reviews dynamic property:
$service = App\Service::find(1);
foreach ($service->reviews as $review) {
//
}
You may also retrieve the owner of a polymorphic relation from the polymorphic model by accessing the name of the method that performs the call to morphTo. In your case, that is the reviewable method on the Review model. So, we will access that method as a dynamic property:
$review = App\Review::find(1);
$reviewable = $review->reviewable;
The reviewable will return the model on the Review model either Service, Plugin or Module

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

Laravel eloquent querying with multiple relationships

I have four tables which is departments, users, items, items_inventories
The relationship is like this:
A user has a assigned department.
An item has a assigned department. item_inventories has many items.
Structure:
users
->id
->name
->password
->access_type (department_id)
departments
->id
->name
items
->id
->name
->department_id
items_inventories
->id
->item_id
->qty
My models:
class Item extends Model
{
public function department()
{
return $this->hasOne('App\Http\Models\Department', "id", "department_id");
}
}
class ItemsInventory extends Model
{
public function item()
{
return $this->hasOne('App\Http\Models\Item', "id", "item_id");
}
}
In my items_inventories how do I query all items that belongs to a specific department? Since items has already a relationship to departments, How do I query like: select all items in items_inventories where item department_id is equal to 3?
My goal is, I have a user who is logged in, and I can access the assigned department to him/her via access_type (department_id) when my page loads, I want to list only items in the items_inventories that is assigned to his/her department. I already checked: https://laravel.com/docs/5.4/eloquent-relationships#relationship-methods-vs-dynamic-properties but can't seem to find something that matches my requirement. Thanks
Your relationships are a bit confusing. The table structure says that items belong to departments and item inventories belong to items. I've based the relationship on your table structure and how you can achieve your desired result. You might want to check on your relationship once more to verify how exactly you want it to pan out. As for the current relationship, my models should give you an idea.
class User extends Model
{
public function department()
{
return $this->belongsTo('App\Http\Models\Department', 'access_type');
}
}
class Department extends Model
{
public function items()
{
return $this->hasMany('App\Http\Models\Item');
}
public function itemInventory()
{
return $this->hasManyThrough('App\Http\Models\ItemsInventory', 'App\Http\Models\Item');
}
}
class Item extends Model
{
public function department()
{
return $this->belongsTo('App\Http\Models\Department');
}
public function itemInventory()
{
return $this->hasMany('App\Http\Models\ItemsInventory');
}
}
class ItemsInventory extends Model
{
public function item()
{
return $this->belongsTo('App\Http\Models\Item');
}
}
Controller logic
$department_id = 3;
$itemInventory = ItemsInventory::whereHas('item', function ($query) use ($department_id) {
$query->where('department_id', $department_id);
})->get();
// With user:department relation and department:iteminventory 'hasManyThrough' relation.
$itemInventory = $user->department()->itemInventory;

Laravel Eloquent Relationship Filter by Column of Relationship

I have 3 Tables
Product:[Table]
Person:[Table]
Payment:[Table]
Many To Many Relationship Between Product and Person
One To Many Relationship Between Product and Payment (One Product Has Many Payments)
One To Many Relationship Between Person and Payment (One Person Has Many Payments)
Payment:[Table]
id
person_id
product_id
amount
The thing is that i am trying to get All persons with products and Product payments filtered by person_id.
Reason is that i dont want to have any other persons record in payments.
This is actually the query i am running yeah i know its wrong cuz i cant filter it by person_id.
$query = $person::with('product', 'payment')->where('is_active', 1);
I want to achieve something like this..
$query = $person::with(array('product', 'payment' => function ($query) {
$query->where('person_id', '=', 'person.id');
}))->where('is_active', 1);
If you setup your relations like:
class Person extends Model
{
public function payments()
{
return $this->hasMany(Payment::class);
}
}
class Payment extends Model
{
public function product()
{
return $this->belongsTo(Product::class);
}
}
Then you should be able to do:
$person = Person::with('payments.product')->where('id',$personId)->where('is_active',1)->first();
Which will return a Person with all the relations loaded and you can access those like:
#foreach($person->payments as $payment)
{{$person->name}} bought {{$payment->product->name}} for {{$payment->amount}}
#endforeach

Eloquent many-to-many

Using Laravel, I'm having some trouble accessing my other tables, which are all many to many.
So basically, I start out with the user id and want to list the customers that user has.
public function customers()
{
return $this->belongsToMany('Customer', 'user_to_customer');
}
This works, assume my user id is 1:
User::find(1)->customers;
However now I want to say, for each of these customers, list their products. However this needs to be within the same result.
I guess I would need something within the Customer model, such as:
public function products()
{
return $this->belongsToMany('Product', 'user_to_customer');
}
I can't seem to work out how to access this within the same query? Something like:
User::find(1)->customers->products;
Not sure.. any suggestions?
You can look into eager loading to accomplish this behavior. Given the following model relationships:
class User extends Eloquent {
public function customers()
{
return $this->has_many( 'Customer' );
}
}
class Customer extends Eloquent {
public function products()
{
return $this->has_many( 'Product' );
}
}
class Product extends Eloquent {}
The following query will return all products belonging to customers belonging to a specific (in this case, first) user:
User::with(array('customers', 'customers.products'))->first();

Categories