I have a situation where I've been forced to use something that SHOULD be a composer package in my Laravel project, instead, as just part of my project files (the composer package as far as I can tell contains bugs that I cannot resolve and I'm using a folder of similar php files my colleague provided to me)
I'll try to give as much context as I can:
I've installed all the files into a folder at this directory: \app\Channels\V1\Helpers\MarketplaceWebService\. The files are similar to this project, but different
In order to get the classes in the above folder loaded, I've added a line to my composer.json file:
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories",
"app/Channels/V1/Helpers/MarketplaceWebService"
]
},
That last line in the classmap array - I used that to load my classes into my project, so I can now require them via use MarketplaceWebService_Client; at the top of any of my normal laravel files
Now for a lot of cases, this works -- I can initiate classes and they pull from the correct place.
However, any time I use one of the MarketplaceWebService that have a relative require_once, it fails
I have ANOTHER composer package by the same guy, tilluels, called amazon-mws-orders, and it looks based on the error message I'm receiving that these relative require_once calls are for some strange reason being made relative to that package, rather than relative to the location of the file I'm in.
So for example, if a file has require_once ('Interface.php');, and Interface.php is in the same folder as that file, it works just fine, BUT if a file has require_once ('../Model.php'), I get this lovely message:
500 - {"message":"MarketplaceWebService_Client::main():
Failed opening required '../Model.php'
(include_path='/home/devchannelapi/laravel/vendor/tilleuls/amazon-mws-orders/src:.:/opt/alt/php72/usr/share/pear')",exception":"Symfony\\Component\\Debug\\Exception\\FatalErrorException",
"file":"/home/devchannelapi/laravel/app/Channels/V1/Helpers/MarketplaceWebService/Model/SubmitFeedResponse.php","line":22
And I set some breakpoints in Xdebug and it is, in fact, line 22 on /Model/SubmitFeedResponse.php where it says require_once('../Model.php'), and the Model.php class is indeed one directory above that file, so you'd expect the require_once statement to work. And in fact, if I make a copy of Model.php and put it into the /Model folder, and change the require statement to require_once('Model.php'), it actually DOES work! But whenever I leave the relative requires, it gives me an error message like above, as if it's looking for relative requires in /home/devchannelapi/laravel/vendor/tilleuls/amazon-mws-orders/src
Now I've already done composer dump-autoload, I don't know enough about Laravel class loading to understand why else this might be happening.
Any help would be appreciated.
I was able to replace all relative imports with __DIR__ imports
eg require_once('../Model.php); becomes require_once(__DIR__ . '/../Model.php);
Was a bit of a pain to edit every file in the folder, but Sublime Text was a great help!
Related
Introduction
Hello,
I moved my files from my local pc, running WAMP to my webserver, which is a Linux machine.
I work with composer to use its autoload functionality to load my MVC structure, more about that later.
The error that I receive on my webpage is the following:
Fatal error: Uncaught Error: Class 'App\Model\DB' not found in <folder_structure>/config/_boot.php:15
I do not have this error on my Windows machine, the code works perfectly there.
Folder structure
I use the same folder structure, which is (simplified) as following:
- config
-- _boot.php
- dist
-- index.php
-- includes
--- header.php
- src
-- app
--- Models
---- db.php
- composer.json
Code parts
My config/_boot.php file looks like this:
use App\Model\DB;
...
$db = new DB($database['host'], $database['dbname'], $database['user'], $database['password']);
My src/app/Model/db.php file looks like this:
namespace App\Model;
class DB
{
}
My composer.json contains this:
"autoload": {
"psr-4": {
"App\\": "src/app/"
},
"files": [
"src/app/functions.inc.php",
"config/_boot.php",
"src/app/Routing.php"
]
}
autoload_psr4.php
return array(
...
'App\\' => array($baseDir . '/src/app'),
...
);
Question
Is there anyone who has an idea of what I am doing wrong?
Things I have tried / Checked
Check the folder permissions
I tried adding "App\\Model\\": "src/app/Model/" to my composer.json as well
PS: This is my first question on Stackoverflow, tips on improving the layout are welcome...
PSR-4 states:
The terminating class name corresponds to a file name ending in .php.
The file name MUST match the case of the terminating class name.
You have broken this rule by placing DB class into db.php file. The reason it works on Windows and not on Linux is that the later is case-sensitive regarding file and folder names.
So the fix is to rename db.php into DB.php.
This is a general question I have out of curiosity and might lead to something useful in projects of mine.
Every time I add a new file (for example a new controller or model) I have to run composer dump-autoload -o for it to include the file, not sure if i'm just doing something wrong or if that is how it works.
Is it possible for me to get composer to see the file automatically after I created the file with its contents?
My first thought was to just create a script to run the command in either a special "refresh" file but that seems to be a waste.
I am using PSR-4 to load my files.
composer.json autoload:
"autoload":{
"psr-4":{
"Website\\":"app"
}
},
You need to configure your composer.json file so that the autoloader knows where to look for specific namespaces:
"autoload": {
"psr-4": {
"App\\": "src/"
},
"files": [
"src/simpleFunctions.php"
]
}
After running composer update, the autoloader will know where to look when a script encounters a namespace that falls under these definitions automatically, without any further command to write.
You have to respect the file hierarchy and psr-4 while naming and creating your classes. In the example above, adding a App\Controller\MyController class is straightforward, you add it in the Controller folder and it will be autoloaded on your next run.
/src
/Controller
MyController.php
/Model
/Mappers
MyMapper.php
simpleFunctions.php
namespace App\Controller;
class MyController {}
Casing is important!
When seeing a namespace like Website\Controllers, the autoloader will look for there files, under the root for the namespace specified, with the same casing. That means, that if you are under a case sensitive system (like Linux distributions) you actually need to respect the case. In your case the class Website\Controllers\Front must be in app/Website/Controllers/Front.php.
Basically, Composer doesn't aware of files that you are creating, you have to run the dump-autoload command which won't download anything new. It just regenerates the list of all classes that need to be included in the project (autoload_classmap.php). Ideal for when you have a new class inside your project.
Ideally, we execute composer dump-autoload -o , for a faster load of your webpages. The only reason it is not default, is because it takes a bit longer to generate (but is only slightly noticeable)
I have a local project with loaded with Composer libs. I uploaded this project to my FTP and received errors, connected with not found classes from some libs.
Can I simply copy vendor/ folder to FTP or I missed something?
Error received:
Fatal error: Class 'AAA\Core\Tools' not found in /home/aaa/public_html/api.php on line 11
api.php:
<?php
use AAA\Core\Tools;
require_once("./vendor/autoload.php");
require_once("./api/" . Tools::getFieldValue('controller') . ".php");
All works fine on localhost!
Linux has a case sensitive file system. That means that files Alex.txt and alex.txt are the same thing in Windows, but not in Linux. Actually on Linux both can happily live in the same directory:
$ tree .
.
├── alex.txt
└── Alex.txt
0 directories, 2 files
Taking this into consideration, I would try to double check that the paths you are using in your namespace are actually identical to what is found at the file system level. (i.e: AAA directory with only uppercase letters ; Core directory capitalized and Tools.php file capitalized)
If you want to keep your existing file system layout, you can use PSR-4 to explicitly tell Composer how to map the namespace to the file system:
Change autoload section from your composer.json:
{
"autoload": {
"psr-4": {"AAA\\DB\\": "db/"}
}
}
where db/ is the actual path from the file system
Update the autoloader:
$ composer dump-autoload
This will take care of directory names, but doesn't apply for files. Meaning that any file inside db/ must be named exactly as used in namespace (for a usage as use AAA\DB\DBCore the file must be db/DBCore.php).
If your file is named dbcore.php and you want to reference it in your namespace as DBCore, you can use classmap feature from Composer:
"autoload": {
"classmap": [
"db/dbcore.php"
]
}
dbcore.php:
<?php
namespace AAA\DB;
class DBCore
{
}
And you can use it as usual:
<?php
require_once("./vendor/autoload.php");
$dbCore = new \AAA\DB\DBCore();
Firstly I would check the autoloader files composer has generated to make sure the paths are valid on your linux server.
Another simple but common issue is that on windows the folder and file names are not case sensitive however they are on Linux. Double check that the folders and files have the correct case as if not it won't find them to auto load.
Rather than trying to upload via FTP which I think is going to be tricky if not impossible to get right, I would suggest you explore getting composer working on your hosting environment.
Composer is entirely PHP based, so should run anywhere that PHP is running.
If you don't have command line access, you can use something like PHPShell which gives you a PHP based command line on which you can then run Composer.
See this other SO answer to get some tips on how to use PHPShell.
Another option is to build a little PHP wrapper that you actually run by visiting it in your browser, in the classic PHP way. See this other SO answer for some tips on how to do that.
Bottom line, you should really look at getting Composer running on your server rather than trying to bodge it another way.
Once you have done your composer process on the server, you must remove the PHPShell or composer wrapper you created so that you don't leave any security holes.
Did you tell the composer where your Class 'AAA\Core\Tools' is?
You can even add your own code to the autoloader by adding an autoload field > to composer.json.
{
"autoload": {
"psr-4": {"Acme\\": "src/"}
}
}
Composer is not meant to be used that way (i.e. you shouldn't be manually transferring vendor directories from one environment to another).
As you add dependencies to your project, the composer.json file will contain those dependencies. When you run composer install or update on your localhost, it "locks" the current version of those dependencies for your project and stores them in the composer.lock file. You should be transferring the composer.json and composer.lock files from your development environment to your production environment and then running composer install on your production environment as part of your deployment process. When you run composer install on your production environment, Composer will look at your composer.lock file and install the specified versions of the dependencies in the vendor directory of the production environment.
You may want to review the composer documentation regarding basic usage (https://getcomposer.org/doc/01-basic-usage.md) and command line options (https://getcomposer.org/doc/03-cli.md) for more details.
I'm new in php and I have to do the testing for an app. I'm trying to make unit testing but an error messages is displayed. I have many weeks ago and I cannot fix it, please help me!!
The message says: Fatal error: Class 'CDbTestCase' not found.
I read and follow many tutorials about this issue but it doesn't work.
I'm using Yii, Eclipse IDE and Composer.
I think the problem is in bootstrap.php but I don't use it because I'm working with composer, this is the composer.json
{
"require-dev": {
"yiisoft/yii": "1.1.*",
"phpunit/phpunit": "4.6.*",
"phpunit/phpunit-selenium": ">=1.2",
"codeception/codeception":"*",
"phpunit/dbunit": ">=1.2"
},
"autoload": {
"psr-0": {"": "vendor/autoload.php"},
"psr-4": {"": "/../framework/test/CDbTestCase.php"}
}
}
The bootstrap file is needed to load the yii framework. CDbTestCase is part of the yii framework so failing to include yii will give you this error if your tests depend on yii's unit test related classes.
Use the included bootstrap file and make sure you also include composer's autoload.php file. I normally add this to my yii config file (I believe by default, yii uses the test.php config file for custom testing related settings. You can include autoload.php inside this file)
Somewhere at the top of your yii config file
// Include composer autoload
require_once 'path/to/composer/vendor/autoload.php';
Your Composer autoloading is completely wrong.
Don't include the composer autoloader "vendor/autoload.php" in the autoloading of your own composer.json. There is only one autoloader, and it is created using your autoload data as well as any libraries.
The PSR-4 autoloading is also wrong. You have to state a directory where classes are put into files according to PSR-4. You point to one single file.
You don't use class prefixes for PSR-0 and PSR-4. This is bad for performance, because you are stating that ANY class could be in the directory. So Composer has to search for that class in this directory as well, even for classes that are guaranteed to not be there. Always use a prefix, and make it as long as possible to allow unique matches: One prefix should only ever point to exactly one directory structure.
You should explain why you don't use a bootstrap file in your tests. The minimal required bootstrap code for PHPUnit is to include the Composer autoloader. Additionally, you should add things that are required in your tests and have to be done once, like initialization of framework components -YMMV.
Vagrant and mounted folders do not play nice with composer using relative paths to folders added in via the
"autoload" option.
It in-correctly detects what the baseDir is and therefore will fail to register the namespaces.
Has anyone come across this before?
For isntance
"autoload": {
"psr-4": { "Inventory\\" : "./core/src/inventory/" }
}
The autoloading is supposed to be given relative to the path where the composer.json file is located. I've never seen that path starting with a dot, so first of all I'd try to get rid of that and see how that works.
Second thing that might simply be is that you got the autoloading wrong in some detail and mistake it for being something related to Vagrant. The way you currently set it up, a class named \Inventory\Foo must be located in the path core/src/inventory/Foo.php. Can you verify that this is the case? Otherwise please give an example of an existing class name and it's file name.