I'm learning Laravel right now and i have following tables and resources (models, controllers, ect.):
tickets
- id
- title
- projectID
- statusID
projects
- id
- title
status
- id
- title
I have to make a list of my Tickets on the Startpage. Not nessesary to say that i need the Project- and Statustiltles and not the IDs. Currently i do:
Route::get('/', function()
{
$tickets = Ticket::all();
return View::make('layout')->with('tickets', $tickets);
});
My current output is:
tickets->id, tickets->title, tickets->projectID, tickets->statusID
The output i want is
tickets->id, tickets->title, tickets->projects->title, tickets->status->title
So i hope anyone can understand what i'm trying to ask here and maybe provide me some help. Thank you!
Resolution: I had to set the foreign_keys first in my DB. Then i used the relationships mentioned in the answers and it works fine.
My Model:
class Ticket extends \Eloquent {
protected $fillable = [];
public function project()
{
return $this->hasOne('Project', 'id', 'projectID');
}
public function status()
{
return $this->hasOne('Status', 'id', 'statusID');
}
}
My View:
#foreach($tickets as $key => $value)
...
<td>{{ $value->project->title }}</td>
<td>{{ $value->status->title }}</td>
...
#endforeach
If you configure you relationships correctly you can do that without problems using the Laravel Eager Loading feature, for example:
Eager Loading (Laravel docs)
Eager loading exists to alleviate the N + 1 query problem...
class Ticket extends Eloquent {
public function project()
{
return $this->belongsTo('Project', 'projectID', 'id');
}
public function status()
{
return $this->belongsTo('Status', 'statusID', 'id');
}
}
Now, just call the fields you want, for example:
foreach (Ticket::all() as $ticket)
{
echo $ticket->project->title;
echo $ticket->status->title;
}
Obs.: In your return object/array you can't see the relationships fields unless you do manual joins, etc. So, just configure your relationships and call the fields you want.
Sorry for my english
Define relationships specifying custom foreign keys (defaults would be status_id and project_id for your models):
// Ticket model
public function project()
{
return $this->belongsTo('Project', 'projectID');
}
public function status()
{
return $this->belongsTo('Status', 'statusID');
}
Then eager load related models:
$tickets = Ticket::with('project','status')->get();
// accessing:
foreach ($tickets as $ticket)
{
$ticket->status; // Status model with all its properties
$ticket->project; // Project model
}
Related
I am working on some kind of ambulance app and I need help on how to load relationship.
So, I have table appointment_statuses (and it is populated over the seeder because I need only 3 states - Done, In Progress, Not Performed), I have also the many-to-many relationship between the User model and Appointment model (appointment_user table which holds only IDs of both models) and now I am working on EMR system which means I can check all appointments that patient had in history.
Here is the image of the issue
So under "Status" I want to load name of that ID from appointment_statuses table instead to have only ID.
These tables have this structure:
Appointments
Status
These tables have these values:
Appointments table
Appointment statuses table
These are relations:
User:
public function role()
{
return $this->belongsTo(Role::class);
}
public function patient()
{
return $this->hasOne(Patient::class);
}
public function appointments()
{
return $this->belongsToMany(Appointment::class);
}
Appointment:
public function users()
{
return $this->belongsToMany(User::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function appointmentStatus()
{
return $this->belongsTo(AppointmentStatus::class);
}
Appointment_Statuses:
public function patient()
{
return $this->belongsTo(Patient::class);
}
public function appointment()
{
return $this->belongsTo(Appointment::class);
}
Here is a controller which is responsible for emr:
After I have added to controller this:
$user = User::with(['appointments', 'appointments.appointmentStatus'])->where('id', $id)->firstOrFail();
I get this in frontend:
{{ dd($user->toArray()) }}
SOLUTION TO THIS ISSUE
For anyone in future who gets this kind of issue just check the convention about the naming of the foreign keys. In my example, it was the issue, and if you are not sure that your foreign key name is correct then just in the model provide more information like this:
public function appointmentStatus()
{
return $this->belongsTo(AppointmentStatus::class,'appointment_statuses_id','id');
}
You can use nested relationship
$user=User::with(['appointments','appointments.appointmentStatus'])
->where('id',$id)
->first();
Also you have to modify relationship
public function appointmentStatus()
{
return $this->belongsTo(AppointmentStatus::class,'appointment_statuses_id','id');
}
For anyone in future who gets this kind of issue just check the convention about the naming of the foreign keys. In my example, it was the issue, and if you are not sure that your foreign key name is correct then just in the model provide more information like this:
public function appointmentStatus()
{
return $this->belongsTo(AppointmentStatus::class,'appointment_statuses_id','id');
}
I have two tables: assessments and benchmarks. benchmarks has a field called content. There is a many to many relationship between them: assessment_benchmark. I want to sort a collection of records from the assessment_benchmark table by the content attribute of the corresponding benchmark. I have tried:
$sorted = AssessmentBenchmark::all()->sortBy(function($assessmentBenchmark){
return $assessmentBenchmark->benchmark->content;
});
But this just does not work (it just returns the original order). However, when I return $assessmentBenchmark->comment for example, it does work (comment is a field in assessment_benchmark).
The models look like this:
class AssessmentBenchmark extends Model
{
public function benchmark()
{
return $this->belongsTo(Benchmark::class);
}
public function assessment()
{
return $this->belongsTo(Assessment::class);
}
}
class Benchmark extends Model
{
public function assessments()
{
return $this->belongsToMany(Assessment::class);
}
}
class Assessment extends Model
{
public function benchmarks()
{
return $this->belongsToMany(Benchmark::class);
}
}
Well, you can use below query for sorting, I'm gonna use Assessment model, because, I'm never use pivot modal before. Actually, I never had pivot model..
$assessments = Assessment::with(["benchmarks"=>function($query){
$query->orderBy("content","DESC");
}])
With method aşso provide you eagerloading, so when you put $assessments in iteration , you won't make new query for each relation
From chat discussion, it found that you have pivot field and for that you can change your belongsToMany relationship like this
class Benchmark extends Model
{
public function assessments()
{
return $this->belongsToMany(Assessment::class)->withPivot('comment','score')->withTimestamps();
}
}
class Assessment extends Model
{
public function benchmarks()
{
return $this->belongsToMany(Benchmark::class)->withPivot('comment','score')->withTimestamps();
}
}
Now fetch data
$assessment = Assessment::with(['benchmarks' => function($query){
$query->orderBy('content', 'desc');
}])->find($assessmentId);
In view you can render it like this
#foreach($assessment->benchmarks as $benchmark)
<tr>
<td>{{$benchmark->id}}</td>
<td>{{$benchmark->name}}</td>
<td>{{$benchmark->pivot->score}}</td>
<td>{{$benchmark->pivot->comment}}</td>
</tr>
#endforeach
For update you can use updateExistingPivot
For details check ManyToMany relationship https://laravel.com/docs/5.6/eloquent-relationships#many-to-many
I am trying to grasp the concept of Eloquent ORM by creating a ticketing system at the moment. What I am trying to achieve is:
The tickets with the user who posted the ticket
The feedback belonging to the ticket and the user who entered the
feedback
This is what I have right now:
// TicketController.php
public function index()
{
$tickets = Ticket::with('feedback')->with('user')->orderBy("created_at", "desc")->get();
//dd($tickets);
return View::make('modules.helpdesk.index')->withTickets($tickets);
}
And the following models
// Ticket.php
class Ticket extends Eloquent {
protected $table = 'helpdesk_tickets';
public function feedback()
{
return $this->hasMany('Feedback');
}
public function user()
{
return $this->belongsTo('User');
}
}
// Feedback.php
class Feedback extends Eloquent {
protected $table = 'helpdesk_tickets_feedback';
public function ticket()
{
return $this->belongsTo('Ticket');
}
}
// User.php
class User extends Eloquent {
protected $table = 'users';
public function ticket()
{
return $this->belongsTo('Ticket');
}
}
What I have now is the tickets, their related feedback and user who created the ticket. What I am trying to achieve now is to also get the user who created the feedback.
You need to fix the relation:
// User model
public function tickets()
{
return $this->hasMany('Ticket'); // adjust namespace if needed
}
Next add the relation:
// Feedback model
public function user()
{
return $this->belongsTo('User'); // namespace like above
}
then use eager loading:
// it will execute 4 queries:
// 1st for tickets
// 2nd for feedback
// 3rd for feedbacks' user
// 4th for tickets' user
$tickets = Ticket::with('feedback.user', 'user')->latest()->get();
you can then access the relations in a loop, like below:
#foreach ($tickets as $ticket)
{{ $ticket->title }} by {{ $ticket->user->name }}
#foreach ($ticket->feedback as $feedback)
{{ $feedback->content }}
#endforeach
#endforeach
What you want to do is create nested relations, just like Ticket add a belgonsTo relation on feeback
When you want to use it you can chain relations using the dot notation feedback.user
The code
// Feedback.php
class Feedback extends Eloquent {
protected $table = 'helpdesk_tickets_feedback';
public function ticket()
{
return $this->belongsTo('Ticket');
}
public function user()
{
return $this->belgonsTo('User')
}
}
// TicketController.php
public function index()
{
$tickets = Ticket::with('feedback')->with('user')->with('feedback.user')->orderBy("created_at", "desc")->get();
//dd($tickets);
return View::make('modules.helpdesk.index')->withTickets($tickets);
}
EDIT:
Even though this would work, it will execute more queries than needed. See Jareks answer.
Original Answer:
First of all you need to get your relationships straightened, in User.php you should call the user relationship with HasMany.
public function ticket() {
return $this->hasMany('Ticket');
}
In modules.helpdesk.index you should now have a Ticket Collection since your attaching the $ticket variable to the view.
If you loop through this collection with a foreach loop then what you should get is a model each loop:
foreach($tickets as $ticket) {
// Prints the name property of the Ticket model
print $ticket->name;
// Since a ticket only belongs to ONE user then that means that you are trying to fetch a model
// What we're doing here is getting the User model via the relationship you made in the model Ticket.php and then getting the name.
print $ticket->user()->first()->username;
// Since a ticket can have MANY feedbacks that means were fetching a collection
// which needs to be broken down to models so we do that looping the collection.
// Here we are doing the same thing as with the User model except with a collection.
foreach($ticket->feedback()->get() as $feedback) {
$feedback->text;
}
}
You should definitely check out the Laravel API and see Collection and Model there. http://laravel.com/api/ You get alot of help from there when you get stuck, trust me :)
I hope this answered your question.
There are three tables.
users:
- ...
- some_param
admins:
- ...
- club_id
- some_param
clubs:
- id
- title
Each user can have multiple admins (related by some_param), each admin can have multiple clubs, and I want to get each club's title.
So I defined a relations:
class User extends Eloquent {
public function admins() {
return $this->hasMany('Admin', 'some_param', 'some_param');
}
}
class Admin extends Eloquent {
public function clubs() {
$this->hasMany('Club', 'id', 'club_id');
}
}
And want to use it in template:
#foreach($user->admins as $admin)
#foreach($admin->clubs as $club)
{{ $club->title }}
#endforeach
#endforeach
But I'm getting an error: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation at line #foreach($admin->clubs as $club).
What's I am doing wrong? Thank you in advance.
In your following function:
public function clubs() {
$this->hasMany('Club', 'id', 'club_id');
}
You didn't return so use return like this:
public function clubs() {
return $this->hasMany('Club', 'id', 'club_id');
}
Also, when getting User collection in $user variable, try to use eager loading, for example:
$user = User::with('admins.clubs')->find(1);
This will reduce the queries.
I'm using Laravel 4 and in particular I'm looking for an answer that uses eloquent ORM.
I have a table "tasks" which containers a client_id and a user_id assigned to each row.
client_id refers to a client on a "clients" table and user_id refers to a user on a "users" table.
What I want to do: show all tasks and display the "clients" name and "users" first_name
So the result would look like this in my (blade) view:
#foreach($tasks as $task)
<tr>
<td>{{ $task->user->first_name }}</td>
<td>{{ $task->client->name }}</td>
<td>{{ $task->description }}</td>
</tr>
#endforeach
The above view spits out the $task->client->name perfectly fine but unfortunately shows a "Trying to get property of non-object" when I add the line $task->user->first_name
My controller looks like this:
$tasks = Task::with(array('user', 'client'))->get();
return View::make('index', compact('tasks'));
As I understand it my models make a difference too, so my models look like this:
class Task extends Eloquent {
protected $guarded = array();
public static $rules = array();
public function client() {
return $this->belongsTo('Client');
}
public function user() {
return $this->belongsTo('User');
}
}
And:
class User extends Eloquent implements UserInterface, RemindableInterface {
public function task()
{
return $this->hasMany('Task');
}
}
And:
class Client extends Eloquent {
public function projects(){
return $this->hasMany('Project', 'client_id');
}
}
Any ideas on how to make this work? I've been scratching my head for a while - also note I'm not a database relationship pro so the simpler the explanation the better :)
I just worked through this and learned quite a few things myself. What I did was setup a many to many relationship between users and clients and created a pivot table for handling the relationship called tasks which also stores the description for each task.
It was too much to type here, but you can check out my code at http://paste.laravel.com/Fpv
Many-to-many relationships can be done like this with Eloquent:
class User extends Eloquent implements UserInterface, RemindableInterface {
public function client()
{
return $this->belongsToMany('Client', 'tasks', 'client_id')->withPivot('description');
}
}
and the inverse relationship...
class Client extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'tasks', 'user_id');
}
}
Haven't tested this, but it should be correct.