Composer - Autoload and PSR-0 vs PSR-4 - php

I'm beginning to study Composer and am developing a system where I separate the files core application files, as follows:
/root
|-- /src
|-- /App
|-- /DBConfig
|-- /Controller
|-- /Model
|-- /Core
|-- /Helper
|-- /Controller
|-- /Model
So, to set this setting in composer.json file and get access to all classes both /App much /Core would be this way?
"autoload" : {
"psr-X" : {
"App\\" : "/src",
"Core\\" : "/src"
}
}
Or is there a more correct way?
I have also read about PSR-0 vs PSR-4 and I am still somewhat in doubt which one to use. In my case what should I implement, PSR-0 or PSR-4?

You didn't need 2 entries just one for the main namespace so something like this for PSR-4:
"autoload" : {
"psr-4" : {
"MyApp\\" : "/src" }
}
As long as everything in src/ uses the same namespace that's all you'll need. Just let the autoloader do it's job.
As to which to use I'd go with PSR-4 because at some point it is expected that PSR-0 will be deprecated and as PSR-4 is made to be backwards compatible minus some warts for older legacy programs there isn't really a difference except of you start using some of it newer features

Related

Composer PSR-4 autoload error. It doesn't seem to find my namespaced classes [duplicate]

I am creating a PHP project and want to implement PSR-4 autoloading.
I don't know which files I need to create in the vendor directory to implement autoloading for class files.
If you are using composer, you do not create the autoloader but let composer do its job and create it for you.
The only thing you need to do is create the appropriate configuration on composer.json and execute composer dump-autoload.
E.g.:
{
"autoload": {
"psr-4": {"App\\": "src/"}
}
}
By doing the above, if you have a file structure like this
├── src/
│ ├── Controller/
│ ├── Model/
│ ├── View/
│ └── Kernel.php
├── public/
│ └── index.php
└── vendor/
After executing composer dump-autoload the autoloader will be generated on vendor/autoload.php.
All your classes should be nested inside the App namespace, and you should put only one class per file.
E.g.:
<?php /* src/Controller/Home.php */
namespace App\Controller;
class Home { /* implementation */ }
And you need only to include the autoloader in your entry-point script (e.g. index.php).
<?php
require '../vendor/autoload.php';
Which will allow you to simply load your classes directly from anywhere after this point, like this:
use App\Controller\Home;
$homeController = new Home();
This is explained at the docs, here.

Symfony 5 and customer github package [duplicate]

I am creating a PHP project and want to implement PSR-4 autoloading.
I don't know which files I need to create in the vendor directory to implement autoloading for class files.
If you are using composer, you do not create the autoloader but let composer do its job and create it for you.
The only thing you need to do is create the appropriate configuration on composer.json and execute composer dump-autoload.
E.g.:
{
"autoload": {
"psr-4": {"App\\": "src/"}
}
}
By doing the above, if you have a file structure like this
├── src/
│ ├── Controller/
│ ├── Model/
│ ├── View/
│ └── Kernel.php
├── public/
│ └── index.php
└── vendor/
After executing composer dump-autoload the autoloader will be generated on vendor/autoload.php.
All your classes should be nested inside the App namespace, and you should put only one class per file.
E.g.:
<?php /* src/Controller/Home.php */
namespace App\Controller;
class Home { /* implementation */ }
And you need only to include the autoloader in your entry-point script (e.g. index.php).
<?php
require '../vendor/autoload.php';
Which will allow you to simply load your classes directly from anywhere after this point, like this:
use App\Controller\Home;
$homeController = new Home();
This is explained at the docs, here.

How to protect files created/imported by composer?

I just installed composer to manage my project's dependencies.
But I end up with a problem: how to protect the files that composer created?
Shouldn't there be an .htaccess file at the root of vendor? (for my case at the root of the libsproduction folder)
Here is my composer.json file :
{
"config": {
"vendor-dir": "libsproduction/"
},
"require": {
"spipu/html2pdf": "^5.2",
"phpmailer/phpmailer": "^6.1",
"tinymce/tinymce": "^5.2",
}
}
Composer files (both the vendor directory and the composer.json and composer.lock files themselves) shouldn't be in a publicly accessible place.
But the way to do this is not to create an .htaccess or something similar under a webserver different from Apache. What you should do is serve a directory different than the one containing these directory and files. Nor changing the vendor name as you are doing.
The way this is generally done, by most (if not all) composer based frameworks, is to create a "public" or "web" directory which is the one you would configure your web server to actually serve, and put your application entry file(s) there.
E.g.
project-root-dir
├── public
│ └── index.php
├── vendor/
├── composer.json
├── composer.lock
The directory your web server should point to would be public in this scenario. So visiting users cannot directly see anything that's not within that directory.
To load composer's autoloader so that all packages classes are available, you simply do something like:
// public/index.php
require dirname( __DIR__ ) . '/vendor/autoload.php';
/* your application/script logic goes here /*
This way you can also put any other file that shouldn't be user accessible (configuration, logs, cache, etc) one level up from the publicly accessible directory, and you have work less to protect your sensitive files.

Composer autoload - load class from parent directory

I'm currently working on a Laravel project that needs to access classes from its parent directory.
composer.json > PSR-4:
"psr-4": {
...
"ModuleA\\": "../ModuleA/baseObjects",
"ModuleB\\": "../ModuleB/baseObjects"
}
Example file structure:
/var/www
+- /xxx (project)
+- /ModuleA
+- /baseObjects
- configClass.inc
+- /ModuleB
+- /baseObjects
- configClass.inc
+- /laravel
- composer.json
I run composer dump-autoload but the project still can't find ModuleA\configClass neither ModuleB\configClass.
Furthermore, inside my autoload_psr4.php, the above gets referenced as following:
'MobuleA\\' => array($baseDir . '/../MobuleA/baseObjects')
'MobuleB\\' => array($baseDir . '/../MobuleB/baseObjects')
PSR-4 requires the loaded files to have a namespaced class, and the namespace structure has to match the directory structure, relative to the "base directory" defined in the configuration (http://www.php-fig.org/psr/psr-4/).
So, in file /var/xxx/ModuleA/baseObjects/configClass.inc should be the class
namespace ModuleA\baseObjects;
class configClass {
...
}
Then in var/www/laravel/composer.json you could have
"psr-4": {
"App\\": "app/",
"ModuleA\\": "../ModuleA"
}
Which means: "directory ../ModuleA should be the root for ModuleA namespace, then follow subnamespaces by matching subdirectories from there".
Use classmap autoload will solve this problem.
{
...
"autoload": {
"classmap": ["ModuleA/", "ModuleB/"]
}
}
It could be used with PSR-4
{
...
"autoload": {
"psr-4": {
"Acme\\": "src/Acme/"
},
"classmap": ["ModuleA/", "ModuleB/"]
}
}
Ref: https://getcomposer.org/doc/04-schema.md#classmap
The problem you're experiencing is not related to parent directories. In fact, your Composer.json autoload configuration is correct for your directory structure.
The problem is the .inc file extension, which is incompatible with the PSR-4 specification. More info here: How To Make Composer (PSR-4) To Work With ".class.php" Extension?
If you cannot update your source code to match the PSR-4 spec, you can use Class Mapping:
The classmap references are all combined, during install/update, into a single key => value array which may be found in the generated file vendor/composer/autoload_classmap.php. This map is built by scanning for classes in all .php and .inc files in the given directories/files.
You can use the classmap generation support to define autoloading for all libraries that do not follow PSR-0/4. To configure this you specify all directories or files to search for classes.
So your config might look like:
"autoload": {
"classmap": [
"../ModuleA/baseObjects",
"../ModuleB/baseObjects"
]
}
Remember, if you use class mapping, you'll need to run composer dump-autoload any time you change composer.json, add a class, modify a class' name/filename/path, etc.
Extra: as pointed out by #alepeino, using autoloader optimization will generate a class map from any PSR-0 and PSR-4 autoload definitions, using the same underlying code that classmap autoload uses. This will "allow" you to use PSR-4 autoloader and the .inc extension. This will still require you to run composer dump-autoload --optimize every time you make a file change, though, just like classmap.
Best recommendation: change your source code to follow PSR-4 specifications, and use the .php extension.
Next best if you can't do that: use classmap for autoloading.
try it:
"psr-4": {
...
"ModuleA\\": "ModuleA/baseObjects",
"ModuleB\\": "ModuleB/baseObjects"
}
According to this answer you can add it in the index.php file:
$loader = require 'vendor/autoload.php';
$loader->add('Namespace\\Somewhere\\Else\\', __DIR__);
$loader->add('Namespace\\Somewhere\\Else2\\', '/var/www/html/xxx');

Composer with PSR-4 autoloading: classes from namespace not loading

I have the follow project structure:
- root
|- src <- Application specifc source
|- [...]
|- tests
|- [...]
|- Vendor
|- myusername <- shared packages for all projects
|- src
|- MyNamespace
|- File.php
|- autoload.php
|- test.php
|- composer.json
composer.json already have a PSR-4 entry:
"autoload": {
"psr-4": {
"MyNamespace\\":"myusername/src"
}
}
/Vendor/test.php
<?php
require 'autoload.php';
$file = new MyNamespace\File();
echo $file->isDone();
Vendor/myusername/src/MyNamespace/File.php
<?php
namespace MyNamespace;
class File
{
public function isDone()
{
return 'Done!';
}
}
But I always get fatal error Fatal error: Class 'MyNamespace\File' not found in [...]
Are the composer settings or file structure correct? What I can do?
EDIT 1:
I can load external vendors fine
There are 2 things wrong with your code.
You are using PSR-4 wrong.
They removed the need to embed the namespace in your folders, making a cleaner footprint in your project folder.
PSR-0
vendor/<VendorName>/<ProjectName>/src/<NamespaceVendor>/<NamespaceProject>/File.php
PSR-4 (See that they removed the namespaces folders? Because you already reference that in composer.json
vendor/<VendorName>/<ProjectName>/src/File.php
So in your case it would be:
Vendor/myusername/src/File.php
Your composer.json is invalid
"MyNamespace\\":"myusername/src"
Doesn't include the full path to the directory with your project's code. It should be like this:
"autoload": {
"psr-4": {
"MyNamespace\\": "Vendor/myusername/src"
}
}
but the best way to store your files would be outside the vendor directory, as that is used by automatically downloaded libraries, instead choose a different "development" directory:
"autoload": {
"psr-4": {
"MyUsername\\MyProject\\": "src/myusername/myproject/src"
}
}
Thanks to Sven in the comments.

Categories