Search code examples
mongodbherokucomposer-phpphp-7doctrine-odm

How to deploy PHP7 with MongoDB ext on Heroku?


I'm trying to deploy an app on Heroku and I'm running into issues related to conflicting composer dependencies. It's working fine from my local dev machine, I can composer update without any issue.

Here is a sample of my composer.json:

"require": {
    "php": "7.1.*",
    "ext-mongo": "*",
    "ext-mongodb": "^1.2",
    "symfony/symfony": "3.2.*",
    "doctrine/orm": "^2.5",
    "doctrine/doctrine-bundle": "^1.6",
    "doctrine/doctrine-cache-bundle": "^1.2",
    "symfony/swiftmailer-bundle": "^2.3.10",
    "symfony/monolog-bundle": "^3.0.2",
    "symfony/polyfill-apcu": "^1.0",
    "sensio/distribution-bundle": "^5.0",
    "sensio/framework-extra-bundle": "^3.0.2",
    "incenteev/composer-parameter-handler": "^2.0",
    "twig/twig": "^1.0||^2.0",
    "mongodb/mongodb": "^1.1",
    "doctrine/mongodb-odm-bundle": "^3.2",
    "alcaeus/mongo-php-adapter": "^1.0",
    "friendsofsymfony/user-bundle": "2.0.0-beta2",
    "friendsofsymfony/oauth-server-bundle": "^1.5",
    "symfony/assetic-bundle": "^2.8",
    "twig/extensions": "^1.4",
    "jms/serializer-bundle": "^1.2",
    "friendsofsymfony/rest-bundle": "^2.1"
},

...and here is the error output from Heroku:

> Loading repositories with available runtimes and extensions
> Updating dependencies
> Your requirements could not be resolved to an installable set of packages.
>
>   Problem 1
>     - Installation request for doctrine/annotations v1.4.0 -> satisfiable by doctrine/annotations[v1.4.0].
>     - Installation request for twig/twig v2.3.2 -> satisfiable by twig/twig[v2.3.2].
>     - Conclusion: don't install php 7.1.3
>     - Installation request for doctrine/mongodb 1.4.0 -> satisfiable by doctrine/mongodb[1.4.0].
>     - doctrine/annotations v1.4.0 requires php ^5.6 || ^7.0 -> satisfiable by php[5.6.30, 7.0.15, 7.0.16, 7.0.17, 7.1.1, 7.1.2, 7.1.3].
>     - don't install php 7.1.1|don't install php 5.5.38
>     - don't install php 7.1.2|don't install php 5.5.38
>     - don't install php 7.0.15|don't install php 5.5.38
>     - don't install php 7.0.16|don't install php 5.5.38
>     - don't install php 7.0.17|don't install php 5.5.38
>         - ext-mongo 1.6.14 requires php 5.5.* -> satisfiable by php[5.5.38].
>     - doctrine/mongodb 1.4.0 requires ext-mongo ^1.5 -> satisfiable by ext-mongo[1.6.14].
>     - ext-mongo 1.6.14 requires php 5.6.* -> satisfiable by php[5.6.30].
>     - Conclusion: don't install php 5.6.30

Solution

  • This is a bigger problem. Let's divide it into two parts:

    Part 1:

    Ext-mongo is a legacy driver that does not exist for PHP7.x. But Doctrine-ODM requires ext-mongo. The workaround is to use an adapter that provides an interface for the old driver that uses the new MongoDB driver. There is an explanation in the Doctrine-ODM documentation, but this explanation isn't up-to-date and therefore incomplete/incorrect.

    In your case, it means that you remove "ext-mongo" and "ext-mongodb" from the "require" section of your composer file and keep the "alcaeus/mongo-php-adapter" (The adapter will require itself "ext-mongodb" - the new driver.) Unfortunately, this still won't work and brings us to Part 2.

    Part 2:

    Integrating the alcaeus/mongo-php-adapter as it is currently provided by Packagist will create a composer dependency conflict. There is some discussion about exactly this problem and also if this might be a general composer issue (see here). Also, several solutions are suggested. One solution works for me (I'm also deploying on Heroku):

    In the composer.json of the alcaeus/mongo-php-adapter replace:

    "provide": {
        "ext-mongo": "1.6.14"
    },
    

    by:

    "replace": {
        "ext-mongo": "1.6.14"
    },
    

    On GitHub, the master branch of alcaeus/mongo-php-adapter uses the "provide"-version, but there is also a composer-replace branch that uses the "replace"-version. Unfortunately, this branch isn't kept up-to-date.

    You can use that "replace" branch as repository for alcaeus/mongo-php-adapter in your composer file:

    "repositories": [
            {
                "type": "vcs",
                "url": "https://github.com/alcaeus/mongo-php-adapter"
            }
        ],
    "require": {
        "alcaeus/mongo-php-adapter": "dev-composer-replace",
        ...
    

    Alternatively, you could fork the master branch, replace "provide" by "replace" and use that fork as repository.