Autoload PHP Classes using Composer - php

I am trying for the first time to autoload PHP Classes using Composer.
I have this dir structure:
-app
-controllers
-models
-MySql.php
-interfaces
-IDatabase.php
My problem is that I am not able to implement the IDatabase interface in my MySql class. It gives me: Fatal error: Interface 'App\Models\I\IDatabase' not found.
composer.json
{
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
}
IDatabase.php
namespace App\Models\I;
interface IDatabase
{
public function connect();
public function execute($query,$param);
}
Mysql.php
namespace App\Models;
use App\Models\I\IDatabase;
class MySql implements IDatabase
{
...
}
What am I doing wrong? I can't figure it out. Thanks.

It looks like
App\Models\I\IDatabase
Should be
App\Models\Interfaces\IDatabase
You can't abbreviate the directory name.
Also as I said in the comments
Casing is important! app vs App, etc. or app\models\interfaces\IDatabase It's probably mainly this one I vs interfaces but Casing will get you on Linux.
So you can either change the directories to be uppercase, or you can change the namespace to be lower cased (but they should be the same).
On windows this may work with the case issues, because windows filesystem is case insensitive. But as soon as you put that on Linux which is case sensitive, well it's not gonna work out to good.
Cheers!

Namespaces should follow the exact directory structure, and are case sensitive.
If your Interface is in the directory app\models\interfaces, the namespace should be App\models\interfaces. App in your case can be with capital A because you explicitly mapped it in the composer.json.
So you can either rename the folders or fix the namespace.
Also, you cannot give custom name to the namespaces (i.e. I in App\Models\I). As I stated before, the namespace must follow the directory structure, unless you create a specific mapping in the composer.json

Related

How to handle autoloading with composer by keeping the WordPress naming conventions?

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.

Laravel Custom Trait Not Found

I'm new to traits, but thought I'd give it a try. But, it doesn't seem to load.
I've created a trait within a folder under the Laravel app directory: app\Helpers called CheckPermsAgainstObjectTrait.php
Here is the trait code:
<?php
namespace App\Helpers;
trait CheckPermsAgainstObjectTrait {
function something{}
}
I try to use it in a controller as such:
<?php
namespace App\Http\Controllers;
use this&that;
use App\Helpers\CheckPermsAgainstObjectTrait;
class PolicyController extends Controller{
use CheckPermsAgainstObjectTrait;
}
Classes in that directory load fine. PHPStorm sees the trait fine. I've clear compiled aritsan and dumped autoload. I'm guessing there is something that Laravel doesn't like with the namespacing? I would hope I don't need to do any manual loading in composer -- but I'm having trouble finding any documentation to give me a hint as to what I'm screwing up.
The error:
FatalErrorException in PolicyController.php line 15:
Trait 'App\Helpers\CheckPermsAgainstObjectTrait' not found
Any thoughts?
Did you dump autoload files?
composer dump-autoload
The answer for me was that I had the wrong namespace at the top of my trait file due to working from a Laravel trait as an example. If your trait is in App/Traits/MyTrait.php then make sure your namespace is:
namespace App\Traits;
trait MyTrait
{
// ..
}
Then from the file that's including the trait:
use App\Traits\MyTrait;
class MyClass
{
use MyTrait;
// ..
}
No need to mess with config/app.php, composer.json or autoloading.
I had a very similar problem where I was getting the error Trait 'Tests\CreatesApplication' not found in '.../my_project/tests/TestCase.php' on line 9 while running tests with phpunit because I manually updated my Laravel project and must have missed some changes. This may also happen to anyone creating a trait or class in a unique namespace.
Anyways, #Devon 's comment on the original question pointed me in the right direction.
I was missing the required autoloader configuration in my composer.json file, so I checked what it should be for my version of Laravel (5.4 in this case) from the Laravel github repository.
In this case, I was not calling from a namespace within App\ (which was already in composer.json.)
Here's what I was missing from composer.json:
{
...,
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
...
}
Thanks goes to Devon! Hope this keeps someone else from pulling their hair out.
composer dumpautoload -o
this worked for me
This may happen sometime when your Trait filename is misspelled or incorrect as with the class name. Do check your file name is same as classname
This may happen sometime when your Trait filename is misspelled or incorrect as with the class name. Do check your file name is same as classname

Including my class in a Laravel 5 Project

I made a class in php with some helper methods that parse HTML files.
I'd like to use this class in my Laravel project, but I'm new to Laravel and it's not clear how to add a simple class to a Laravel 5 project.
Is this possible? Or do I need to go to all the trouble of creating a composer package for my class, hosting it somewhere, and then require it in my composer.json file. That seems like a lot of work for including a simple PHP class, and I'm hoping there's an easier way.
As it stands right now there's not a great/easy way to do this in Laravel 5 (possibly by design). The two approaches you can take are
Create a new class in the App namespace
By default Laravel 5.0 looks for App\ prefixed classes in the app/ folder, so something like this should work
#File: app/Helpers/Myclass.php
<?php
namespace App\Helpers;
class Myclass
{
}
and then create your class with
$object = new App\Helpers\Myclass;
This approach, however, relies on you creating classes in the App\ namespace, and there's some ambiguity around if the App\ namespace is owned by Laravel, or is owned by the developer of the application.
Create your own Namespace and Register as PSR-4 autoloader
A better, but more complicated, approach would be to create classes in your own namespace, and then tell Laravel about this namespace by registering a new PSR autoloader.
First, you'd create the class definition
#File: application-lib/Myclass.php
<?php
namespace Pulsestorm;
class Myclass
{
}
Notice we've created a new folder off the root folder to hold our classes named application-lib. You could name this folder anything you like, because in the next step, you're going to add a section to your composer.json file's autoloader section
#File: composer.json
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/",
"Pulsestorm\\": "application-lib/"
}
},
The section we've added is this
"Pulsestorm\\": "application-lib/"
The key to the object (Pulsestorm\) is your namespace. The value (application-lib) is the folder where composer should look for class definition files with the specified namespace.
Once you've added this to composer.json, you'll need to tell Composer to regenerate it's autoload cache files with the dumpautoload command
$ composer dumpautoload
Generating autoload files
After doing the above, you should be able to instantiate your class with
$object = new Pulsestorm\Myclass;
The "real" right way to do this would be to create a generic composer package for your helper class, and then require that composer package into your laravel project. That may, however, be more work than you care to take on for a simple library helper.
If your class is generic enough to use it in other projects, the best way is to release it as a package.
Here's how you create packages with Laravel 5: http://laravel.com/docs/5.0/packages

Strategy to override a class in a library installed with Composer

I am using Codeigniter and Composer. One of the requirements is PHPExcel. Now I need to change a function in one of the classes. What should be the best strategy to do it? Should I change the code in the vendor folder? If so, how to maintain the change across all the instances? If not how do I override that particular class. Though I mention PHPExcel I would like a generic solution.
I am not sure if this is the right forum for this question. If not i will remove this. Please let me know if any more details are needed.
Thank You.
In composer.json, under ["autoload"]["psr-4"], add an entry with namespace as the key and path as the value:
{
"autoload": {
"psr-4": {
"BuggyVendor\\Namespace\\": "myfixes/BuggyVendor/Namespace"
}
}
}
Copy files you want to override under that path (keeping sub-namespace directory structure) and edit them there. They will be picked in preference to the library package's original "classpath". It would seem that namespace->path mappings added to composer.json in this manner are considered before those added by required packages. Note: I just tried it and it worked, though I don't know if it is an intended feature or what possible gotchas are.
EDIT: found a gotcha. Sometimes when you subsequently require another package with composer require vendor/package, you will "lose" the override. If this happens, you must issue composer dump-autoload manually. This will restore the correct autoload order honoring your override.
Adding these last 2 lines to the autoload section of my composer.json is what worked for me when I wanted to override just one file within the vendors directory:
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
},
"exclude-from-classmap": ["vendor/somepackagehere/blah/Something.php"],
"files": ["app/Overrides/Something.php"]
},
Remember that the namespace within app/Overrides/Something.php needs to match whatever the original was in vendor/somepackagehere/blah/Something.php.
Remember to run composer dump-autoload after editing the composer.json.
Docs: https://getcomposer.org/doc/04-schema.md#files
There is one more option.
In case you need to rewrite the only class you can use files in composer.json like this
"autoload": {
"files": ["path/to/rewritten/Class.php"]
}
So if you want to rewrite class Some\Namespace\MyClass put it like this
#path/to/rewritten/Class.php
namespace Some\Namespace;
class MyClass {
#do whatever you want here
}
Upon each request composer will load that file into memory, so when it comes to use Some\Namespace\MyClass - implementation from path/to/rewritten/Class.php will be used.
Changing an existing class is against OOP and SOLID principles (Open to extension/Closed for modification principle specificaly). So the solution here is not to change the code directly, but to extend the code to add your functionnality.
In an ideal world you should never change a piece of code that you don't own.
In fact, with composer you can't because your change will be overrided when updating dependencies.
A solution in your case is to create a class at the application level, and extend the class you want to change (which is at the library level) to override with your code. Please look at extending a class in PHP if you don't know how.
Then typically, you load your class instead of their class, this way, you add your functionnality on top of their functionnality, and in case of an update, nothing break (in case of a non breaking update).

Class not found with composer autoload

I have my file structure as
/
/app/
/app/logs/
/app/templates/
/app/index.php
/public_html/
/public_html/.htaccess
/public_html/index.php
/vendor
/vendor/(all vendor here)
My vhost is pointing to /public_html
in app/Index.php
namespace App;
class Index {}
Composer.json
"autoload":
{
"psr-0":
{
"App\\": "app/"
}
}
Yet it is still showing as ( ! ) Fatal error: Class 'App\Index' not found in C:\wamp\www\project\public_html\index.php on line 34
Line 34:
new \App\Index();
Using Slimframework as well if that matters, can't think what is wrong
Since you were using the PSR-0 standard, PHP was looking for the file app/App/Index.php, which does not exist. Note that in PSR-0, you define a base directory (app in your case) where the mapped namespace (App) can be found. However, the file structure within that base directory should exactly match the fully qualified class names. So class App\FooBar should be in the file app/App/FooBar.php. Note that app is the base directory, and App is the directory that contains all subdirectories and PHP files for that namespace.
Since this is not the case in your application (and also because PSR-0 has been deprecated), you should (as you already did) use PSR-4, the new autoloading standard, instead. In PSR-4, you can directly map a certain namespace to a certain directory. In your case, you have mapped the App namespace to the app directory, so that PHP will open the app/Index.php file if you need to use the App\Index class.

Categories