Weave Code
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 Prefix Bundle Laravel Package

borsaco/doctrine-prefix-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require borsaco/doctrine-prefix-bundle
    

    Enable the bundle in config/bundles.php:

    return [
        // ...
        Borsaco\DoctrinePrefixBundle\DoctrinePrefixBundle::class => ['all' => true],
    ];
    
  2. Basic Configuration Create config/packages/doctrine_prefix.yaml:

    doctrine_prefix:
        table_prefix: "app_"
        column_prefix: "usr_"
    

    Ensure naming_strategy is set in config/packages/doctrine.yaml:

    doctrine:
        orm:
            naming_strategy: Borsaco\DoctrinePrefixBundle\Doctrine\ORM\Mapping\PrefixNamingStrategy
    
  3. First Use Case Define an entity (e.g., src/Entity/User.php):

    namespace App\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    
    /** @ORM\Entity */
    class User
    {
        /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
        private $id;
    
        /** @ORM\Column(type="string", length=255) */
        private $name; // Will become `usr_name` in DB
    }
    

    Run migrations (php bin/console doctrine:migrations:diff and php bin/console doctrine:migrations:migrate). Verify the table (app_user) and column (usr_name) prefixes in the database.


Implementation Patterns

Workflows

  1. Multi-Tenant Prefixing Dynamically set prefixes per tenant by overriding the PrefixNamingStrategy:

    # config/packages/doctrine_prefix.yaml
    doctrine_prefix:
        table_prefix: "%tenant_prefix%_" # e.g., "client1_"
        column_prefix: "usr_"
    

    Use environment variables or runtime logic (e.g., middleware) to inject %tenant_prefix%.

  2. Legacy Schema Integration For existing databases, manually adjust PrefixNamingStrategy to skip specific tables/columns:

    // src/Doctrine/ORM/Mapping/ExtendedPrefixNamingStrategy.php
    namespace App\Doctrine\ORM\Mapping;
    
    use Borsaco\DoctrinePrefixBundle\Doctrine\ORM\Mapping\PrefixNamingStrategy;
    
    class ExtendedPrefixNamingStrategy extends PrefixNamingStrategy
    {
        public function classToTableName(\Doctrine\ORM\Mapping\ClassMetadata $class)
        {
            if ($class->getTableName() === 'legacy_table') {
                return $class->getTableName(); // Skip prefix
            }
            return parent::classToTableName($class);
        }
    }
    

    Update doctrine_prefix.yaml:

    doctrine_prefix:
        naming_strategy:
            class: App\Doctrine\ORM\Mapping\ExtendedPrefixNamingStrategy
    
  3. Custom Naming Strategies Combine with Doctrine’s built-in strategies (e.g., UnderscoreNamingStrategy):

    doctrine_prefix:
        naming_strategy:
            class: Doctrine\ORM\Mapping\UnderscoreNamingStrategy
            arguments: ['CASE_LOWER', true] # Converts camelCase to snake_case
    

    Result: Userapp_users (table), createdAtusr_created_at (column).

Integration Tips

  • Migrations: Always run doctrine:migrations:diff after changing prefixes to avoid schema conflicts.
  • Fixtures: Update doctrine/doctrine-fixtures-bundle fixtures to reflect prefixed column names.
  • Queries: Use QueryBuilder with explicit aliases to avoid ambiguity:
    $qb->select('u.usr_name as name') // Explicit alias for prefixed column
       ->from('App\Entity\User', 'u');
    
  • Symfony Forms: Bind form fields to prefixed column names:
    $builder->add('usr_name', TextType::class); // Matches DB column
    

Gotchas and Tips

Pitfalls

  1. Case Sensitivity Prefixes are case-sensitive in some databases (e.g., PostgreSQL). Ensure consistency in naming_strategy arguments (e.g., CASE_LOWER).

  2. Migration Conflicts Changing prefixes mid-project may break existing migrations. Use a new migration branch or database dumps to avoid corruption.

  3. Circular Dependencies Avoid prefixing tables/columns that reference each other (e.g., app_usersapp_user_rolesapp_roles). Use explicit foreign key names:

    # config/packages/doctrine_prefix.yaml
    doctrine_prefix:
        foreign_key_prefix: "fk_"
    
  4. Doctrine Cache Clear the metadata cache after changing prefixes:

    php bin/console cache:clear
    php bin/console doctrine:cache:clear-metadata
    

Debugging

  • Verify Prefixes: Dump entity metadata to confirm prefixes:

    php bin/console debug:container --parameter=doctrine_prefix
    

    Or inspect an entity’s metadata:

    $em->getClassMetadata(User::class)->getTableName(); // Should return "app_user"
    
  • SQL Logging: Enable logging to check generated queries:

    # config/packages/dev/doctrine.yaml
    doctrine:
        dbal:
            logging: true
            logging_format: '%%sql%%'
    

Extension Points

  1. Dynamic Prefixes Override PrefixNamingStrategy to fetch prefixes from a database or API:

    class DynamicPrefixNamingStrategy extends PrefixNamingStrategy
    {
        public function tableName($className)
        {
            $prefix = $this->fetchPrefixFromService(); // Custom logic
            return $prefix . '_' . parent::tableName($className);
        }
    }
    
  2. Exclude Entities Skip prefixing for specific entities (e.g., AuditLog):

    // src/Doctrine/ORM/Mapping/ExcludedPrefixNamingStrategy.php
    class ExcludedPrefixNamingStrategy extends PrefixNamingStrategy
    {
        public function classToTableName(ClassMetadata $class)
        {
            if ($class->getName() === AuditLog::class) {
                return $class->getReflectionClass()->getShortName();
            }
            return parent::classToTableName($class);
        }
    }
    
  3. Custom Prefix Logic Use the onGenerateTableName and onGenerateColumnName events (Symfony 5.3+):

    # config/services.yaml
    Borsaco\DoctrinePrefixBundle\Doctrine\ORM\Mapping\PrefixNamingStrategy:
        arguments:
            $tablePrefixGenerator: '@custom.table_prefix_generator'
    
    // src/Service/CustomTablePrefixGenerator.php
    class CustomTablePrefixGenerator
    {
        public function generate(string $entityName): string
        {
            return match ($entityName) {
                'User' => 'client_',
                default => 'app_',
            };
        }
    }
    

Configuration Quirks

  • Empty Prefixes: Set table_prefix: "" or column_prefix: "" to disable prefixes entirely.
  • Underscore Strategy: If using UnderscoreNamingStrategy, ensure it’s loaded before PrefixNamingStrategy in the chain:
    doctrine_prefix:
        naming_strategy:
            class: Doctrine\ORM\Mapping\UnderscoreNamingStrategy
            arguments: ['CASE_LOWER', true]
    
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope