Relationships with same foreign key to same table Laravel 5 - php

I am building a referral system, the table User is referred by another, for example:
User table:
id
name
Referrals table:
id
referred_by (user_id)
refers_to (user_id)
Same foreign key to the same table. Which are the relationships between User table and Referrals?

I am assuming your user model is App\User and your Referral model is App\Referral:
If you want to get, via your user, who they have referred you can do in App\User:
function referredBy() {
return $this->hasMany('App\Referral', 'referred_by');
}
If you want to get, via your user, who they were referred by:
function referredTo() {
return $this->hasMany('App\Referral', 'refers_to');
}
Anywhere you have a $user object, you can get a list of all other referenced users by $user->referredTo() or $user->referredBy()
The Eloquent models allow you to create many different style relations with different key names.
Reference: https://laravel.com/docs/5.5/eloquent-relationships#introduction

The question is bit-ambiguous but if you want relationship in same table it can be done like this -
When building a table 'referrals_table' in the schema -
$table->foreign('refers_to')->references('referred_by')->on('referrals_table')
In the model the relationship will be (assuming name of this model file is ReferralTable) -
public function name_your_function() {
returns $this->belongsTo(ReferralTable::class)
}
You can call this function now to use it.

Related

No data fetched from associated table : Laravel

I have users and user_roles tables, and id of user_roles is used as foreign key in users. I fetched data from users using User::with('userRole')->find($user). In returned result userRole is present, however it is empty, instead it was supposed to have data from user_roles for the particular foreign key.
Please, share what can be the possible issues with the functionality or if anyone can explain working of laravel associations in brief.
/* User Model */
public function userRole()
{
return $this->belongsTo('App\UserRole');
}
/* UserRole Model */
public function user()
{
return $this->hasMany('App\User');
}
Thank You,
Many to many relationships in Laravel often require you to have 2 models and 3 tables. One to many relationships require you to have 2 models and 2 tables. One to one relationship also requires you to have 2 models and 2 tables.
Many to many relationship
Let's take User and Role models, since each User can have multiple roles and one Role can be assigned to different users, you will naturally want a Many to many relationship. Now, you will need to create an intermediate table in which you will store the results, why? Because you already defined both User and Role and since it is Many to many none of those objects will have any identifier of the other one inside of them, but rather will have their own identifier in the intermediate table, and this is how Laravel fetches the relationship, it connects Models primary key with foreign key inside of the intermediate table.
One to many relationships
Let's take User and Role models again and let's say that this time, one Role can be assigned to multiple users, but one User can ONLY have 1 Role. Naturally you will have a field role_id inside of your User model and you will connect role_id from users with id from roles.
One to one relationships
Lets take User and Role models again :D Let's say you want to create a separate Role for every user, then you will have 2 models and 2 tables where your users table will have all the users and your roles table will contain id, name, user_id and now when you try to retrieve the relationship, if you define one to one laravel will return only 1 result, no matter if you have multiple same user_id on the roles table, Laravel will return only 1 role because you told him explicitly it's 1-to-1 relationship.
EDIT:
Here is an example of one to one relationship:
/* User Model */
public function userRole()
{
return $this->belongsTo('App\UserRole', 'user_role_id', 'id');
}
#Tim and #Nikola
Thank you, for your efforts mates.
However, I found the reason behind the problem. It was because the wrong naming of userRole function in User model.
I was using foreign key of user_roles as user_roles_id in users table and defined function with name of userRole in User model. This leads to ORM not found the relevant column for attaching user_roles data.
The solution is either I have to change the name of user_roles_id to user_role_id or userRole function name to userRoles. And I choose the first one and it worked fine. :)
For reference on the naming conventions of laravel please refer to Laravel - Database, Table and Column Naming Conventions?.

Foreign key relationships with the same table for two different foreign key columns

Lets say I have a user and appointment table.
users - id, name, email, type(doctor/patient)
appointment- id, doctor_user_id, patient_user_id
My user table data-
And my appointment table data-
I could make two belongs to relationships from appointment with user table.
As you can see my appointment table, I want to store only user that type is doctor to doctor_user_id and patient to patient_user_id. But in this case i can add any user id to doctor_user_id field either it is doctor or patient but i want to add only user id as doctor_user_id only if its type is doctor.
I know how to achieve this with two different table but I was wondering is there any way to achieve this with single user table, Thanks.
Yes, you can achieve this by creating one user table only.
Create 2 foreign key for the "doctor_user_id" and "patient_user_id" of appointment table which references to User table.
You can use two belongsToMany() relationships and use the table as I pivot:
public function doctors()
{
return $this->belongsToMany(User::class, 'appointment', 'patient_user_id', 'doctor_user_id');
}
public function patients()
{
return $this->belongsToMany(User::class, 'appointment', 'doctor_user_id', 'patient_user_id');
}
If you'll use the appointment table a lot, you can also add two hasMany() relationships to the Appointment model and two belongsTo() relationships to the User model. So, you could use belongsToMany(), hasMany() and belongsTo() relationships simultaneously for in this case.

How do I allow multiple many-to-many entries in laravel?

In my Laravel5 app I have users, tasks, and user_tasks. A user can complete a task multiple times:
User:
id
name
...
Task:
id
name
value
...
UserTask:
id
user_id
task_id
completed_on
If this were a normal many-to-many relationship I would have this function in the user class:
class User extends Model {
// ...
public function tasks(){
return $this->belongsToMany(Task::class, 'user_tasks', 'user_id', 'task_id');
}
}
But I believe this means that user_id/task_id is a primary key on user_tasks. How do I change the relationships between Task and User if I want duplicate user_id/task_id entries in the join table?
Second question, what if I want a list of all unique tasks a user has completed, regardless of how many time a user has completed them?
EDIT: Sorry, I wasn't trying to mean it would place a unique key on those columns. I meant that it seems like belongsToMany should be used in a situation where there is only one join between any pair of User and Task objects, so situations where user_id/task_id could be a unique key.

Why the name convention of Laravel relationships so weird?

I have three tables:
users
columns: id, name
books
columns: id, name
book_user:
columns: user_id, book_id, state(not read yet, reading, read already)
I intended to user book_user as many-to-many relation table, so I follow the name convention from doc:
To define this relationship, three database tables are needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names, and contains the user_id and role_id columns.
I wrote code:
class User extends Model
{
public function books()
{
return $this->belongsToMany('App\Book');
}
}
, and I can retrieve the books which related to the user by call user->books().
That works well, but when I try to retrieve the state of the book which related to a user, I create model:
class BookUser extends Model
{
//
}
When I use this Model, it claims:
Base table or view not found: 1146 Table 'myapp.book_users' doesn't exist
Conclusion:
the name convention of a table which can be used as many-to-many is <singular_noun>_<singular_noun> (such as book_user).
the name convention of table with multiple words which mapping to a Model is <singular_noun>_<plural_noun> (such as book_users).
I know I can set the table name manually which a model mappings to, but I just wonder:
Does that conflict is a design flaw or just I'm doing wrong in designing tables and models?
You don't need define a model for pivot table,just add withPivot
class User extends Model
{
public function books()
{
return $this->belongsToMany('App\Book')->withPivot('state');
}
}
Then you can retrieve book states from model pivot
Generally you don't need a model for pivot tables. You can define the inverse of the relationship. And if you want to store extra data in pivot table maybe you can check withPivot method. Or explain what are you trying to do.
But if you want to create a model, you need to specify your table name in your model manually. Because Laravel doesn't know if its a pivot table or normal table. It just tries to guess the table name by making it plural.

two foreign keys, how to map with laravel eloquent

I have two tables in MySQL, where the first one is called users and the second one is called games. The table structure is as follows.
users
id (primary)
email
password
real_name
games
id (Primary)
user_one_id (foreign)
user_one_score
user_two_id (foreign)
user_two_score
My games table is holding two foreign relations to two users.
My question is how do I make the model relations for this table structure?? - According to the laravel documentation, I should make a function inside the model and bind it with its relations
for instance
public function users()
{
$this->belongsTo('game');
}
however I can't seem to find anything in the documentation telling me how to deal with two foreign keys. like in my table structure above.
I hope you can help me along the way here.
Thank you
A migration:
$table->integer('player1')->unsigned();
$table->foreign('player1')->references('id')->on('users')->onDelete('cascade');
$table->integer('player2')->unsigned();
$table->foreign('player2')->references('id')->on('users')->onDelete('cascade');
And a Model:
public function player1()
{
$this->belongsTo('Game', 'player1');
}
public function player2()
{
$this->belongsTo('Game', 'player2');
}
EDIT
changed 'game' to 'Game' as user deczo suggested.
Unfortunately the way you have this setup is not likely to work in the current context. You may have more luck with the belongsTo method, but again that only supports one relationship.
You could implement a user1() belongsTo, a user2() belongsTo and finally just declare a non eloquent function to return both (something like $users = array($this->user1(), $this->user2())

Categories