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

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.

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.

Relationships with same foreign key to same table Laravel 5

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.

Multiple "statuses" for many-2-many table relationship in a Laravel Data Model? Best approach?

I am new to Laravel (only been coding a few months). I've created a DB model that connects two tables "Players" and "Teams" via a pivot table.
class Player extends Model
{
public function teams()
{
# With timetsamps() will ensure the pivot table has its created_at/updated_at fields automatically maintained
return $this->belongsToMany('p4\Team')->withTimestamps();
}
}
class Team extends Model
{
public function players()
{
return $this->belongsToMany('p4\Player')->withTimestamps();
}
}
Players can be members of (many) teams, "own" teams, be "recruited" to teams, and be "rejected" from teams. Both Teams and Players can initiate requests for each of these statuses, allowing the other party to confirm/reject. In each case, they should be linked and can only occupy one of the four statuses. What is the best way to link these two tables such that the relationship between any two instances can be given 4 "statuses"?
I need to give the users (whom control teams and players in this open management/recruitment environment), the ability to request/approve classification in each of the "statuses".
It strikes me that the cleanest way to do this would be to use a single pivot table that "assigns" these given statuses to each linked ID pair. I, however, have only seen simpler examples of this concept executed and am as a result unsure as to what the best way to do that is. I would appreciate some guidance here.
Schema::create('player_team', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
# `book_id` and `tag_id` will be foreign keys, so they have to be unsigned
# Note how the field names here correspond to the tables they will connect...
# `book_id` will reference the `books table` and `tag_id` will reference the `tags` table.
$table->integer('player_id')->unsigned();
$table->integer('team_id')->unsigned();
# Make foreign keys
$table->foreign('player_id')->references('id')->on('players');
$table->foreign('team_id')->references('id')->on('teams');
});
*Again, I'm pretty fresh. Apologies if this has an obvious solution I'm just missing.
If I understood you correctly, you can add status column to a pivot table:
$table->tinyInteger('status')->unsigned();
Don't forget to add withPivot() to relations:
return $this->belongsToMany('p4\Player')->withPivot('status')->withTimestamps();
You can access this column with pivot and set or unset it by adding an array to attach() and detach() methods:
$team->players()->attach($playerId, ['status' => 3]);
Read more about it in docs:
https://laravel.com/docs/5.3/eloquent-relationships#many-to-many
https://laravel.com/docs/5.3/eloquent-relationships#inserting-and-updating-related-models

Laravel 4 eloquent pivot table

I have three tables: users, items and user_items. A user has many items and a item belongs to many users.
The tables:
Users
id
username
password
Items
id
name
equipable
User_items
id
user_id
item_id
equipped
The models:
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items')
->withPivot('equipped');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items');
}
}
In the pivot (user_items) table I've a very important column named "equipped".
I've a form where users can equip, unequip and throw items. This form has a hidden field with the pivot (user_items) table row id. So, when a user tries to equip an item, the system checks if the item is equipable.
So, I want a object with the pivot data and the item data, based on item_id from the pivot table, I can send to the handler (where all logic is handled).
So what I've to do is to first access the pivot table and then access the item table.
Something like this (does not work):
$item = User::find(1)->items->pivot->find(1);
Is this possible to do?
You first have to include 'equipable' on your pivot call:
return $this->belongsToMany('User', 'user_items')
->withPivot('equipable');
Then you can ask Eloquent if your item is equipable or not:
$item = User::with('items')->get()->find(1)->items->find(2)->pivot->equipable;
Keep two things in mind:
Eloquent uses 'items' as a key internally, so that might interfere.
Whatever method you put before "get()" is part of the db query. Everything after "get()" is handled by PHP on the Object. The latter will be slower in most cases.

Categories