php - Laravel filtering users with categories associeted in BelongsToMany
Get the solution ↓↓↓in our application each category and user can associate with together.
each category can associate with one or many users and each user can associate with one or many categories
for example you suppose we have this category structure:
application
web
php
laravel
lumen
web_design
html
css
js
mobile
java
flutter
in this structure each category can be have one or many child which we usedparent_id
in database structure to implementing them.
now, each one of this categories or some of categories associated with one or many user, for example:
application (Alfred)
web (Alfred)
php (Alfred)
laravel (Alfred)
lumen (Alfred)
web_design (Alfred)
html (Alfred)
css (Alfred)
js (Alfred)
mobile (Alfred)
java (Alfred)
flutter (Alfred)
all categories in this structure associated with this user:(Alfred)
and each category can be associated with another user, for example:
application (Alfred)
web (Alfred)
php (Alfred,Ella)
laravel (Alfred,Ella)
lumen (Alfred,Ella)
web_design (Alfred,Elizabeth)
html (Alfred,Elizabeth)
css (Alfred,Elizabeth)
js (Alfred,Elizabeth)
mobile (Alfred,Jack)
java (Alfred,Jack)
flutter (Alfred,Jack)
or in the another word you can suppose we have this structure:
application (Alfred)
web (Alfred)
php (Alfred, Ella)
laravel (Alfred, Ella)
lumen (Alfred,Ella ,Linda)
web_design (Alfred, Elizabeth)
html (Alfred,Elizabeth)
css (Alfred,Elizabeth)
js (Alfred,Elizabeth, Scarlett)
mobile (Alfred, Jack)
java (Alfred, Jack)
flutter (Alfred, Jack, Jim)
this users areBelongsToMany
withRole
, which we synced them into database
- Alfred : is-portal-manager
- Ella : is-manager
- Elizabeth : is-manager
- Jack : is-editor
- Scarlett : is-writer
- Jim : is-writer
we usedcategory_user
table to sync this structure to associating categories and users
then we have five table:users
,categories
,roles
and middle tables:category_user
androle_user
migrations
database and tables:
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->nullable()->constrained();
$table->string('name');
$table->string('family');
$table->string('username');
//...
});
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('parent_id')->nullable();
$table->string('name');
//...
});
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('label');
$table->timestamps();
});
Schema::create('category_user', function (Blueprint $table) {
$table->foreignId('category_id')->constrained()->onDelete('cascade');
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->primary(['category_id', 'user_id']);
});
Schema::create('role_user', function (Blueprint $table) {
$table->foreignId('role_id')->constrained()->onDelete('cascade');
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->primary(['role_id', 'user_id']);
});
in the end, whats our problem:
we want to get logged user's categories which associated and defined withcategory_user
table, that means whenAlfred
logging into system should be have all categories that associated with them.(one or many of categories), another users should be have the same strategy,
- Alfred : is-portal-manager (ALL CATEGORY WITH SUB CATEGORIES: application,web,php,laravel,lumen,web_design,html,css,js,mobile,java,flutter)
- Ella : is-manager (php,laravel,lumen)
- Elizabeth : is-manager (web_design,html,css,js)
- Jack : is-editor (mobile,java,flutter)
- Scarlett : is-writer (js)
- Jim : is-writer (flutter)
COMPLETE STRUCTURE:
application (Alfred: is-portal-manager)
web (Alfred: is-portal-manager)
php (Alfred: is-portal-manager, Ella: is-manager)
laravel (Alfred: is-portal-manager, Ella: is-manager)
lumen (Alfred: is-portal-manager,Ella: is-manager ,Linda)
web_design (Alfred: is-portal-manager, Elizabeth: is-manager)
html (Alfred: is-portal-manager,Elizabeth: is-manager)
css (Alfred: is-portal-manager,Elizabeth: is-manager)
js (Alfred: is-portal-manager,Elizabeth: is-manager, Scarlett: is-writer)
mobile (Alfred: is-portal-manager, Jack: is-editor)
java (Alfred: is-portal-manager, Jack: is-editor)
flutter (Alfred: is-portal-manager, Jack: is-editor, Jim: is-writer)
Models:
class Category extends Model
{
public function parent(): BelongsTo
{
return $this->belongsTo(Category::class, 'parent_id', 'id', 'parent');
}
public function subcategories(): HasMany
{
return $this->hasMany(Category::class, 'parent_id', 'id');
}
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class);
}
}
class Role extends Model
{
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class);
}
}
class User extends Authenticatable
{
use Notifiable;
/**
* Get the parent User to which the current User belongs.
*/
public function parent(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get all Users which belong to the current User.
*/
public function kids(): HasMany
{
return $this->hasMany(User::class);
}
public function categories(): BelongsToMany
{
$categories = $this->belongsToMany(Category::class);
return $categories;
}
/**
* Determine whether the current user has prime Role of Portal Manager.
*/
public function isPortalManager(): Boolean
{
return $this->roles->contains('label', 'is-portal-manager');
}
/**
* Determine whether the current user has prime Role of Manager.
*/
public function isManager(): Boolean
{
return $this->roles->contains('label', 'is-manager');
}
/**
* Determine whether the current user has prime Role of Editor.
*/
public function isEditor()
{
return $this->roles->contains('label', 'is-editor');
}
/**
* Determine whether the current user has prime Role of Writer.
*/
public function isWriter()
{
return $this->roles->contains('label', 'is-writer');
}
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}
/**
* Determine whether current User has the given role.
* Given role can be a Role object or string or int
*
* @param Role|string|int $role
* @return boolean
*/
public function hasRole($role)
{
//dd('a');
/** When $role is an object of class Role */
if ($role instanceof Role) {
return !!$role->intersect($this->roles)->count();
}
/** When $role is an integer */
if (is_int(($role))) {
return $this->roles->contains('id', $role);
}
/**
* When $role is string
* - Check against id (in case id is uuid stored as string)
* - Check against name
* - Check against label
*/
if (is_string($role)) {
return !!(
$this->roles->contains('id', $role) ||
$this->roles->contains('name', $role) ||
$this->roles->contains('label', $role)
);
}
}
public function hasRoleByName($role)
{
if ($role == null) {
return false;
}
if (is_string($role)) {
return $this->roles->contains('name', $role) || $this->roles->contains('label', $role);
} else {
return !!$role->intersect($this->roles)->count();
}
}
}
we want to get all categories (one or many) for each user like with this code:
$user = User::find(1);
return $user->categoires();
Answer
Solution:
You can try the following trait
namespace App\Concerns;
use App\Models\Category;
use Illuminate\Database\Eloquent\Collection;
trait HasCategories
{
/**
* Get all Categories associated with the User in nested tree structure
*/
public function availableCategories(): Collection
{
$categories = $this->categories;
$parents = $categories->filter(fn($cat) =>
!in_array($cat->parent_id, $categories->pluck('id')->all()) || is_null($cat->parent_id)
);
$parents->map(fn($parent) => $this->setNested($parent, $categories));
return $parents;
}
/**
* Set the nested structure for the given $parent with relation.
*/
protected function setNested($parent, $categories)
{
$parent->setRelation('subcategories', $categories->where('parent_id', $parent->id));
$parent->subcategories->map(function($sub) use($categories){
if($categories->contains('parent_id', $sub->id)) {
$this->setNested($sub, $categories);
}
return $sub;
});
return $parent;
}
}
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: your lock file does not contain a compatible set of packages. please run composer update.
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.