PHPackages                             feroz/dynamic-db-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. feroz/dynamic-db-bundle

ActiveSymfony-bundle[Database &amp; ORM](/categories/database)

feroz/dynamic-db-bundle
=======================

Symfony bundle to manage dynamic database connections using Doctrine ORM.

0.0.1-beta5(1mo ago)033↓92.5%MITPHPPHP &gt;=8.1CI failing

Since Mar 30Pushed 3w agoCompare

[ Source](https://github.com/saifulferoz/DynamicDbBundle)[ Packagist](https://packagist.org/packages/feroz/dynamic-db-bundle)[ RSS](/packages/feroz-dynamic-db-bundle/feed)WikiDiscussions main Synced 6d ago

READMEChangelog (3)Dependencies (12)Versions (7)Used By (0)

DynamicDbBundle
===============

[](#dynamicdbbundle)

`DynamicDbBundle` is a Symfony bundle that allows you to store database connection configurations in a database table and seamlessly fetch and instantiate connections and entity managers at runtime.

With this bundle, you can natively use `$doctrine->getConnection('dynamic_name')` or `$doctrine->getManager('dynamic_name')` just like any conventionally configured connection in your `doctrine.yaml`.

---

Features
--------

[](#features)

- **Seamless Doctrine Integration**: Fetches database configuration dynamically via Doctrine's `ManagerRegistry`.
- **Inherited ORM Configuration**: Dynamically boots new entity managers by automatically inheriting the configuration (metadata mapping drivers, naming strategies, custom functions, filters, etc.) of the default `EntityManager`. No need to redefine entity paths or configs.
- **Dynamic Connection Discovery**: Extends standard `ManagerRegistry` lookup methods (`getConnections()`, `getConnectionNames()`, `getManagers()`, and `getManagerNames()`) to include dynamically created connections/managers alongside static ones.
- **Universal Database Support**: Supports all database drivers supported by Doctrine DBAL (MySQL, PostgreSQL, SQLite, Oracle, SQL Server, etc.) via structured parameter mapping or DSN URLs.
- **Auto Cache Rebuilding**: Automatically handles clearing the Symfony cache when your dynamic database connection entities are created, updated, or removed, ensuring any new connections are immediately discoverable.
- **Runtime Secret Injection**: Allows the consumer application to supply a decryption secret via Symfony's DI container, which is automatically forwarded to the connection entity via `setSecret()` before the connection config is built.

---

Installation
------------

[](#installation)

Add the bundle to your project via Composer (if published):

```
composer require feroz/dynamic-db-bundle
```

Ensure the bundle is registered in your `config/bundles.php`:

```
return [
    // ...
    Feroz\DynamicDbBundle\DynamicDbBundle::class => ['all' => true],
];
```

---

Usage Guide
-----------

[](#usage-guide)

### 1. Create a Configuration Entity

[](#1-create-a-configuration-entity)

Create a standard Doctrine Entity in your application that stores the database connection configurations. **Crucially, this entity must implement `DynamicDbConnectionInterface`** and provide implementations for all interface methods, including `setSecret()`.

The `setSecret()` method is called automatically by `DynamicDbProvider` before building the connection config, allowing your entity to make the secret available to downstream logic (e.g., for custom password decryption).

```
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Feroz\DynamicDbBundle\Contract\DynamicDbConnectionInterface;

#[ORM\Entity]
class TenantConnection implements DynamicDbConnectionInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $connectionName = null; // e.g., "tenant_1"

    #[ORM\Column(length: 255)]
    private ?string $dbHost = null;

    #[ORM\Column(length: 255)]
    private ?string $dbName = null;

    #[ORM\Column(length: 255)]
    private ?string $dbUser = null;

    #[ORM\Column(length: 255)]
    private ?string $dbPassword = null;

    private ?string $secret = null;

    // --- DynamicDbConnectionInterface implementation ---

    public function getConnectionName(): string { return $this->connectionName; }
    public function getConnectionString(): ?string { return null; } // Optional: Return DSN URL or Oracle TNS string here
    public function getDatabaseDriver(): string { return 'pdo_mysql'; } // Hardcode or map a column
    public function getDatabaseHost(): string { return $this->dbHost; }
    public function getDatabasePort(): int|string { return 3306; }
    public function getDatabaseName(): string { return $this->dbName; }
    public function getDatabaseUser(): string { return $this->dbUser; }
    public function getDatabasePassword(): string { return $this->dbPassword; }

    /**
     * Called automatically by DynamicDbProvider before the connection config is built.
     * The secret is null when none is configured — implement your decryption logic here.
     */
    public function setSecret(?string $secret): void
    {
        $this->secret = $secret;
    }
}
```

### 2. Fetch the Dynamic Connection

[](#2-fetch-the-dynamic-connection)

You can fetch the connection or the manager directly through Symfony's core Doctrine integration! The bundle decorates the Doctrine registry to seamlessly integrate.

```
namespace App\Controller;

use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class TenantController extends AbstractController
{
    #[Route('/tenant/{tenantName}', name: 'tenant_dashboard')]
    public function index(string $tenantName, ManagerRegistry $doctrine): Response
    {
        // Behind the scenes, the bundle fetches the row matching $tenantName
        // and initializes the connection seamlessly!
        $connection = $doctrine->getConnection($tenantName);

        // Alternatively, grab the dynamic EntityManager
        $entityManager = $doctrine->getManager($tenantName);

        // Run queries for this specific tenant's database
        $results = $connection->executeQuery('SELECT * FROM users')->fetchAllAssociative();

        return $this->json($results);
    }
}
```

### 3. Password Encryption (Consumer Responsibility)

[](#3-password-encryption-consumer-responsibility)

The bundle does **not** provide a built-in encryption utility. Password encryption and decryption are entirely the consumer's responsibility.

The recommended pattern is:

1. **Encrypt** the password before persisting the entity (using any encryption library of your choice).
2. **Decrypt** the password inside `getDatabasePassword()` of your entity, using the secret injected via `setSecret()`.

```
public function setSecret(?string $secret): void
{
    $this->secret = $secret;
}

public function getDatabasePassword(): string
{
    if ($this->secret !== null) {
        // Decrypt using your own logic / library
        return MyEncryptionHelper::decrypt($this->dbPassword, $this->secret);
    }

    return $this->dbPassword; // Return as-is if no secret configured
}
```

### 4. Passing a Secret via Dependency Injection (for Encrypted Passwords)

[](#4-passing-a-secret-via-dependency-injection-for-encrypted-passwords)

`DynamicDbProvider` accepts `$secret` as an **optional constructor parameter**. The recommended approach is to bind it in your application's `services.yaml` using a Symfony parameter (e.g. from an environment variable):

```
# config/services.yaml
parameters:
    dynamic_db_secret: '%env(DYNAMIC_DB_SECRET)%'

services:
    Feroz\DynamicDbBundle\Service\DynamicDbProvider:
        arguments:
            $secret: '%dynamic_db_secret%'
```

With this configuration, `DynamicDbProvider` will automatically call `$entity->setSecret($secret)` on the fetched connection entity before building the connection config, giving the entity access to the secret for custom decryption logic.

If no secret is needed, simply omit the binding — the `$secret` parameter defaults to `null` and `setSecret()` will not be called.

---

How it Works
------------

[](#how-it-works)

1. When you call `$doctrine->getConnection('X')` or `$doctrine->getManager('X')`, the wrapped `DynamicRegistryDecorator` intercepts the request.
2. If Doctrine natively doesn't know about connection `X`, `DynamicDbProvider` kicks in.
3. It finds the class implementing `DynamicDbConnectionInterface` dynamically and uses the default EntityManager to fetch the entity matching `connectionName = 'X'`.
4. If a `$secret` was configured (via DI), it calls `$entity->setSecret($secret)` on the fetched entity.
5. The `DynamicEntityManagerFactory` boots up the new ORM connection using the database connection parameters (or parses a DSN URL using Doctrine's `DsnParser`).
6. The new dynamic `EntityManager` is instantiated by inheriting the exact configuration (metadata mappings, naming strategies, proxies, etc.) of the default `EntityManager`.
7. Standard methods like `$doctrine->getConnections()` or `$doctrine->getManagers()` are decorated to dynamically include the newly instantiated connections/managers alongside the statically defined ones.
8. The connection is cached locally for the remainder of the request.

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance94

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity34

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~26 days

Total

5

Last Release

31d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/42f7ccbb50ac26336f56240519756fffae416abcdc6ff44540947bd2cc941487?d=identicon)[saifulferoz](/maintainers/saifulferoz)

---

Top Contributors

[![saifulferoz](https://avatars.githubusercontent.com/u/15348453?v=4)](https://github.com/saifulferoz "saifulferoz (12 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/feroz-dynamic-db-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/feroz-dynamic-db-bundle/health.svg)](https://phpackages.com/packages/feroz-dynamic-db-bundle)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k18.3M418](/packages/easycorp-easyadmin-bundle)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

12017.1k](/packages/rcsofttech-audit-trail-bundle)[kimai/kimai

Kimai - Time Tracking

4.8k9.4k1](/packages/kimai-kimai)[2lenet/crudit-bundle

The easy like Crud'it Bundle.

1617.3k16](/packages/2lenet-crudit-bundle)[ahmed-bhs/doctrine-doctor

Runtime analysis tool for Doctrine ORM integrated into Symfony Web Profiler. Unlike static linters, it analyzes actual query execution at runtime to detect performance bottlenecks, security vulnerabilities, and best practice violations during development with real execution context and data.

12413.3k](/packages/ahmed-bhs-doctrine-doctor)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
