I'm trying to split up a long file into smaller chunks, so I created an src folder, and am trying to reference it from the main Extension.php file (which loads and works fine, by the way).
So, I add the src folder to the psr-4 autoloading array:
"psr-4": {
"Bolt\\Extension\\AndyJessop\\SurveyMonkey\\": [
"",
"src/"
]
}
I create the Test.php file inside src:
<?php
namespace Bolt\Extension\AndyJessop\SurveyMonkey;
class Test
{
public function test() {
return 'success';
}
}
In the Extension.php file (which is under the same namespace), I have this function that is called:
use Bolt\Extension\AndyJessop\SurveyMonkey\Test;
public function testing(){
return Test::test();
}
But I get the following error:
Error: Class 'Bolt\Extension\AndyJessop\SurveyMonkey\Test' not found
File: extensions/local/andyjessop/surveymonkey/Extension.php
First, either run composer update or composer dump-autoload to generate the autoload system.
Next, make sure that you include (require_once is preferable) the autoload at the top of your entrypoint(s):
require_once __DIR__ . '/path/to/vendor/autoload.php';
N.B.: if you have PHP 5.3 or lower, replace __DIR__ with dirname(__FILE__).
Related
I am new with this namespace thing.
I have 2 classes(separate files) in my base directory, say class1.php and class2.php inside a directory src/.
class1.php
namespace \src\utility\Timer;
class Timer{
public static function somefunction(){
}
}
class2.php
namespace \src\utility\Verification;
use Timer;
class Verification{
Timer::somefunction();
}
When I execute class2.php, i get the Fatal error that
PHP Fatal error: Class 'Timer' not found in path/to/class2.php at
line ***
I read somewhere on SO, that I need to create Autoloaders for this. If so, how do I approach into creating one, and if not, then what else is the issue?
UPDATE
I created an Autoloader which will require all the required files on top of my php script.
So, now the class2.php would end up like this.
namespace \src\utility\Verification;
require '/path/to/class1.php'
use Timer;
//or use src\utility\Timer ... both doesn't work.
class Verification{
Timer::somefunction();
}
This also does not work, and it shows that class not found. But, if I remove all the namespaces, and use's. Everything works fine.
We can solve the namespace problem in two ways
1) We can just use namespace and require
2) We can use Composer and work with the autoloading!
The First Way (Namespace and require) way
Class1.php (Timer Class)
namespace Utility;
class Timer
{
public static function {}
}
Class2.php (Verification Class)
namespace Utility;
require "Class1.php";
//Some interesting points to note down!
//We are not using the keyword "use"
//We need to use the same namespace which is "Utility"
//Therefore, both Class1.php and Class2.php has "namespace Utility"
//Require is usually the file path!
//We do not mention the class name in the require " ";
//What if the Class1.php file is in another folder?
//Ex:"src/utility/Stopwatch/Class1.php"
//Then the require will be "Stopwatch/Class1.php"
//Your namespace would be still "namespace Utility;" for Class1.php
class Verification
{
Timer::somefunction();
}
The Second Way (Using Composer and the autoloading way)
Make composer.json file. According to your example "src/Utility"
We need to create a composer.json file before the src folder. Example: In a folder called myApp you will have composer.json file and a src folder.
{
"autoload": {
"psr-4": {
"Utility\\":"src/utility/"
}
}
}
Now go to that folder open your terminal in the folder location where there is composer.json file. Now type in the terminal!
composer dump-autoload
This will create a vendor folder. Therefore if you have a folder named "MyApp"
you will see vendor folder, src folder and a composer.json file
Timer.php(Timer Class)
namespace Utility;
class Timer
{
public static function somefunction(){}
}
Verification.php (Verification Class)
namespace Utility;
require "../../vendor/autoload.php";
use Utility\Timer;
class Verification
{
Timer::somefunction();
}
This method is more powerful when you have a complex folder structure!!
You are going to need to implement an autoloader, as you have already read about it in SO.
You could check the autoloading standard PSR-4 at http://www.php-fig.org/psr/psr-4/ and you can see a sample implementation of PSR-4 autoloading and an example class implementation to handle multiple namespaces here https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md.
I'm trying to build a site with slim and autoloading my controller classes for the routes. I'm currently setting up the base structure and testing with a single route with nothing more than a simple "Test" output.
I prevously did this stuff with defining a spl_autoload_register function, but as this approach isn't recommended by slim and composer I want to do it right and I'm not trying to autoload my classes.
My Project is set up as this:
The class BlockController inside the file with the same Name under Controller is inside a namespace defined with namespace MyAPI\Controller;
app/Controller/BlockController.php
namespace MyAPI\Controller;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class BlockController
{
public function getList(Request $request, Response $response, $args)
{
return $response->withStatus(200)
->withHeader('Content-Type', 'text/html')
->write("Test");
}
}
I'm loading the dependencies and settings and after that all my routes (which contains currently only some small ones for testing my architecture):
public/index.php:
require __DIR__ . '/../vendor/autoload.php';
$settings = require __DIR__ . '/../app/settings.php';
$app = new \Slim\App($settings);
require __DIR__ . '/../app/dependencies.php';
require __DIR__ . '/../app/routes.php';
$app->run();
app/routes.php (is very simple, will be extended with more Route-files):
require 'Routes/BlockRoute.php';
app/Routes/BlockRoute.php:
use MyAPI\Controller\BlockController;
$container["BlockController"] = function ($container) {
return new BlockController($container);
};
$app->group('/block', function() use ($container) {
$this->get('[/]', 'BlockController::getList');
});
So the first command inside BlockRoute.php is the use of the BlockController-namespace. Everything under app/ should have the Base-Namespace MyAPI.
As described in the slim-documentation I planned to do that with to autoload feature of composer, so I modified my composer.json and added the following:
{
"require": { .. },
"autoload": {
"psr-4": {
"MyAPI\\": "app"
}
}
}
Edit: updated path to app-folder after the answer from Adam Lavin
After that I ran composer update. Is that the right command for those changes? Or should I use composer install? Couldn't find any more information what I have to do after making those additions in the autoload-section.
When I run the site now with the php webserver and navigate to this route /block I get the following RuntimeException:
Callable BlockController::getList does not exist
File: C:\Prog\src\vendor\slim\slim\Slim\CallableResolver.php
So the problem is that BlockController doesn't get included/autoloaded correctly but I don't understand why or what exactly the problem is. I tried to find some examples of working configurations with slim+composer+autoloading of classes but couldn't find something related.
Any input appreciated.
Since you're pointing MyApp\\ to ../src (the same directory as composer), the autoloader is going to try and find the controller in src/Controllers/BlockController.php.
It should be pointing to ../src/app, though since composer.json is in the src folder it can be simplified to app in the resulting composer.json file.
{
"require": { .. },
"autoload": {
"psr-4": {
"MyAPI\\": "app"
}
}
}
Additionally, In your example, the namespace of the BlockController is MoinAPI\Controllers, and should be MyAPI\Controllers.
And finally, in slim, you use a single colon instead of a double to refer to a callable route. BlockController::getList should be BlockController:getList
Run this from within docker container, or using the same php binary that composer used.
composer dump-autoload -o -vvv #-o fixed my problem in my case
I'm developing a REST API with Silex and I'm facing a problem regarding autoloading of my custom librairy. It looks like Composer's autoload is not including it, because when I include it myself it works.
# The autoload section in composer.json
# Tried with :
# "Oc\\": "src/Oc"
# "Oc\\": "src/"
# "": "src/"
"autoload": {
"psr-4": {
"Oc\\": "src/"
}
}
<?php
// api/index.php <-- public-facing API
require_once __DIR__.'/../vendor/autoload.php';
$app = require __DIR__.'/../src/app.php';
require __DIR__.'/../src/routes.php'; // <--
$app->run();
<?php
// src/routes.php
// When uncommented, it works!
//include('Oc/ParseImport.php');
use Symfony\Component\HttpFoundation\Response;
use Oc\ParseImport;
$app->get('/hello', function () use ($app) {
return new Response(Oc\ParseImport(), 200);
});
<?php
// src/Oc/ParseImport.php
namespace Oc {
function ParseImport() {
return 'foobar!';
}
}
I run composer dumpautoload after each composer.json manipulation, and I do see the line 'Oc\\' => array($baseDir . '/src/Oc') (or anything I tried) in vendor/composer/autoload_psr4.php.
I can't figure out what is wrong.
Almost everything you did was correct.
When trying to autoload classes in a namespace, given that a class is named Oc\Foo and is located in the file src/Oc/Foo.php, the correct autoloading would be "PSR-4": { "Oc\\": "src/Oc" }.
However, you do not have a class. You have a function. And functions cannot be autoloaded by PHP until now. It has been proposed more than once (the one proposal I found easily is https://wiki.php.net/rfc/function_autoloading), but until now this feature hasn't been implemented.
Your alternative solutions:
Move the function into a static method of a class. Classes can be autoloaded.
Include the function definition as "files" autoloading: "files": ["src/Oc/ParseImport.php"] Note that this approach will always include that file even if it isn't being used - but there is no other way to include functions in PHP.
As illustration see how Guzzle did it:
Autoloading in composer.json
Conditional include of functions based on function_exists
Function definition
I am new with this namespace thing.
I have 2 classes(separate files) in my base directory, say class1.php and class2.php inside a directory src/.
class1.php
namespace \src\utility\Timer;
class Timer{
public static function somefunction(){
}
}
class2.php
namespace \src\utility\Verification;
use Timer;
class Verification{
Timer::somefunction();
}
When I execute class2.php, i get the Fatal error that
PHP Fatal error: Class 'Timer' not found in path/to/class2.php at
line ***
I read somewhere on SO, that I need to create Autoloaders for this. If so, how do I approach into creating one, and if not, then what else is the issue?
UPDATE
I created an Autoloader which will require all the required files on top of my php script.
So, now the class2.php would end up like this.
namespace \src\utility\Verification;
require '/path/to/class1.php'
use Timer;
//or use src\utility\Timer ... both doesn't work.
class Verification{
Timer::somefunction();
}
This also does not work, and it shows that class not found. But, if I remove all the namespaces, and use's. Everything works fine.
We can solve the namespace problem in two ways
1) We can just use namespace and require
2) We can use Composer and work with the autoloading!
The First Way (Namespace and require) way
Class1.php (Timer Class)
namespace Utility;
class Timer
{
public static function {}
}
Class2.php (Verification Class)
namespace Utility;
require "Class1.php";
//Some interesting points to note down!
//We are not using the keyword "use"
//We need to use the same namespace which is "Utility"
//Therefore, both Class1.php and Class2.php has "namespace Utility"
//Require is usually the file path!
//We do not mention the class name in the require " ";
//What if the Class1.php file is in another folder?
//Ex:"src/utility/Stopwatch/Class1.php"
//Then the require will be "Stopwatch/Class1.php"
//Your namespace would be still "namespace Utility;" for Class1.php
class Verification
{
Timer::somefunction();
}
The Second Way (Using Composer and the autoloading way)
Make composer.json file. According to your example "src/Utility"
We need to create a composer.json file before the src folder. Example: In a folder called myApp you will have composer.json file and a src folder.
{
"autoload": {
"psr-4": {
"Utility\\":"src/utility/"
}
}
}
Now go to that folder open your terminal in the folder location where there is composer.json file. Now type in the terminal!
composer dump-autoload
This will create a vendor folder. Therefore if you have a folder named "MyApp"
you will see vendor folder, src folder and a composer.json file
Timer.php(Timer Class)
namespace Utility;
class Timer
{
public static function somefunction(){}
}
Verification.php (Verification Class)
namespace Utility;
require "../../vendor/autoload.php";
use Utility\Timer;
class Verification
{
Timer::somefunction();
}
This method is more powerful when you have a complex folder structure!!
You are going to need to implement an autoloader, as you have already read about it in SO.
You could check the autoloading standard PSR-4 at http://www.php-fig.org/psr/psr-4/ and you can see a sample implementation of PSR-4 autoloading and an example class implementation to handle multiple namespaces here https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md.
app/Core
contollers
This is my website structure to put the main class, I user composer psr-4 rule to import class under app/Core folder.
composer.json
{
"autoload": {
"psr-4": {
"Core\\": ["app/Core"]
}
}
}
index.php
<?php
include 'vendor/autoload.php';
new Core/Api; // it's work
It works fine, but I want to autoload class under controllers folder without use namespace, so I use __autoload function like:
index.php
<?php
include 'vendor/autoload.php';
function __autoload($class_name) {
include 'controllers/' . $class_name . '.php';
}
new Test // Fatal error: Class 'test'
If I remove include 'vendor/autoload.php'; it will work, so I think the code is correct, I know I can use classmap in composer.json, but it need to dump-autoload everytime I add a new class, how to deal with the conflict?
You do not have to use your own implementation of autoloading. You could use composer autoloading for all classes.
{
"autoload": {
"psr-0": { "": "src/" }
}
}
https://getcomposer.org/doc/04-schema.md#psr-0
Or, you could create class map
https://getcomposer.org/doc/04-schema.md#classmap
p.s. indeed, you could use empty namespace with psr-4.