I'm developing a Laravel package but I have a problem with composer autoloading.
My package has 2 folders under src folder. One of them is named Laravel and the other one is Telegram. Here is the package structure:
./packages
.../typhoon
...../src
......./Laravel
........./Providers
............LumenServiceProvider.php
............LaravelServiceProvider.php
......./Telegram
..........Api.php
.....composer.json
This package is developed under SaliBhdr/Typhoon namespace.
I have added the packages/typhoon/src directory in Laravel's composer file like so:
"autoload": {
"psr-4": {
"App\\": "app/",
"SaliBhdr\\Typhoon\\" : "packages/typhoon/src/"
}
},
And add the src/ address in package composer.json file like so:
"autoload": {
"psr-4": {
"SaliBhdr\\Typhoon\\": "src/"
}
},
Here is the strange behavior begins. When I execute the php artisan serve command Laravel throws an error that says :
Class 'Salibhdr\Typhoon\Laravel\Providers\LumenServiceProvider' not found
And if I check if the class exists with class_exists('Salibhdr\Typhoon\Laravel\Providers\LumenServiceProvider') function it returns false. But if I check if Salibhdr\Typhoon\Telegram\Api exists it returns true.
I checked the autoload_classmap file and notice that the composer includes all the classes under Telegram subfolder but not Laravel subfolder.
Why composer acts weird like this? why did it include one subfolder and not the other? It is something that I do every day and never seen anything like this.
I desperately need help. Any help would be appreciated
You are trying to initialize Salibhdr\Typhoon\Laravel\Providers\LumenServiceProvider but in your composer it's "SaliBhdr\\Typhoon\\": "src/".
Notice the capital B in your composer. PHP classes are case sensitive so you have to make sure it's either both lowercase or both uppercase.
Also make sure to run composer dumpautoload if you modify composer.json.
Related
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/"]
}
There is a vendor that I want to use that was originally created for Symphony and it isn't namespaced into Laravel, I'm not too sure on how to make it work.
Here is the package: https://github.com/caponica/AmazonMwsComplete
I read somewhere that I would have to add psr-0 into composer and I already have the psr-4 default data in composer so I added:
"psr-0": {
"MWS\\": "caponica/amazon-mws-complete"
},
The MWS\\ I just made up since I wasn't too sure what to do and the other portion is the vendor folders, figured that's what I needed.
So, when I tried to call the class into routes for testing I tried:
use MWS\CaponicaAmazonMwsComplete\AmazonClient\MwsProductClient;
and it keeps saying that the MwsProductClient class isn't found.
It happened because you are trying to use wrong path and namespace. Accrording to the source code of package you are trying to use the namespace you want to load is namespace CaponicaAmazonMwsComplete\AmazonClient;
So you need to include this into you composer.json file:
"psr-0": {
"CaponicaAmazonMwsComplete\\": "caponica/amazon-mws-complete/src"
},
I'm not 100% sure but it should work. Don't forget to run composer dump-autoload before using.
If it doesn't work add a comment here and I will check it again.
UPDATE:
So I managed it to work using PSR-4 autoload:
"psr-4": {
"App\\": "app/",
"CaponicaAmazonMwsComplete\\": "vendor/caponica/amazon-mws-complete/src/CaponicaAmazonMwsComplete",
"AmazonPhpClientLibrary\\": "vendor/caponica/amazon-mws-complete/src/AmazonPhpClientLibrary"
}
But note that this library is quite outdated and it's documentation doesn't fits it's code.
I'm experiencing a weird problem with a package I'm developing in the workbench. It involves this little peice of my Composer file:
"psr-0": {
"Vendor\\": "src/"
}
What I'm wanting to do is change the path like this:
"psr-0": {
"Vendor\\": "src/models/"
}
Laravel has problems with this. The classes get added to my application just fine, but all Laravel pathing to package resources get jacked up.
Things like this:
View::make('package::myview')
Config::get('package::myvars')
These do not work at all. I get errors like this:
No hint path defined for [packge]
But if I remove the "models/" from the PSR-0 path then it all works fine.
So basically, it looks like Laravel insists that my Composer file have only "src/" in my PSR-0 paths.
This is a bug or am I missing something?
Laravel presumes 2 levels down from the Provider file, but you can manually set the path to the src/ when you register the package:
$this->package('vendor/package', null, __DIR__.'/../../../');
I have this composer.json file
{
"require": {
"filp/whoops": "1.*"
}
}
However, I have a folder for my own project called vendor/imaqtpie/framework/src. This is not hosted anywhere, so if I do composer update to update autoload files, it gives an error.
The requested package "imaqtpie/framework" could not be found in any version, there may be a typo in package name.
I had to add this myself to autoload file to make it work.
'Framework' => array($vendorDir . '/imaqtpie/framework/src')
Is there any way to solve this?
I want to tell Composer that this local vendor folder has to be autoloaded each time regardless of checking server/version, or looking for a more elegant solution since I'm new to composer.
You have to create your own local git repository with your package code to achieve that.
After that, put something like this into your composer.json file.
"repositories": [
{
"type":"vcs",
"url":"/path/to/your/source"
}
],
"require":{
"filp/whoops":"dev-master"
}
Autoloading shouldn't be an issue if you implement it this way...
There are a few ways you can do this.
1.
I'd say the most correct way, is to host it and use Satis to produce a private 'packagist'. Then composer will behave "normally" and get the latest version, do version checking etc. but you say you don't care for this.
If you want more details I can expand on this, I have set up many satis packages and it works really well. (Note there's also the new commercial Toran Proxy which I haven't trialled yet.)
2.
If your 'imaqtpie' library is a fake vendor library (it sounds like you just have some files you've stored there, like you would an old-fashioned include library?), then you could simply use a classmap to point the autoloader to that folder from your top level application. This only makes sense if you are including that folder in your top-level app.
So your app's composer json could look like:
{
"require": {
"filp/whoops": "1.*"
},
"autoload": {
"classmap":[
"vendor/imaqtpie/framework/src"
]
}
}
So this tells composer there's a bunch of classes in that folder. When you run composer dump-autoload it will scan the folder and generate vendor/composer/autoload_classmap.php with all your files listed.
This isn't how you're supposed to use composer, but you're not asking to use composer for package management you're asking how to use composer's autoloader, which I guess is fine! as long as you understand the risks.
3.
If your package is either PSR0 or 4 (it sounds likely from the "src" folder) then you'd similarly do this in your top-level app:
{
"require": {
"filp/whoops": "1.*"
},
"autoload": {
"psr-4": {
"Imaqtpie\\Framework\\":"vendor/imaqtpie/framework/src"
}
}
}
Which again is a bit odd, but should work!
Normally, you'd specify this path in your package's composer.json and then when you do an update it gets merged into your composer.lock and then the vendor/composer/installed.json (which is the source used for the dump-autoload). But in theory you can load whatever you want from the top level app, and therefore you can 'hard code' a package into the vendor library and classpath to it.
I'd probably recommend not doing this though! The vendor folder is a tenuous location which most people and programs would assume can be destroyed and rebuilt at a whim. So it's a dangerous place to store anything which isn't in a package. It's also confusing for any other developers who will assume the same.
So I'd recommend moving your library to another location away from the vendor folder, e.g. 'lib', and then using the classpath approach above to include it in the autoloader.
I am starting to use Composer and am a bit confused on how to specify how things should be autoloaded.
My initial assumption was that one would define how to autoload classes of a package within this package. I'm however getting the impression that one should specify this in the project where the package is used. Is that the case?
I hope not! I don't want the users of a library to know how autoloading of this library works, such as for instance in which directory the classes are located. For instance, I do not want some client to know that "MyLibrary" has its classes in a directory called "includes":
"autoload": {
"classmap": [
"vendor/MyLibrary/includes/",
]
}
If on the other hand my current impression is wrong, and thus my initial assumption correct, then my question is how to achieve this. I tried using the following in the composer.json file of one of my libraries, but upon installing it somewhere, no entries would show up in the generated autoload classmap.
"autoload": {
"classmap": [
"includes/",
]
}
My initial assumption was correct. One needs to define the autoloading for a package within the composer.json file of the package. Nothing outside of the package should know about how its autoloading is done. I am unsure why what I was doing failed to work. In any case, I have not run into this recently.