3slab/vdm-library-doctrine-orm-transport-bundle
Installation Require the package via Composer:
composer require 3slab/vdm-library-doctrine-orm-transport-bundle
Ensure your project uses Symfony Flex (recommended for Laravel-like workflows) or manually register the bundle in config/bundles.php if using Symfony.
Basic Setup
The package bridges Value Object (VDM) patterns with Doctrine ORM. Start by defining a Value Object (e.g., Email) and a Domain Model (e.g., User) that embeds it.
Example VDM class:
// src/ValueObject/Email.php
namespace App\ValueObject;
use Vdm\ValueObject;
class Email extends ValueObject
{
private string $email;
public function __construct(string $email)
{
$this->email = $email;
}
public function getEmail(): string
{
return $this->email;
}
}
First Use Case: Embedding VDMs in Entities
Use the transport bundle to map VDMs to Doctrine columns. Example User entity:
// src/Entity/User.php
namespace App\Entity;
use App\ValueObject\Email;
use Doctrine\ORM\Mapping as ORM;
use Vdm\ValueObject;
#[ORM\Entity]
class User
{
#[ORM\Embedded(class: Email::class, columnPrefix: false)]
private Email $email;
// Getters/setters...
}
Run migrations:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
[ORM\Embedded] to map VDMs to database columns.
#[ORM\Embedded(class: Address::class, columnPrefix: false)]
private Address $address;
columnPrefix: false avoids redundant column names (e.g., address_street → street).Address, Coordinates) in a parent VDM for cleaner mappings.class PhoneNumber extends ValueObject
{
public function __construct(string $number)
{
if (!preg_match('/^\+?[0-9]{10,15}$/', $number)) {
throw new \InvalidArgumentException('Invalid phone number');
}
$this->number = $number;
}
}
// src/Repository/UserRepository.php
namespace App\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class UserRepository extends ServiceEntityRepository
{
public function findByEmail(string $email): ?User
{
return $this->createQueryBuilder('u')
->where('u.email.email = :email')
->setParameter('email', $email)
->getQuery()
->getOneOrNullResult();
}
}
ValueObject::equals() for complex comparisons in queries.// src/DTO/UserDTO.php
namespace App\DTO;
class UserDTO
{
public function __construct(
public string $id,
public string $email, // From Email VDM
public string $address // From Address VDM
) {}
}
// src/EventListener/UserEmailListener.php
namespace App\EventListener;
use App\Entity\User;
use Doctrine\ORM\Event\LifecycleEventArgs;
class UserEmailListener
{
public function postUpdate(User $user, LifecycleEventArgs $args)
{
if ($user->getEmail()->isVerified() !== $user->wasEmailVerified()) {
// Dispatch event (e.g., send verification email)
}
}
}
services.yaml:
services:
App\EventListener\UserEmailListener:
tags: ['doctrine.event_listener', 'doctrine.orm.entity_listener']
[ORM\Embedded] requires VDMs to implement ValueObject and have a no-arg constructor (for hydration).
__construct() with default values or a custom hydrator.columnPrefix consistency.fetch="LAZY" for large datasets.
#[ORM\Embedded(class: LargeVDM::class, fetch="LAZY")]
private LargeVDM $data;
dd($entity->getEmail()->getEmail()) to inspect hydrated values.getEmail() → email column).public function testEmailValidation()
{
$this->expectException(\InvalidArgumentException::class);
new Email('invalid-email');
}
// src/DataFixtures/UserFixture.php
namespace App\DataFixtures;
use App\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
class UserFixture extends Fixture
{
public function load(ObjectManager $manager)
{
$user = new User();
$user->setEmail(new Email('test@example.com'));
$manager->persist($user);
$manager->flush();
}
}
// src/Hydrator/CustomVDMHydrator.php
namespace App\Hydrator;
use Doctrine\ORM\Mapping\ClassMetadata;
use Vdm\Hydrator\ValueObjectHydrator;
class CustomVDMHydrator extends ValueObjectHydrator
{
public function hydrate(ClassMetadata $metadata, $data, $object)
{
// Custom logic (e.g., parse JSON fields)
return parent::hydrate($metadata, $data, $object);
}
}
services:
App\Hydrator\CustomVDMHydrator:
tags: ['doctrine.orm.hydrator']
php bin/console doctrine:migrations:diff --env=laravel
// config/services.php
'entities' => [
App\Entity\User::class => \App\Entity\User::class,
];
composer require doctrine/orm:^3.0 --dev
How can I help you explore Laravel packages today?