I don't know if this is exactly a problem in autoloading, but I am having this problem, here is my code:
index.php
require __DIR__ . '/app/autoload.php';
Folder structure:
index.php
app/
--autoload.php
autoload.php
function autoloader($className) {
// List Directories to Autoload Classes
$paths = array(
__DIR__ . '/system/',
__DIR__ . '/app/models/',
__DIR__ . '/app/dao/'
);
foreach($paths as $path) {
$file = $path . '/' . $className . '.php';
if (is_file($file))
include $file;
}
}
For some reason it doesn't work even I do:
__DIR__ . '../system/
... et al.
DIR in the autoload file will refer to /app.
try:
function autoloader($className) {
// List Directories to Autoload Classes
$paths = array(
'../system/',
'/models/',
'/dao/'
);
foreach($paths as $path) {
$file = $path . '/' . $className . '.php';
if (is_file($file))
require_once $file;
}
}
If that fails start echoing out paths and dir to see if they are referenced properly.
I would try it this way.
Anywhere before the autoload.php is loaded (should be file which is always loaded, i guess in your case its index.php) i would define ROOT variable somwhere at begining of the script
/**
* Use the DS to separate the directories (just a shortcut)
*/
if (!defined('DS')) {
define('DS', DIRECTORY_SEPARATOR);
}
/**
* The full path to the directory which holds application files, without a trailing DS.
*/
if (!defined('ROOT')) {
define('ROOT', dirname(__FILE__));
}
and then in your autoload use ROOT
$paths = array(
ROOT . DS. 'system' . DS,
ROOT . DS. 'app' . DS . 'models' . DS,
ROOT . DS. 'app' . 'dao' . DS
);
Related
See my last question as this links to it: PHP - Moving multiple files with different files names to own directory
So i decided to using the Joomla API however, the documentation was for 1.5 and 2.5 system only but i'm using 3.0. I have a number of files that look like this:
"2005532-JoePharnel.pdf"
and
"1205121-HarryCollins.pdf"
Basically I want to create a PHP code that when someone ftp uploads those files to the upload folder that it will 1) Create a directory if it doesn't exist using there name 2) Move the files to the correct directory (E.g. JoePharnel to the JoePharnel Directory ignoring the number at the beginning)
Updated: 23/10/14 - 14:05:
My new code creates the folder but won't move the file in the upload into that new folder, code is below:
<?php
define( '_JEXEC', 1);
define('JPATH', dirname(__FILE__) );
if (!defined('DS')){
define( 'DS', DIRECTORY_SEPARATOR );
$parts = explode( DS, JPATH );
$script_root = implode( DS, $parts ) ;
// check path
$x = array_search ( 'administrator', $parts );
if (!$x) exit;
$path = '';
for ($i=0; $i < $x; $i++){
$path = $path.$parts[$i].DS;
}
// remove last DS
$path = substr($path, 0, -1);
if (!defined('JPATH_BASE')){
define('JPATH_BASE', $path );
}
if (!defined('JPATH_SITE')){
define('JPATH_SITE', $path );
}
/* Required Files */
require_once ( JPATH_SITE . DS . 'includes' . DS . 'defines.php' );
require_once ( JPATH_SITE . DS . 'includes' . DS . 'framework.php' );
require_once ( JPATH_SITE . DS . 'libraries' . DS . 'joomla' . DS . 'factory.php' );
//Import filesystem libraries. Perhaps not necessary, but does not hurt
jimport('joomla.filesystem.path');
jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');
jimport('joomla.user.user');
//First we set up parameters
$searchpath = JPATH_BASE . DS . "upload";
//Then we create the subfolder called png
if ( !JFolder::create($searchpath . DS ."Images") ) {
//Throw error message and stop script
}
//Now we read all png files and put them in an array.
$png_files = JFolder::files($searchpath,'.png');
//Now we need some stuff from the JFile:: class to move all files into the new folder
foreach ($png_files as $file) {
JFile::move($searchpath. DS . ".png" . $file, $searchpath . DS. "Images" . $file);
}
//Lastly, we are moving the complete subdir to the root of the component.
if (JFolder::move($searchpath . DS. "Images",JPATH_COMPONENT) ) {
//Redirect with perhaps a happy message
} else {
//Throw an error
}
}
?>
Only error i get is Notice: Use of undefined constant JPATH_COMPONENT - assumed 'JPATH_COMPONENT' in /upload.php on line 70. But doesn't stop it working, am so close on this any help is greatly appreciated. I want to know where its taking the image, i think i have worked out the "DS" now.
Thanks
I have a file that auto loads each of my classes.
This is what it contains:
spl_autoload_register(function($class){
require_once 'classes/' . $class . '.php';
});
require_once 'functions/sanitize.php';
require_once 'functions/hash.php';
But when I require_once this file from another php file that is inside my ajax folder, it will try looking for the classes, the function will look from my classes with the path: main_folder/ajax/classes instead of just main_folder/classes.
Does anyone know how to fix this?
FIX:
spl_autoload_register(function($class){
if (file_exists('classes/' . $class . '.php')) {
require_once 'classes/' . $class . '.php';
}
elseif (file_exists('../classes/' . $class . '.php')) {
require_once '../classes/' . $class . '.php';
}
elseif (file_exists('../../classes/' . $class . '.php')) {
require_once '../../classes/' . $class . '.php';
}
You should simple use this function just once - in the main file (usually index.php) and not in another files.
However if it's not possible (but I don't see any reason when could it be not possible) you can change it for example that way:
spl_autoload_register(function($class){
if (file_exists('classes/' . $class . '.php')) {
require_once 'classes/' . $class . '.php';
}
elseif (file_exists( $class . '.php')) {
require_once $class . '.php';
}
});
Here is a proper way, It should universally work.
EDIT: Make sure to specify levels on dirname in order to find the correct path.
spl_autoload_register(function ($classname) {
$file_realpath = dirname(realpath(__FILE__), levels: 1 /* Change that? */) . DIRECTORY_SEPARATOR . dirname($classname);
$classpath = sprintf('%s' . DIRECTORY_SEPARATOR . '%s.php', $file_realpath, basename($classname, '.{php,PHP}'));
if (file_exists($classpath)) {
echo "Loading <b>$classpath</b>...<br>";
require($classpath);
}
});
You need to know the absolute path to the classes directory, then just use a full qualified path to get there.
Make sure your document root is correctly configured with your http server. Furthermore this is usually solved by routing all requests to index.php and deriving the base path (document root) from there. Here is your code modified:
spl_autoload_register(function($class) {
$resolved = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . $class . '.php';
if(file_exists($resolved)) {
require_once $resolved;
} else {
// make it known to your that a class failed to load somehow
return;
}
})
Here is another implementation that I use for simple projects
I've just begun using autoloader lazy loading in my app, and I'm running afoul of namespacing. The autoloader is trying to load things like new DateTime() and failing. Is there a trick to making my autoloader spcific to only my own namespaced classes?
Here is the code I have currently. I suspect it is a mess, but I'm not seeing just how to correct it:
<?php namespace RSCRM;
class Autoloader {
static public function loader($className) {
$filename = dirname(__FILE__) .'/'. str_replace("\\", '/', $className) . ".php";
if (file_exists($filename)) {
include_once($filename);
if (class_exists($className)) {
return TRUE;
}
}
return FALSE;
}
}
spl_autoload_register('\RSCRM\Autoloader::loader');
Happy to RTM if someone can point to a solid example.
What I use is actually adapted from the autoloader used to Unit Test a few of the AuraPHP libraries:
<?php
spl_autoload_register(function ($class) {
// a partial filename
$part = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
// directories where we can find classes
$dirs = array(
__DIR__ . DIRECTORY_SEPARATOR . 'src',
__DIR__ . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'src',
__DIR__ . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'src',
);
// go through the directories to find classes
foreach ($dirs as $dir) {
$file = $dir . DIRECTORY_SEPARATOR . $part;
if (is_readable($file)) {
require $file;
return;
}
}
});
Just make sure the array of '$dirs' values point to the root of your namespaced code.
You can also take a look at the PSR-0 example implementation (http://www.php-fig.org/psr/psr-0/).
You might also want to look an into existing autoloader, like Aura.Autoload or the Symfony ClassLoader Component, although those might be overkill depending on what your requirements are.
I hope this helps.
I'm trying to build my own framework for internal usage.
I got structure like this:
index.php
boot /
booter.php
application /
controllers /
indexcontroller.php
core /
template.class.php
model.class.php
controller.class.php
cache /
memcached.php
something /
something.php
Booter.php contains: (it's currently working only with files located in core directory):
class Booter
{
private static $controller_path, $model_path, $class_path;
public static function setDirs($controller_path = 'application/controllers', $model_path = 'application/models', $classes_path = 'core')
{
self::$controller_path = $controller_path;
self::$model_path = $model_path;
self::$class_path = $classes_path;
spl_autoload_register(array('Booter', 'LoadClass'));
if ( DEBUG )
Debugger::log('Setting dirs...');
}
protected static function LoadClass($className)
{
$className = strtolower($className);
if ( file_exists(DIR . '/' . self::$model_path . '/' . $className . '.php') )
{
require(DIR . '/' . self::$model_path . '/' . $className . '.php');
}
else if ( file_exists(DIR . '/' . self::$class_path . '/' . $className . '.class.php') )
{
require(DIR . '/' . self::$class_path . '/' . $className . '.class.php');
}
else if ( file_exists(DIR . '/' . self::$controller_path . '/' . $className . '.php') )
{
require(DIR . '/' . self::$controller_path . '/' . $className . '.php');
}
if ( DEBUG )
Debugger::log('AutoLoading classname: '.$className);
}
}
My application/controllers/indexcontroller looks like this:
<?
class IndexController extends Controller
{
public function ActionIndex()
{
$a = new Model; // It works
$a = new Controller; //It works too
}
}
?>
And here comes my questions:
[Question 1]
My code is working currently like this:
$a = new Model; // Class Model gets included from core/model.class.php
How I can implement including files by classes with namespaces? For example:
$a = new Cache\Memcached; // I would like to include file from /core/CACHE/Memcached.php
$a = new AnotherNS\smth; // i would like to include file from /core/AnotherNS/smth.php
and so on. How I can produce the handling of the namespace?
[Question 2]
Is it a good practice to use single autoload for Classes, Controllers and models or I should define 3 different spl_autoload_register with 3 different methods and why?
I normally have a bootstrap.php file inside a folder conf that is in the application root. My code is normally located inside an src folder, also located in the root, so, this works fine for me:
<?php
define('APP_ROOT', dirname(__DIR__) . DIRECTORY_SEPARATOR);
set_include_path(
implode(PATH_SEPARATOR,
array_unique(
array_merge(
array(
APP_ROOT . 'src',
APP_ROOT . 'test'
),
explode(PATH_SEPARATOR, get_include_path())
)
)
)
);
spl_autoload_register(function ($class) {
$file = sprintf("%s.php", str_replace('\\', DIRECTORY_SEPARATOR, $class));
if (($classPath = stream_resolve_include_path($file)) != false) {
require $classPath;
}
}, true);
You can generalize this into your "Booter" class and append directories to the include path. If you have well defined namespace names, there will be no problems with colisions.
Edit:
This works if you follow PSR-1.
Question 1:
In your autoloader, change the \ (for the namespace) into DIRECTORY_SEPARATOR. This should work:
protected static function LoadClass($className)
{
$className = strtolower($className);
$className = str_replace('\\', DIRECTORY_SEPARATOR, $className);
...
}
Always use DIRECTORY_SEPARATOR, especially if the software has the potential to be used on other platforms.
Question 2:
I would use one and separate your classes by namespace. However, I think that comes down to how you want to structure your framework and how you separate your code. Someone else may be able to better answer that question.
I am trying to autoload classes that are in different folders. Is that possible?
function __autoload($class){
require $class.'.php';
require 'libs/'.$class.'.php';
//this won't work.
}
I want to autoload classes that are either in libs folder or on the root. Any thoughts? Thanks a lot.
First, I suggest you look into spl_autoload_register, which is superior for doing this.
Second, you should use is_file to test whether the file exists, then try to load it. If you require a file that doesn't exist, your script will halt.
spl_autoload_register(function($class) {
if (is_file($class . '.php')) {
require $class . '.php';
} elseif (is_file('libs/' . $class . '.php')) {
require 'libs/' . $class . '.php';
}
});
If you have multiple folders where the file could be, you could do something like this:
spl_autoload_register(function($class) {
$folders = array ('.', 'libs', 'somewhere');
foreach ($folders as $folder) {
if (is_file($folder . '/' . $class . '.php')) {
require $folder . '/' . $class . '.php';
}
if (class_exists($class)) break;
}
});