## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require baks-dev/users-groups
php artisan vendor:publish --provider="BaksDev\UsersGroups\UsersGroupsServiceProvider" --tag="migrations"
php artisan migrate
php artisan baks:assets:install
First Use Case:
use BaksDev\UsersGroups\Entity\Role;
$adminRole = new Role();
$adminRole->setName('admin');
$adminRole->setDescription('Full access');
$em->persist($adminRole);
$em->flush();
$user->addRole($adminRole); // Assuming User entity has `addRole()` method
$em->flush();
Where to Look First:
src/Entity/ (e.g., User.php, Role.php, Group.php).src/Service/ (e.g., RoleService.php, GroupService.php).src/Repository/ for custom queries.src/Console/ for CLI utilities (e.g., baks:assets:install).Role-Based Access Control (RBAC):
if ($user->hasRole('admin')) {
// Grant access
}
$user->setRoles([$role1, $role2]); // Bulk assignment
Group Management:
$group = new Group();
$group->setName('Editors');
$group->addRole($editorRole);
$em->persist($group);
$group->addUser($user);
$em->flush();
Integration with Auth:
// In AuthServiceProvider.php
public function boot()
{
$this->registerPolicies();
$this->gate()->define('admin-access', function ($user) {
return $user->hasRole('admin');
});
}
Middleware for Role Checks:
namespace App\Http\Middleware;
use Closure;
use BaksDev\UsersGroups\Entity\UserInterface;
class CheckRole
{
public function handle($request, Closure $next, $role)
{
if (!$request->user() instanceof UserInterface || !$request->user()->hasRole($role)) {
abort(403);
}
return $next($request);
}
}
Register in app/Http/Kernel.php:
protected $routeMiddleware = [
'role' => \App\Http\Middleware\CheckRole::class,
];
Usage in routes:
Route::get('/admin', function () {})->middleware('role:admin');
Event Listeners:
// In EventServiceProvider.php
protected $listen = [
'BaksDev\UsersGroups\Event\RoleAssigned' => [
\App\Listeners\LogRoleAssignment::class,
],
];
$em->beginTransaction();
try {
$user->addRole($role);
$em->flush();
$em->commit();
} catch (\Exception $e) {
$em->rollBack();
throw $e;
}
N+1 queries by eager-loading roles/groups:
$user = $em->getRepository(User::class)->findOneBy(['id' => 1], ['roles' => 'join']);
$hasRole = cache()->remember("user_{$user->id}_roles", now()->addHours(1), function () use ($user) {
return $user->hasRole('admin');
});
Entity Manager Confusion:
EntityManager (e.g., Doctrine\ORM\EntityManagerInterface).EntityManager via constructor or use Doctrine\ORM\EntityManagerInterface from the service container.Circular Dependencies:
User and Role entities reference each other bidirectionally, configure orphanRemoval and cascade carefully in yaml/xml mappings to avoid stale data.# config/doctrine/orm/Entity/User.orm.yml
ManyToMany:
roles:
targetEntity: BaksDev\UsersGroups\Entity\Role
joinTable:
name: user_roles
joinColumns:
user_id:
referencedColumnName: id
inverseJoinColumns:
role_id:
referencedColumnName: id
orphanRemoval: true
cascade: ["persist"]
Migration Conflicts:
php artisan doctrine:migrations:diff
php artisan doctrine:migrations:migrate
--dry-run to preview changes:
php artisan doctrine:migrations:diff --dry-run
Permission Caching:
hasRole('admin')) if roles can change frequently. Use short TTL or invalidate cache on role updates.Asset Installation:
baks:assets:install command may overwrite existing files. Backup public/ before running it in production.Query Logging: Enable Doctrine logging to debug queries:
$em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
Or use Laravel’s built-in logging:
\DB::enableQueryLog();
$em->flush();
\DB::getQueryLog(); // Inspect queries
Event Debugging:
$dispatcher->addListener('*', function ($event) {
\Log::debug('Event:', [$event->getName(), $event->getSubject()]);
});
Role Assignment Issues:
Role entity should have a users collection).orm.xml/yaml.Custom Role Strategies:
BaksDev\UsersGroups\Service\RoleService to add custom logic (e.g., hierarchical roles):
class CustomRoleService extends RoleService
{
public function hasInheritedRole(UserInterface $user, string $roleName): bool
{
// Implement logic for role inheritance
}
}
config/services.php:
'role_service' => \App\Service\CustomRoleService::class,
Custom Groups:
Group entity or create a new entity that implements GroupInterface:
class TeamGroup implements GroupInterface
{
// Custom group logic
}
API Resources:
namespace App\Http\Resources;
use BaksDev\UsersGroups\Entity\User;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'roles' => $this->roles->map(fn($role) => $role->getName()),
];
}
}
Testing:
phpunit --group=users-groups
public function testUserHasRole()
{
$this->markTestSkipped('Example test for role assignment');
$user = new User();
$role = new Role();
$role->setName('test');
$user->addRole($role);
$this->assertTrue($user->hasRole('test'));
}
BaksDev\UsersGroups\UsersGroupsServiceProvider is registered in config/app.php under `How can I help you explore Laravel packages today?