I have relation method for a model which has a comparison on a property(created_at) of the model itself. Where I want to compare the created_at date of the 'Appointment' model with the created_at of the 'Treatment'. I only want a 'Treatment' if its 'created_at' date is later than that of the 'Appointment'
AppointmentController.php
public function index(): JsonResource
{
$users = User::with([
'appointment' => function ($query) {
$query->with(['appointment_events']);
},
])
->active()
->get();
return UserResource::collection($users);
}
Appointment.php
public function appointment_events(): HasMany
{
return $this->hasMany(AppointmentEvent::class)
->with([
'customer' => function ($query) {
$query->with([
'section' => function ($subquery) {
$subquery
->with([
'advice',
'treatment' => function ($subquery) {
$subquery->where('created_at', '>', blank); //How can I get the model's created_at date.
},
]);
},
]);
},
]);
}
Is there a way to do this?
I think you should move the query to a scope on Appointment model and keep the relationship definition simple.
Note: Below assumes table names and column names as per standard Laravel conventions. If you have different convention, please modify the table names and column names accordingly.
class Appointment extends Model
{
public function scopeWithFutureTreatments($query)
{
return $query->with([
'appointment_events' => function($query) {
$query->with([
'customers' => function($query) {
$query->with([
'section' => function($query) {
$query->with([
'advice',
'treatment' => function($query){
$query->join('sections', 'section.id', '=', 'treatments.section_id')
->join('customers', 'customers.id', '=', 'sections.customer_id')
->join('appointment_events', 'appointment_events.id', '=', 'customer.appointment_events_id')
->join('appointments', 'appointments.id', '=', 'appointment_events.appointment_id')
->whereColumn('treatments.created_at', '>', 'appointments.created_at')
->select('treatments.*')
}
]);
}
]);
}
]);
}
]);
}
public function appointment_events(): HasMany
{
return $this->hasMany(AppointmentEvent::class);
}
}
Then in AppointmentController the following should get you the desired results
public function index(): JsonResource
{
$users = User::with([
'appointment' => function ($query) {
$query->withFutureTreatments();
},
])
->active()
->get();
return UserResource::collection($users);
}
If I understand yours relations are
User ->HasManyAppointments ->HasManyAppointmentsEvents.
You can access quite directly to appointments events data from a user
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get all of the appointment_events for the user.
*/
public function appointment_events()
{
return $this->hasManyThrough(Appointment::class, AppointmentEvent::class);
}
}
From Laravel Doc: Has Many Through
So you can query
$collection = User::with(['appointments','appointment_events'])->where()->get();
which give you all appointments and related appointment_events on a particular user. and you can tap on that collection or filter or whatever business logic you want.
Related
For a small chat purpose, I am using below relationship
Model
class Chat extends Model
{
protected $table = 'chats';
protected $primaryKey = 'chat_id';
protected $filllable = [
'chat_id',
'sender_id',
'reciever_id',
'content',
'sender_type',
'reciever_type',
'view_status'
];
class Admin extends Authenticatable
{
public function chats()
{
return $this->hasMany(Chat::class, 'sender_id', 'admin_id');
}
}
but the issue is both user's are in the same table some times it is sender_id sometimes it is reciever_id so I want to return the above relationship with the condition (if the receiver type in chat table is 1 it should be reciever_id else it should be the sender_id)
Controller
$seller_id = auth()->guard('seller')->user()->seller_id;
$chatLists = Admin::whereHas('chats', function ($q) {
$q->where('reciever_type', 2);
$q->orWhere('sender_type', 2);
})
->with(['chats' => function ($q) {
$q->where('reciever_type', 2);
$q->orWhere('sender_type', 2);
}])
->orderBy('created_at', 'desc')
->get();
return view('seller.chat.index', compact('chatLists'));
}
sender_type and receiver_type don't seem to do much.
If you retrieve $seller_id and intend to get all chats from $seller_id,
both chats with $seller_id as sender
and chats with $seller_id as receiver
Then your query could look like this.
$seller_id = auth()->guard('seller')->user()->seller_id;
$chatLists = Admin::whereHas('chats', function ($q) use ($seller_id) {
$q->where('receiver_id', $seller_id)
->orWhere('sender_id', $seller_id);
})
->with(['chats' => function ($q) use ($seller_id) {
$q->where('receiver_id', $seller_id)
->orWhere('sender_id', $seller_id);
}])
->latest()
->get();
I am trying to return a view with 2 tables, orders and order_menu. What I want to do is to display what orders the customer ordered based on order_id to my view.
Here is the database table for orders and this is database table for order_menu.
I've tried using join table in my controller but it won't work. Here is my controller:
public function show(Order $order)
{
$data = DB::table('order_menu')
->join('menus', 'menus.id', '=', 'order_menu.menu_id')
->join('orders', 'orders.id', '=', 'order_menu.order_id')
->select('orders.*', 'menus.name', 'order_menu.quantity')
->get();
return view('admin.order.detail')->with([
'order' => $order,
'data' => $data,
]);
}
Is there any solutions to solve this?
You just need to add a filter for order id in your query, I assume $order is the instance of model and has order data
$data = DB::table('order_menu')
->join('menus', 'menus.id', '=', 'order_menu.menu_id')
->join('orders', 'orders.id', '=', 'order_menu.order_id')
->select('orders.*', 'menus.name', 'order_menu.quantity')
->where('orders.id', $order->id)
->get();
Or if you already have relations in place in your model then using eloquent you can query the data as
class Order extends Model
{
public function menus()
{
return $this->belongsToMany(Menu::class, 'order_menu ', 'order_id', 'menu_id')->withPivot('quantity');
}
}
class Menu extends Model
{
public function orders()
{
return $this->belongsToMany(Order::class, 'order_menu ', 'menu_id','order_id');
}
}
$data = Order::with('menus')->find($order->id);
public function show(Order $order)
{
$data = DB::table('orders*')
->join('order_menu*', 'order_menu.id', '=', 'orders.id')
->groupBy('orders.id')
->get();
return view('admin.order.detail')->with([
'data' => $data,
]);
}
Models:
Category (id, name)
Item (id, name, category_id, ...)
OrderList (id, user_id, ...)
OrderListItem(id, item_id, order_list_id, user_sort_order, ...)
I want OrderListItems of each OrderList to be sorted:
By user_sort_order
Or by Category name
What I do:
$grouped = $request->input('grouped', false) === "true";
$user = User::findOrFail($id);
$order_lists = OrderList::where('kitchen_id', $user->id)
->with(['order_list_items' => function ($q) use ($grouped) {
$q->when($grouped, function ($q) {
return $q->with(['item' => function ($q) {
return $q->with(['category' => function ($q) {
return $q->orderBy('name', 'asc');
}]);
}]);
}, function ($q) {
return $q->orderBy('kitchen_sort_order', 'asc');
})->with('supplier')
->with(['item' => function ($q) {
return $q->with('category');
}]);
}])->get();
Ordering by category name isn't working. I had been searching for hours but found no answer. Is it possible to do something like this in Eloquent ORM? Btw, Django is able to do it in a really nice way.
You can use a HasManyThrough relationship as a BelongsToThrough and combine it with a modified withCount().Not the most elegant solution, but it works:
class OrderListItem extends Model {
public function category() {
return $this->hasManyThrough(Category::class, Item::class,
'id', 'id', 'item_id', 'category_id');
}
}
$order_lists = OrderList::where('kitchen_id', $user->id)
->with(['order_list_items' => function ($q) use ($grouped) {
$q->when($grouped, function ($q) {
return $q->withCount(['category as category_name' => function ($q) {
$q->select('categories.name');
}])->orderBy('category_name');
}, function ($q) {
return $q->orderBy('kitchen_sort_order', 'asc');
})->with('supplier')
->with(['item' => function ($q) {
return $q->with('category');
}]);
}])->get();
I'm still learning Laravel and I can't find the solution for this problem.
I need to get invoices(with expenses) that are related to specific Partner Type.
I tried this:
$p = Project::with(['invoices.partner.partnerType' => function($query){
$query->where('partnerTypeName', 'Lieferant');
}, 'expenses'
])->where('id', $id)
->first();
I want to select invoices for Lieferant, but I get all invoices for one project.
Project Model:
public function invoices()
{
return $this->hasMany('App\Invoice');
}
Invoice Model
public function expenses()
{
return $this->hasMany('App\Expense');
}
public function partner()
{
return $this->belongsTo('App\Partner');
}
Partner Model
public function partnerType()
{
return $this->belongsTo('App\PartnerType');
}
Edit: PartnerType Model
public function partners()
{
return $this->hasMany('App\Partner');
}
Edit 2: Database
Partner(partnerID, name, partnerTypeId)
PartnerType(partnerTypeId, partnerTypeName)
Project(projectID, name)
Invoice(invoiceID, name, projectID, partnerID)
Expenses(expenseID, invoiceID)
If your models look like that.
Should be like :
$p = Project::with(['invoices' => function($query){
$query->where('partnerTypeName', 'Lieferant')
->with(['expenses','partner' => function($q){
$q->with('partnerType');
}]);
}])->where('id', $id)
->first();
return dd($p);
The solution to your problem is to update your query like this:
$p = Project::with(['invoices' => function($query){
$query->with('expenses')->whereHas('partner.partnerType', function($q){
$q->where('partnerTypeName', 'Lieferant');
});
}])
->where('id', $id)
->first();
But a cleaner solution would be using a scope for your problem.
In your Invoice model.
// Invoice.php
public function scopeByPartnerType($query, $partnerType)
{
$query->whereHas('partner.partnerType', function($q) use ($partnerType) {
$q->where('partnerTypeName', $partnerType);
});
}
And then in your Project model, add another relation that will just get Invoices with a particular partner type.
// Project.php
public function lieferantInvoices()
{
return $this->hasMany('App\Invoices')->byPartnerType('Lieferant');
}
Now you can do just this:
$project->find($id)->load('lieferantInvoices');
I have a table user - User(Model), which has relationship:
public function roles()
{
return $this->belongsToMany(Config::get('entrust.role'), Config::get('entrust.role_user_table'), 'user_id', 'role_id');
}
public function regions() {
return $this->belongsToMany('App\Regions', 'user_region', 'user_id', 'region_id');
}
I am trying this query, but it doesn't me the required result
$result = User::with(['roles' => function($query) {
$query->select('user_id','role_id');
},
'regions' => function($query) {
$query->select('user_id','region_id', 'region_name');
}])
->where('user_id', '=', $id)
->get()->toArray();
It only gives me data from user table and doesn't give the relationship data.
What am I missing out??
The notation you are using should be used for constraints. From your code it seems you don't actually need any contraints.
$result = User::with(['roles', 'regions'])
->where('user_id', '=', $id)
->first()->toArray();
The relationship you defined is only a belongsTo. You should probably use a hasMany relationship.
If you're using 5.1 try this:
$result = User::whereHas(['roles' => function($query) {
$query->lists('user_id','role_id');
},
'regions' => function($query) {
$query->lists('user_id','region_id','region_name');
}])
->where('user_id', '=', $id)
->all();
if not remove all() and use get()
This worked for me.
$users = User::with('regions', 'roles')->get();
$userInfo = [];
foreach ($users as $user)
{
$userInfo[] = [
'users' => $user,
'regions' => $user->regions->toArray(),
'roles' => $user->roles->toArray(),
];
}