Installation:
Replace "sonata-project/user-bundle": "^4.1" with "runroom/user-bundle": "4.x-dev" in composer.json and run:
composer update runroom/user-bundle
Enable the Bundle:
Add to config/bundles.php:
Runroom\UserBundle\SonataUserBundle::class => ['all' => true],
Database Setup:
Run migrations (adjust User entity namespace if needed):
php bin/console doctrine:schema:update --force
First Use Case:
Create a basic user registration form by extending SonataUserBundle's controllers or using its built-in CRUD:
php bin/console generate:sonata:crud User
config/packages/sonata_user.yaml (auto-generated after setup).src/Entity/User.php (default user model).templates/SonataUserBundle/ (override defaults in templates/).config/routes/sonata_user.yaml (customize routes if needed)./register). Customize via:
# config/packages/sonata_user.yaml
sonata_user:
registration:
form:
type: App\Form\RegistrationType # Extend Sonata\UserBundle\Form\Type\RegistrationType
login.html.twig) or extend SonataUserBundle:Security:login route.php bin/console generate:sonata:admin User
Customize fields in src/Admin/UserAdmin.php:
protected function configureListFields(ListMapper $listMapper) {
$listMapper->add('username');
$listMapper->add('email');
}
profile route or build a custom controller:
// src/Controller/UserController.php
public function showProfile(User $user) {
return $this->render('user/profile.html.twig', ['user' => $user]);
}
User entity to add custom role fields:
// src/Entity/User.php
/**
* @ORM\Column(type="json")
*/
private $customRoles = [];
Update UserManager to handle serialization:
// src/Service/UserManager.php
public function setCustomRoles(User $user, array $roles) {
$user->setCustomRoles($roles);
$this->em->persist($user);
$this->em->flush();
}
sonata_user:
class:
user: FOS\UserBundle\Entity\User # Point to FOS User entity
# config/packages/api_platform.yaml
resources:
App\Entity\User:
collectionOperations:
get:
method: GET
path: /api/users
Template Overrides:
Copy templates from vendor/runroom/user-bundle/templates/ to templates/SonataUserBundle/ to avoid updates overwriting changes.
Event Listeners:
Use Sonata’s events (e.g., sonata.user.register) for custom logic:
// src/EventListener/UserListener.php
public function onUserRegister(UserEvent $event) {
$user = $event->getUser();
// Add logic (e.g., send welcome email)
}
Register in services.yaml:
services:
App\EventListener\UserListener:
tags:
- { name: kernel.event_listener, event: sonata.user.register, method: onUserRegister }
Testing:
Use Symfony’s WebTestCase for user-related tests:
public function testRegistration() {
$client = static::createClient();
$crawler = $client->request('GET', '/register');
// Assert form fields, submit, etc.
}
PHP Version Quirks:
array_column() instead of ArrayObject methods.createFunction()). Patch via:
// In a custom UserManager
public function createUser() {
$user = new User();
$user->setEnabled(true); // Manually set defaults
return $user;
}
Doctrine Migrations:
doctrine:schema:update. Prefer migrations:
php bin/console make:migration
php bin/console doctrine:migrations:migrate
User, create a migration:
php bin/console make:entity User
# Add field (e.g., bio: string, 255)
php bin/console make:migration
Caching Issues:
php bin/console cache:clear
.env (APP_DEBUG=1) to see template errors.Route Conflicts:
/profile) may clash with custom routes. Use _sonata_admin prefix or customize:
# config/routes/sonata_user.yaml
sonata_user_profile:
path: /my-profile
defaults: { _controller: SonataUserBundle:Profile:show }
Symfony Profiler:
Enable in config/packages/dev/debug.yaml:
framework:
profiler: { only_exceptions: false }
Check the "Events" tab for sonata.user.* events.
Logging:
Add to config/packages/monolog.yaml:
handlers:
sonata:
type: stream
path: "%kernel.logs_dir%/sonata.log"
level: debug
channels: ["sonata"]
Log Sonata events in a listener:
$this->logger->debug('User registered', ['user' => $user->getId()]);
Common Errors:
Runroom\UserBundle is autoloaded (check composer dump-autoload).RegistrationType:
$builder->add('bio', TextType::class, [
'constraints' => [new Length(['max' => 500])],
]);
ROLE_USER is assigned in RegistrationType:
$user->addRole('ROLE_USER');
Custom User Fields:
Extend the User entity and update the UserManager:
// src/Entity/User.php
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $phoneNumber;
Add to RegistrationType:
$builder->add('phoneNumber', TextType::class);
Custom Validation: Use Symfony’s constraints:
// src/Entity/User.php
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @UniqueEntity(fields="phoneNumber", message="Phone number already taken")
*/
API Tokens:
Integrate with lexik/jwt-authentication-bundle:
sonata_user:
security:
handler:
jwt: true # Enable JWT for API auth
Multi-Tenancy:
Add tenantId to User and filter queries:
// src/Repository/UserRepository.php
public function findByTenant($tenantId) {
return $this->createQueryBuilder('u')
->where('u.tenantId = :tenantId')
->setParameter('tenantId', $tenantId)
How can I help you explore Laravel packages today?