I have this folder structure that I composerized:
|--repo-name
|---lib
|--TalentLMS
|--TalentLMS.php
My autoload is this
"autoload": {
"psr-4": {
"TalentLMS\\": "lib/"
}
}
When I tried calling the TalentLMS class, I always get Class 'TalentLMS' not found.
I tried removing the trailing slash in lib in the composer.json but still no joy.
Am I missing something here?
Figured out the problem.
All I did was reorganized the structure and added proper namespacing.
Related
I need to clone a project of my company on my local machine.
Problem: There is a module required in the main composer.json from our old agency which does not exist anymore, so I don't have the access keys needed to download it, BUT I have the latest code of that module.
The composer.json of that module says its name is "randomagency/import", so I added the code at vendor/randomagency/import. Then I removed the module from the main composer.json.
But I get this error:
Class 'RandomAgency\ProcessPipelines\Helper\Condition\AbstractCondition' not found#0 /var/www/company/src/vendor/composer/ClassLoader.php(444): include()
#1 /var/www/company/src/vendor/composer/ClassLoader.php(322): Composer\Autoload\includeFile()
#2 [internal function]: Composer\Autoload\ClassLoader->loadClass()
#3 [internal function]: spl_autoload_call()
My colleague told me that I need to add the module in the main composer.json under the autoload section, but Im not sure how exactly it works.
The best approach to solve it would be to create a new composer package and replace the agency URL in composer.json with my own, but I need a quick & dirty method for now.
Don't put it into vendor (as it is expected to get removed in time and the name of the vendor-dir is a configuration detail), so technically you have already put it in the wrong location. However, this is easy to recover from, just use a different path within the project root directory, e.g. create a directory where you put packages into (pkg in the following). This works already with autoloader configuration only (if that library requires no other configuration to work):
PSR-4 Autoloader (only) from Project Directory
Then add that path to the projects autoload configuration (see autoload (Composer configuration schema) - Autoload mapping for a PHP autoloader.:
{
"autoload": {
"psr-4": {
"RandomAgency\\Import\\": "pkg/random-agency-import-4.2"
}
}
}
It's good practice you have a single folder for the package - not two as in <vendor>/<package> pattern - and append an identifier of the package version.
Require as Composer Package from Project Directory
Better thought, if that package still contains the composer.json configuration file, add it as a path repository and require it with a version constraint that matches the ./pkg/random-agency-import-4.2/composer.json#/version or * if the "version" member is missing:
{
"require": {
"random-agency/import": "*"
},
"repositories": [
{
"type": "path",
"url": "./pkg/random-agency-import-4.2"
}
]
}
You then don't need to configure the autoloader manually as it is taken from the libraries composer.json configuration. This is equally true for any other configuration part incl. the dependencies of the library.
The great benefit of the path repository is, that is accepts relative paths to your projects configuration file (composer.json).
Compare with your previous understanding:
The best approach to solve it would be to create a new composer package and replace the agency URL in composer.json with my own, but I need a quick & dirty method for now.
You either have solved it by now (the package you require has a composer.json file) or you still need to add the package information, but you don't need to create a new package or exchange URLs.
Package Repository: Inline a Composer Package from Project Directory
That is because you can inline the package as well in Composer with the package repository that now has the path and if you look at /repositories/0/package closely, you can see that this is another composer.json document, just inline at that place (and the /dist member is new):
{
"repositories": [
{
"type": "package",
"package": {
"name": "random-agency/import",
"version": "4.2.0",
"dist": {
"type": "path",
"url": "./pkg/random-agency-import-4.2"
},
"autoload": {
"psr-4": {
"RandomAgency\\Import\\": ""
}
}
}
}
],
"require": {
"random-agency/import": "4.2.0"
}
}
When you do updates etc., Composer then will install the packages files into the vendor folder (where-ever it may be, and regardless how often you remove it).
If - and only if - there is no ./pkg/random-agency-import-4.2/composer.json file, you would need to create a "package", as that is the composer.json in the end.
Alternative: compser.json within the package directory
Similar as you added the autoload part to composer.json and as an alternative to the package repository, you can create the ./pkg/random-agency-import-4.2/composer.json file your own, then the path repository already suffices and it is perhaps easier to configure / maintain as the roots project composer.json file does not expand all the package details.
But that is your preference, just showing that you have a couple of options within the project itself without creating outside / "new" packages.
Figured it out. Had to add it like this:
"autoload": {
"psr-4": {
"RandomAgency\\Import\\": "vendor/random-agency/import"
},
I have the following declaration for PSR-4 autoloading in my composer.json file:
"autoload": {
"psr-4": {
"Application\\": "../source/",
"ACME\\": "source/"
}
}
My directory structure is as follows:
acme-testbed/
framework/
source/
Interfaces/
Helpers/
I18N.php
Helpers/
I18N.php
composer.json
source/
Interfaces/
Modules/
Frontend.php
Modules/
Frontend.php
This way, I can do things like \ACME\Helpers\I18N::getLanguages() or \Application\Modules\Frontend::setLanguage("es") (I would really use aliases to do just I18N::getLanguages() or Frontend::setLanguage("es") but it's just for illustrative purposes).
The problem I have is my application finds every single class under the ACME namespace but not the Application one. As you can see, every declaration for the ACME namespace is inside the framework folder (same as the composer.json file) but every declaration of the Application namespace lies within the application root, which is its parent directory.
How can I adjust the composer.json file so I can use both namespaced declarations?
EDIT #1: just realized I shown the wrong folder structure (there's no Application folder for the Application namespace declarations). My bad :)
If your namespaces match directories names, you should define autoload rules like this:
"autoload": {
"psr-4": {
"Application\\": "../source/Application/",
"ACME\\": "source/"
}
}
In your case Application namespace is in acme-testbed/source/Application, so you need to point it directly.
I am new to composer and I used it to install the oauth2-client. I think I am having some sort of misunderstanding about how this is supposed to work.
From thephpleague github page I installed from the command line using
composer require league/oauth2-client
This added files to /usr/local/bin/vendor/league/oauth2-client.
The file structure looks the same as it does on github, except I don't have all the same files.
And the php in the files is looking for files in \League\OAuth2, so I am getting errors that it can't find included files, because I don't have that directory.
Did I do it wrong, or am I just not getting something?
The backslash is the PHP namespace separator, not the directory separator.
In the composer.json for oauth2 from TheLeague, this is the autoload directive:
"autoload": {
"psr-4": {
"League\\OAuth2\\Client\\": "src/"
}
},
It says that the code inside of src directory is in the League\OAuth2\Client namespace.
Composer follows PSR-4 with regards to namespacing and autoloading, so check that out if you want to know what goes on.
UPDATE:
If you've installed other League extensions, like oauth2-facebook, it will install itself into the same src directory - because of the autoload directive in composer.json.
Why?
Well, because of the namespace, you will find 'Facebook' in the League\OAuth2\Client\Provider namespace.
Because of PSR-4, this means that they need to go into the same directory, even though they are different packages.
That is the reason why you'll see Facebook.php in src/Providers directory. Check the oauth2-facebook repository
You probably have required oauth2-facebook and oauth2-google, or one of your other required packages requires it. It rarely just add themselves. :)
In regards to Laravel, I got a question about Composer autoloading i.e. the difference between "psr-4" and "classmap" autoloading.
1 difference that I know is PSR-4 does not need repeated dumpautoload for every changes or addition of new files whereas classmap needs dumpautoload for every change in existing files containing classes or addition of new file in specified directory.
PSR-4 standard requires of you a strict filesystem structure based on namespaces. Say you have an app in src directory with App namespace, then all sub-namespaces will mirror subdirectories and class names will be the same as file names without the .php extension.
{
"autoload": {
"psr-4": { "App\\": "src/" }
}
}
src/
Foo/
Bar.php <---- App\Foo\Bar class
Baz.php <---- App\Baz class
The autoloader then "knows" where to look for the class of a certain fully qualified name and therefore doesn't require the dump-autoload command to sniff files for classes.
Performance issues are then solved with composer dump-autoload --optimize-autoloader flag, or -o, which will generate class map a similar way the classmap autoloading does.
On the other hand, classmap autoloading does not require you to have almost any certain file or directory structure, it will recursively go through .php and .inc files in specified directories and files and sniff for classes in them.
{
"autoload": {
"classmap": ["src/", "lib/", "Something.php"]
}
}
Those classes are then added to a list (cached in a PHP file in vendor/composer directory) which is used for autoloading.
Any new class then must be added to that list by running composer dump-autoload command.
I tried to autoload a file with PSR-0 ,but it is not auto loading that file. I tried the same file with PSR-4 auto loading. With PSR-4 it worked perfectly. Is there any difference in folder structure needed for PSR-0?
I couldn't make PSR-0 working even if keep the folder structure mentioned in What is the difference between PSR-0 and PSR-4?
Here is my folder structure.
Test
--Package
--Test.php
I have in Test.php:
<?php
namespace Test\Package;
class Test
{
public function __construct()
{
echo "In Test class";
}
}
and composer.json looks like
{
"autoload": {
"psr-0": {
"Test\\Package\\": "Test/Package/"
}
}
}
Counter-intuitively, the composer documentation on PSR-0 includes a partial path making it seem that PSR-0 requires a path to the package in order to load classes. In reality, PSR-0 constructs the path based on the package, so it only needs a path specified if the code lives inside a folder like src/ or lib/ that is not part of the namespace path. If the namespace based directory structure starts in the same directory as composer.json, then no path is required.
Assuming a directory structure as specified in the question, there's several ways to load this class using composer.
PSR-0
{
"autoload": {
"psr-0": { "Test\\Package\\": "" }
}
}
Note that even though the code lives in Test/Package/, this folder is not specified in PSR-0.
PSR-4
For PSR-4 autoloading, the path to the package source must appear in the composer.json file.
{
"autoload": {
"psr-4": { "Test\\Package\\": "Test/Package/" }
}
}
Classmap
When the requirement exists to load classes which aren't organized into the typical namespace folder tree, it is also possible to simply specify a list of folders in which to search for classes using the classmap array.
{
"autoload": {
"classmap": [ "Test/Package/" ]
}
}
In general, however, using PSR-0 or PSR-4 will provide an easier experience, as the classmap approach requires every folder to be separately specified.