Implementing namespaces in fatfree framework - php

I am trying to use namespaces in fatfree framework, but somehow its not able to find the class following is my setup
routes.ini
[routes]
GET /=Src\Controllers\Index->index
index.php
namespace Src\Controllers;
class Index {
function index($f3) {
$f3->set('name','world');
echo View::instance()->render('template.htm');
}
}
Global index.php
// Retrieve instance of the framework
$f3=require('lib/base.php');
// Initialize CMS
$f3->config('config/config.ini');
// Define routes
$f3->config('config/routes.ini');
// Execute application
$f3->run();
UPDATE:
Error:
Not Found
HTTP 404 (GET /)
• index.php:13 Base->run()
UPDATE 2:
config.ini
[globals]
; Where the framework autoloader will look for app files
AUTOLOAD=src/controllers/
; Remove next line (if you ever plan to put this app in production)
DEBUG=3
; Where errors are logged
LOGS=tmp/
; Our custom error handler, so we also get a pretty page for our users
;ONERROR=""
; Where the framework will look for templates and related HTML-support files
UI=views/
; Where uploads will be saved
UPLOADS=assets/
I'm not sure what's going wrong.
Thanks In advance.

The autoloader of the Fat-Free Framework is very basic. It expects you to define one or more autoloading folders, each of them will map to the root namespace.
So let's say you define $f3->set('AUTOLOAD','app/;inc/') and your file structure is:
- app
- inc
- lib
|- base.php
- index.php
Then a class named MyClass belonging to the Foo\Bar namespace (full path: Foo\Bar\MyClass) should be stored in either app/foo/bar/myclass.php or inc/foo/bar/myclass.php (remember: we specified two autoloading folders).
NB: don't forget to specify namespace Foo\Bar at the beginning of myclass.php (the autoloader won't do it for you).
--
So to answer your specific problem, having the following file structure:
- lib
|- base.php
- src
|- controllers
|- index.php
- index.php
three configurations are possible:
Config 1
$f3->set('AUTOLOAD','src/controllers/')
Then all the files under src/controllers/ will be autoloaded, but remember : src/controllers/ maps to the root namespace, so that means the Index class should belong to the root namespace (full path: \Index).
Config 2
$f3->set('AUTOLOAD','src/')
Then all the files under src/ will be autoloaded, which means the Index class should belong to the Controllers namespace (full path: \Controllers\Index).
Config 3
$f3->set('AUTOLOAD','./')
Then all the files under ./ will be autoloaded, which means the Index class should belong to the Src\Controllers namespace (full path: \Src\Controllers\Index).

Fat-Free is always the root namespace "\". (the following might be wrong) Since F3 loads your classes through the autoloader, you always have to add the root namespace to your own namespaces. In this case you have to change it to
namespace \Src\Controllers;
And of course you have to change it in your routes.ini too.
GET /=\Src\Controllers\Index->index
To help you finding those issues in the future you can higher the DEBUG value with
$f3->set('DEBUG', 2); // 0-3; 0=off, 3=way too much information

Try this config - Your class:
namespace Creo\Controllers;
Framework routes
GET|POST / = \Creo\Controllers\IndexController->indexAction
folder location
_your_app_dir/app/Creo/Controllers
Your bootstrap file (in this case in _your_app_dir/app/)
spl_autoload_register(function ($className) {
$filename = __DIR__ . '/' . str_replace('\\', '/', $className) . ".php";
if (file_exists($filename)) {
include($filename);
if (class_exists($className)) {
return true;
}
}
return false;
});
Hope this will help.

Related

Can't get my autoloader to work with namespaces

I'm having an issue with my folder structure in combination with my PHP files and their namespaces.
Here's my folder structure:
myproject
|
-- entry.php
-- src
|
-- IndexController.php
My entry.php looks like this:
<?php
spl_autoload_register(function (String $class) {
$sourcePath = __DIR__ . DIRECTORY_SEPARATOR . 'src';
$replaceRootPath = str_replace('myproject\Controllers', $sourcePath, $class);
$replaceDirectorySeparator = str_replace('\\', DIRECTORY_SEPARATOR, $replaceRootPath);
$filePath = $replaceDirectorySeparator . '.php';
if (file_exists($filePath)) {
require($filePath);
}
});
$indexController = new myproject\Controllers\IndexController;
$result = $indexController->controlSomething('this thing');
print($result);
My src/IndexController.php looks like this:
<?php
namespace myproject\Controllers;
class IndexController
{
public function controlSomething(string $something): string {
return $something;
}
}
This works perfectly fine. However, I want a bit of a different folder structure. I would like to go one folder deeper to keep my Controllers somewhere organised. So I want a Controllers folder to keep my Controllers there. Changing my folder structure to this:
myproject
|
-- entry.php
-- src
|
-- Controllers
|
-- IndexController.php
results in an error saying Class 'myproject\Controllers\IndexController' not found.
How can I achieve this? I've tried adding /Controllers to the code where paths and namespaces are defined, but I keep getting this error.
In your current setup, you've mapped the folder src to the base namespace myproject\Controllers. Whatever comes after myproject\Controllers, is expected to mirror a subdirectory structure starting at src.
What follows is the following: when you put IndexController in the directory src\Controllers, the autoloader would only find it if the full class name were myproject\Controllers\Controllers\IndexController.
What you probably want to do instead, is map src to myproject directly, eg.
$replaceRootPath = str_replace('myproject', $sourcePath, $class);
The solution I tend to favour, and is the current industry standard for php, is to use composer as autoloader.
Once installed, configuring your autoloader would become as simple as this json segment:
"autoload": {
"psr-4": {
"myproject\\": "src"
}
},
And, optionally,
"autoload-dev": {
"psr-4": {
"myproject\\Test\\": "tests"
}
},
Using composer has the additional benefit of being able to pull from a vast collection of open source modules to simplify your life.
Try
<?php
namespace myproject\src\Controllers;

Namespaces used for test in official exemple don't work for me [duplicate]

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.

How to use composer psr-4 fallback correctly

I have one directory that is going to keep all "helper" classes and functions. Let's call the directory helpers.
I want to configure PSR-4 fallback directory to point to this helpers directory:
"autoload": {
"psr-4": {
"": "helpers/"
}
}
From Composer documentation:
... fallback directory where any namespace will be looked for.
So my understanding is that if my files/classes in that directory have PSR-4 compliant names my application should be able to find them there.
Now I created a file helpers/Logger.php with class Logger
What namespace should be for this class in order to 1) comply with PSR-4 and 2) just work?
I have tried
namespace Logger;
And load class as
$logger = new Logger();
But I receive error Class Logger not found
Deeper dive into composer code (loadClass() method) showed me that it actually finds and includes the file helpers/Logger.php, but the class still cannot be found for some reason.
According to PSR-4 namespace should be something like this:
namespace Helpers;
And class should be called like this:
$logger = new Helpers\Logger();
I have Class Helpers\Logger not found, but in addition the file helpers/Logger.php is not even included.
The logic inside Composer's loadClass() method for fallback is following:
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
........
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
So it actually tries to match the file name against the fully qualified class name.
So it seems that I am missing something in my understanding of PSR-4.
But what exactly?
Edit
To check it all I run a simple file from project root, all other libraries that are configured via composer are loaded correctly (for example, Pimple is working fine):
<?php
require_once __DIR__ . '/vendor/autoload.php';
$app = new \Pimple\Container();
/** Register logger */
$app['logger'] = function ($c) {
return new Helpers\Logger();
};
$app['logger']->info('test');
This fallback works as a definition of directory for global namespace. So yes, it may be used for autoloading any class in any namespace, but you still need to follow PSR-4 rules for them. Directory structure should represent namespaces structure. If you have rules like:
"autoload": {
"psr-4": {
"": "helpers/"
}
}
your Helpers\Logger class should be in helpers/Helpers/Logger.php, because in this way Composer will resolve class file path from autoloading rules.
helpers/Helpers/Logger.php
^ ^ ^
| | |
| | Class name part
| |
| Namespace part
|
Static prefix for global namespace
PSR4 is working case-sensitive, so if you place a class in the folder helpers and the class itself uses the namespace Helpers, that won't work.

Cakephp: create new object and access controller class in index.php root page that is inside webroot folder

I am trying to access CustomersController class from index.php page that is inside webroot folder in cakephp 3.When I use below code, it says it cannot find the class.
require dirname(__DIR__) . '/src/Controller/CustomersController.php';
$customers = new CustomersController;
Am I doing something wrong?
Here is the error I get from cakephp index.php page: "Error: Class 'CustomersController' not found "
You have to understand that CakePHP 3 uses PSR4 autoloading (check also composer) and also namespaces. If you go and remove the namespace from from the controller you will see that it works. But this will probably break other stuff.

Doctrine Autoloader appending namespace to include path

I have the following folder setup
/common
/classes
-sharedClass.php
/project
/classes
-coreClass.php
index.php
bootstrap.php
In my bootstrap.php I'm setting up a namespace
$autoloader = new ClassLoader('CommonFiles', dirname(__DIR__) . '/common/classes/');
$autoloader->register();
In index.php:
require_once 'classes/coreClass.php'
$core = new CoreClass();
in coreClass():
use CommonFiles\SharedClass;
//Other code
I'm getting an error that sharedClass.php can't be found, and the actual namespace is being appended to the file path being checked so that it's:
c:/web/common/classes/CommonFiles/sharedClass.php
So... how do I stop the autoloader from including the namespace as part of the path root it's looking for?
So after some closer review apparently this is just how autoloading works. I reviewed some of the baked in Doctrine samples and it looks like the namespace is appended automatically to all your use statements. This wasn't just a fluke but a design decision and accounting for it meant an easy fix.

Categories