Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Vdm Library Doctrine Orm Transport Bundle Laravel Package

3slab/vdm-library-doctrine-orm-transport-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

First Steps

  1. 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.

  2. 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;
        }
    }
    
  3. 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
    

Implementation Patterns

1. VDM Embedding in Entities

  • Pattern: Use [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_streetstreet).
    • Tip: Group related VDMs (e.g., Address, Coordinates) in a parent VDM for cleaner mappings.

2. Type Safety with VDMs

  • Pattern: Enforce invariants in VDM constructors to ensure data integrity.
    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;
        }
    }
    
    • Laravel Integration: Use Laravel’s Form Requests to validate VDM inputs before persistence.

3. Repository Integration

  • Pattern: Extend Doctrine repositories to query VDM-embedded fields.
    // 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();
        }
    }
    
    • Tip: Use ValueObject::equals() for complex comparisons in queries.

4. DTOs for API Responses

  • Pattern: Convert entities with VDMs to DTOs for API responses.
    // 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
        ) {}
    }
    
    • Laravel Tip: Use Fractal or Spatie’s Laravel Data Transfer Objects to transform entities.

5. Event-Driven Workflows

  • Pattern: Trigger events when VDMs change (e.g., email verification).
    // 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)
            }
        }
    }
    
    • Register in services.yaml:
      services:
          App\EventListener\UserEmailListener:
              tags: ['doctrine.event_listener', 'doctrine.orm.entity_listener']
      

Gotchas and Tips

1. Doctrine Mapping Pitfalls

  • Gotcha: [ORM\Embedded] requires VDMs to implement ValueObject and have a no-arg constructor (for hydration).
    • Fix: Use __construct() with default values or a custom hydrator.
  • Tip: For nested VDMs, ensure all embedded classes are mapped with columnPrefix consistency.

2. Performance Considerations

  • Gotcha: Eager-loading VDMs can bloat queries. Use fetch="LAZY" for large datasets.
    #[ORM\Embedded(class: LargeVDM::class, fetch="LAZY")]
    private LargeVDM $data;
    
  • Tip: Denormalize frequently accessed VDM fields into separate columns if performance is critical.

3. Debugging VDM Hydration

  • Gotcha: Doctrine may fail to hydrate VDMs if column names don’t match getter/setter methods.
    • Debug: Use dd($entity->getEmail()->getEmail()) to inspect hydrated values.
    • Fix: Ensure VDM properties match Doctrine’s naming conventions (e.g., getEmail()email column).

4. Testing Strategies

  • Tip: Test VDM invariants in isolation:
    public function testEmailValidation()
    {
        $this->expectException(\InvalidArgumentException::class);
        new Email('invalid-email');
    }
    
  • Tip: Use Doctrine’s ORM fixtures to seed test data with VDMs:
    // 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();
        }
    }
    

5. Extending the Bundle

  • Extension Point: Override the default hydrator for custom VDM logic:
    // 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);
        }
    }
    
    • Register as a service:
      services:
          App\Hydrator\CustomVDMHydrator:
              tags: ['doctrine.orm.hydrator']
      

6. Laravel-Specific Quirks

  • Gotcha: Laravel’s Eloquent and Doctrine ORM can conflict. Use DoctrineBundle alongside Laravel Doctrine Bridge if needed.
  • Tip: For Laravel migrations, generate them via Doctrine:
    php bin/console doctrine:migrations:diff --env=laravel
    
  • Tip: Use Laravel’s Service Container to bind Doctrine entities:
    // config/services.php
    'entities' => [
        App\Entity\User::class => \App\Entity\User::class,
    ];
    

7. Versioning and Maintenance

  • Gotcha: The package is abandoned (last release: 2020). Fork or patch if critical bugs arise.
  • Tip: Monitor for Doctrine ORM 3.x compatibility issues. Test with:
    composer require doctrine/orm:^3.0 --dev
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai