Using 'with' in many-to-many relationship in Laravel - php

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(),
];
}

Related

Laravel use model property in relation method

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.

How to return data from 2 tables with foreign keys in laravel

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

Retrieving data from multiple tables

I have Student table in my database which connect many to many with Courses table , when I try to select student from the table ,give me error :
"Undefined property: stdClass::$courses (View: C:\xampp\htdocs\laravel\resources\views\admin\student\index.blade.php)
<td>
#foreach($student->courses as $course)
<label>{{$course->name_courses}}</label>
#endforeach
</td>
edit and update have error:
public function edit(Student $student)
{
$id = $student->id;
$students = DB::table('student')
->join('contacts', 'student.contact_id', '=', 'contacts.id')
->join('users', 'contacts.user_id', '=', 'users.id')
->select('contacts.*', 'users.*', 'student.*')
->where(['student.id' => $id])
->first();
$courses = Course::all();
$course2 = array();
foreach ($courses as $course) {
$course2[$course->id] = $course->name;
}
return view('admin.student.edit', ['student' => $students]);
}
function update:
public function update(Request $request, Student $student)
{
Student::updateStudent($request->all());
if (isset($request->courses)) {
$student->courses()->sync($request->courses);
} else {
$student->courses()->sync(array());
}
return redirect("/admin/student")->with('success','Has been Update');
}
in the model Student
public static function createStudent($data) {
/*
$user = User::create([
'username' => $data['user_name'],
'role_id' => 1,
'password' => Hash::make($data['password']),
]);*/
$user = User::createUser($data) ;
$data['user_id'] = $user['id'];
$contactId = Contact::createContact($data);
$student = Student::create([
'contact_id' => $contactId
]);
return $student;
}
public static function updateStudent($data) {
/* DB::table('users')
->where('id', $data['user_id'])
->update([
'username' => $data['username']
]);*/
User::updateUser($data);
Contact::updateContact($data);
}
public function courses()
{
return $this->belongsToMany('App\Course');
}
Could someone tell me what to do to fix this ?
Looks like you are using Route model binding, and your student is injected, if thats the case you don't need to use DB::table(...
public function edit(Student $student)
{
$courses = Course::all();
$course2 = array();
foreach ($courses as $course) {
$course2[$course->id] = $course->name;
}
return view('admin.student.edit', ['student' => $student]);
}
You have 2 problems in your code:
1-
The below indicates that you're using Query Builder instead of Eloquent
$students = DB::table('student')
->join('contacts', 'student.contact_id', '=', 'contacts.id')
->join('users', 'contacts.user_id', '=', 'users.id')
->select('contacts.*', 'users.*', 'student.*')
->where(['student.id' => $id])
->first();
And you didn't join the courses table.
2-
Query Builder will return Array, not an object. So to access the course you should do this instead, $course['name_courses']:
<td>
#foreach($student->courses as $course)
<label>{{$course['name_courses']}}</label>
#endforeach
</td>
To fix the issue, it's easier to do the following:
$students = Student::with('courses', 'contacts, 'contacts.users')
->where('id', '=', $id) //the 'id' here refers to 'student' ID.
->first();
and then you can loop over the courses that belong to this particular student.

Eloquent ORM order by deep relation

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

Laravel 5: DB::table() and relationship in Eloquent

I have a hasMany relationship between Community and LangCommunity and I am trying to sort by name field without losing the relationship in the view.
Model Community
protected $fillable = ['province_id', 'active', 'address', 'phone', 'google_map'];
public function langs()
{
return $this->hasMany('App\Models\LangCommunity');
}
Model LangCommunity
protected $fillable = ['community_id', 'lang_id', 'name', 'text'];
public function community()
{
return $this->belongsTo('App\Models\Community');
}
In controller, I have:
$data['communities'] = DB::table('communities')
->join('lang_communities', 'communities.id', '=', 'lang_communities.community_id')
->select('communities.*', 'lang_communities.name')
->where('lang_communities.lang_id', '1')
->orderBy('lang_communities.name', 'asc')
->paginate($num);
This work, but I can't use the relationship in the view. I have tried to do it in the following way:
$data['communities'] = Community::with(['langs' => function($query)
{
$query
->where('lang_id', '1')
->join('communities', 'communities.id', '=', 'lang_communities.community_id')
->orderBy('lang_communities.name', 'asc');
}])->paginate($num);
But this does not sort by name. Any idea?
Ok. I have managed to solve it ;)
$data['communities'] = Community::join('lang_communities', 'communities.id', '=', 'lang_communities.community_id')
->select('communities.*', 'lang_communities.name')
->where('lang_communities.lang_id', '1')
->orderBy('lang_communities.name', 'asc')
->paginate($num);
Did you try :
$data['communities'] = Community::with(['langs' => function ($q) {
$q->orderBy('name', 'asc');
}])
->whereHas('langs', function ($query) {
$query->where('lang_id', 1);
})->get();

Categories