okapon/doctrine-set-type-bundle
Symfony bundle that adds a Doctrine DBAL type for MySQL SET columns, letting you map SET fields to PHP arrays instead of comma-separated strings. Includes schema support and simple configuration for legacy or MySQL-specific databases that rely on SET values.
The DoctrineSetTypeBundle adds a custom Doctrine DBAL type named set that maps PHP arrays to MySQL SET columns. A SET column stores zero or more values from a fixed list in a single column — think of it as a multi-select enum.
1. Install
composer require okapon/doctrine-set-type-bundle
Given the last release was January 2017, treat the version constraint carefully. It was written for Symfony 2/3 and Doctrine DBAL 2.x. On a modern stack you will almost certainly need to pin the bundle to a compatible branch or vendor a copy.
2. Register the bundle
// app/AppKernel.php (Symfony 2/3)
$bundles = [
// ...
new Okapon\DoctrineSetTypeBundle\DoctrineSetTypeBundle(),
];
3. Register the DBAL type
The bundle ships a compiler pass that should wire the type automatically, but verify in config.yml that the type is available:
doctrine:
dbal:
types:
set: Okapon\DoctrineSetTypeBundle\DBAL\Types\SetType
4. First use case — a multi-value column
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Column(type="set", options={"values" = {"red","green","blue"}})
*/
private $colors = [];
Doctrine passes the values option into the type's getSQLDeclaration(), producing SET('red','green','blue'). On persist, the array is joined with commas; on hydration, the string is split back into an array. The column then behaves like a normal array property in entity code:
$entity->setColors(['red', 'blue']);
$em->flush();
Treat the property as a plain array. The type handles the conversion, so entities, forms, and serializers just see array<string>. Keep a default of [] so newly created entities flush to '' rather than null unless the column is nullable.
Author forms with multiple choice fields.
$builder->add('colors', ChoiceType::class, [
'choices' => ['Red' => 'red', 'Green' => 'green', 'Blue' => 'blue'],
'multiple' => true,
'expanded' => true, // checkboxes are natural for SET
]);
Because the underlying column can only hold values from its declared list, keep form choices in sync with the options={"values" = {...}} on the mapping. Duplicating the list in a constant or enum is worth the effort since mismatches surface only at the DB layer.
Querying SET columns. MySQL does not index SET members usefully with = for "contains" semantics. Use FIND_IN_SET:
$qb->andWhere('FIND_IN_SET(:color, e.colors) > 0')
->setParameter('color', 'red');
The Doctrine query builder has no expression method for this, so use ->andWhere() with a raw DQL string, or add a small custom DQL function if you do this often. For "exactly one value" queries, e.colors = :value works; for multi-value matches, FIND_IN_SET on each member or a LIKE '%,red,%' fallback (brittle at edges) is the alternative.
Migrations. If you generate migrations with Doctrine Migrations, the schema diff usually produces the correct SET(...) DDL because it flows through getSQLDeclaration(). However, changing the declared values often results in a drop/recreate. Write those migrations by hand if the data matters — a SET change with existing data will either error or silently truncate invalid members.
Keep the values list stable. If you need to add a value, MySQL allows ALTER TABLE ... MODIFY COLUMN ... SET('a','b','c') without data loss as long as you only append. Reordering or removing values rewrites existing rows.
Type method signatures (getSQLDeclaration gained a $platform argument, getName() conventions changed). On DBAL 3+ you will likely need a fork or a small shim that returns Types::SET yourself. Confirm the version you install matches your DBAL major version before wiring the compiler pass.SET members in the order they appear in the column definition, and the type splits that order out. If you care about user-chosen ordering, use a separate join table instead — SET is not an ordered list.SET cannot contain duplicates; ['red','red'] becomes 'red'. If duplicate semantics matter (e.g., quantities), SET is the wrong tool.[] or null means "unset" and be consistent across the entity default and migrations — otherwise you get surprising '' values.doctrine:schema:validate and doctrine:schema:update handle the type via getSQLDeclaration, but some tools (phpMyAdmin exports, IDE schema introspection) will show SET as a raw string, which is expected.SHOW COLUMNS FROM table to see the actual declared SET(...) — a mismatch between the mapping's values option and the live column is the most common cause of silent truncation warnings in MySQL.convertToDatabaseValue(['a','b']) and convertToPHPValue('a,b') to catch regressions if you fork the type for a newer DBAL.How can I help you explore Laravel packages today?