atournayre/doctrine-types-bundle
Installation:
composer require atournayre/doctrine-types-bundle
Register the bundle in config/bundles.php:
Atournayre\Bundle\DoctrineTypes\AtournayreDoctrineTypesBundle::class => ['all' => true],
First Use Case:
Define a custom Doctrine type in your entity. For example, create a JsonArrayType for handling JSON arrays in a PostgreSQL jsonb column:
use Atournayre\Types\Doctrine\Types\JsonArrayType;
#[ORM\Entity]
class Product
{
#[ORM\Column(type: JsonArrayType::NAME)]
private array $tags;
}
Verify Configuration:
Check config/packages/atournayre_doctrine_types.yaml (auto-generated by Flex) for available types and their mappings.
Custom Type Registration:
Extend existing types or create new ones by implementing Doctrine\DBAL\Types\Type:
namespace App\Doctrine\Types;
use Atournayre\Types\Doctrine\Types\AbstractType;
class CustomEnumType extends AbstractType
{
public const NAME = 'custom_enum';
public function getSQLDeclaration(array $column, AbstractPlatform $platform)
{
return 'ENUM(' . implode(',', $this->getEnumValues()) . ')';
}
// Implement required methods: convertToDatabaseValue(), convertToPHPValue(), etc.
}
Register in config/packages/atournayre_doctrine_types.yaml:
doctrine_types:
types:
custom_enum: App\Doctrine\Types\CustomEnumType
Integration with Symfony Forms: Use custom types in form fields:
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
$builder->add('status', ChoiceType::class, [
'type' => 'custom_enum', // Matches your registered type
'choices' => ['active', 'inactive'],
]);
Querying with Custom Types: Use DQL or QueryBuilder with custom types:
$query = $entityManager->createQuery(
'SELECT p FROM App\Entity\Product p WHERE p.tags @> :search'
)->setParameter('search', '["electronics"]');
Migrations: Update database schema migrations to include custom types:
// src/Migrations/VersionYYYYMMDDHHMM.php
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE product ADD tags jsonb USING tags::jsonb');
}
Type Name Collisions:
Ensure custom type names (e.g., JsonArrayType::NAME) are unique across the application to avoid conflicts with Doctrine’s built-in types.
Platform-Specific SQL:
Custom types must implement platform-specific SQL generation (e.g., PostgreSQL jsonb vs. MySQL JSON). Use AbstractPlatform to check the database platform:
if ($platform->getName() === 'postgresql') {
return 'jsonb';
}
return 'json';
Circular References in JSON:
Avoid circular references in JSON-serialized fields (e.g., tags containing the Product entity). Use @ORM\Column(type: 'json') with serialize: false or implement __serialize()/__unserialize() in the entity.
Doctrine Cache Invalidation: After adding custom types, clear the Doctrine metadata cache:
php bin/console doctrine:cache:clear-metadata
Type Not Recognized?
Verify the type is registered in config/packages/atournayre_doctrine_types.yaml and the bundle is enabled in bundles.php.
SQL Errors?
Check the generated SQL with doctrine:schema:update --dump-sql and ensure the custom type’s SQL declaration matches your database schema.
Serialization Issues?
Override convertToDatabaseValue() and convertToPHPValue() to handle edge cases (e.g., null values, empty arrays).
Custom Type Factories: Create a factory service to dynamically generate types:
// src/Service/CustomTypeFactory.php
class CustomTypeFactory
{
public function createEnumType(string $name, array $values): Type
{
return new EnumType($name, $values);
}
}
Bind it in services.yaml:
services:
App\Service\CustomTypeFactory: ~
Event Listeners:
Listen to doctrine.dbal.types events to modify type behavior at runtime:
// src/EventListener/TypeListener.php
class TypeListener
{
public function onTypeConvertToDatabaseValue(TypeEventArgs $args)
{
if ($args->getType() instanceof JsonArrayType) {
$args->setDatabaseValue(json_encode($args->getValue()));
}
}
}
Register the listener in services.yaml:
services:
App\EventListener\TypeListener:
tags:
- { name: 'doctrine.event_listener', event: 'onTypeConvertToDatabaseValue' }
Validation Constraints: Combine custom types with Symfony’s validation:
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
class Product
{
#[ORM\Column(type: JsonArrayType::NAME)]
#[Assert\All({
new Assert\Type(type: 'string'),
new Assert\Length(min: 1, max: 50)
})]
private array $tags;
}
config/packages/atournayre_doctrine_types.yaml file and manually define types in config/packages/doctrine.yaml:
doctrine:
dbal:
types:
json_array: Atournayre\Types\Doctrine\Types\JsonArrayType
How can I help you explore Laravel packages today?