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.
Related
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.
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.
I have 2 packages on Packagist.
https://packagist.org/packages/erayalakese/envato-market-api (A)
https://packagist.org/packages/erayalakese/envato-update-checker (B)
B requires A.
Now I'm using B package on my projects. But I'm getting Class 'erayalakese\Envato_Update_Checker' (package B) not found error.
This is my composer.json file
{
"name": "",
"description": "",
"require": {
"erayalakese/envato-update-checker": "^1.3"
},
"authors": ...
}
And my project file:
<?php
require_once(__DIR__.'/vendor/autoload.php');
new erayalakese\Envato_Update_Checker(...);
When I add this to my composer.json as temporary solution, it's working :
"autoload": {
"classmap": ["vendor/"]
}
But I'm not sure I really need to add vendor folder to autoload . I was expecting it will autoload my vendors automatically.
Can you tell me what's I'm missing?
You have to change the composer.json of both packages.
Both packages need to define a autoload section.
Referencing: https://getcomposer.org/doc/04-schema.md#classmap
erayalakese/envato-market-api
https://github.com/erayalakese/envato-market-api/blob/master/composer.json
{
"name": "erayalakese/envato-market-api",
"description": "Envato Market API to verify and download Envato purchases",
"authors": [
{
"name": "Eray Alakese",
"email": "erayalakese#gmail.com"
}
],
"require": {},
"license": "GPL v2",
"autoload": {
"classmap": ["Envato_Market_API.php"]
}
}
Now this package has a autoload classmap definition, which consists of one PHP file. When you composer install, the autoload definition of the package will be added to the Composer Autoloader.
Same game for the other package:
erayalakese/envato-update-checker
https://github.com/erayalakese/envato-update-checker/blob/master/composer.json
{
"name": "erayalakese/envato-update-checker",
"description": "Checks Envato WordPress plugins' updates and download its if any update available",
"require": {
"erayalakese/envato-market-api": "^1.0"
},
"authors": [
{
"name": "Eray Alakese",
"email": "erayalakese#gmail.com"
}
],
"license": "GPL v2",
"autoload": {
"classmap": ["Envato_Update_Checker.php"]
}
}
In your main project:
require the "updater" package in the composer.json of your main project
the updater packages included the api package via it's require section (so you get both)
add require_once(__DIR__ . '/vendor/autoload.php'); to the project bootstrap
enjoy Class via Composers Autoloader: new erayalakese\Envato_Update_Checker(...);
Remove this line:
https://github.com/erayalakese/envato-update-checker/blob/master/Envato_Update_Checker.php#L11
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.
I'm trying to create a composer package but I'm getting a class not found error. I'm using Laravel 4 but I'm trying to create a generic PHP package.
I created the package in my vendor/ directory.
vendor/
theninthnode/
defaqto/
src/
Defaqto.php
vendor/
composer.json
Here is my composer.json file
{
"name": "theninthnode/defaqto",
"description": "",
"authors": [
{
"name": "Billy Jones",
"email": "billyjones26#gmail.com"
}
],
"minimum-stability": "dev",
"require": {
"php": ">=5.3.0"
},
"autoload": {
"classmap": ["src"]
}
}
And my class:
<?php
class Defaqto
{
....
}
When I try to call the package class from my app like so
$defaqto = new Defaqto();
I just get
Class 'Defaqto' not found
I've tried composer dump-autoload from within my package and also my applications root.
I also tried adding theninthnode/defaqto to my root composer.json file.
Am I missing something?