I am importing a third-party package into my project using composer.
The composer.json of the package autoloads its classes using "classmap":
{
...
"name"=>"vendor/project",
...
"require": {
"php": ">=5.2.0"
},
"type": "library",
"include-path":["src/"],
"classmap": [
"src/path/to/lib1",
"src/path/to/lib2"
]
...
}
My project composer.json pulls the package in using "require".
{
...
"require": {
"vendor/project": "m.n.*",
}
...
}
I'd like to add a namespace that can prefix all the classes of that package when I use it in my project, can I do this in composer?
I am aware I can use autoload at the level of my project, but presumably these classes don't need loading again and where do I point it?
You cannot add a namespace to a project without editing every individual file in the project and adding a namespace .. declaration at its top. This is likely infeasible.
If you namespace your own code, there should be no possible problem of a name clash.
If the library clashes with yet another non-namespaced third party library which you also cannot feasibly namespace, then you're in trouble. Unless this is the case, there's no real reason to worry about it.
If composer's definition is set up properly, all you should need to do is simply use the class:
$foo = new \VendorClass;
Composer's autoloading will take care of loading the class, a missing namespace is of no concern (see above).
Related
I'm a bit confused because I'm programming a plugin for WordPress by using composer as it's the real way to go.
So I've created a composer file inside my plugin and some other stuff. In the composer file I've added my namespace for autoloading:
"autoload": {
"psr-4": {
"Johnny\\Lolkick\\": [
"includes/classes/"
]
}
}
Inside my classes folder I've created now a class with the name class-main.php. I've decided to take this name because of the WordPress naming conventions:
https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#naming-conventions
The class by itself was named class Main {. Inside my base plugin file I've created now a new instance of my class which failed. After changing the file name to Main.php it worked.
So in result the WordPress naming convention broke the autoloading of composer. I want to know now how do you handle this problem? How should I keep the naming convention by using composer?
Since your code base is not compatible with PSR-4 autoloading, a psr-4 mapping inside your composer.json's autoload section won't work, as you noticed.
I'd say you have two choices here:
First one would be to use classmap instead:
{
"autoload": {
"classmap": ["includes/classes/"]
}
}
This would simply parse all the files recursively within that folder and map the classes to their names, no matter what naming scheme you're following.
Second one would be to build your own autoloader, and use files to have it loaded automatically:
{
"autoload": {
"files": ["includes/autoloader.php"]
}
}
That autoloader would have to define what should happen (which class should be loaded, or not) when referring to a given class name.
In both cases, don't forget to run composer dump-autoload afterward.
I'm trying to create a composer package that also contains src/functions.php with some general functions. I have the following in composer.json to make it autoload:
"autoload": {
"files": ["src/functions.php"]
}
When I import this package into a project it will try to load src/functions.php in the current project (local) in stead of the imported package. Is there a way to ensure the correct file is loaded when imported (./vendor/bla/src/functions.php)?
Autoloading is not for loading everything. If src/functions.php contains class just ensure it's properly namespaced and I see no reason why autoloader would pick your local class instead of package's. If you are using the same namespace for the package and for code in your project then basically you should stop doing so.
If src/functions.php is just bunch of functions, then I strognly suggest refactoring the code and wrap them in properly namespaced class. You can make your functions static methods so basically not much would change from usage perspective.
EDIT
Once you finish refactoring, change your composer.json from what you shown in question to:
"autoload": {
"classmap": ["src/"]
}
I'm currently developing a framework but I couldn't figure out how am I going to set autoloading. First I created a package with sample class and composer.json. I've autoloaded that sample class by:
"autoload": {
"classmap": [
"libs/"
]
}
I've checked /vendor/mypackage/vendor/composer/autoload_classmap.php and confirmed that package's autoloader is working fine. But the problem is I can't reach that package's class from main app unless I directly include that package's autoload.php.
UPDATE
/vendor/foo/mypackage/composer.json
"autoload": {
"psr-4": {
"Http\\": "libs/"
}
}
/vendor/foo/mypackage/libs/Request.php
namespace Http;
class Request {}
First of all, it's often better to use psr-0 or psr-4 autoloading config. With the classmap, you have to redump the autoloader each time you add a new class or rename one.
You always need to include the Composer autoloader by using require 'vendor/autoload.php';. The best place to add such require statement is in your front controller file.
Solved it by myself. I just had to reinstall package whenever I change pacakge's composer.json.
Previously I have only been using third party libraries that use namespaces together with Zend Framework 2. Now I need to use a library that does not use namespaces, and I cannot seem to make it work. I installed it via Composer, and it is installed fine into the vendor directory. I am trying to use it as follows:
$obj = new \SEOstats();
The result is a fatal error indicating that the class could not be found. I have tried to manually configure the StandardAutoloader, but so far without any luck. I thought that the autoloading would be done for me automatically when installing through Composer, but I guess that is not the case without namespaces? I haven't seen any reference to the library in the autoload files that Composer generated. I guess I have to do it manually - but how?
Thanks in advance.
You can use the files and classmap keys.
As an example consider this composer.json:
{
"require": {
"vendor-example/non-psr0-libraries": "dev-master",
},
"autoload":{
"files": ["vendor/vendor-example/non-psr0-libraries/Library01.php"]
}
}
Using the files key you can then use
$lib = new \Library01();
Use the classmap key when you need to load multiple files containing classes. The composer.json would be:
{
"require": {
"vendor-example/non-psr0-libraries": "dev-master",
},
"autoload":{
"classmap": ["vendor/vendor-example/non-psr0-libraries/"]
}
}
Composer will scan for .php and .inc files inside the specified directory configuring the autoloader for each file/class.
For more info you can check http://getcomposer.org/doc/04-schema.md#files and http://getcomposer.org/doc/04-schema.md#classmap
If you are under a namespace while creating the object, you must use the "\" (root namespace), otherwise you will use the Library01 class under the current namespace (if you have one, if you don't have one you'll get an error).
I've started a new project, where I use Composer to handle some dependencies, as well as their auto-loading.
I only keep the composer.json file in the VCS, instead of the entire vendor directory, so I don't want to start adding my code in there.
How should I handle my own project specific code, so that it auto loads as well?
This is actually very simple. Excluding vendors directory from your repository is the right approach. Your code should be stored in a separate place (like src).
Use the autoload property to make that composer recognizes your namespace(s):
{
"autoload": {
"psr-4": {
"Acme\\": "src/"
}
}
}
Assuming you have class names following the psr-4 standard, it should work. Below some example of class names and their locations on the file system:
Acme\Command\HelloCommand -> src/Command/HelloCommand.php
Acme\Form\Type\EmployeeType -> src/Form/Type/EmployeeType.php
Remember to define a namespace for each class. Here's an example of Acme\Command\HelloCommand:
<?php
namespace Acme\Command;
class HelloCommand
{
}
Don't forget to include the autoloader in your PHP controllers:
<?php
require 'vendor/autoload.php';
Read more on PSR-4 standard on PHP Framework Interoperability Group.
Note that if you edit composer.json, you need to either run install, update or dump-autoload to refresh the autoloader class paths.