Laravel: query many-to-many relationship - php

I have a User model which belongsToMany() Conferences. Conferences hasMany Users, also a m:m relationship.
I am working on a link() method in my ConferencesController, but I'm not sure how to go about.
I collect the given Conference by id, and the Auth::check-ed User. How do I add the conference and user into the pivot table?

create a pivot table
//conference_user
Schema::create('conference_user', function(Blueprint $table) {
$table->increments('id');
$table->integer('conference_id')->unsigned()->index();
$table->foreign('conference_id')->references('id')->on('conferences');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
now in User model, add this method
public function conferences()
{
return $this->belongsToMany('Conference','conference_user');
}
and in Conference model, add this method
public function users()
{
return $this->belongsToMany('User','conference_user');
}
now in your controller, you can use something like this
$conferences=$user->conferences;
or
$users=$conference->users;

Related

Laravel multi relationship

I am working on chat application in laravel/vue and in this app I have users where each user have several rooms each room has at least 2 user in it and several messages I am trying to make relation or query to get all the rooms for each users and the messages in them
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->enum('status',['active','busy','Do Not Disturb']);
$table->timestamp('email_verified_at')->nullable();
$table->string('image')->default('user0.jpg');
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Schema::create('rooms', function (Blueprint $table) {
$table->id();
$table->string('room_unique');
$table->foreignId('user_id')->constrained()->onDelete('cascade')->onUpdate('cascade');
$table->timestamps();
});
Schema::create('messages', function (Blueprint $table) {
$table->id();
$table->enum('type',['text','image','link']);
$table->string('content');
$table->foreignId('user_id')->constrained()->onDelete('cascade')->onUpdate('cascade');
$table->foreignId('room_id')->constrained()->onDelete('cascade')->onUpdate('cascade');
$table->timestamps();
});
What you have is good. I would just take out the foriegn key user_id from rooms and access user's room through their messages. Hence, messages will be like a pivot table making the relationship between users and rooms many to many.
Hence to access the rooms of a user I would
$rooms = User::find(1)->rooms()->get();
To access users in a room
$users = Room::find(1)->users()->get();
To display messages of a user per room would be like accessing pivot table. Hence
$user = User::find(1);
foreach ($user->rooms as $rooms) {
echo $rooms->pivot->content;
}
So, this is many to many relationship and message is the pivot table. I will stick with the documentation for more details.
The best solution i have found is to make complex relation like this
//relations
public function message()
{
return $this->hasMany(messages::class)->take(1);
}
public function friends()
{
return $this->belongsToMany(User::class, 'friends', 'user_id', 'friend_id');
}
public function rooms()
{
return $this->belongsToMany(Room::class,'user_room','user_id','room_id');
}
public static function getInit()
{
//get room of auth user
$rooms = DB::table('user_room')->where('user_id',Auth::id())->select('room_id')->get()->toArray();
//flatten the array
$roomArray = array_column(json_decode(json_encode($rooms), true),'room_id');
//get users friends and rooms belong to auth user with the last message
$user = User::with(array('friends.rooms' => function($query) use ($roomArray){
$query->whereIn('rooms.id',$roomArray);
},'friends.rooms.messages' => function($query) {
$query->orderBy('created_at','Desc');
}))->whereId(Auth::id())->get()->toArray();
return $user;
}
in getinit I just use this relation after each other like (friends.rooms)
laravel will use friends relation then each result will use rooms relation on it in my case i just need to pick rooms that user and friend have so i limited the relation by using where in rooms belong to the auth user like if we say the auth user has rooms 2,3,4 and his friend has 3,1,5 so the room relation will only return the union of auth user rooms and friend rooms in our case it's 3 then i return messages in each room but for design purpose i just need the last message for each room so i limit my relation message to take 1 and in getinit order them by created date desc

Laravel how to get User Profile field from separate table

I am new to Laravel and Eloquent is quite a challenge for me to understand. I have a User and a UserProfile model and table. UserProfile table has user_id (FK to user's id), 'key, and value fields.
I want to get the values of all the UserProfile fields associated with the user_id. Here is my code but nothing works. I am sure I am making some stupid mistakes but still learning :) Laravel.
UserProfile Model
class UserProfile extends Model
{
public $timestamps = FALSE;
protected $fillable = [
'user_id',
'key',
'value',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
User Model method
public function profileFields(){
return $this->hasMany(UserProfile::class);
}
UserProfile Migration
public function up()
{
Schema::create('user_profiles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id')->unsigned();
$table->string('key', 191);
$table->longText('value');
$table->foreign('user_id', 'user_profile_uid_fk')
->references('id')
->on('users')
->onDelete('cascade');
$table->unique(['user_id', 'key'], 'user_profile_unique_key');
});
}
I am trying to get the profile fields for the user using User::findOrFail(10)->profileFields but it is giving me property not defined exception.
Need Help: Can anyone help me to make it work so I can get all user_profiles
fields from the profile table?
Error Output (Tinker)
>>> User::findOrFail(10)->profileFields
Illuminate/Database/QueryException with message 'SQLSTATE[42S02]: Base
table or view not found: 1146 Table 'velvetpaper.user_user_profile'
doesn't exist (SQL: select user_profiles.*,
user_user_profile.user_id as pivot_user_id,
user_user_profile.user_profile_id as pivot_user_profile_id from
user_profiles inner join user_user_profile on user_profiles.id
= user_user_profile.user_profile_id where user_user_profile.user_id = 10)'
The relation between users and user_profiles is a one to many.
You might have not restarted Tinker since you are getting the wrong error, dont forget to exit Tinker after the modification in the code. Once tinker is started, code changes wont affect it.
you can use join to implement this stuff. like this...
this is query builder
$data['profile']=DB::table(usertable)
->where('usertable.id',$id)
->leftjoin('userprofiletable','usertable.id','=','userprofiletable.user_id')
->first();
return view('profile_view',$data)
//view
$profile->fullname
$profile->sex
$profile->phone
...

How to delete rows from a pivot table in Laravel?

I have a films table which contains a many to many relation e.g AgeRatings with a pivot table called film_age_rating which contains a film_id as a foreign key I have this with 3 other relations too.
Right now my app has no functionality to make a deletion request to remove a film, so right now I hard delete rows in the films DB table. When I delete a film from the films table it deletes items, but the data within the pivot table remains unchanged which I don't want to happen.
films_table
public function up()
{
Schema::create('films', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('name')->nullable();
}
film_age_rating
public function up()
{
Schema::create('film_age_ratings', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('age_rating_id');
$table->uuid('film_id');
$table->timestamps();
});
}
Film Model
public function ageRatings(): BelongsToMany
{
return $this->belongsToMany(
AgeRatings::class,
'film_age_rating',
'film_id',
'age_rating_id'
);
}
Age Rating Model
public function film(): BelongsToMany
{
return $this->belongsToMany(
Film::class,
'film_age_rating',
'age_rating_id',
'film_id'
);
}
I know an option is to add an onDelete cascade to the pivot tables, but that will require lots of migration tables. Is there another way to tackle this without adding a DELETE request for now or is adding the cascade the only option?
Could you please advise me on the most efficient option?
The only way I can imagine is to use softDeletes
On this way, there will be only one query to delete a film, and it will be a logical delete.
You can delete data using the sync() method. It releases the relation from the pivot table. I assuming that you want to delete a film. So this is a sample method in your controller.
public function deleteFilm($id)
{
$film = Film::find($id);
$film->ageRatings()->sync([]);
$film->delete();
}

Where in pivot tables

I have next pivot table:
Schema::create('coach_user', function(Blueprint $table)
{
$table->integer('coach_id')->unsigned()->index();
$table->foreign('coach_id')->references('id')->on('coaches')->onDelete('cascade');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->tinyInteger('rank');
});
In User.php:
public function coaches()
{
return $this->belongsToMany(\App\Coach::class)->withPivot('rank');
}
How I can receive coaches of user with some rank? Something like this:
$user->coaches->where('rank',1)->get().
use wherePivot() to filter the results returned by belongsToMany.
$user->coaches()->wherePivot('rank',1)->get();
Use wherePivot for pivot columns and relation as method:
$user->coaches()->wherePivot('rank',1)->get().

Laravel - A show can have multiple providers

So I am trying to figure a solution to this but not sure exactly how to do this. I have a table that stores all the shows that happen. In a given show I can have multiple providers attend that show. A provider could also attend many shows as well. So how do I store this in the DB and do the eloquent relationship?
Show Schema
Schema::create('shows', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('number')->unsigned();
$table->dateTime('airDate');
$table->string('podcastUrl')->nullable();
$table->timestamps();
});
Provider Schema
Schema::create('providers', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('shortName')->nullable();
$table->string('image')->nullable();
$table->string('social')->nullable();
$table->timestamps();
});
Would I store the provider_id in the shows schema?
Update 1
So I created a new migration for a pivot table
Schema::create('provider_show', function (Blueprint $table) {
$table->integer('provider_id')->unsigned()->index();
$table->foreign('provider_id')->references('id')->on('providers')->onDelete('cascade');
$table->integer('show_id')->unsigned()->index();
$table->foreign('show_id')->references('id')->on('shows')->onDelete('cascade');
$table->primary(['provider_id', 'show_id']);
});
Then in the show model I created the following
public function providers()
{
return $this->belongsToMany(Provider::class);
}
Now when I am saving a new show I added a multiselect to select the providers I want
$show = new Show;
$show->name = $request->name;
$show->number = $request->number;
$show->airDate = $request->airDate;
$show->podcastUrl = $request->podcastUrl;
$show->providers()->attach($request->providerList);
$show->save();
Session::flash('message', "Created Successfully!");
return back();
Then when I save I get the following error
SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: provider_show.show_id (SQL: insert into "provider_show" ("provider_id", "show_id") select 1 as "provider_id", as "show_id" union all select 2 as "provider_id", as "show_id")
Create a provider_show migration which will act as your pivot table.
This table would contain both provider_id and show_id which will provide the many-to-many relationship between those entities.
Then on your Provider model you can provide a shows() method which returns a BelongsToMany relationship.
// In your Provider model
public function shows()
{
return $this->belongsToMany('App\Show');
}
Note that Laravel by default looks for a pivot table name based alphabetically on the two relationships.
You can also add the inverse on your Show model by providing a providers() method that also returns a BelongsToMany relationship.

Categories