Composer ignoring zip dependecies' composer.json file - php

I'm using Composer for a project that needs to handle some dependencies but I got a really weird issue. Composer is ignoring the composer.json file contained in child packages.
My project needs to retrieve some custom zip packages, in these packages a composer.json file defines other requirements. The repositories of these requirements are declared in the root composer.json file since Composer cant recursively fetch repositories.
The thing is that after my zip package is downloaded, unpacked and placed in the vendor dir, composer totally ignores its composer.json where other requirements are defined...
The zip archive is something like this:
/dir1
/dir2
file1
file2
composer.json
To give you an idea this is how my root composer.json looks like:
{
"name": "myproject/project",
"type": "library",
"repositories": [
{
"packagist" : false
},
{
"type": "package",
"package": {
"name" : "giulianobundles/mybundle",
"version" : "1",
"dist": {
"url": "http://url/to/zip/file",
"type": "zip"
}
}
},
{
"type": "package",
"package": {
"name" : "giulianobundles/mybundlerequirement",
"version" : "1",
"dist": {
"url": "http://url/to/zip/file",
"type": "zip"
},
}
},
],
"require": {
"php": ">=5.3.2",
"giulianobundles/mybundle": "*"
},
"autoload": {
"psr-0": {
"config": "./"
}
},
}
and the bundle's composer.json package looks like
{
"name": "giulianobundles/mybundle",
"type":"library",
"require": {
"giulianobundles/mybundlerequirement": "1"
}
}
Mybundle package get succesfully installed but its composer.json file is totally ignored. Any idea? What am I missing?

Indeed, Composer will not recursively look at composer.json files in the file system. It needs to see the composer.json files in the repository. The way it usually works is that a package has a git or svn URL somewhere. Composer will fetch, for instance, git://<host>/<package>/composer.json directly from the repository to figure out that package's dependencies before it's even installed to calculate the overall dependencies.
In your case, you are defining a package inline in your own composer.json file. This is used instead of a composer.json file in the dependency. This means Composer takes the "package": { ... } to be the canonical composer.json file for that package, it will not look into the code itself; especially not after unpacking it. It treats the Zip file as if it had no composer.json file of its own.
Define the dependencies in the "package": { ... } or host the code in a version control system from which Composer can fetch the composer.json file.

Related

Private repo composer.json not being used

My problem is that a privately made repo's composer.json seems to be broken when trying to use it as a package elsewhere.
I have a private repo with code needed for other projects. The repo's composer.json looks like this:
{
"name": "somevendor/global",
"require": {
"nesbot/carbon": "^1.21"
},
"autoload": {
"psr-4": {
"" : "src/"
},
"files": [
"somedir/somefile.php"
]
}
}
The src is in the base directory of the repo, and contains PSR-4 namespaced classes. I have namespace folders within that, e.g. a Foo directory with classes in the Foo namespace:
-- src
-- Foo
// some Foo\... classes
// some global namespace classes
-- somedir
somefile.php // A file with helper functions
In the project folder, I'm accessing the somevendor/global repo via a composer.json file:
{
"require": {
"somevendor/global-folder": "dev-master"
},
"repositories": [
{
"type": "package",
"package": {
"name": "somevendor/global",
"version": "dev-master",
"type": "package",
"source": {
"url": "git#bitbucket.org/somevendor/global.git",
"type": "git",
"reference": "master"
}
}
}
]
}
Running composer install in the project folder seems to work at first. I have installed SSH keys properly so it can access the private repo on Bitbucket and grab the files:
$ composer install
Loading composer repositories with package information
Updating dependencies (including require-dev)
- Installing somevendor/global (dev-master master)
Cloning master
Writing lock file
Generating autoload files
And then in the project's PHP code I require vendor/autoload.php, but none of the classes are being autoloaded, including the Carbon package specified in the first repo's composer.json file:
Fatal error: Uncaught Error: Class 'Foo\Foo' not found in...
I've clearly made a mistake here, have I structured the first repo wrongly?
I "solved" this by taking out all of the "require" entries from the remote repo's composer.json file and moving them to the local website's composer.json file.
This is what the files looked like:
The remote private repo's composer.json:
{
"name": "somevendor/global",
"license": "proprietary",
"autoload": {
"psr-4": {
"" : "src/"
},
"files": [
"functions/functions.php"
]
}
}
The local website's composer.json:
{
"require": {
"nesbot/carbon": "^1.21",
"somevendor/global": "dev-master"
},
"repositories": [
{
"type": "vcs",
"url": "git#bitbucket.org:somevendor/global.git"
}
]
}
It kept throwing Composer\Repository\InvalidRepositoryException because I forgot to put the name into the remote repo's composer.json file, so don't forget that bit!
Also remember to set up your git ssh keys if you've set them up. I used this Bitbucket tutorial to do this.

Composer not autoloading files included through repositories > type > path

The Problem
I have two PSR-4 composer projects and I wish to classes from one in the other, the file structure is as follows:
projectfoo
-public
--index.php
-src
--CompanyName
---Foo
----Foo.php
-composer.json
projectbar
-src
--CompanyName
---Bar
----Bar.php
-composer.json
The composer.json files are defined for projectfoo as (note the repositories > type > path dependency):
{
"name": "companyname/foo",
"require": {
"companyname/bar": "*"
},
"repositories": [
{
"type": "path",
"url": "../projectbar"
}
],
"autoload": {
"psr-4": {
"CompanyName\\": "src/CompanyName"
}
}
}
And projectbar as:
{
"name": "companyname/bar",
"version": "1.0.0",
"autoload": {
"psr-4": {
"CompanyName\\": "src/CompanyName"
}
}
}
Running composer update correctly produces the vendor folder containing the companyname/foo folder.
In index.php in projectfoo I have:
require_once '../vendor/autoload.php';
$bar = new \CompanyName\Bar\Bar();
However, when run \CompanyName\Bar\Bar is undefined.
The question
Why is Bar not being included in the autoload.php file?
What I've tried
Refreshing the autoload file using:
composer install
composer update
composer dump-autoload
Changing the vendor name CompanyName to something different.
Looking at the installed.json file in the vendor\composer folder the bar project is listed as:
#
{
"name": "companyname/bar",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"dist": {
"type": "path",
"url": "../companyname/bar",
"reference": "f35ed0ad82c8280db9b603712dd256074f99e196",
"shasum": null
},
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"CompanyName\\": "src/CompanyName",
}
}
}
Strangely, when bootstrapping the autoload.php file to phpunit the files autoload correctly and are available in my test classes.
The issue revolves around the way composer links "path" projects using symlinks.
In short
Because I was developing on a windows system and executing the code on an Ubuntu vagrant box the symlinks set up on windows, when running composer install were resolving to broken paths inside the box. This also explains why tests run on windows managed to locate Bar but not tests run in the virtual box.
Solutions
To solve this I initially forced composer to mirror the project rather than symlink it, however, this still caused issues with symlinks in the vendor folder.
I have now started hosting my libraries in seperate repositories and importing them using the "type": "vcs" tag which works well. Composer also handles updating package when new commits are made which doesn't happen when using the "type": "path" tag with mirroring.

Test my own composer package does not work

I want to make a composer package. However, I am still in the development phase, would or would but the earlier test out.
I have an empty vendor folder with the autoloader from composer:
/vendor
/composer
autoload.php
So now I've tried my package "simulate" and creates my folder structure and composer.json:
/vendor
/composer
/me
/package
/src
/tests
composer.json
autoload.php
This is my composer.json:
{
"name": "me/package",
"description": "",
"license": "",
"authors": [
{
"name": "",
"email": ""
}
],
"minimum-stability": "dev",
"require": {
"php": ">=5.4.0"
},
"autoload": {
"psr-4": {
"Me\\Package\\": "src/"
}
}
}
And here is my class:
namespace Me\Package;
class Test {
// ...
}
If I want to call it:
if(file_exists('vendor/autoload.php')) require 'vendor/autoload.php';
$test = new \Me\Package\Test();
i become Fatal error: Class 'Me\Package\Test' not found.
Of course, I also inserted a composer.json in the root directory, but I can still bad at require my package state since it was not published, right? But how do I test it then and say to composer he should autoload my package?
If you want to use composer to include a package that is not listed on http://Packagist.org/ you would add a 'repositories' stanza into the composer.json (project root file). This reads the project, and gets the composer.json from it, using the name for the main-'requires' section.
"repositories": [
{
"type": "vcs",
"url": "https://github.com/example/private-repo.git"
}
}
The 'url' part, can also in fact be any valid URL for a git, SVN or HG repository - even a file:// based reference.

Composer, Laravel and local packages

My issue is I have a package which isn't a repository and I am trying to get it to play nice with Laravel and composer. It is still located under the vendor folder, the only issue is that if I simply set:
"psr-0": {
"Test\\Test": "vendor/test/test/src/"
}
This will load the service provider but none of the controllers etc will autoload. What is the correct way to implement a package with larval that does not have it's own repository. Or does this go against the nature of packages and this should simply be structured under the applications controllers.
The package was created by me using workbench but I found i did not really need this as a separate repository but it would still be good to keep it as a package. Therefore the structure is exactly the same as a regular package:
vendor
testvendor
testpackage
public
src
tests
.gitignore
composer.json
phpunit.xml
UPDATE:
As a solution for the time being I am using:
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php",
"vendor/package"
]
},
As an entry in the class map. Looking forward I will probably refactor this into the app folder or create a repository for this package.
If you have some classes that you're calling "package", you're not supposed to add those files to your vendor folder. This folder is managed by composer and at any time you might loose it. Create a subfolder in your application and put those files there.
You have to be sure your PSR-0 autoloading will work for every single file in your folder structure. So, if your root is vendor/test/test/src/ and your namespace is
Test\\Test
All your files must be in
vendor/test/test/src/Test/Test/ClassFileName.php
PSR-4 is easier to deal and understand, this
"psr-4": {
"Test\\Test\\": "vendor/test/test/src/"
}
Means that your files would have to be like:
vendor/test/test/src/ClassFileName.php
Doublecheck your namespaces. It's easy to make mistakes when using namespaces with PSR-0 and remember that
composer dump-autoload
Must be ran every time you change things in composer.json or create new files. If it's a simple class autoloading, every time you create a file, if it's a PSR-X autoloading, everytime you create or update a namespace in your composer.json file.
If what you have is is really a package you should use Composer: when your package is structured as a composer package (check Laravel's composer.json as an example), the correct way of adding it to your application, if it's not list in Packagist, is via repositories.
You can have (non-packagist) packages in a public VCS repository:
{
"require": {
"monolog/monolog": "dev-bugfix"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/igorw/monolog"
}
]
}
You can have (non-packagist) packages in a protected by password VCS repository (git, bitbucket...):
{
"require": {
"vendor/my-private-repo": "dev-master"
},
"repositories": [
{
"type": "vcs",
"url": "git#bitbucket.org:vendor/my-private-repo.git"
}
]
}
You can have your packages zipped in your hard drive and load them via the artifact repository type:
"repositories": [
{
"type": "artifact",
"url": "path/to/directory/with/zips/"
}
],
Though #Antonio Carlos Ribeiro's answer is really nice, I had problem with installing custom packages locally(which is also stated in the last part of his answer)
Let's assume this is the directory structure of the package we are trying to install:
D:/test_pack
src/
composer.json
If you do not want to upload your custom package (that most likely you have developed, yourself) to online repositories you can use one of the following two methods:
Method I
(You have to specify version for your package, otherwise you'll get this error: The requested package could not be found in any version, there may be a typo in the package name.)
1) In composer.json, Add version to your package. your package's json should look something like this:
{
"name": "gandalf/test_pack",//This is your package's name
"description": "some desc",
"version": "1.0.0",//This is the version that you have to specify
"authors": [
{
"name": "gandalf the grey",
"email": "fake#yahoo.com"
}
],
"minimum-stability": "dev",
"require": {
"laravel/framework": "~5.4"
},
"autoload": {
"psr-4": {
"Gandalf\\BotPack\\": "src/"
}
} }
2) zip your package(let's assume the zip file is in D:/test_pack/test_packa.zip)
3) In laravel's composer.json add your package name (in our case gandalf/test_pack into require part of json) and add the repository array to the composer.json file and in that array specify the directory in which your package's zip file exists(in our case D:/test_pack) . like this
{
...,
"require": {//adding our package name to laravel's composer.json
...,
"gandalf/test_pack": "*"//package's name
},
...,
"repositories": [
{
"type": "artifact",
"url": "D:/test_pack"
}
]
}
Method II(My Favorite method, You have to initialize your package directory as git local repository using git init and then git add . and git commit -m "your message")
1) initialize the package directory as git directory and commit all your changes to the local repository
(let's say D:/test_pack is the directory that contains your package(src/ directory and composer.json))
go to D:/test_pack directory and run these commands
git init
git add .
git commit -m "your message for this commit"
2) In your packages composer.json file add minimum-stability
{
"name": "gandalf/test_pack",
"description": "some desc",
"authors": [
{
"name": "gandalf the grey",
"email": "fake#yahoo.com"
}
],
"minimum-stability": "dev",//setting minimum-stability
"require": {
//dependencies that your package needs
},
"autoload": {
"psr-4": {
"Gandalf\\BotPack\\": "src/"
}
}
}
3)In laravel's composer.json file require the "dev-master" of your package
{
...,
"require": {
...,//some dependencies that laravel needs
"gandalf/test_pack": "dev-master"//requiring dev-master from repository
},
"repositories": [
{
"type": "git",
"url": "D:/test_pack"//path of the local repository directory which contains your package
}
]
}
To any Laravel project load local packages. which is stored in your machine.
In laravel's (Project) composer.json file add
"autoload": {
"psr-4": {
"YourPackage\\Namespace\\": "./local_Package_path/src"
}
},
and fire command in Laravel Project directory
composer dump-autoload
Optional
If package is still not available in your Project. then
Register your package's Service Provider.
To register your service provider, you just need to add an entry to the array of service providers in the config/app.php file.
'providers' => [
/*
* Laravel Framework Service Providers...
*/
...
YourPackage\Namespace\PackageServiceProvider::class,
],
Hope now your package loaded successfully in your laravel project.

Load vendor dependencies with composer.json

I have recently forked robmorgan/phinx project and modified the composer.json file in my project to use the forked version:
{
"name": "...",
"description": "...",
"repositories": [
{
"type": "package",
"package": {
"name": "lube8uy/phinx",
"version": "master",
"source": {
"url": "https://github.com/lube8uy/phinx.git",
"type": "git",
"reference": "master"
}
}
}
],
"require": {
"php": ">=5.3.0",
"lube8uy/phinx": "dev-master"
}
}
First question: additional vendors
Now, when I load the composer.json file in my project I get this forked version correctly.
What I don't know is how to load the dependencies from the phinx project itself:
https://github.com/lube8uy/phinx/blob/master/composer.json
If I use the original packagist source everything works fine and I got all the dependencies, but now that I use my own repository I can't get them.
Second question: updates
How can I receive the modifications I made to my github source?
I made some modifications, pushed them to the correct branch, then I run composer update but nothing was updated... what am I doing wrong?
Thank you very much
For your first question:
Try to require it as a VCS repository (Version Control System, see composer doc on vcs repositories), like the following:
{
"name": "...",
"description": "...",
"repositories": [
{
"type": "vcs",
"url": "https://github.com/lube8uy/phinx"
}
],
"require": {
"php": ">=5.3.0",
"robmorgan/phinx": "dev-master"
}
}
It now requires the package robmorgan/phinx which is found at https://github.com/lube8uy/phinx which is the desired fork. It still has the original name robmorgan/phinx but is found at a different location.
It still has the same name because of the package name in its composer.json. If you want to change the name to lube8ye/phinx, change it in the composer.json in the fork.
For your second question:
The changes made in a package you require via composer should be updated automatically when you execute php composer.phar update in your project. If this does not work, try to force composer to require a specific commit by adding the commit hash after dev-master in your require section like so:
"require": {
"robmorgan/phinx": "dev-master#1234abcd"
}
Whereat 1234abcd is the hash of the desired commit.
Also: Try clearing composer's cache by deleting the folders content to avoid loading a cached version (see composer doc on COMPOSER_CACHE_DIR)

Categories