Problems with the namespace autoloading in composer - php

This is a more cosmetical question...
I'm using composer.phar in an existing project to autoload my classes.
This is an example snippet of composer.json for my project named Acme:
{
"autoload": {
"psr-0": {
"Acme\\Mail": "modules/mail/src/",
}
}
}
and a par of my file structure is like:
app.php
composer.phar
vendor/
modules/
mail/
src/
Acme/
Mail.php (contains Acme\Mail\Mail.php)
I have to stick to the folder "modules/mail" in my case and can't rename them.
Basically this works, but I have to create an additional folder Acme below src which is a little bit ugly.
How must the autoloading be defined, if I want to leave out the highest namespace part Acme in my mail folder so it looks like this:
app.php
composer.phar
vendor/
modules/
mail/
src/
Mail.php (contains Acme\Mail\Mail.php)
and I still can use it like that in a php file:
use Acme\Mail;
$mail = new Mail();
Or isn't that possible?

PSR4 is going to allow that to be possible. See: https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md and http://www.sitepoint.com/battle-autoloaders-psr-0-vs-psr-4/

You can use the classmap generation if you do not want to follow PSR-0 standard (which, you really should re-consider doing). See the reference at http://getcomposer.org/doc/04-schema.md#autoload

Related

Where should I write my code so that Composer can autoload my PHP classes?

I'm new to Composer, namespaces, and autoload and I wasn't able to figure out where to write my code (under vendor?).
I have created a directory named ilhan under the vendor, and a file named People.php. Then in the main index.php file using use ilhan\People.php as People; doesn't work because I think it must have been written in autoload_namespaces.php initially.
But if I register ilhan as a vendor then I think Composer will look into the packagist.org which it isn't there.
Create ilhan inside root of your project directory, not in vendor directory and put following in your composer.json,
"autoload": {
"psr-4": {
"Ilhan\\": "ilhan/"
}
},
Most probably you already have psr-4 autoload config added in your composer.json file if you are using some sort of framework, in that case just add "Ilhan\\": "ilhan/" in to it.
Now create People.php inside ilhan directory with following content
<?php
namespace Ilhan;
class People{}
Make sure require __DIR__.'/vendor/autoload.php'; is included in index.php any how, then run composer dump-autoload.
Now in index.php just bellow require __DIR__.'/vendor/autoload.php'; following should work,
use Ilhan\People;
But why do you want to use People class in index.php?
Your code goes into the root directory of your project (or any subdirectory). The vendor folder is only for packages/libraries downloaded by composer, you should never change anything in there.
To start a project just create a new file e.g. /my-project/index.php and require the autoload.php which is automatically created by composer:
<?php
require __DIR__.'/vendor/autoload.php';
// here comes your project code
For more information about autoloading see the official composer documentation at Basic Usage: Autoloading

How to distinct vendor classes and native classes in PHP autoload?

How to distinct vector classes and native project classes in PHP autoload?
see a part of the file and namespace structure:
app/
app/Models/
app/Models/User.php
app/Contoller/
app/Contoller/Login.php
vendor/
vendor/company/package/Helper.php
Now PSR-4 says if there a class is needed to be included, autoload must include it from vendor, so how can I include my native project classes like including a model in a controller?
For Example following code:
$user = new App\Models\User();
autoload looks for "App" company (folder) in vendor folder, one approach could be use some conditions in autoload and if the namespace starts with "App" look for class in native project, is it the standard approach?
Second one, what about this, there is a package in vendor which its company name is "App" in vendor name, what is complete way?
The best solution is setting PSR-4 autoloads in your composer.json file as the following example illustrates:
// Part of composer.json
"autoload" : {
"psr-4" : {
"App\\" : "app/"
}
}
Now you don't need to extra autoload, the Composer autoload will do it for you.
When the requested class is under App namespace, Composer looking for it in the app folder as it set in the composer.json file above.

Composer: How to recursively autoload subfolders in /src

I'm writing some tests for a composer package, but i cannot load classes in subfolders of /src.
My folder structure
root
- src
- file1.php
- folder1
- folder2
- file2.php
- tests
The tests' folder structure reflects the one of src.
In my composer.json i've:
{
"autoload": {
"psr-4": {
"Namespace1\\\Package_Namespace\\\": "src"
}
}
}
Now, when i launch the tests, only the ones in src can well include their own classes, while the ones that use the classes in subfolders can't (for example, file2.php is never loaded).
I've tried also to explicitly specify the subfolders in composer.json file, but it seems not working.
I hope someone can help me. If you need more info, please let me know and i'll provide them.
Thank you and i wish you a merry Christmas!
I think you may need to escape the namespace in the config:
"autoload": { "psr-4": { "Namespace1\\Package_Namespace\\": "src" } }
and make sure your classes / filenames follow PSR-4. Also, be sure PHPUnit / whatever test suite you're running loads the composer autoload file.
ETA:
You can also manually add your tests to the namespace in the bootstrap.php file (if you're using one for your tests):
$loader = require __DIR__ . "/../vendor/autoload.php";
$loader->addPsr4('Namespace1\\Package_Namespace\\', __DIR__.'/testdir');
Obviously you'll need to adjust the above accordingly to your paths.
I think there is something wrong with the way Composer loads psr-4 maps.
Infact i've changed namespace reflecting the folder structure and now all work well.
I think namespace can be different from folder structure, but this doesn't work.
I cannot better explain my solution, but only that reflecting the folder structure works. Is it a casuality? Mah!
Anyway, it now works...

PHP Namespace directory structure

It is my understanding that namespaces are declared as follows : vendor\module\classname.
And directory structure would be:
/Acme
/Module1
/src
/Module1
/Class.php
And a valid way to instantiate the class is : new Acme\Module1\Class();
Are my assumptions correct? If so, what's the benefit of using the src folder?
Convention usually.
If you're using composer and you want to autoload your classes, it looks like you're trying to do PSR-0 autoloading.
So if you have "Acme": "src/"
Then in the same directory as your composer.json file would be a src folder, and in the src folder would be a Acme folder. All files in that folder would be namespace Acme; and all files in subdirectories of that folder would be namespace Acme\Subdirectory;.
In the console you need to type composer dump-autoload every time you make changes to the autoloading part of your composer.json file. (or for classmap autoloading, every time you add new files to directories being autoloaded.) This causes the files generated by composer to be updated. (you can find these files in the vendor/composer directory).
So if there was a src/Acme/Subdirectory/ClassName.php with a class in it named ClassName then to instantiate that class you could type new \Acme\Subdirectory\ClassName();
edit: so if this is your composer.json file
{
"autoload": {
"psr-0": {
"Acme": "src/"
}
}
}
then your directory structure would be something like this
/ProjectRoot
composer.json
/src
/Acme
/Module1
Class.php
And you would create a new instance of your class by typing
new \Acme\Module1\Class();

Organizing Laravel and autoloading sub directories

I am wanting to structure my laravel app in a way that all of my code is under the src directory. My project structure would look something like the below. How would I do this where I can still call Route::get('accounting/item/{id}','AccountingItemController#getId')
I am wanting to avoid adding every module under src to the ClassLoader. Is there a way to tell the class loader to load all sub-directories under the parent directory src?
app
app/src
app/src/accounting
app/src/accounting/controllers
app/src/accounting/models
app/src/accounting/repos
app/src/accounting/interfaces
app/src/job
app/src/job/controllers
app/src/job/models
app/src/job/repos
app/src/job/interfaces
Yes, it's called PSR-0.
You should namespace all of your code. Typically you'll have a vendor name that you'll use a the top level namespace. Your application structure should then look something like this.
app/src/Vendor/Accounting/Controllers
app/src/Vendor/Job/Controllers
Your controllers will then be namespaced accordingly.
namespace Vendor\Accounting\Controllers;
And when using them in routes.
Route::get('accounting/item/{id}','Vendor\Accounting\Controllers\ItemController#getId');
Lastly, you can register your namespace with Composer in your composer.json.
"autoload": {
"psr-0": {
"Vendor": "app/src"
}
}
Of course, if you don't want that top level Vendor namespace you can remove it, but you'll need to register each component as PSR-0.
"autoload": {
"psr-0": {
"Accounting": "app/src",
"Job": "app/src",
}
}
Once done, run composer dump-autoload once and you should be able to add new controllers, models, libraries, etc. Just make sure the directory structure aligns with the namespacing of each file.
Do you have composer installed? You should use this:
composer dump-autoload
But you can could add directories to the Laravel's classloader. Check the reference here: http://laravel.com/api/class-Illuminate.Support.ClassLoader.html

Categories