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

Doctrine Types Bundle Laravel Package

besimple/doctrine-types-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation Add the bundle via Composer:

    composer require besimple/doctrine-types-bundle
    

    Enable the bundle in config/bundles.php:

    return [
        // ...
        BeSimple\DoctrineTypesBundle\BeSimpleDoctrineTypesBundle::class => ['all' => true],
    ];
    
  2. Basic Usage Register a custom Doctrine type in config/packages/besimple_doctrine_types.yaml:

    besimple_doctrine_types:
        types:
            custom_type:
                class: App\Doctrine\DBAL\Types\CustomType
                mapping_type: string
                mapped_by: ['custom_type']
    
  3. First Use Case Create a custom Doctrine DBAL type (e.g., App\Doctrine\DBAL\Types\CustomType) extending Doctrine\DBAL\Types\Type:

    namespace App\Doctrine\DBAL\Types;
    
    use Doctrine\DBAL\Types\Type;
    use Doctrine\DBAL\Platforms\AbstractPlatform;
    
    class CustomType extends Type
    {
        const NAME = 'custom_type';
    
        public function getSQLDeclaration(array $column, AbstractPlatform $platform)
        {
            return 'TEXT'; // Example: Store as TEXT in DB
        }
    
        public function convertToPHPValue($value, AbstractPlatform $platform)
        {
            return json_decode($value, true); // Example: Convert JSON to array
        }
    
        public function convertToDatabaseValue($value, AbstractPlatform $platform)
        {
            return json_encode($value); // Example: Convert array to JSON
        }
    
        public function getName()
        {
            return self::NAME;
        }
    
        public function requiresSQLCommentHint(AbstractPlatform $platform)
        {
            return true;
        }
    }
    
  4. Apply to Entity Use the type in an entity field:

    use Doctrine\ORM\Mapping as ORM;
    use BeSimple\DoctrineTypesBundle\Annotation as DoctrineTypes;
    
    /**
     * @ORM\Entity
     */
    class MyEntity
    {
        /**
         * @ORM\Column(type="custom_type")
         * @DoctrineTypes\Type("custom_type")
         */
        private $customData;
    }
    

Implementation Patterns

Usage Patterns

  1. Type Registration

    • Register types in besimple_doctrine_types.yaml for centralized management.
    • Use annotations (@DoctrineTypes\Type) or XML/YAML configurations for entity mapping.
  2. Platform-Specific Logic Override getSQLDeclaration() to handle platform-specific SQL (e.g., MySQL, PostgreSQL):

    public function getSQLDeclaration(array $column, AbstractPlatform $platform)
    {
        return $platform->getJsonTypeDeclarationSQL($column);
    }
    
  3. Serialization/Deserialization Implement convertToPHPValue() and convertToDatabaseValue() for seamless data conversion:

    // Example: Convert JSON string to object
    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        return $value ? json_decode($value) : null;
    }
    
  4. Query Builder Integration Use custom types in DQL or QueryBuilder:

    $query = $entityManager->createQuery(
        'SELECT e FROM App\Entity\MyEntity e WHERE e.customData = :data'
    );
    $query->setParameter('data', $customValue);
    

Workflows

  1. Development Workflow

    • Start with simple types (e.g., JSON, enum) before complex custom logic.
    • Test types with doctrine:schema:validate and doctrine:schema:update.
  2. Migration Strategy

    • Use doctrine:migrations:diff to generate migrations for new types.
    • Handle backward compatibility by supporting multiple SQL declarations.
  3. Testing

    • Test types with Doctrine\DBAL\Driver\PDOSqlite\Driver for isolation.
    • Mock AbstractPlatform for unit tests:
      $platform = $this->createMock(AbstractPlatform::class);
      $platform->method('getJsonTypeDeclarationSQL')->willReturn('JSON');
      

Integration Tips

  1. Symfony Forms Use DataTransformer to handle custom type rendering:

    use Symfony\Component\Form\DataTransformerInterface;
    
    class CustomTypeTransformer implements DataTransformerInterface
    {
        public function transform($value)
        {
            return json_encode($value);
        }
    
        public function reverseTransform($value)
        {
            return json_decode($value, true);
        }
    }
    
  2. API Platform Configure serialization groups in api_platform.metadata.yaml:

    resources:
        App\Entity\MyEntity:
            properties:
                customData:
                    serialization_context:
                        groups: ['api']
    
  3. Event Listeners Attach listeners to prePersist/preUpdate for pre-processing:

    $entityManager->getEventManager()->addEventListener(
        'prePersist',
        function ($entity) {
            if ($entity instanceof MyEntity) {
                $entity->setCustomData(json_encode($entity->getCustomData()));
            }
        }
    );
    

Gotchas and Tips

Pitfalls

  1. Caching Issues

    • Clear Doctrine cache (php bin/console cache:clear) after adding new types.
    • Ensure requiresSQLCommentHint() returns true for custom types to avoid caching conflicts.
  2. Platform Incompatibility

    • Test types across databases (e.g., MySQL, PostgreSQL). Some features (e.g., JSON) may not be supported everywhere.
    • Fallback to TEXT or STRING if platform-specific types fail:
      public function getSQLDeclaration(array $column, AbstractPlatform $platform)
      {
          return $platform->getClobTypeDeclarationSQL($column);
      }
      
  3. Annotation Conflicts

    • Avoid mixing @ORM\Column(type="...") with @DoctrineTypes\Type. Stick to one approach.
    • If using annotations, ensure the bundle is loaded early in the kernel.
  4. Serialization Errors

    • Handle json_decode errors gracefully:
      public function convertToPHPValue($value, AbstractPlatform $platform)
      {
          return $value ? json_decode($value, true) : null;
      }
      
  5. Migration Downtime

    • Custom types may break migrations if SQL declarations change. Use doctrine:schema:update --dump-sql to preview changes.

Debugging

  1. Enable SQL Logging Add to config/packages/dev/doctrine.yaml:

    dbal:
        logging: true
        logging_events: [connection, statement]
    
  2. Check Type Registration Verify types are registered via:

    php bin/console debug:doctrine-types
    
  3. Query Debugging Use Doctrine\DBAL\Logging\EchoSQLLogger to inspect generated SQL:

    $connection->getConfiguration()->setSQLLogger(new EchoSQLLogger());
    

Config Quirks

  1. YAML Configuration

    • Use mapping_type to define the base Doctrine type (e.g., string, integer).
    • mapped_by specifies which fields should use this type (e.g., ['json', 'custom_type']).
  2. Priority Order

    • Annotations (@DoctrineTypes\Type) override YAML configuration. Use YAML for global defaults.
  3. Autowiring Ensure custom type classes are autowired by placing them in src/Doctrine/DBAL/Types/.

Extension Points

  1. Custom Platform Support Extend AbstractPlatform to support new databases:

    class CustomPlatform extends AbstractPlatform
    {
        public function getCustomTypeDeclarationSQL(array $column)
        {
            return 'CUSTOM_TYPE';
        }
    }
    
  2. Dynamic Type Loading Load types dynamically via a compiler pass:

    use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    
    class LoadCustomTypesPass implements CompilerPassInterface
    {
        public function process(ContainerBuilder $container)
        {
            $definition = $container->findDefinition('besimple_doctrine_types.type_registry');
            $definition->addMethodCall('addType', [new Reference('custom_type')]);
        }
    }
    
  3. Hybrid Collections Combine custom types with Doctrine collections:

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Item", mappedBy="parent", fetch="EXTRA_LAZY")
     * @DoctrineTypes\Type("custom_type")
     */
    private $items;
    
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.
hamzi/corewatch
minionfactory/raw-hydrator
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