Laravel pivot consultation - php

I need advice about my model relationships,
Logic
Group has many users
Group has many admins
User has many groups (as user)
User has many groups (as admin)
Database Structure
Group Table
User Table
Group_Users table (save id of user and id of group)
Group_Admins table (save id of user and id of group)
Relationship Code
User model
public function groupsUser() {
return $this->hasMany(GroupUser::class);
}
public function groupsAdmin() {
return $this->hasMany(GroupAdmin::class);
}
Group model
public function users() {
return $this->hasMany(GroupUser::class);
}
public function admins() {
return $this->hasMany(GroupAdmin::class);
}
GroupUser model
public function group() {
return $this->belongsTo(Group::class);
}
public function user() {
return $this->belongsTo(User::class);
}
GroupAdmin model
public function group() {
return $this->belongsTo(Group::class);
}
public function user() {
return $this->belongsTo(User::class);
}
Help wanted
Basically as the relationships between users and groups is many to many normally I shouldn't need models of GroupUser and GroupAdmin and then just using sync() function in order to add/remove users and group id's from those tables.
What is my concerns then?
Normally I use that type of connection when I want input bulk ids into database (let say adding tags to posts, suddenly relate 10 tags id to 1 post) that moment using sync() and removing GroupUser and GroupAdmin models makes sense but in my case as users joins/adds to groups one by one, what do you suggest for this relationships?
Is my current approach makes sense?
Is is better if I remove those GroupUser and GroupAdmin models and add them to user, group model like:
public function users()
{
return $this->hasMany(User::class, 'group_users', 'user_id', 'id');
}
and such so?
What do you think is the best practice?

users and groups is many to many
your tables like this?
users, user_group , groups ?
How about use 'belongsToMany' relation?
Laravel many to many relation
// User model
public function groups() {
return $this->belognsToMany(Group::class);
}
// Group model
public function users() {
return $this->belognsToMany(User::class);
}
And use like.
User::find(1)->groups; // return user 1 groups
User::find(1)->groups()->sync($groupIds); // relate user and groups
Group::find(1)->users; // return group 1 users
If you have role column in your users table, you cold add relation like.
// Group model
public function users() {
return $this->belognsToMany(User::class)->where('role', 'the role of normal user');
}
public function admins() {
return $this->belognsToMany(User::class)->where('role', 'the role of admin user');
}
Hope it helps you.

Related

Many to Many Relationship with 2 FK referencing from same PK Laravel 8

Hello I am working on a Laravel project, that i have to assign for one Mentorship «Mentoria», one Mentor «Mentor» and one student «Mentorando». The data of the student and the mentor, came from the Users table (i assigned them roles, using Spatie) , and the other table is called «Mentoria» Since there exists a many to many relation i created the pivot table that is called «utilizador_mentoria» and has ID_Mentor, ID_Mentorando (both are FKs coming from the users table),and ID_mentoria (coming from Mentoria table). I defined both models as this:
User Model:
protected $casts = [
'email_verified_at' => 'datetime',
];
public function interesses(){
return $this->belongsToMany(AreaInteresse::class, 'utilizador_interesse', 'id_utilizador', 'id_interesse');
}
public function mentorias(){
return $this->belongsToMany(Mentoria::class, 'utilizador_mentoria', 'id_mentoria', 'id_mentorando', 'id_mentor');
}
ps: I have interesses function with other model, that is working properly. my problem is with the «mentorias»
Mentoria Model:
public function users(){
return $this->belongsToMany(User::class, 'utilizador_mentoria','id_mentor','id_mentorando','id_mentoria');
}
With this, i am trying to get the data from all Mentorias, and the data of the Mentor that is assigned to that that Mentoria, however when i am doing this code on the controller, the data coming from the user appears empty, despite i have the DB filled with data. I tried a echo for testing, and it only shows the data of the Mentoria, and where it should appear the data of the Mentor assigned to that MEntoria, it is empty
the code from the controller:
public function mentorias(){
$mentorias = Mentoria::with('users')->get();
echo $mentorias;
return view('admin/mentorias/admin_mentorias', ['mentorias' => $mentorias]);
}
the output of the echo
[{"id":2,"titulo":"teste","titulo_en":"test","descricao":"fe","descricao_en":"ewfwe","created_at":"2021-12-28T01:32:10.000000Z","updated_at":"2021-12-28T01:32:10.000000Z","users":[]}]
Since as i already said, i already used data from 2 tables with Many to Many relation, however with only 1 FK per PK, and it is working properly, i have no idea why it is not working this way . I already checked for similar questions, however with no luck
Edit:
For testing purposes, i removed the column of one of the two FK that reference from the same PK, and i managed to work, however with this aditional FK i am not managing to make it work . I believe that the problem is with the relation, in the models but i have no idea how to make it work
I rearranged the funcitons in the models as they are now
User Model:
public function mentorias(){
return $this->belongsToMany(Mentoria::class, 'utilizador_mentoria', 'id_mentor', 'id_mentorando', 'id_mentoria');
}
Mentoria Model:
public function users(){
return $this->belongsToMany(User::class, 'utilizador_mentoria','id_mentoria','id_mentorando','id_mentor');
i also tried to took out,example «id_entorando» from the main () and put it after with the «withPivot» method, but it still didn't worked
I don't know if I properly understood the problem but your relationship is not a single "many to many", but two "one to many". In the end I'll show why it's convenient to consider them as two separated relationships.
First: If a user can have multiple mentorships but a mentorship can have only 1 mentor (which I suppose is what's happening), then you should use the "hasMany/belongsTo" pair:
User Model:
public function mentorias(){
return $this->hasMany(Mentoria::class);
}
Mentoria Model:
public function user(){
return $this->belongsTo(User::class);
}
Second: Complete the scenario with the other relationship bewteen the mentorship and the students:
User Model:
public function mentorias(){
return $this->hasMany(Mentoria::class);
}
public function mentoria(){
return $this->belongsTo(Mentoria::class);
}
Mentoria Model:
public function user(){
return $this->belongsTo(User::class);
}
public function mentorandos(){
return $this->hasMany(User::class);
}
There should be a user_id column in the mentorias table that represents the Teacher which the mentorships belong to:
Schema::table('mentorias', function (Blueprint $table) {
$table->unsignedInteger('user_id')->nullable();
});
And there should also be a mentor_id column in the users table that represents the mentorship which the students belong to:
Schema::table('users', function (Blueprint $table) {
$table->unsignedInteger('mentoria_id')->nullable();
});
Third: This double representation of the User Model could lead to confusion, since two different objects (teacher and student) are using the same model but are not meant to have both relationships simultaneously: A teacher shouldn't be mentored and a student shouldn't lead mentorships.
In order to roperly manage Teachers and Students and prevent confusion, you could create additional models that inherit the User Model and define the relationships for them (instead of the User Model), so you can limit the fields and the relationships for each one of them.
User Model:
// No relationships
Teacher Model:
// Extending from User allows you to have all the User Model functionality
class Teacher extends User
{
public function mentorias(){
return $this->hasMany(Mentoria::class)->with('students');
}
}
Student Model:
// Extending from User allows you to have all the User Model functionality
class Student extends User
{
public function mentoria(){
return $this->belongsTo(Mentoria::class)->with('teacher');
}
}
Mentoria Model:
public function teacher(){
return $this->belongsTo(Teacher::class);
}
public function students(){
return $this->hasMany(Student::class);
}
In the end, you'll have all the info you need from the mentorship when you call objects like this:
Teacher::with('mentorias')->get();
// This will show the Teacher's mentorias and the students in each one
Student::with('mentoria')->get();
// This will show the Student's mentoria and its teacher
Mentoria::with(['teacher', 'students'])->get();
// This will show the teacher and the students for each mentoria

laravel- Eloquent relationship between users, user infos, user addresss, and user contacts

I am creating a bunch of models in my laravel project. There are four models, meaning four tables in my database. Namely the models are User, UserInfo,UserAddress,UserContact. The user table is the master table and the structure of the columns are as below:
users -> id , email, password,....other unimportant stuff.
user_info -> id, name, identity num, ......
user_address -> id, user_id, address1, address2,address3, shipping address,....
user_contact-> id, user_id, mobile_num,emergency_num,......
As you can see, the id column is the key identifier to know the entire information for any user. I am trying to define an eloquent relationship between them four and couldn't know if I am correct. This is what I have so far:
User Model:
public function user_info(){
return $this->hasOne('App\Models\UserInfo');
}
public function user_address(){
return $this->hasOne('App\Models\UserAddress');
}
public function user_contact(){
return $this->hasOne('App\Models\UserContact');
}
UserInfo Model:
public function user(){
return $this->belongsTo('App\Models\User');
}
public function user_address(){
return $this->hasMany('App\Models\UserAddress');
}
public function user_contact(){
return $this->hasMany('App\Models\UserContact');
}
UserAddress Model:
public function user(){
return $this->belongsTo('App\Models\User');
}
public function user_info(){
return $this->belongsTo('App\Models\UserInfo');
}
public function user_contact(){
return $this->hasMany('App\Models\UserContact');
}
UserContact Model:
public function user(){
return $this->belongsTo('App\Models\User');
}
public function user_info(){
return $this->belongsTo('App\Models\UserInfo');
}
public function user_address(){
return $this->belongsTo('App\Models\UserAddress');
}
So the question is that I am unsure for example, is user contact the child of user address or the other way round?
Is user contact the child of user info?
Can anyone shed some light on this?
Appreciate it.
Hi just keep all relations in User model and access them through it. In other Model just relation back to User Model. I am your structure modifying little bit, let user add multiple address check box for default shipping address, also multiple contacts if you want you can keep just one contact also.
users -> id , email, password,....other unimportant stuff.
user_info -> id,user_id ,name, identity num, ......
user_address -> id, user_id, address,shipping address,....
user_contact-> id, user_id, mobile_num,emergency_num,......
User Model
public function user_info(){
return $this->hasOne('App\Models\UserInfo');
}
public function user_address(){
return $this->hasMany('App\Models\UserAddress');
}
public function user_contact(){
return $this->hasMany('App\Models\UserContact');
}
in you all other user related models just add this
public function user(){
return $this->belongsTo('App\Models\User');
}
you can access relation through user model
$user_info = UserInfo::with('user')->first();
$user_info->user->user_contact();
if just user Model
$user = User::with(['user_info','user_contact','user_address'])->first();
echo $user->user_info->name;
update
user_id is the foreign key in each table other than user table, if you want to test the relations create User db seed and 4 factories (user, user_address, user_contact, user_info) to fill fake data, after creating models and data in database fetch first User and call its relations, do the same thing for other models fetch first record and call user relation from this model.
this is my UserTableSeeder class run method
public function run()
{
factory(App\User::class, 10)->create()->each(function ($user) {
$user->user_address()->save(factory(App\Models\UserAddress::class)->make());
$user->user_contact()->save(factory(App\Models\UserContact::class)->make());
$user->user_info()->save(factory(App\Models\UserInfo::class)->make());
});
}

Laravel 5.2 Model User->Invoice->InvoiceDetails

I have 3 models and i don't know which relationship do i need to write for each model
User | Invoice | InvoiceDetails
A User can have many Invoices and one Invoice is made by only one User.
So in User Class i write:
public function invoice(){
return $this->hasMany('App\Invoice');
}
and inside Invoice Class i write:
public function user(){
return $this->belongsTo('App\User');
}
Is this ^ correct?
And now, one Invoice has one InvoiceDetail does that mean for each Invoice there is only one row in table invoice_details?
I just don't know what to write inside each model, how to connect them?
I have made a little schema just to show what it should be like:
So the question is, which functions to write inside each Model to declare proper connections between them?
What you've written so far is fine, it links users to invoices properly (almost). The only thing is you need to rename owner_id to user_id, or specify that it should use the owner_id field.
User class
// Note that the function should be plural as it's for many
public function invoices(){
return $this->hasMany('App\Invoice', 'owner_id', 'ID');
}
Invoice class
public function user(){
return $this->belongsTo('App\User', 'ID', 'owener_id');
}
Then you just need to define the relationship with InvoiceDetails
Invoice class
public function invoiceDetails()
{
return $this->hasMany('App\InvoiceDetails');
}
InvoiceDetails class
public function invoice()
{
return $this->belongsTo('App\Invoice');
}

Polymorphic many to many from User to Post and Category

I need to implement a follow system like twitter but with exception a user can follow many Post and can follow whole Category or a user can follow a User.
I have come up with this relationship. I am using Laravel 5.1
User Model
public function followers()
{
return $this->belongsToMany('App\User', 'user_follows', 'user_id', 'follow_id');
}
public function follows()
{
return $this->belongsToMany('App\User', 'user_follows', 'follow_id', 'user_id');
}
and for follow a Category
Category Model
public function followers()
{
return $this->belongsToMany('App\User', 'category_follows', 'user_id', 'category_id');
}
and for Post is the same way, as you can see I need 3 tables (user_follows, category_follows, post_follows) to make this work.
I know there is Polymorphic Relation but I cant wrap my head around it.
Please help how i can simplify it. once again below are the requirements
User can follow many Posts
User can follow many Category
User can follow many User
You can use morphedByMany to create polymorphic many to many relations. Instead of having separate *_follows tables, you can have a single followables table with the following schema:
user_id int # user_id that is following something
followable_id int # id of the thing that is being followed
followable_type string # type of the thing that is being followed
Here's a sample implementation:
Category, Post and User models
/*
* This function gets the followers of this entity. The
* followable_id in the followables relation would be
* the id of this entity.
*/
function followers() {
return $this->morphToMany('App\User', 'followable');
}
User model
/*
* Gets the list of users that are followed by this user.
*/
function users() {
return $this->morphedByMany('App\User', 'followable');
}
/*
* Gets the list of posts that are followed by this user.
*/
function posts() {
return $this->morphedByMany('App\User', 'followable');
}
/*
* Gets the list of categories that are followed by this user.
*/
function categories() {
return $this->morphedByMany('App\User', 'followable');
}
Note that in this case, a User is both morphed by many and morphed to many, creating a self-reference many to many relationship.
Every new followable entity you create, you will need to add the followers() function to that entity, and a corresponding inverse relation to the Users entity. You could define a Followable trait containing that function, and simply add use Followable; to the new entity you add.

Can't get Eloquent's hasManyThrough to work for a basic example

Here are my relationships:
User
id
Collection
id
UserCollection
user_id
collection_id
How can I get something like $user->collections to return all Collection objects that belongs to the user? A UserCollection simply links a User to a Collection. This allows a user to have multiple collections, but also allows a collection to belong to multiple users.
What I'm currently trying is to specify that UserCollection belongs to a User on user_id, and belongs to a Collection on collection_id.
// UserCollection
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function collection()
{
return $this->belongsTo(Collection::class, 'collection_id');
}
Then specifying that a User has many Collections through UserCollection.
// User
public function collections()
{
return $this->hasManyThrough(Collection::class, UserCollection::class);
}
I've also tried explicitly setting the column names of the hasManyThrough relationship, but the join tries to use an id column on the UserCollection model, which does not exist as there is no primary key:
public function collections()
{
return $this->hasManyThrough(Collection::class, UserCollection::class, 'user_id', 'collection_id');
}
You're overcomplicating things here. You don't need hasManyThrough. What you need is belongsToMany() for a many-to-many relationship.
First, get rid of your UserCollection model. You don't need it.
Then change your relations to this:
public function collections(){
return $this->belongsToMany('Collection', 'user_collections');
}
public function users(){
return $this->belongsToMany('User', 'user_collections');
}
For more information take a look at the official docs on relations

Categories