A Symfony bundle that adds a configurable prefix to Doctrine ORM table and column
names, without replacing your naming strategy — it wraps whichever one you already
use (underscore, default, or a custom one) and prefixes its output. Useful when
several applications share one database schema and need namespaced tables/columns
(e.g. t_user / c_first_name), or when an existing schema convention requires it.
- PHP ^8.2 (PHP 8.4+ is required when running on Symfony 8)
symfony/framework-bundle^7.0 || ^8.0doctrine/orm~3.2
composer require tavvet/tavvet-doctrine-prefix-bundleIf your app doesn't use Symfony Flex to auto-register bundles, add it manually in
config/bundles.php:
return [
// ...
Tavvet\DoctrinePrefixBundle\TavvetDoctrinePrefixBundle::class => ['all' => true],
];Point Doctrine's naming_strategy at the service this bundle registers, then
configure the prefixes:
doctrine:
orm:
naming_strategy: tavvet_doctrine_prefix.prefix_naming_strategy
tavvet_doctrine_prefix:
table_prefix: t_ # default ''
column_prefix: c__ # default ''
naming_strategy: # base naming strategy this bundle wraps
type: doctrine.orm.naming_strategy.underscore # default - 'doctrine.orm.naming_strategy.underscore'
arguments: [] # constructor arguments for the base naming strategy, default = []| Key | Type | Default | Description |
|---|---|---|---|
table_prefix |
string | '' |
Prepended to every table name. |
column_prefix |
string | '' |
Prepended to every column name. |
naming_strategy.type |
string | doctrine.orm.naming_strategy.underscore |
Container service id of the base naming strategy to wrap. Must resolve to a real service — doctrine/doctrine-bundle registers doctrine.orm.naming_strategy.default and doctrine.orm.naming_strategy.underscore out of the box; you can also point this at your own service id. Resolved once, at container-compile time — a typo fails fast with a clear ServiceNotFoundException instead of breaking silently at runtime. |
naming_strategy.arguments |
array | [] |
Constructor arguments used to build a new instance of the resolved class (e.g. [1] for UnderscoreNamingStrategy's CASE_UPPER). This instance is private to the prefixing strategy — it does not reuse or affect the shared naming_strategy.type service elsewhere in the container. |
PrefixNamingStrategy implements Doctrine's NamingStrategy and delegates every
call to the wrapped base strategy, prefixing the result:
classToTableName('App\Entity\User') -> table_prefix . underscore('User') -> 't_user'
propertyToColumnName('firstName', …) -> column_prefix . underscore('firstName') -> 'c_first_name'
Because the wrapped strategy is built from a class name, not a live service, a
compiler pass (ResolveNamingStrategyPass) resolves naming_strategy.type from a
service id to its class at container-compile time — this is what lets
naming_strategy.arguments construct a differently-configured instance than
whatever doctrine-bundle already wired up for that id.
Doctrine only consults a naming strategy when a name is not given explicitly. So an entity or field with an explicit name is not prefixed:
#[ORM\Table(name: 'legacy_users')] // stays 'legacy_users', no table_prefix
#[ORM\Column(name: 'raw_email')] // stays 'raw_email', no column_prefixIf you rely on the prefix being applied across the whole schema (e.g. a shared
database), avoid hard-coding name: on tables and columns and let the naming
strategy generate them.
On PHP 8.4 with doctrine-bundle 3.x you may hit, when the entity manager boots:
Symfony LazyGhost is not available. Please install the "symfony/var-exporter"
package version 6.4 or 7 to use this feature or enable PHP 8.4 native lazy objects.
This is a Doctrine / PHP 8.4 concern, not this bundle — on that stack symfony/var-exporter
resolves to v8, which dropped the LazyGhost helper, so the ORM needs PHP native lazy
objects. Enable them in your Doctrine config:
doctrine:
orm:
enable_native_lazy_objects: trueRecent doctrine-bundle recipes may already set this; the option requires doctrine-bundle 3.x and PHP 8.4+.
Everything runs in Docker, no local PHP toolchain needed.
docker compose up -d
docker compose exec php composer install
docker compose exec php vendor/bin/phpunit # tests (incl. a functional schema-generation test)
docker compose exec php vendor/bin/phpstan analyse # static analysis (level 9)
docker compose down -v --rmi local # tear down: remove container, image and volumeOr, as a single ephemeral run that leaves nothing behind:
docker compose run --rm php sh -c "composer install && vendor/bin/phpunit && vendor/bin/phpstan analyse"
docker compose down -v --rmi localMIT — see LICENSE.