symfony/doctrine-bridge
Symfony Doctrine Bridge integrates Doctrine with Symfony components, providing glue code for ORM/DBAL usage across the framework. Part of the main Symfony repository; report issues and submit pull requests there.
Installation:
composer require symfony/doctrine-bridge
This package is typically included as a dependency of symfony/framework-bundle, so explicit installation is rare unless extending functionality.
First Use Case:
@UniqueEntity or @Assert constraints in your Doctrine entities:
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[UniqueEntity(fields: ['email'], message: 'Email already taken')]
class User {}
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
$builder->add('user', EntityType::class, [
'class' => User::class,
'choice_label' => 'email',
]);
Where to Look First:
Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntitySymfony\Bridge\Doctrine\Form\Type\EntityTypeSymfony\Bridge\Doctrine\Security\User\EntityUserProvider#[ORM\Entity]
#[UniqueEntity('username')]
class User {
#[Assert\NotBlank]
#[Assert\Length(min: 3)]
private string $username;
}
Validator automatically checks these during form submission or manual validation.message parameter.$form = $this->createFormBuilder($user)
->add('name')
->add('email')
->getForm();
EntityType for entity selection fields.DataTransformer for complex mappings (e.g., JSON fields).FormEvent::SUBMIT listeners.use Symfony\Bridge\Doctrine\Security\User\EntityUserProvider;
$provider = new EntityUserProvider(
$entityManager,
User::class
);
UserInterface in your entity.security.yaml to use EntityUserProvider.loadUserByIdentifier().use Doctrine\ORM\Event\LifecycleEventArgs;
$eventManager->addEventListener(
\Doctrine\ORM\Events::prePersist,
fn(LifecycleEventArgs $args) => $args->getObject()->setCreatedAt(new \DateTime())
);
services.yaml or a bundle.EventDispatcher to trigger custom logic (e.g., logging, notifications).DatabaseTestCase for database-aware tests.
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class UserTest extends KernelTestCase {
public function testUserCreation() {
$user = new User();
$this->getEntityManager()->persist($user);
$this->getEntityManager()->flush();
$this->assertNotNull($user->getId());
}
}
KernelTestCase for full Symfony/Doctrine integration.getEntityManager() to interact with the database.Doctrine\DBAL\Types\Type and register in Symfony:
# config/packages/doctrine.yaml
doctrine:
dbal:
types:
json: App\Doctrine\DBAL\Types\JsonType
SchemaManager for migrations:
use Symfony\Bridge\Doctrine\ManagerRegistry;
$schemaManager = $registry->getManager()->getConnection()->createSchemaManager();
$schemaManager->createTable((new \Doctrine\DBAL\Schema\Table('users'))->addColumn('name', 'string'));
framework.yaml:
framework:
messenger:
transports:
doctrine: '%env(MESSENGER_DOCTRINE_DSN)%'
AbstractDoctrineExtension with standalone services:
// Before (deprecated)
class MyExtension extends AbstractDoctrineExtension {}
// After
class MyExtension {
public function __construct(private EntityManagerInterface $em) {}
}
EntityManager::clear() or configure doctrine.orm.enable_lazy_ghost_objects:
doctrine:
orm:
enable_lazy_ghost_objects: false
schema_filter may not apply in custom listeners (pre-v8.0.6).SchemaListener::getSchemaFilter() in listeners.UidType may fail with custom UID generators.UidFactory is properly configured in services.yaml.DataTransformerInterface with proper type hints.validator.errors in the response:
$errors = $validator->validate($entity);
foreach ($errors as $error) {
echo $error->getPropertyPath() . ': ' . $error->getMessage();
}
config/packages/dev/doctrine.yaml:
doctrine:
dbal:
logging: true
profiling: true
EventDispatcher::addListener() with a closure to inspect events:
$dispatcher->addListener(Events::prePersist, function($event) {
error_log('PrePersist: ' . $event->getObject()->getId());
});
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Doctrine\ORM\EntityManagerInterface;
class CustomValidator extends ConstraintValidator {
public function __construct(private EntityManagerInterface $em) {}
public function validate($value, Constraint $constraint) {
$query = $this->em->createQuery('SELECT COUNT(u) FROM App\Entity\User u WHERE u.email = :email');
$query->setParameter('email', $value);
if ($query->getSingleScalarResult() > 0) {
$this->context->buildViolation($constraint->message)
->addViolation();
}
}
}
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\Mapping\ClassMetadata;
$metadata = $em->getClassMetadata(User::class);
$form = $this->createFormBuilder($user)
->add('dynamicField', EntityType::class, [
'class' => $metadata->getAssociationMappings()['role']['targetEntity'],
]);
Doctrine\Common\EventSubscriber for cross-cutting concerns:
use Doctrine\
How can I help you explore Laravel packages today?