Laravel User Roles recursive - laravel

I use Laravel with UserAuth and Roles. All works fine. Now I want to add many Roles.
The Roles Should be Recursive.
Schema::create('role_user', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unsignedBigInteger('role_id');
$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
});
Schema::create('role_role', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->unsignedBigInteger('parent_id');
$table->foreign('parent_id')->references('id')->on('roles')->onDelete('cascade');
$table->unsignedBigInteger('child_id');
$table->foreign('child_id')->references('id')->on('roles')->onDelete('cascade');
});
$user->roles(); give me all roles where the user is direct asigned.
Example:
User is in Role1 in role_user table
Role 1 is in Role 2 in role_role table
Role 2 is in Role 3 in role_role table
$user->roles(); Result is Role1.
$user->roles(); Result should contain Role1, Role2, Role3. Not as text. It should be an array
I've to manipulate
public function roles()
{
return $this->belongsToMany(Role::class);
}
But how?
Very Thanks.

You need to do a recursive relationship:
public function childrenRoles()
{
return $this->hasMany(Role::class, 'parent_id', 'id');
}
public function allChildrenRoles()
{
return $this->childrenRoles()->with('allChildrenRoles');
}
You can then access all your roles using
$role = Role::with('allChildrenRoles')->first();
$role->allChildrenRoles->first()->allChildrenRoles; // .. and so on

I've made my own Solutions and it works good.
Role.php:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
public function users()
{
return $this->belongsToMany(User::class);
}
public function belongsToUser(User $user,$int)
{
if ($this->hasUser($user)) {
return true;
}
$children = $this->childrenRoles();
if ($int > 10) {
return false;
}
foreach ($children->get() as $child)
{
if ($child->belongsToUser($user,$int+1)) {
return true;
}
}
return false;
}
public function childrenRoles()
{
return $this->belongsToMany(Role::class, 'role_role', 'child_id', 'parent_id');
}
public function hasUser(User $user)
{
return null !== $this->users()->where('user_id', $user->id)->first();
}
}
User.php
public function roles()
{
$r = Role::where('id','<>', 'null');
foreach ($r->get() as $role)
{
if (! $role->belongsToUser($this,0)) {
$r = $r->where('id', '<>', $role->id);
}
}
return $r->get();
}

Related

Need to save foreign key manually on belongsTo relationship with withDefault()?

it seems that I need to save the original model on the newly generated model in order to save the relation correctly.
I hope the below test case illustrates my problem:
// migrations
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->bigInteger('user_id')->nullable();
$table->timestamps();
});
//models
class User extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
class Post extends Model
{
public function user()
{
return $this->belongsTo(User::class)
->withDefault(['name' => 'Guest User']);
}
}
//test
public function test_foreign_key()
{
$post = factory(Post::class)->create();
$user = $post->user; // created from ->withDefault()
$user->save();
$this->assertNotNull($post->user);
$this->assertNotNull($post->user_id);
}
With additional association of the original model the test passes:
public function test_foreign_key_associates()
{
$post = factory(Post::class)->create();
$post->user->save();
$this->assertNotNull($post->user);
$post->user()->associate($post);
$this->assertNotNull($post->user_id);
}
edit: what I'm doing right now is the following for the withDefault relationship:
class Post extends Model
{
public function user()
{
return $this->belongsTo(User::class)
->withDefault(function (User $user, Post $post) {
$user->name = "Guest User";
$user->save();
$post->user_id = $user->id;
});
}
}

on cascade delete on many to many relationship in laravel

I had used many to many relationship.i have three table named:product,tag,productstag. in here I want whenever I am going to delete a product it will also delete the relationship it had on productstag table.
public function up()
{
Schema::create('productstags', function (Blueprint $table) {
$table->integer('product_id');
$table->integer('tag_id');
$table->primary(['product_id','tag_id']);
$table->timestamps();
});
}
as you can see I have used product_id and tag_id as the primary key.
so I can't use this
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->foreign('tag_id')->references('id')->on('products')->onDelete('cascade');
so what's the alternative?
on my product model
public function tags()
{
return $this->belongsToMany('App\Tag','productstags','product_id','tag_id')->withTimestamps();
}
on my tag model:
public function products()
{
return $this->belongsToMany('App\Product','Productstags','tag_id','product_id');
}
on my produduct destroy function:
public function destroy(Request $request,$id)
{
$product=Product::findOrFail($id);
if($request->file('image')==''){
$input=$request->except('photo_id');
}
else{
$input=$request->all();
unlink(public_path()."/images/".$product->image->name);
}
$product->delete($input);
Session::flash('deleted_user','the user has been deleted');
return redirect(route('product.index'));
}
It's not as pretty as cascade but you could override the delete method and do this:
public function delete(){
$this->name_of_the_relationship()->delete();
return parent::delete();
}

How to make a reflexive relationship in Laravel migration and model

I would like to have a table that has a one to many with itself. Eg: I have like a people table that can have many other people.This is how my code looks like:
public function up()
{
Schema::create('people', function (Blueprint $table) {
$table->string('id')->primary();//Here my PK is a string
$table->string('name');
$table->string('title')->nullable();
$table->string('parent_id');//Here is the foreign key of another person
$table->timestamps();
});
}
And in my Person.php model I have this:
public function people()
{
return $this->belongsTo('App\Person')->withDefault();
}
public function person()
{
return $this->hasMany('App\Person');
}
Take a look to this image:
In Person.php model:
public function parent()
{
return $this->belongsTo('App\Person', 'parent_id');
}
public function child()
{
return $this->hasMany('App\Person', 'parent_id');
}
Add parent_id in your migration and define relationship in you model
public function people()
{
return $this->belongsTo('App\Person')->withDefault();
}
public function person()
{
return $this->hasMany(self::class, 'parent_id');
}

Laravel 5.7 Relationship One To Many Columns

i have team and match table. All match information save on match table with two team, winner team, match time etc.
on match table i have three field team_1, team_2, winner_team
i want to relation those field with team table
Here is my code
Team Model
class Team extends Model
{
public function league()
{
return $this->belongsTo('App\League');
}
public function matchs()
{
return $this->hasMany('App\Match');
}
}
Match Model
class Match extends Model
{
public function team_1()
{
return $this->belongsTo('App\Team','id');
}
public function team_2()
{
return $this->belongsTo('App\Team','team_2');
}
public function winner()
{
return $this->belongsTo('App\Team','winner');
}
public function league()
{
return $this->belongsTo('App\League');
}
public function teams() {
return $this->team_1()->merge($this->team_2());
}
}
Migration File
Schema::create('matches', function (Blueprint $table) {
$table->increments('id');
$table->integer('team_1')->unsigned()->index();
$table->integer('team_2')->unsigned()->index();
$table->integer('league_id')->unsigned()->index();
$table->integer('winner')->nullable();
$table->dateTime('match_time');
$table->timestamps();
$table->foreign('team_1')->references('id')->on('teams')
->onDelete('restrict')
->onUpdate('cascade');
$table->foreign('team_2')->references('id')->on('teams')
->onDelete('restrict')
->onUpdate('cascade');
$table->foreign('league_id')->references('id')->on('leagues')
->onDelete('restrict')
->onUpdate('cascade');
$table->foreign('winner')->references('id')->on('teams')
->onDelete('restrict')
->onUpdate('cascade');
});
public function team_1()
{
return $this->belongsTo('App\Team', 'team_1');
}
public function team_2()
{
return $this->belongsTo('App\Team', 'team_2');
}

One to Many Relationship not working on Laravel

I have three models that are related. First I have User that belongs to a Role. On the other hand, Role has many roles. Role belongs to many permissions and Permissions belongs to many Role. I am using the AuthServiceProvider as suggested by jeffrey way . However, when I'm fetching all the permissions of a User I am having error which is, "Call to a member function getKey() on boolean". Can someone please help me on this. Please refer to the codes below.
User.php
public function role()
{
return $this->belongsTo('App\Role');
}
public function assignRole($role)
{
return $this->roles()->save(
Role::whereName($role)->firstOrFail()
);
}
public function hasRole($role)
{
if(is_string($role)){
return $this->role->contains('name', $role);
}
return !! $role->intersect($this->role)->count();
}
Role.php
class Role extends Model
{
public function users()
{
return $this->hasMany('App\User');
}
public function permissions()
{
return $this->belongsToMany('App\Permission');
}
public function givePermissions(Permission $permission)
{
return $this->permissions()->save($permission);
}
}
Permission.php
class Permission extends Model
{
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
AuthServiceProvider
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
//get all permissions
foreach ($this->getPermissionTo() as $permission ) {
$gate->define($permission->name, function($user) use ($permission){
return $user->hasRole($permission->roles);
});
}
}
public function getPermissionTo()
{
return Permission::with('roles')->get();
}
and lastly, heres the user table that has a foreign key of role_id
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->integer('role_id')->unsigned();
$table->string('id_no')->unique()->index();
$table->string('u_first_name');
$table->string('u_middle_name');
$table->string('u_last_name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});

Resources