besimple/doctrine-types-bundle
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],
];
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']
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;
}
}
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;
}
Type Registration
besimple_doctrine_types.yaml for centralized management.@DoctrineTypes\Type) or XML/YAML configurations for entity mapping.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);
}
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;
}
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);
Development Workflow
doctrine:schema:validate and doctrine:schema:update.Migration Strategy
doctrine:migrations:diff to generate migrations for new types.Testing
Doctrine\DBAL\Driver\PDOSqlite\Driver for isolation.AbstractPlatform for unit tests:
$platform = $this->createMock(AbstractPlatform::class);
$platform->method('getJsonTypeDeclarationSQL')->willReturn('JSON');
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);
}
}
API Platform
Configure serialization groups in api_platform.metadata.yaml:
resources:
App\Entity\MyEntity:
properties:
customData:
serialization_context:
groups: ['api']
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()));
}
}
);
Caching Issues
php bin/console cache:clear) after adding new types.requiresSQLCommentHint() returns true for custom types to avoid caching conflicts.Platform Incompatibility
MySQL, PostgreSQL). Some features (e.g., JSON) may not be supported everywhere.TEXT or STRING if platform-specific types fail:
public function getSQLDeclaration(array $column, AbstractPlatform $platform)
{
return $platform->getClobTypeDeclarationSQL($column);
}
Annotation Conflicts
@ORM\Column(type="...") with @DoctrineTypes\Type. Stick to one approach.Serialization Errors
json_decode errors gracefully:
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return $value ? json_decode($value, true) : null;
}
Migration Downtime
doctrine:schema:update --dump-sql to preview changes.Enable SQL Logging
Add to config/packages/dev/doctrine.yaml:
dbal:
logging: true
logging_events: [connection, statement]
Check Type Registration Verify types are registered via:
php bin/console debug:doctrine-types
Query Debugging
Use Doctrine\DBAL\Logging\EchoSQLLogger to inspect generated SQL:
$connection->getConfiguration()->setSQLLogger(new EchoSQLLogger());
YAML Configuration
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']).Priority Order
@DoctrineTypes\Type) override YAML configuration. Use YAML for global defaults.Autowiring
Ensure custom type classes are autowired by placing them in src/Doctrine/DBAL/Types/.
Custom Platform Support
Extend AbstractPlatform to support new databases:
class CustomPlatform extends AbstractPlatform
{
public function getCustomTypeDeclarationSQL(array $column)
{
return 'CUSTOM_TYPE';
}
}
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')]);
}
}
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;
How can I help you explore Laravel packages today?