13

I have multiple composer.json having multiple seperate dependency and want to install all the dependency in the both composer.json using single composer install command.

The location is like this:

| - composer.json
| - Custom
    | - Package1
        | - composer.json

First composer.json

{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": ">=5.6.4",
        "barryvdh/laravel-debugbar": "^2.3",
        "laravel/framework": "5.4.*",
        "laravel/tinker": "~1.0",
        "laravelcollective/html": "^5.4.0"
    },
    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~5.7",
        "symfony/css-selector": "3.1.*",
        "symfony/dom-crawler": "3.1.*"
    },
    "autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/",
        }
    },
    "autoload-dev": {
        "psr-4": {
          "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-root-package-install": [
            "php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "php artisan key:generate"
        ],
        "post-install-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postInstall",
            "php artisan optimize"
        ],
        "post-update-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postUpdate",
            "php artisan optimize"
        ]
    },
    "config": {
        "preferred-install": "dist",
        "sort-packages": true,
        "optimize-autoloader": true
    }
}

Second composer.json inside Package1 directory

{
    "name": "custom/package1",
    "description": "",
    "require": {
        "php": ">=5.6",
        "composer/installers": "~1.0",
        "lavary/laravel-menu": "1.7.1"
    },
    "autoload": {
        "psr-4": {
            "Custom\\Package1\\": ""
        }
    }
}

I want to install the lavary/laravel-menu inside the Package1 to the main vendor directory where all the default packages are installed.

|- vendor  //<==want here
| - composer.json
    | - Custom
        | - Package1
            | - vendor  //<== not here
            | - composer.json

I have tested this solution:

https://stackoverflow.com/a/27735674

like this:

{
    "config": {
        "vendor-dir": "../../vendor/"
    }
}

This installs the packages but we need to get into the second composer.json instead of main composer.json and removes the installed package from first composer.json.

How can i install the all the dependency from the main composer.json without getting into the second or multiple composer.json in single vendor directory?

PaladiN
  • 4,625
  • 8
  • 41
  • 66
  • 1
    Try to mege those 2 composer files. –  Oct 05 '17 at 07:54
  • composer deals with all this already. you shouldn't touch vendor code. if you cant get packages to resolve, try deleting composer.lock files – delboy1978uk Oct 05 '17 at 07:55
  • 1
    @MohammadTrabelsi I cannot merge the different composers as they should be kept separately to maintain the dependency and they would be removed if we remove the custom package – PaladiN Oct 05 '17 at 08:05
  • 2
    Composer doesn't support this by itself, but you can use the [composer-merge-plugin](https://github.com/wikimedia/composer-merge-plugin) package for that. – rickdenhaan Oct 05 '17 at 08:07
  • @delboy1978uk I am not talking about touching the vendor codes. It will remove the other dependency as there will be dependency that is listed in the vendor but not in the second composer.json. Also composer.lock won't hamper me as i could use composer update but that is not the issue for me. – PaladiN Oct 05 '17 at 08:09
  • Why not define your custom package (the second composer.json) as a metapackage and require it in the first package? – JParkinson1991 Oct 05 '17 at 08:12
  • Why not set a private repository entry in your composer.json, and require the lib in like you would any other? Look here https://getcomposer.org/doc/05-repositories.md#loading-a-package-from-a-vcs-repository – delboy1978uk Oct 05 '17 at 08:12
  • 5 seconds in it delboy ;) I think we're right with that approach, i use it in my latest project and it works a treat – JParkinson1991 Oct 05 '17 at 08:13
  • @delboy1978uk and JParkinson1991: If i add the package as private repository it will get the package as the read-only package similar to vendor packages, and i want is not like that as i need to modify the codes and use vcs etc. – PaladiN Oct 05 '17 at 08:14
  • It sounds like an XY problem. Why are you trying to do this? – delboy1978uk Oct 05 '17 at 08:16
  • You can still modify your code within that package. Just follow semantic versioning and version your changes. If you dont hard set a version number in your main project you can update the package like you would any other – JParkinson1991 Oct 05 '17 at 08:16
  • @JParkinson1991 So should i do like this to include in the metapackage? https://stackoverflow.com/a/19582417/3887342 – PaladiN Oct 05 '17 at 08:19
  • Yes, but you will need to configure the local repository so your project knows where to find the package. Then simply version your package and update it as its needed in the project – JParkinson1991 Oct 05 '17 at 08:21

2 Answers2

21

After some research and suggestion i figured out there are multiple ways to achieve this solution.

  1. Using external package to maintain the dependency.

Thanks to rickdenhaan to let me know about

Composer Merge Plugin

https://github.com/wikimedia/composer-merge-plugin

First we need to require this package:

composer require wikimedia/composer-merge-plugin

Then my composer.json becomes like this:

{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": ">=5.6.4",
        "barryvdh/laravel-debugbar": "^2.3",
        "laravel/framework": "5.4.*",
        "laravel/tinker": "~1.0",
        "wikimedia/composer-merge-plugin": "^1.4"
    },
    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~5.7",
        "symfony/css-selector": "3.1.*",
        "symfony/dom-crawler": "3.1.*"
    },
    "autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/"
        }
    },
    "autoload-dev": {
        "psr-4": {
          "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-root-package-install": [
            "php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "php artisan key:generate"
        ],
        "post-install-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postInstall",
            "php artisan optimize"
        ],
        "post-update-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postUpdate",
            "php artisan optimize"
        ]
    },
    "config": {
        "preferred-install": "dist",
        "sort-packages": true,
        "optimize-autoloader": true
    },
    "extra": {
        "merge-plugin": {
            "include": [
                "Custom/*/composer.json"
            ],
            "recurse": true,
            "replace": false,
            "ignore-duplicates": true,
            "merge-dev": true,
            "merge-extra": false,
            "merge-extra-deep": false,
            "merge-scripts": true
        }
    }
}

Now, run

composer install

or

 composer update

Then your composer.json in each of the directory will be merged into default vendor directory.

  1. Next solution could be to publish the package to the packagist and require in the composer.json and during composer install all the dependency will be installed.

    Like the Asgardcms has done.

  2. Adding the private repository to the composer.json.

    Configuring composer.json with private bitbucket mercurial repository

  3. This option needs to add the composer.json of metapackage to the main composer.json file.

(I am not sure about the option but thanks to JParkinson1991 Someone who knows this solution could add explaination on this option. Adding just to let someone know this solution exists.)

Here is the example solution:

PHP & Composer, how do I combine composer.json files

In this the first solution suits my case. Hope this helps someone who spent alot of time searching.

PaladiN
  • 4,625
  • 8
  • 41
  • 66
  • 5
    have you tried composer path repositories? https://getcomposer.org/doc/05-repositories.md#path The plugin you have mentioned has lots of issues reported and is not being updated anymore. Could your problem also not be solved with composer repositories path? – niko craft Aug 01 '19 at 22:16
  • 2
    See also this issue on Drupal "Stop using wikimedia/composer-merge-plugin". There are a number of disadvantages to using this plugin, though: It has a performance penalty (the composer process is slower and downloads more metadata) and a complexity penalty. Proposed resolution Remove the wikimedia merge plugin and replace it with a Composer 'path' repository, a native Composer feature which serves the same needs as the merge plugin with fewer disadvantages. – niko craft Aug 01 '19 at 22:17
-2

Here is an alternative way that hopefully serves the use case of multiple composer JSON files.

Generally, we want to use multiple JSON files to differentiate production & development packages.

Packages that require in development only, we can use with require-dev

Here is an example of composer file:
{
    "name": "name",
    "type": "library",
    "description": "Dummy Description",
    "autoload": {
        "psr-4": {
            "Vendor\\Cache\\":"cache/",
        }
    },
    "require-dev": {
        "phpunit/phpunit": "^9",
        "yoast/phpunit-polyfills": "^1.0"
    }
}

So now if we want to use only production packages then use below command:

composer install --no-dev (It will not install packages that is inside require-dev)

If we need both development & production packages then use below command.

composer install (It will install all the packages)

It is just a suggestion. Hopefully, it may be helpful.

SK Shewa
  • 106
  • 1
  • 9
  • Please add some explanation to your answer such that others can learn form it. How does these commands help if you want to use multiple `composer.json` files? – Nico Haase Aug 22 '22 at 09:59
  • Updated, hopefully it will be helpful – SK Shewa Aug 22 '22 at 10:45
  • "Generally, we want to use multiple JSON files to differentiate production & development packages" - why do we want that? That's why Composer uses `require` and `require-dev` dependencies – Nico Haase Aug 22 '22 at 11:19
  • I think you didn't face such situation. Keep working, you may face someday! – SK Shewa Aug 22 '22 at 14:57
  • Please add all details to your answer by editing it. Which situation do you talk about? Why not focus on the original question, where the packages from **both** files should get installed? – Nico Haase Aug 22 '22 at 15:00
  • For example, you can take a WordPress plugin where are you using some composer packages (like DOM PDF) that is required for the production. Besides, you are using some packages that are required for only development purposes like PHPUnit. So now, when you build a plugin to release, you will not want to shift the PHPUnit package's files. It is not required in production at all. In that case, you may want to write different composer files, or the way I showed (--no-dev) above will be helpful. Get it? – SK Shewa Aug 22 '22 at 15:09
  • I have recently come across this situation & I handled it this way. Do you have any better way of doing that? Please share – SK Shewa Aug 22 '22 at 15:10
  • Then please share more details by editing your answer. If you used multiple Composer files, and somehow merged them such that the dependencies of all these files can be used in conjunction, this should be explained **within your answer**. It's not about having one file for production dependencies, and another one for development dependencies, it about having multiple files with production dependencies – Nico Haase Aug 22 '22 at 18:38
  • And no, I don't have an answer about the problem, but I don't see either how your approach handles the initial problem in any way – Nico Haase Aug 22 '22 at 18:39