I'm struggling to work out how to correctly build and autoload my first composer package. I understand that if I follow the PSR-0 naming convention, autoloading should "just work". I am trying to set up with:
vendor: Programster
package name: CoreLibs
I have managed to debug a project that includes the package to the point where I am outputting the search path by putting a print in the findFileWithExtension() function of the ClassLoader.php file
/home/stuart/Desktop/test-project/vendor/Programster/CoreLibs/Programster/Programster/CoreLibs/Core.php
I know that the file is actually located at:
/home/stuart/Desktop/test-project/vendor/Programster/CoreLibs/Core.php
My Package's composer.json file:
{
"name": "Programster/CoreLibs",
"type": "library",
"description": "Core libraries for PHP 5.3+",
"keywords": ["core","library"],
"homepage": "http://svn.yadda-yadda.com/php/core-libs",
"license": "none",
"authors": [
{
"name": "xxxx",
"email": "my.email#email.com",
"homepage": "http://mywebsite.com/",
"role": "Developer"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-0": {
"Programster": "Programster"
}
}
}
The following is a tiny script in a project that includes the package to test if is working:
<?php
require_once(__DIR__ . '/../vendor/autoload.php');
$loader = new \Composer\Autoload\ClassLoader();
$loader->register();
use \Programster\CoreLibs as programster;
programster\Core::println("hello world");
The project's composer.json file to include the package:
{
"repositories": [ { "type": "composer", "url": "http://satis.mydomain.com/" } ],
"require": {
"Programster/CoreLibs": "dev-trunk"
}
}
Is my package's config wrong, or do I really need to create Programster/CoreLibs/ subdirectories within the CoreLibs repository source code?
use \Programster\CoreLibs as programster;
programster\Core::println("hello world");
Your class name evaluates to \Programster\CoreLibs\Core.
With this PSR-0 autoloading,
"psr-0": {
"Programster": "Programster"
}
the class name will be completely converted into a path name like "Programster/CoreLibs/Core.php", and this path will be searched inside the directory "Programster" relative to your libraries composer.json location.
Using PSR-4 autoloading,
"psr-4": {
"Programster\\CoreLibs\\": ""
}
the prefix in this definition will be removed from the classname, the remainder will be converted to a path (i.e. "Core.php") and be searched in the path mentioned (in this case, in the main directory of the library, because "" + "Core.php" is pointing to a file in without any sub directory).
Your second definition is better in some regards. It uses a longer prefix, which is relevant if you include more than one library using the same prefix, because then Composer would have to search more than one path to find the class. And it uses a shorter path, which also allows for slightly faster disk I/O operations (I haven't done any performance measurements, though).
I managed to get it working by using the PSR-4 standard that others suggested in the comments and updating my package's composer.json file (see the autoload section):
{
"name": "Programster/CoreLibs",
"type": "library",
"description": "Core libraries for PHP 5.3+",
"keywords": ["core","library"],
"homepage": "http://svn.mydomain/core-libs",
"license": "none",
"authors": [
{
"name": "MY name",
"email": "my.email#email.com",
"homepage": "http://my-website.com/",
"role": "Developer"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Programster\\CoreLibs\\": ""
}
}
}
This is my script in the project that has the package installed:
require_once(__DIR__ . '/../vendor/autoload.php');
\Programster\CoreLibs\Core::println("hello world");
#sectus was right, I did not need to use $loader = new \Composer\Autoload\ClassLoader();$loader->register();
Related
I have created a package to separate out business logic into easier to distribute modules. The composer file looks like this:
{
"name": "aggiq/johnny-cash",
"description": "A collection of controllers, models, migrations, and tests for a phonebanking backend.",
"license": "MIT",
"authors": [ ... ],
"require": {
"illuminate/database": ">=5.5"
},
"require-dev": {
"fzaninotto/faker": "~1.4"
},
"autoload": {
"psr-4": {
"Johnny\\Phonebanking\\": "src/"
}
}
}
And our source files are indeed in src/:
src/Controllers/PhonebankController.php
src/Models/Phonebank.php
...
I saved and pushed this to our gitlab repo, and then included it as a dependency in a test project:
{
...,
"repositories": [{
"type": "package",
"package": {
"name": "aggiq/johnny-cash",
"version": "0.1",
"type": "package",
"source": {
"url": "gitlab url",
"type": "git",
"reference": "dev"
}
}
}],
"require": {
"aggiq/johnny-cash": "*",
},
...
}
And when I do composer update, it successfully grabs the project and downloads it into the vendor folder:
vendor/aggiq/johnny-cash/Controllers/PhonebankController.php
...
However, when I look in the test project's autoload_psr4.php, it's not there. Is there a step I missed?
Edit: updates the directories to have capital letters to match the namespaces, and here is the generated PSR4 php file:
<?php
// autoload_psr4.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
You have registered autoloading at your package's composer.json correctly:
"autoload": {
"psr-4": {
"Johnny\\Phonebanking\\": "src/"
}
}
This means, any class in Johnny\Phonebanking namespace will be in src directory. E.g.:
Johnny\Phonebanking\SomeClass => src/SomeClass.php
Johnny\Phonebanking\SomeNamespace\AnotherClass => src/SomeNamespace\AnotherClass.php
As you can see, it has to respect CapitalLetters.
Saying that, you should correct first letters of your directories, from:
src/controllers/PhonebankController.php
src/models/Phonebank.php
to
src/Controllers/PhonebankController.php
src/Models/Phonebank.php
I have solved it. We needed to do two things.
The repository type specified in the parent pacakge should be vcs not package since we are loading from a git server:
"repositories": [{
"type": "vcs",
"url": "git#xxx.git"
}]
The package type in the child package should be library:
"type": "library"
Once those two changes were made, composer update installed not only the child package but also its dependencies, proving it is being recognized by composer.
I am in the midst of learning how to better maintain the code that I write. I have two projects that I am currently working on - both are in development and both are pushed to GitHub.
I am trying to include the one project in the other (by declaring it a dependency in the one project's composer.json file) - but after it is included, it is missing the proper autoload configurations.
I'll explain a little better: Project A's composer.json file has an autoload line for "psr-4" mapping the namespace to the "src" directory - all is good and working after I run:
composer install
I am then able to include the /vendor/autoload.php file and immediately start working with the project. When I look at the generated "autoload_psr4.php" file in that project's vendor directory, I can see the array contains a reference for the mapped namespace / directory per the composer.json file.
The problem comes when I try to include Project A within Project B as a dependency - everything looks to work after running the composer install - the vendor directory is created and the files are copied there - however when I look at the generated "autoload_psr4.php" file in project B it is missing the mapped namespace / directory per Project A's composer.json file.
Can someone point me in the direction for what I might be missing to get the autoload line to carry over into Project B?
Here's the two composer.json files:
Project A:
{
"name": "jfreynik/hydra-net",
"description": "Network classes for the Hydra framework.",
"type": "library",
"keywords": [ "http", "net", "rest" ],
"license": "MIT",
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"hydra\\net\\": "src/"
}
}
}
Project B:
{
"name": "jfreynik/simple-mvc",
"description": "A pretty simple MVC framework for building websites.",
"type": "framework",
"keywords": [ "MVC", "Website Framework" ],
"license": "MIT",
"repositories": [
{
"type":"package",
"package": {
"name": "jfreynik/hydra-net",
"version":"*-dev",
"source": {
"url": "https://github.com/jfreynik/hydra-net.git",
"type": "git",
"reference":"master"
}
}
}
],
"require": {
"jfreynik/hydra-net": "*-dev"
},
"minumum-stability": "dev"
}
Thank You!
The issue was that I was including Project A into Project B as a "package". I believe "packages" are not scanned for their contained composer.json files. (please correct me if I'm wrong) - by changing Project B's composer.json file to reference Project A as "vcs" then the autoloading works again. - Here is the adjusted composer.json file for Project B.
{
"name": "jfreynik/simple-mvc",
"description": "A pretty simple little MVC framework for building websites.",
"type": "framework",
"keywords": [ "MVC", "Website Framework" ],
"license": "MIT",
"repositories": [
{
"type":"vcs",
"url": "https://github.com/jfreynik/hydra-net"
}
],
"require": {
"jfreynik/hydra-net": "dev-master"
},
"minumum-stability": "dev"
}
I really had trouble finding working examples as I am really just starting to use composer and prior to this had only included professional packages from packagist. I have much to learn (even in regard to terminology) - so if anyone can add additional relevant information for the proper way to include 1 development project in another I will accept your answer.
So, I'm trying to use jcleblanc/reddit-php-sdk, but it follows no standards whatsoever and does not have a repository available, so I've had to manually define it myself in my composer.json file:
"repositories" : [{
"type": "package",
"package": {
"name": "jcleblanc/reddit-php-sdk",
"version": "dev-master",
"source": {
"url": "https://github.com/jcleblanc/reddit-php-sdk",
"type": "git",
"reference": "origin/master"
},
"autoload": {
"classmap": ["reddit-php-sdk/", "/", "reddit.php", "config.php"]
}
}
}],
Directory structure in vendor/ here:
However, when I then run composer dump-autoload, the classes in this project are not autoloaded, and don't appear in any of the autoload_*.php composer files. This means I of course get a "Class 'reddit' not found" error whenever I try and use it.
Solutions?
You can use Composer's file autoloading.
{
"autoload": {
"files": ["src/MyLibrary/functions.php"]
}
}
However, that's more geared towards helper function files and I've not tried it with a Class file (although there's no reason it shouldn't work).
Ended up forking the project myself, but it turns out the original project is broken anyway.
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
I'm using the excellent phpwkhtmltopdf library and want to update to latest version and for this I need to use composer.
File structure:
vendor
--mikehaertl
--php-shellcommand
--php-tmpfile
autoload.php
Composer.json file:
{
"name": "mikehaertl/phpwkhtmltopdf",
"description": "A slim PHP wrapper around wkhtmltopdf with an easy to use and clean OOP interface",
"keywords": ["pdf", "wkhtmltopdf", "wkhtmltoimage" ],
"homepage": "http://mikehaertl.github.com/phpwkhtmltopdf/",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Michael Haertl",
"email": "haertl.mike#gmail.com"
}
],
"require": {
"php": ">=5.0.0",
"mikehaertl/php-tmpfile": "1.0.*",
"mikehaertl/php-shellcommand": "1.0.*"
},
"autoload": {
"psr-4": {
"mikehaertl\\wkhtmlto\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
}
}
I'm trying to use the library like this:
require '/home/bookmark/vendor/autoload.php';
use mikehaertl\wkhtmlto\Pdf;
...
$pdf = new Pdf('http://anysite.com'); <-- error points to this line
The problem is I get the error:
Fatal error: Class 'mikehaertl\wkhtmlto\Pdf' not found in /home/bookmark/public_html/ajax/action.php on line 132
This is my first time using composer, any idea what I'm doing wrong?
If you are using some package, you must not copy their composer.json file - that won't work.
The best thing would be to run composer init once to create an initial composer.json file for your project, and composer require mikehaertl/phpwkhtmltopdf:~2.0 to add this package you want to work with.
After that, it should work.