59

I am a Composer beginner and I am trying to make one project dependent of another one, while both project only exist on my local machine.

The composer.json in my library project (ProjectA) is:

{
    "name" : "project/util",
    "type" : "library"
}

I initialized git in the base folder of this project.

My composer.json in the project depending on the first one (ProjectB):

{
    "repositories": [
        {
            "name" : "util", 
            "type" : "git",
            "url" : "/d/workspaces/util"
        }   
    ],

    "require": {
        "project/util" : "*"
    },
}

When I run composer install from ProjectB, I get the following error:

[RuntimeException]
Failed to clone , could not read packages from it
fatal: repository '' does not exist

I asume something is wrong with the url of the repository, but I am not sure what else to write there.

Jeff Puckett
  • 37,464
  • 17
  • 118
  • 167
Banana
  • 4,010
  • 9
  • 33
  • 49

7 Answers7

62

Autoload local package using composer (without going to packagist every time you change).

There are many ways to do so, I will be covering 2 of them:

In all cases we have 2 main parties:
- the local package (the code that we do not want to publish on packagist to be able to autoload it in our project composer).
- the main project (the code base that needs to use the local package code, can be another package and or any project).


Method 1: (direct namespace)

Open the main project composer.json file and autoload the local package namespaces using any method (PSR-4, PSR-0, ...).

example:

if in the composer.json of the local package we have:

  "autoload": {
    "psr-4": {
      “Local\\Pack\\": "library"
    }
  },
  "autoload-dev": {
    "psr-4": {
      "Local\\Pack\\Tests\\": "tests"
    }
  },

then in the composer.json of the main project we should have:

  "autoload": {
    "psr-4": {
      "Mahmoudz\\Project\\": "src",
      "Local\\Pack\\": "../path/to/local/pack/library”                   << referencing the other local package
    }
  },
  "autoload-dev": {
    "psr-4": {
      "Mahmoudz\\Project\\Tests\\": "tests"
    }
  },

Advantages:
- you don’t touche the vendor directory (running composer update by mistake will not override your local changes)
- you don’t need your package to be on packagist to use it
- you work in one place (the local package) and the changes are automatically loaded in the main project
Disadvantages:
- you cannot publish the composer.json on production (needs editing before publishing to require the real package)

Method 2: (local repository)

Download the local package from a local repository.

local package:
1. initialize git in the package (even if you don’t want to use it - no need to commit anything)
2. add composer.json file. In the file make sure you have the following:

"name": "vendor-name/package-name",  

"autoload": { …   // use whichever method you prefer, but make sure it’s being loaded correctly

"minimum-stability": "dev"  
  1. composer dump-autoload

main project:
1. edit your composer.json to contain the following:

  "repositories": [
    {
      "type": "vcs",
      "url": "/full/path/to/the/local/package/package-name"
    }
  ],
  "require": {
    "vendor-name/package-name": "dev-master"
  },
  1. composer update vendor-name/package-name
  2. now check your vendor directory you should see the vendor-name/package- name

NOTE: whenever you make change in the local package (not the vendor) you need to git commit then you can composer update the main project, it will get the latest copy of the repo to the main project vendor directory.

Advantage:
- you don’t touch the vendor directory (running composer update by mistake will not override your local changes) - you don’t need your package to be on packagist to use it
Disadvantage:
- you have to keep committing your changes (in the local package) and then running composer update in the main project
- you cannot publish the composer.json on production (needs editing before publishing to require the real package)

Glen Solsberry
  • 11,960
  • 15
  • 69
  • 94
Mahmoud Zalt
  • 30,478
  • 7
  • 87
  • 83
  • 7
    Thanks, excellent! **note:** if you are you using the _vcs_ approach (#2), don't forget to commit your composer.json changes. Easy to forget and you'll be scratching your head as to why composer is barfing up your package with "package version not found" errors. – mangonights May 09 '16 at 14:20
  • second method and @mangonights comment saved me too...thanks you all bro – Zaffar Saffee Aug 19 '16 at 20:36
  • Another advantage of the second approach over the first is the accessibility of the code for the IDE for code completion. – nibra Mar 29 '17 at 22:49
  • 1
    I used the second method and i got this error: No valid composer.json was found in any branch or tag of ..., could not load a package from it. And in order to fix it I used @mangonights reply, and commited changes to my local repository and that solved my problem – Gandalf Oct 22 '17 at 07:31
  • 1
    Method 1 is really great in terms of dev productivity, since I don't have to waste time for "composer update" command. However, composer Autoloader does not cope well with **transitive dependencies**. In other words, if "ProjectA" depends on "ProjectB" and latter depends on "ProjectC", then Method 1 is not really working, unless I explicitly specify in ProjectA's composer.json file that "ProjectA" depends on both "ProjectB/ProjectC". But this approach does not scale well in case you 20+ small projects. The autoloader management becomes nightmare. @Mahmoud, do you have any ideas on this? – Miroslav Dzhokanov Jul 13 '18 at 08:44
  • Method 2 worked for me, but only once I realized two things. First, `dev-master` is the git branch name prepended by `dev-`. The default branch name is `master`, but my branch was named `my-branch-xyz`, so in the JSON I had to put `dev-my-branch-xyz`. Second issue, I didn't realize that simply modifying files and then running `composer update` would ignore whatever changes you made. For Composer to recognize your changes, you must make a local commit of the changes (no need to push to github.com). This answer mentions that, but I was mislead by Step 1: ..."no need to commit anything" – Micah Lindstrom Apr 10 '20 at 07:09
  • Anyone run into issues when the local package requires other packages? Running the first method worked but it didn't install the "require" packages in the local package. – Chris Jul 20 '21 at 18:53
  • In solution, 2, I note that the main project's `composer.json` file has a `require: { "vendor/package": "dev-master" }`. I tried to `require: { "vendor/package": "1.2.0" }`, but it seems that Composer isn't intelligent enough to read the local tags in my local Git repo (which have not yet been pushed to origin). I find that frustrating. – cartbeforehorse Dec 05 '22 at 23:38
24

I think you've just got the syntax wrong. The type should just be VCS, and then composer figures out what type of VCS it is.

So in your project B, the entry for repositories should be:

"repositories": [
    {
        "type": "vcs",
        "url" : "/d/workspaces/util"
    }
],

You don't need to name what library is available in /d/workspaces/util. Composer will scan the composer.json file in that directory and know what project name is available there, and use the project from that directory in preference to a version listed on packagist or other repository.

Danack
  • 24,939
  • 16
  • 90
  • 122
9

The easiest way is to use type=path https://getcomposer.org/doc/05-repositories.md#path

{
    "repositories": [
        {
            "type" : "path",
            "url" : "/d/workspaces/util"
        }   
    ],
    "require": {
        "project/util" : "*"
    },
}
aimme
  • 6,385
  • 7
  • 48
  • 65
IonV
  • 372
  • 2
  • 7
6

I found this tutorial really useful: https://johannespichler.com/developing-composer-packages-locally/ when I was facing issues with local package production

Note the symlink condition allowing the vendor folder to be a symlink which then means you no longer need to composer update each time you want to see change

"options": {
        "symlink": true
      }
Friendly Code
  • 1,585
  • 1
  • 25
  • 41
4

In addition to Danack's solution: Changing the path from /d/ to d:/ worked for me.

Like this:

"repositories": [
    {
        "type": "vcs",
        "url" : "d:/workspaces/util"
    }
],
Max
  • 121
  • 6
0

NOTE: This answer assumes that you have something like a Package Registry or GIT repository where you can retrieve the releases of your package. If you do not yet have this. https://getcomposer.org/doc/05-repositories.md

Composer enables us to autoload a local development package without contaminating the composer.lock file. When Composer finds a conflict between two or more packages it wil autoload only one of these packages.

You can use the autoload-dev to autoload a specific folder for development. (https://getcomposer.org/doc/04-schema.md#autoload-dev)

The autoload-dev (and autoload) settings do not touch the composer.lock file

In your projects composer.json file:

"repositories": {
    "99999999": {
        "type": "composer",
        "url": "https://gitlab.com/api/v4/group/99999999/-/packages/composer/packages.json"
    }
}
"require": {
    "a-vendor-name/test-package": "1.0.*"
}, 
"autoload-dev": {
    "classmap": [
        "./../../packages/a-vendor-name/test-package"
    ],
    "exclude-from-classmap": [
        "vendor/a-vendor-name/test-package"
    ]
}

In this example the packages directory lives outside the project root and contains its own package GIT repositories.

autoload-dev because we only want this folder to load when we are developing. (https://getcomposer.org/doc/04-schema.md#autoload-dev)

classmap to load the packages from a local directory. (https://getcomposer.org/doc/04-schema.md#classmap)

exclude-from-classmap to disable loading the package within the vendor directory. Will also suppress the warning about multiple classes with the same namespace. (https://getcomposer.org/doc/04-schema.md#exclude-files-from-classmaps)

Running DEVELOPMENT (default behaviour):

composer update a-vendor-name/test-package // or any other composer command 

Your package will still be downloaded from your Package Registry. This downloaded package is not only ignored in you applications code, its also possible to update it according to the project composer.json file. Which in turn will update the composer.lock file, the right way.

Running DTAP / PRODUCTION by using the --no-dev flag:

composer update a-vendor-name/test-package --no-dev // or any other composer command 
feskr
  • 759
  • 6
  • 10
0

In addition to @Glen Solsberry's solutions, if you're running in a docker container like me, you can add a volume to your docker-compose.yml file like:

services:
  theservicename:
    ...
    volumes:
      - ../:/var/www
      - /path/to/src/package:/var/www/vendor/path/to/src/package
    ...

When you make changes locally they will reflect in the container.

Chris
  • 4,643
  • 6
  • 31
  • 49