I have a little problem,
i can't see how can i make a three table relation on Laravel.
DELETED
If someone can help me, I take notes !
Thanks !
As far as I can see, you need to create a relationship to your pivot table and then, you can create relationships to both table.
class Contact extends Model
{
public function filmJobs()
{
return $this->hasMany(ContactFilm::class);
}
}
class ContactFilm extends Model
{
public function film()
{
return $this->hasOne(Film::class);
}
public function job()
{
return $this->hasOne(Job::class);
}
}
You can now use it like that: $contact->filmJobs[0]->film and $contact->filmJobs[0]->job.
Related
Very new to Laravel but am loving what I am seeing so far.
I am working on an application where Clients attend Sessions and Sessions can be attended by many Clients. In addition to this, Clients may also complete Assessments in Sessions they attend on an individual basis (i.e. one client = one assessment). Also worth pointing out that they may or may not complete an assessment.
Best way to explain this is...
It's also important to point out that the data must be consistent - a completed assessment must be done in a session where a client was present. i.e. the client must have been present at the session - the same is true of the inverse - a client can't have completed and assessment for a session he or she was not present at.
This is more of trying to wrap my head around the best structure for this and use the Eloquent ORM in Laravel. I know I can make a working solution to this which definitely will be garbled and messy, but I would rather know the correct way.
Some pertinent code:
class Client extends Model
{
public function sessions()
{
return $this->hasMany('App\Session');
}
public function assessments()
{
return $this->hasMany('App\Assessment');
}
}
class Session extends Model
{
public function clients()
{
return $this->hasMany('App\Client');
}
public function assessments()
{
return $this->hasMany('App\Assessment');
}
}
//This is where I am having difficulty...
class Assessment extends Model
{
public function client()
{
return $this->hasOne('App\Client');
}
public function session()
{
return $this->hasOne('App\Session');
}
}
The issue I face is how to create this three way relationship between "Client", "Session" and "Assessment" in such a way that integrity is enforced and access is available.
Few things I have thought about:
Create a "client_session" pivot table and add an additional field to it called "assessment_id" and use this to bind an assessment to a unique combination of client and session. I'm not sure how (or even if it is possible) to define such a relationship to a table without a model.
Use "Assessments" as the pivot table. I don't really like this idea as it is possible that no assessments take place but I still need that relationship between client and session and storing that in "Assessments" feels wrong.
Create a separate table "Attendance" and an associated "pivot class" i.e. extends Pivot not Model - really unsure about this one!
I have managed to structure the data using simple tables and use INNER JOINs away from Laravel but wanted to understand how best to implement this with Eloquent.
I've also seen the belongsToMany() relationship using a Pivot (i.e. extends Pivot rather than Model) or the hasManyThrough() relationship.
I also saw https://github.com/jarektkaczyk/Eloquent-triple-pivot but this hasn't been maintained in 4 years so I assume this can be done with whatever ships with Eloquent/Laravel.
Any help, greatly appreciated!
**** UPDATE ****
Okay, so #barghouthi has help massively with my understanding. Currently my models look like the following:
class Client extends Model
{
public function sessions()
{
return $this->belongsToMany('App\Session', 'attendance')->using('App\Attendance');
}
}
class Session extends Model
{
public function clients()
{
return $this->belongsToMany('App\Client', 'attendance')->using('App\Attendance');
}
}
class Attendance extends Pivot
{
public function client()
{
return $this->belongsTo('App\Client', 'attendance');
}
public function session()
{
return $this->belongsTo('App\Session', 'attendance');
}
public function assessment()
{
return $this->hasMany('App\Assessment','attendance');
}
}
class Assessment extends Model
{
public function attendance()
{
return $this->belongsTo('App\Attendance');
}
public function client()
{
// for now
return $this->attendance()->client();
}
public function session()
{
// for now
return $this->attendance()->session();
}
}
I've purposefully renamed the pivot table so that reflects the Pivot Class.
I've put some dummy data into the attendance table such that:
When I query the client sessions for client ID 1 this returns four entries rather than two. Four is correct in terms of the attendance table but I would like to have only two records returned - i.e. the sessions.
**** UPDATE
Okay - so a lot of learning and I'm not quite there. This is my current solution:
class Client extends Model
{
public function sessions()
{
return $this->belongsToMany('App\Session', 'attendance')->using('App\Attendance')->distinct('session_id');
}
public function assessments()
{
return $this->hasManyThrough('\App\Assessment', '\App\Attendance', 'client_id', 'id');
}
}
class Session extends Model
{
public function clients()
{
return $this->belongsToMany('App\Client', 'attendance')->using('App\Attendance')->distinct('client_id');
}
public function assessments()
{
return $this->hasManyThrough('\App\Assessment', '\App\Attendance', 'session_id', 'id');
}
}
class Assessment extends Model
{
public function client()
{
return $this->belongsToMany('\App\Client', 'attendance', 'id', 'client_id')->using('\App\Attendance');
}
public function session()
{
return $this->belongsToMany('\App\Session', 'attendance', 'id', 'session_id')->using('\App\Attendance');
}
}
The attendance table simply has id, client_id and session_id. I figured there was no need for assessment_id as there is a one to one relationship (i.e. an assessment(s) may or not be carried out by a client at a particualr session)
class Attendance extends Pivot
{
public function clients()
{
return $this->belongsTo('App\Client', 'attendance');
}
public function sessions()
{
return $this->belongsTo('App\Session', 'attendance');
}
public function assessments()
{
return $this->belongsTo('App\Assessment','attendance');
}
}
This seems to to do the trick apart for the most part. If I try and call
$assessment->client->id
I get the follwing:
Property [id] does not exist on this collection instance.
Which means my relationships in Assessment are not quite right if I want to read the properties of related elements.
When I use
$assessment->client
The output is
[{"id":1,"created_at":"2018-10-24 19:15:41","updated_at":"2018-10-24 19:15:41","date_of_birth":"26 Sep 1974","gender":1,"initial_contact_date":"2013-05-01","initial_session_offered_date":"2002-07-06","contact_from":1,"presentation":"Vitae qui et nesciunt iste autem numquam earum. Illo repudiandae deleniti vel nesciunt non iure. Sunt est nemo ut excepturi illum temporibus.","counsellor_id":1,"pivot":{"id":1,"client_id":1}}]
So I am guessing I am close.
so if you have client_session or attendance table with id, client_id, session_id and you use this table as foreign key in assessments table.
The thing is the pivot table can be a model
see Many to Many : Defining Custom Intermediate Table Models
class Client extends Model
{
public function sessions()
{
// using intermediate model
return $this->belongsToMany('App\Session')->using('App\Attendance');
}
}
class Session extends Model
{
public function clients()
{
// using intermediate model
return $this->belongsToMany('App\Session')->using('App\Attendance');
}
}
class Attendance extends Pivot
{
public function clients()
{
return $this->belongsTo('App\Client');
}
public function session()
{
return $this->belongsTo('App\Session');
}
public function Assessments()
{
return $this->hasMany('App\Assessment');
}
}
class Assessment extends Model
{
public function attendance()
{
return $this->belongsTo('App\Attendance');
}
public function client()
{
// for now
return $this->attendance()->client();
}
public function session()
{
// for now
return $this->attendance()->client();
}
}
so this way you can't have an assessment without an attendance and an
attendance can have many assessments.
Assessment would look like:
id, attendance_id: refers to client and sessions
I have 3 tables.
People, Assignments and Projects
each person in People table can be assigned to one or more Projects.
Each project in Projects table can have one ore more person assigned to it.
Here are the columns of each table:
People
id
name
Assignments:
person_id
project_id
Projects
id
title
My question is: in my Project model, how do I define the relationship?
What I want is to be able to get the names of all person assigned to a specific project.
I NEED:
$project->assignedPeople
So I can:
foreach($projects as $project)
$project->title
foreach(projects->assignedPeople as $person)
$person->name
I NEED YOUR HELP PLEASE
THANK YOU!
Actually You need Many-to-Many relationship.
You can define the Models like this
Project Model
class Project extends Model {
public function peoples()
{
return $this->belongsToMany('App\People');
}
}
And
People Model
class People extends Model {
public function projects()
{
return $this->belongsToMany('App\Project');
}
}
Now you can access the names of all person assigned to a specific project like this.
$project->peoples
And you can run your foreach loop like this
foreach($projects as $project) {
echo $project->title;
foreach(project->peoples as $person) {
echo $person->name;
}
}
Hope it may solve your problem.
Thanks
// Inside Model Project
class Project extends Model {
public function people()
{
return $this->hasMany('App\Models\People');
}
}
// Inside Model People
class People extends Model {
public function project()
{
return $this->belongsToMany('App\Models\Project');
}
}
// In case of custom joining table:
class People extends Model {
public function project()
{
return $this->belongsToMany('App\Models\Project', 'Assignments', 'person_id', 'project_id');
}
}
I have a pivot table of users_operators.
I want to grab the operator_id of the user.
This is how i do this now, but its seems like verbose way.
if (Auth::user()->type === 'operator') {
$user = Auth::user();
// There is a better way to do this?
$operator_id = $user->operator[0]['pivot']['operator_id'];
Session::put('operatorId', $operator_id);
}
class Operator extends \Eloquent
{
public function users() {
return $this->belongsToMany('User');
}
}
class User extends \Eloquent
{
public function operator() {
return $this->belongsToMany('Operator');
}
}
I'm, battling insomnia and not functioning at 100%, but you should be able to get away with $user->operator->id based on what I'm interpreting your models to be (it looks like you had a typo when you copied them into the question).
If that doesn't work, you might want to check out the "Dynamic Properties" section in the Eloquent docs for more info, if you haven't already.
I'm a real newbie to Laravel but I'm loving it so far. I'm struggling on thing however, I want to retrieve the data for the user that is logged in and I am not sure how to go about this.
I have a few tables but I'll keep it basic for now, I have projects table and a users table, I've defined the relationships between these two in the models as so:
user.php
public function projects() {
return hasMany('project');
}
project.php
<?php
use Illuminate\Database\Eloquent\ModelNotFoundException;
class Project extends Eloquent
{
public function user()
{
return belongsTo('user');
}
}
I know I can do the following to retrieve all projects in the database with a foreach loop, however this doesn't retrieve the logged in users projects:
$projects = DB::table('projects')->get();
I saw one tutorial which wasn't very in depth but he said to access the model query I would have to use the following command:
$project = User::all()->projects;
However this hasn't worked either. Can anyone point me into the right direction with real tutorials or post simple examples?
Thanks in advance
Those are the projects of your logged in user:
if (Auth::check())
{
$projects = Auth::user()->projects;
}
And this must be in your relation:
class User extends Eloquent
{
public function projects() {
return this->hasMany('Project');
}
}
You also need to add $this to your Project relation:
class Project extends Eloquent
{
public function user()
{
return $this->belongsTo('User');
}
}
I was creating a like system for my website. in this I wanted one user can only like one time for a post. and a post can be liked by many user. Also many user can like many post.
So if I guess it right, It is a many to many reletionship.
in this context,
I create the following table
... users table:
id
name
....
posts table :
id
post
...post_likes table
id
user id
poost_id
Now I am having the following model for
user :
class User extends SentryUserModel {
public function post_likes()
{
return $this->has_many('Post_like', 'id');
}
}
post :
class Post extends Eloquent {
public function post_likes()
{
return $this->has_many('Post_like', 'id');
}
}
post_like :
class Post_like extends Eloquent {
public function posts()
{
return $this->belongs_to('Post', 'post_id');
}
public function users()
{
return $this->belongs_to('User', 'user_id');
}
}
now when I am going to insert into the database (for post_likes table) I am getting an error called
Illuminate \ Database \ Eloquent \ MassAssignmentException
user_id
Also I want to know is there any way to inset into database like
$user->like()->save($user); ?????
Thank you in advance. Happy coding . \m/
I'll start with a basic issue, firstly you might want to make sure all your tables are lower case (still as a snake case as well), it's not required but it's ultimately how it's expected to be with Laravel so it makes life easier to keep with that. Also a note to the wise, like Class names, database tables are typically in the singular so user instead of users
Secondly yes you can do an insert with $user->post_likes()->save($debate); as your post_likes method on the user class returns has_many.
Thirdly, your design of the Post_like class is a bit off, you could be better off make it like so:
class PostLike extends Eloquent { // note that PostLikes is a more standard naming for a class, they should ideally be camel case names but with all capitals for words
protected $table = 'post_like'; // specifies the table the model uses
public function post() // this should be singular, the naming of a belngs_to method is important as Laravel will do some of the work for you if let it
{
return $this->belongs_to('Post'); // by naming the method 'post' you no longer need to specify the id, Laravel will automatically know from the method name and just adding '_id' to it.
}
public function users()
{
return $this->belongs_to('User');
}
}
Fourthly, your other classes could be better as:
class Post extends Eloquent {
public function post_likes()
{
return $this->has_many('PostLike'); // doesn't require you to specify an id at all
}
}
I can't exactly tell you why you're getting that mass assign error, your post is a bit garbled and doesn't look like you've included the code that actually causes the exception? I have a feeling though is that you're trying to do an insert for multiple database rows at one time but haven't defined a fillable array for PostLike such as with here: http://four.laravel.com/docs/eloquent#mass-assignment
According to Laravel 5:
User Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
public function post_likes()
{
return $this->hasMany('App\PostLike');
}
}
Post Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model {
public function post_likes()
{
return $this->hasMany('App\PostLike');
}
}
PostLike Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class PostLike extends Model {
protected $table = 'post_like';
public function posts()
{
return $this->belongsTo('App\Post');
}
public function users()
{
return $this->belongsTo('App\User');
}
}
and if you want to save the post_like data then:
$inputs['post_id'] = 1;
$inputs['user_id'] = 4;
$post_like = PostLike::create($inputs);
Hope this helps!!