Doctrine cli with multiple databases

When adding doctrine orm into your project – there is a cli commands present that allows you to do some operations, such as clear cache or update database schema from entities code etc.

While typical instruction from doctrine docs talk about adding cli-config.php file into project root and then using vendor/bin/doctrine script – I find this is just not flexible enough for my needs as I often have multiple databases per project and where such default approach would not work (unless im missing something in which case i’m happy to be corrected).

Thus my preferred approach is to setup separate doctrine console scripts to handle each separate database, here’s how to do it.

Note – im using a laminas framework for this example. If you use different framework – the only real difference would be how you would retrieve your configured entity manager. Do note that many frameworks (including Laminas) have doctrine integrating packages that can handle multi-database functionality out of the box.

For example laminas framework has following packages:

^ if you use any of those refer to their documentation instead, this tutorial is for devs that prefer using vanilla doctrine packages.

composer.json should include doctrine orm and symfony console packages

Example require block from one of my laminas applications:

    "require": {
        "php": ">=8.0",
        "composer/installers": "^1.8",
        "swiftmailer/swiftmailer": "^6.0",

        "laminas/laminas-component-installer": "^2.1.2",
        "laminas/laminas-mvc": "^3.2",
        "laminas/laminas-mvc-form": "^1.0",
        "laminas/laminas-permissions-acl": "^2.7"

        "symfony/console": "^5.1",
        "doctrine/orm": "^2.10",

        "symfony/process": "^5.1",
        "monolog/monolog": "^2.2",
        "symfony/cache": "^5.3"
    },

Add doctrine console scripts -one per database

Here’s the example script (reverse-engineered from official doctrine cli) that you should put into the root of your application (or wherever you want), I typically name it after my database names.

For this example – let’s assume we have 2 databases: shop and cms. Then we could name our doctrine console applications like so:

  • ./doctine-shop (for database named “shop”)
  • ./doctrine-cms (for database named “cms”)

Here’s the code for ./doctrine-cms file:

#!/usr/bin/env php

<?php
    // doctrine-cms
    use Symfony\Component\Console\Application as SymfonyApplication;
    use Laminas\Mvc\Application as LaminasApplication;

    use Symfony\Component\Console\Helper\HelperSet;
    use Doctrine\ORM\Tools\Console\ConsoleRunner;

    //Initialize the laminas application with only purpose being to get the entity manager
    $appConfig = require __DIR__ . '/config/app.php';
    $laminasApplication = LaminasApplication::init($appConfig);
    $serviceManager = $laminasApplication->getServiceManager();
    $entityManager = $serviceManager->get('entity-manager-cms');

    $helperSet =  ConsoleRunner::createHelperSet($entityManager);
    $commands = [];

    ConsoleRunner::run($helperSet, $commands);

And here’s the code for ./doctrine-shop file:

#!/usr/bin/env php

<?php
    // doctrine-cms
    use Symfony\Component\Console\Application as SymfonyApplication;
    use Laminas\Mvc\Application as LaminasApplication;

    use Symfony\Component\Console\Helper\HelperSet;
    use Doctrine\ORM\Tools\Console\ConsoleRunner;

    //Initialize the laminas application with only purpose being to get the entity manager
    $appConfig = require __DIR__ . '/config/app.php';
    $laminasApplication = LaminasApplication::init($appConfig);
    $serviceManager = $laminasApplication->getServiceManager();
    $entityManager = $serviceManager->get('entity-manager-shop');

    $helperSet =  ConsoleRunner::createHelperSet($entityManager);
    $commands = [];

    ConsoleRunner::run($helperSet, $commands);

I’m sure you already got the idea – with doctrine each database requires separate entity manager, meaning you would need to create above scripts as many times as many databases you have (each using its own entity manager). And that’s really the only difference between above 2 scripts – entity manager choice.

Configuring entity manager goes beyond the scope of this post.

Don’t forget to make your script(s) executable, for example in this case with 2 databases (shop and cms):

linuxdev@hs-dev1:/mnt/480g_drive/projects/cms$ chmod +x ./doctrine-cms
linuxdev@hs-dev1:/mnt/480g_drive/projects/cms$ chmod +x ./doctrine-shop

Run any doctrine cli command

At this point you can simply invoke the above script(s). As a test we could simply list all registered entities from cms database, for example:

linuxdev@hs-dev1:/mnt/480g_drive/projects/cms$  ./doctrine-cms orm:info

 Found 19 mapped entities:

 [OK]   Dorm\Entity\Cms\IdentitiesUsername
 [OK]   Dorm\Entity\Cms\ImageDimensions
 [OK]   Dorm\Entity\Cms\TokensRememberMe
 [OK]   Dorm\Entity\Cms\CmsGroups
 [OK]   Dorm\Entity\Cms\AclResources
 [OK]   Dorm\Entity\Cms\AclActions
 [OK]   Dorm\Entity\Cms\ImageSources
 [OK]   Dorm\Entity\Cms\Images
 [OK]   Dorm\Entity\Cms\AclAccountPermissions
 [OK]   Dorm\Entity\Cms\IdentitiesEmail
 [OK]   Dorm\Entity\Cms\Profiles
 [OK]   Dorm\Entity\Cms\Passwords
 [OK]   Dorm\Entity\Cms\ImageCrops
 [OK]   Dorm\Entity\Cms\Accounts
 [OK]   Dorm\Entity\Cms\TokensEmailConfirmation
 [OK]   Dorm\Entity\Cms\AclGroupPermissions
 [OK]   Dorm\Entity\Cms\CmsAccountGroups
 [OK]   Dorm\Entity\Cms\ImageRatios
 [OK]   Dorm\Entity\Cms\TokensPasswordReset

As long as entity managers have been configured correctly – you should see output similar to an example above.

Fin. Thanks for reading.

Leave a Comment