Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure a composer package to be globally installed?

I'm trying to make a little CLI tool and package it up with composer.

Below is an extremely simplified version of the program, but it's enough to demonstrate the problem I'm encountering.

The project has one dependency, and one "binary" file

composer.json

{
  "name": "alice/yamldump",
  "version": "0.2.0",
  "bin": [
    "bin/yamldump"
  ],
  "require": {
    "symfony/yaml": "2.5.3"
  }
}

bin/yamldump

#!/usr/bin/env php
<?php

// use Yaml namespace
use Symfony\Component\Yaml as Yaml;

// autoload
require_once "vendor/autoload.php";

// read yaml
$yaml = file_get_contents(sprintf("%s/%s", getcwd(), $argv[1]));

// create parser
$parser = new Yaml\Parser();

// parse the yaml
var_dump($parser->parse($yaml));

So when I install it globally, I get this

$ composer global require alice/yamldump=dev-master

Files are installed to

  • ~/.composer/vendor/bin/yamldump -> ../alice/yamldump/bin/yamldump
  • ~/.composer/vendor/alice/yamldump/
  • ~/.composer/vendor/symfony/yaml/

This is a problem, because I did not intend to globally install symfony/yaml and my package's vendor/autoload.php can no longer find the Yaml package in the proper location.

I don't mind that symfony/yaml was installed globally, but it would make sense to me that composer global require would install the package like this:

  • ~/.composer/vendor/bin/yamldump -> ../alice/yamldump/bin/yamldump
  • ~/.composer/vendor/alice/yamldump/
  • ~/.composer/vendor/alice/yamldump/vendor/symfony/yaml/

After all, what if I have Package A that depends on symfony/yaml=2.5.3 and Package B that requires symfony/yaml=2.6.x?

If the composer global require installs dependencies to ~/.composer/vendor/*, each globally required package can't maintain it's own version requirement of its dependency...

I know this is sort of a convoluted problem, but I really don't know how to begin fixing it.


The goal

A user should be able to

$ composer global require alice/yamldump=dev-master
$ yamldump sample.yml

The error

$ yamldump sample.yml
Warning: require_once(vendor/autoload.php): failed to open stream: No such file or directory in /Users/alice/.composer/vendor/alice/yamldump/bin/yamldump on line 8

Fatal error: require_once(): Failed opening required 'vendor/autoload.php' (include_path='.:') in /Users/alice/.composer/vendor/alice/yamldump/bin/yamldump on line 8

The question

Here it is in black & white:

How am I intended to write the require "vendor/autoload.php" line and have it work for both locally installed packages and globally installed packages?

like image 965
Mulan Avatar asked Aug 22 '14 01:08

Mulan


People also ask

Is there any way to install composer globally on Windows?

Installation - Windows# This is the easiest way to get Composer set up on your machine. Download and run Composer-Setup.exe. It will install the latest Composer version and set up your PATH so that you can call composer from any directory in your command line. Note: Close your current terminal.

Where does composer install global packages?

This will install PHPUnit and all its dependencies into the ~/. composer/vendor/ directory and, most importantly, the phpunit CLI tools are installed into ~/. composer/vendor/bin/.

How do I update composer globally?

To update Composer itself to the latest version, run the self-update command. It will replace your composer.phar with the latest version. If Composer was not installed as a PHAR, this command is not available. (This is sometimes the case when Composer was installed by an operating system package manager.)

Should I install composer locally or globally?

The safest bet is to use the same version of composer. phar along the development pipeline. Alternatively, as mentioned before, keeping the globally installed composer regularly updated. Save this answer.


1 Answers

Targeting vendor/autoload.php is generally not a good idea and only works if you run the script from the correct directory. The following should serve you better:

require_once __DIR__.'/../vendor/autoload.php';

However, this still might be an issue if your application is installed as a dependency. In that case, you might need something more substantial:

if (
    (!$classLoader = includeIfExists(__DIR__.'/../vendor/autoload.php')) &&
    (!$classLoader = includeIfExists(__DIR__.'/../../../autoload.php'))
) {
    echo 'You must set up the project dependencies, run the following commands:'.PHP_EOL.
        'curl -sS https://getcomposer.org/installer | php'.PHP_EOL.
        'php composer.phar install'.PHP_EOL;
    exit(1);
}

This first looks for the autoloader in the location you would expect it to be if you are working directly on your application. If that does not exist, it looks where the autoloader would be if your application is installed as a dependency.

like image 99
Beau Simensen Avatar answered Sep 20 '22 16:09

Beau Simensen