Laravel seeds wrong id values in many to many relations - php

I currently learn Laravel 5.8 and created database where users can have two roles: admin or user stored in roles table. I tried to populate role_users intermediate table but Laravel doubles rows and seeds wrong data like this: Crazy ROLE_USER Table. role_id should be only 1 or 2. user_id should be unique. What did I do wrong?
User model:
public function roles() {
return $this->belongsToMany('App\Role', 'role_users')->withTimestamps();
}
Role model:
public function roles() {
return $this->belongsToMany('App\User', 'role_users')->withTimestamps();
}
create_role_users_table migration:
Schema::create('role_users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('role_id');
$table->unsignedBigInteger('user_id');
$table->timestamps();
});
RoleUsersFactory factory:
$factory->define(RoleUser::class, function (Faker $faker) {
return [
'role_id' => Role::all()->random()->id,
'user_id' => User::all()->random()->id,];
});
RoleTableSeeder seeder:
$role_user = new Role();
$role_user->role = 'user';
$role_user->save();
$role_admin = new Role();
$role_admin->role = 'admin';
$role_admin->save();
DatabaseSeeder seeder:
$this->call(RoleTableSeeder::class);
factory(User::class, 5)->create()->each(function($user) {
$user->roles()->save(factory(RoleUser::class)->make());
});

create a role then.
$role = Role::create(['role_name' => 'admin']);
use attach()
factory(User::class, 100)->create()->each(function ($user) use ($role ) {
$role ->users()->attach($user);
});
Try the above code.
This will create 100 different users with admin as role.
you can add other roles like this.
hope this suite for you.

You have the wrong relationships (you state that you want all the users to have a single role, which should be a BelongsTo / HasMany).
On the User model, have this method:
public function role() {
return $this->belongsTo('App\Role');
}
Create this method on the Role model:
public function users() {
return $this->hasMany('App\User');
}
Delete the migration you made where the role_users table is created and create a new migration with the following code:
Schema::table('users', function(Blueprint $table) {
// remove the nullable if a user HAS to have a role at all times
$table->unsignedBigInteger('role_id')->nullable();
}
Now, as a last step, the seeders. Your Role-seeder is correct. You shouldn't change that. Change your User-seeder to the following:
factory(User::class, 100)->create(['role_id' => Role::all()->random()->id]);
This will create a database with 100 users, where each has a role of admin or normal user. You can get all the users attached to a role with $role->users and get the role of a user with $user->role.

Related

Booking system ala airbnb many to many laravel relationship?

I'm trying to create a system to log all bookings for a few airbnb hosts, at first I had two models Home and Guest, where a home can have many guests and a guest could book for many homes,
then I thought about creating a guest_home pivot table to link both tables... then things got complicated in my head, what about a Booking model, and (have that booking model act as a pivot table ?) , to me doing new Booking() seemed better than attaching ids to home model?
How could you guys go about this, it's making my brain malt right now...
I thought of doing something like this in my BookingController:
public function createBooking(Request $request)
{
$guestIds = Guest::latest()->take(3)->pluck('id');
$home = Home::findOrFail($request->input('home_id', 2));
$booking = new Booking();
$booking->home_id = $home->id;
$booking->guests()->attach($guestIds);
$booking->save();
return response()->json([
'booking' => $booking,
]);
}
Should I create home_guest pivot table, is a pivot table even needed? what models would I link, please bear with me, so far this is what I got:
Models
class Guest extends Model
{
public function bookings()
{
return $this->belongsToMany('App\Models\Home', 'bookings', 'guest_id', 'home_id');
}
}
class Home extends Model
{
public function guests()
{
return $this->belongsToMany('App\Models\Guest', 'bookings', 'home_id', 'guest_id');
}
public function bookings()
{
return $this->hasMany('App\Models\Booking');
}
}
class Booking extends Model
{
//Is Booking needed or I could make a pivot table like home_guest called 'bookings' ?
public function guests()
{
return $this->belongsToMany('App\Models\Guest', 'booking_guest', 'booking_id', 'guest_id');
}
}
Migrations:
Schema::create('bookings', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('home_id')->index();
$table->foreign('home_id')->references('id')->on('homes')->onDelete('cascade')->onUpdate('cascade');
$table->unsignedInteger('guest_id')->nullable()->index();
$table->foreign('guest_id')->references('id')->on('guests')->onDelete('cascade')->onUpdate('cascade');
$table->timestamps();
});
Schema::create('homes', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('host_id')->index();
$table->foreign('host_id')->references('id')->on('hosts')->onDelete('cascade')->onUpdate('cascade');
$table->string('fullAddress')->unique();
$table->integer('rooms')->unique();
$table->timestamps();
});
Schema::create('guests', function (Blueprint $table) {
$table->increments('id');
$table->string('fullName')->unique();
$table->string('identificationType')->unique();
$table->text('country')->nullable();
$table->timestamps();
});

How to handle user likes another user logic in Laravel?

I would like to build 'likes' functionality in my app where one user (user1) can like another user (user2), and then if user2 likes back user1 they would match. What is the best way to implement that kind of logic? My current idea is something like this.
users_table
public function up()
{
Schema::create('users', function(Blueprint $table)
{
$table->increments('id');
$table->string('email');
$table->string('first_name');
$table->string('last_name');
$table->string('password', 60);
$table->rememberToken()->nullable();
$table->timestamps();
});
}
likes_users_table
public function up()
{
Schema::create('likes_users', function(Blueprint $table)
{
$table->integer('liked_user_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('liked_user_id')->references('id')->on('users');
$table->primary(array('user_id', 'liked_user_id'));
});
}
User.php
public function likes()
{
return $this->belongsToMany('User', 'likes_users', 'user_id', 'liked_user_id');
}
UserController.php
public function getIndex()
{
$not_friends = User::where('id', '!=', Auth::user()->id);
if (Auth::user()->likes->count()) {
$not_friends->whereNotIn('id', Auth::user()->likes->modelKeys());
}
$not_friends = $not_friends->get();
return View::make('dashboard.index')->with('not_friends', $not_friends);
}
public function add(User $user)
{
$user->likes()->attach($user->id);
}
public function store($id)
{
$user = User::find($id);
Auth::user()->add($user);
return Redirect::back();
}
This is a quick solution. There could be a more efficient way to accomplish this. Suggestions welcome.
My idea is to set a is_mutual flag for user likes. If the users like each other the is_mutual flag will be set.
Let's start with the migration.
Create user_likes table.
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('user_likes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id')->comment('user who liked this');
$table->unsignedBigInteger('liked_user_id')->comment('user whom this liked');
$table->boolean('is_mutual')->default(false)->comment('is users like each other');
$table->timestamps();
$table->softDeletes();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('liked_user_id')->references('id')->on('users');
});
}
Then, I have updated my User model to add the following relations
public function likedUsers()
{
return $this->belongsToMany('App\User', 'user_likes', 'user_id', 'liked_user_id');
}
public function mutualFriends()
{
return $this->belongsToMany('App\User', 'user_likes', 'user_id', 'liked_user_id')
->where('is_mutual',1);
}
Now Let's create a controller to handle the User Likes logic.
public function storeUserLikes(Request $request)
{
$user = Auth::user(); // Take the currently authenticated user
// Ofcourse, you should validate the $request
$likedUser = $request->likedUser;
// Let's findout if the other user already likes the current user
$isLikedAlready = UserLike::where([
'user_id' => $likedUser,
'liked_user_id' => $user->id,
])
->first();
// Store the user like record in the db
UserLike::create([
'user_id' => $user->id,
'liked_user_id' => $likedUser,
'is_mutual' => $isLikedAlready ? true : false
]);
// If the other user already likes the current user,
// they are a mutual connection.
// Update the row accordingly
if ($isLikedAlready) {
$isLikedAlready->is_mutual = true;
$isLikedAlready->save();
}
// Done! Now show a proper response to the User.
// I am leaving it to you :-)
}
Now, let's add the routes
Auth::routes();
Route::group(['prefix' => 'user', 'middleware' => 'auth'], function ($router) {
$router->get('/like-user/{likedUser}', ['uses' => 'UserLikesController#storeUserLikes']);
});
Now, add some users to your database (for testing). Refer Laravel database seeding and factory for more details.
How it works
The logged-in user can go to DOMAIN/user/like-user/x to like a user.
Where x is the id of the User to be liked.
Note: I have added a get route for ease. You can use POST/GET methods of your choice.
Now, Let's find a list of mutual friends from the DB
Add a function to the UserLikes controller.
/**
* This function will return a JSON Response with mutually liked users
* for the current logged in user.
**/
public function listLikedUsers()
{
$user = Auth::user();
return response()->json([
'status' => true,
'data' => $user->mutualFriends()->get()
]);
}
Now add a route for getting the mutually liked users. Just below the current route add the following GET route
$router->get('/likes', ['uses' => 'UserLikesController#listLikedUsers']);
You can have a pivot boolean column (is_liked_back) in likes_users table. In this way you will only have one entry for likes getting from either side.

How to cache and find first match in pivot table withing laravel collections?

I have these tables
User
role
user_roles
In user_roles table there are following fields
start_date
end_date
is_active
How can I read all active and not expired roles if current user and put them in cache for one hour?
Is there any way clean cache on one role deactivation?
The relationship is not defined correctly. This should be like the following:
User model
class User {
public function roles() {
return $this->hasMany(App\Role::class);
}
}
Role model
class Role {
public function users() {
return $this->hasMany(App\User::class);
}
}
Now create the appropriate pivot table to deal with this relationship
role_user schema
Schema::create('role_user', function(Blueprint $table){
$table->increments('id');
$table->integer('role_id')->unsigned();
$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
$table->integer('role_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamp('start_date');
$table->timestamp('end_date');
$table->integer('is_active')->default(0); //change to 1 if you want always to be active
});
Now modify our User class and add ->withPivot('start_date', 'end_date', 'is_active'); to our roles() relationship.
Updated User model
class User {
public function roles() {
return $this->hasMany('App\Role::class')->withPivot('start_date', 'end_date', 'is_active');
}
}
But wait, this doesn't get me active roles for my user?! No problem, let's do that with a query scope.
class User {
//...
public function scopeOnlyActiveRoles ($query) {
return $query->whereHas('roles', function($query){
return $query->where('start_date', '>=', Carbon::now())
->where('end_date', '<=', Carbon::now())
->where('is_active', 1);
});
}
}

Laravel belongsToMany only works one way

I'm trying to make a many to many relation, in this example with user and role.
In User model I got this:
public function roles()
{
return $this->belongsToMany('App\Role', 'user_role', 'user_id', 'role_id');
}
In Role model I got this:
public function users()
{
return $this->belongsToMany('App\User', 'user_role', 'role_id', 'user_id');
}
And my pivot table user_role:
public function up()
{
Schema::create('user_role', function(Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('role_id')->unsigned();
$table->timestamps();
$table->foreign('role_id')->references('id')->on('roles');
$table->foreign('user_id')->references('id')->on('users');
});
}
Now when I do $user->roles()->attach(1); it makes a row in the user_role table. But the problem is when I want to access it: $user->roles; it returns nothing. It works with $role->users; but not the other way. What am I doing wrong?
Solved : Laravel 5.2.29
make sure the table name is role_user
$user = User::find(1);
$role = Role::find(2);
// In this example I am passing in a Role object but $role->id also works
$user->roles()->attach($role);
Hope this works for you.
You have to reload the relationship after attaching like so
$user->roles()->attach($role);
$user->load('roles');

Laravel 5.1 Multiple Many to Many Relationship on the Same Model

I seen to of got tangled in Laravel's ORM with the following:
Scenerio: All Users have a Watchlist, the Watchlist contains other Users.
I can't seem the get the relationships to work correctly as they are cyclical, so far I have the following:
class UserWatchlist extends Model
{
protected $table = 'UserWatchlist';
public function Owner() {
return $this->belongsTo('App\User');
}
public function WatchedUsers() {
return $this->hasMany('App\User');
}
}
Schema::create('UserWatchlist', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('Users')->onDelete('cascade');
$table->integer('watched_id')->unsigned();
$table->foreign('watched_id')->references('id')->on('Users')->onDelete('cascade');
$table->timestamps();
});
class User extends Model
{
public function Watchlist() {
return $this->hasOne('App\UserWatchlist');
}
public function WatchedBy() {
return $this->belongsToMany('App\UserWatchlist');
}
}
It is not pulling through the correct in formation i'm expecting. Am I missing something fundamental?
Since UserWatchlist is a pivot table, i suppose you are facing a many to many relationship with both the elements of the relation being the same model (User)
If that is the case, you should not build a model for the pivot table UserWatchlist but all you have to do is to set the relation between the users through the pivot table:
class User extends Model
{
//get all the Users this user is watching
public function Watchlist()
{
return $this->belongsToMany('User', 'UserWatchlist', 'user_id', 'watched_id' );
}
//get all the Users this user is watched by
public function WatchedBy()
{
return $this->belongsToMany('User', 'UserWatchlist', 'watched_id', 'user_id' );
}
}
Check here for more info on many-to-many relationship

Categories