Weave 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 Set Type Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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();

Implementation Patterns

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.

Gotchas and Tips

  • Age / compatibility is the big pitfall. The package has not been updated since 2017 and supports Doctrine DBAL 2.x. DBAL 3 renamed and changed several 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.
  • Ordering is not preserved. MySQL stores 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.
  • Duplicate values. A SET cannot contain duplicates; ['red','red'] becomes 'red'. If duplicate semantics matter (e.g., quantities), SET is the wrong tool.
  • Empty vs null. An empty array converts to an empty string. If the column is nullable, decide explicitly whether [] or null means "unset" and be consistent across the entity default and migrations — otherwise you get surprising '' values.
  • Schema tool limitations. 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.
  • Extension point. If you need a PostgreSQL/MySQL enum-with-multiple-values equivalent that is portable, this bundle will not help — it is MySQL-specific. For portability, model the multi-value as a join table or a JSON column with application-level validation.
  • Debugging tips. When values appear mangled, temporarily log the parameter and result in a repository, or check 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.
  • Testing. In unit tests, the DBAL Type is cheap to test directly: call convertToDatabaseValue(['a','b']) and convertToPHPValue('a,b') to catch regressions if you fork the type for a newer DBAL.
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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels