I would like to be able to use OOP and create new objects in my controllers in CodeIgniter. So I need to use an autoload-function:
function __autoload( $classname )
{
require_once("../records/$classname.php");
}
But how can I add that to CodeIgniter?
You can add your auto loader above to app/config/config.php. I've used a similar autoload function before in this location and it's worked quite neatly.
function __autoload($class)
{
if (strpos($class, 'CI_') !== 0)
{
#include_once(APPPATH . 'core/' . $class . EXT);
}
}
Courtesy of Phil Sturgeon. This way may be more portable. core would probably be records for you; but check your paths are correct regardless. This method also prevents any interference with loading CI_ libs (accidentally)
the User guide about Auto-loading Resources is pretty cleat about it.
To autoload resources, open the application/config/autoload.php file and add the item you want loaded to the autoload array. You'll find instructions in that file corresponding to each type of item.
I would suggest using hooks in order to add this function to your code.
Enable hooks in your config/config.php
$config['enable_hooks'] = TRUE;
In your application/config/hooks.php add new hook on the "pre_system" call, which happens in core/CodeIgniter.php before the whole system runs.
$hook['pre_system'] = array(
0 => array(
'function' => 'load_initial_functions',
'filename' => 'your_hooks.php',
'filepath' => 'hooks'
)
);
Then in the hooks folder create 2 files:
First: application/hooks/your_functions.php and place your __autoload function and all other functions that you want available at this point.
Second: application/hooks/your_hooks.php and place this code:
function load_initial_functions()
{
require_once(APPPATH.'hooks/your_functions.php');
}
This will make all of your functions defined in your_functions.php available everywhere in your code.
Related
I wrote custom classes and want to use them in pimcore application.
I took them to /website/lib/Custom directory on server. Afterwards, I wrote recursive script includer for each Class located in the directory and included that script in /index.php file.
It is absolutely not pimcore standard but it works.
In pimcore/config/startup.php exists snippet:
$autoloaderClassMapFiles = [
PIMCORE_CONFIGURATION_DIRECTORY . "/autoload-classmap.php",
PIMCORE_CUSTOM_CONFIGURATION_DIRECTORY . "/autoload-classmap.php",
PIMCORE_PATH . "/config/autoload-classmap.php",
];
$test = PIMCORE_ASSET_DIRECTORY;
foreach ($autoloaderClassMapFiles as $autoloaderClassMapFile) {
if (file_exists($autoloaderClassMapFile)) {
$classMapAutoLoader = new \Pimcore\Loader\ClassMapAutoloader([$autoloaderClassMapFile]);
$classMapAutoLoader->register();
break;
}
}
I guess that this provides inclusion of all those classes put into returning array from autoload-classmap.php.
Having in mind that /pimcore/config/autoload-classmap.php exists, the mentioned loop would break at first iteration so classes that I would put into custom autoload-classmap are not going to be included in project.
My question is can I change files from /pimcore directory and expect that everything would be fine after system update?
No, you should not overwrite anything in the pimcore directory, since the files in there get overwritten by the update mechanism.
You can do what you want by using the /website/config/startup.php which will not get overwritten:
https://www.pimcore.org/wiki/display/PIMCORE4/Hook+into+the+startup-process
But instead of loading all your classes as you did, take advantage of the autoloader by adding this to the /website/config/startup.php:
// The first line is not absolutely necessary, since the $autoloader variable already gets
// set in the /pimcore/config/startup.php, but it is a more future-proof option
$autoloader = \Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace('Custom');
If you are properly using namespaces and naming your files correctly that's all you need to do.
I'm trying to use FirePHP with Zend Framework 2, but there seems to be something missing. Here's the basic code I'm trying to run:
$writer = new Zend\Log\Writer\FirePhp();
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('FirePHP logging enabled');
The error I get is "FirePHP Class not found". I was initially puzzled because I do have a FirePhp class in my Zend/Log/Writer folder. But then I saw that the class constructor requires a FirePhp\FirePhpInterface object. So I checked the Zend/Log/Writer/FirePhp folder and there's a FirePhpBridge class in there that implements FirePhpInterface, but it also requires a FirePHP instance in the constructor. I don't have any FirePHP.php file in my Zend/Log/Writer/FirePhp folder. Am I supposed to get this from somewhere else?
Update
I now have managed to get FirePHP working, but I'm trying to figure out how to do it in a clean way so this works. The only way I've gotten it to work is putting it in the root directory of my project and doing the following:
include_once('FirePHP.php');
$writer = new Zend\Log\Writer\FirePhp(new Zend\Log\Writer\FirePhp\FirePhpBridge(FirePHP::getInstance(true)));
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('FirePHP logging enabled');
I assume that normally I should be able to create a writer like so:
$writer = new Zend\Log\Writer\FirePhp();
However, where this goes wrong I believe is in the getFirePhp() function of the Zend\Log\Writer\FirePhp class. The class does this:
if (!$this->firephp instanceof FirePhp\FirePhpInterface
&& !class_exists('FirePHP')
) {
// No FirePHP instance, and no way to create one
throw new Exception\RuntimeException('FirePHP Class not found');
}
// Remember: class names in strings are absolute; thus the class_exists
// here references the canonical name for the FirePHP class
if (!$this->firephp instanceof FirePhp\FirePhpInterface
&& class_exists('FirePHP')
) {
// FirePHPService is an alias for FirePHP; otherwise the class
// names would clash in this file on this line.
$this->setFirePhp(new FirePhp\FirePhpBridge(new FirePHPService()));
}
This is where I get lost as to how I'm supposed to set things up so that this class_exists('FirePHP') call finds the right class and new FirePHPService() also works properly.
First you should add this code to Module.php of your module
return array(
//...
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
);
and here content of autoload_classmap.php
<?php
return array(
'FirePHP' => realpath(APPLICATION_PATH . '/vendor/FirePHP').'/FirePHP.php',
);
FirePHP.php(renamed from FirePHP.class.php) downloaded from official site.
then you can write below code in any place of your module and it will work
use Zend\Log\Writer\FirePhp;
use Zend\Log\Logger;
$writer = new FirePhp();
$logger = new Logger();
$logger->addWriter($writer);
$logger->info("hi");
Am I supposed to get this from somewhere else?
Yes, you need to get FirePHP into your project and autoloading.
If you're using composer (and I recommend that you do), just add:
"firephp/firephp-core" : "dev-master"
(or similar) in your composer.json and update. If you're not using composer, you should grab the firephp libs, and let your autoloader know about them.
im currently working on some sort of upload with automatic video conversion. At the moment i am executing a php script via php shell command after the upload is finished so the user doesn't have to wait until the conversion is completed. Like so:
protected function _runConversionScript() {
if (!exec("php -f '" . $this->_conversionScript . "' > /dev/null &"))
return true;
return false;
}
Now in my conversion script file i am using functions from another class "UploadFunctions" to update the status in the database (like started, converted, finished...). The problem there is though that this UploadFunctions class inherits from another class "Controller" where for example the database connection gets established. Currently i am using spl_autoloader to search specific directories for the files needed (for example controller.php), but because the conversion script is out of context with the whole autoloader stuff it doesn't recognize the Controller class and throws an fatal php error.
Here is some code from the conversion script:
require_once('uploadfunctions.php');
$upload_func = new UploadFunctions();
// we want to make sure we only process videos that haven't already
// been or are being processed
$where = array(
'status' => 'queued'
);
$videos = $upload_func->getVideos($where);
foreach ($videos as $video) {
// update database to show that these videos are being processed
$update = array(
'id' => $video['id'],
'status' => 'started'
);
// execute update
$upload_func->updateVideo($update);
.........
Am i doing this completly wrong or is there a better way to accomplish this? If you need more code or information please let me know!
Thanks a lot
Here is my spl_autoload code:
<?php
spl_autoload_register('autoloader');
function autoloader($class_name) {
$class_name = strtolower($class_name);
$pos = strpos($class_name ,'twig');
if($pos !== false){
return false;
}
$possibilities = array(
'..'.DIRECTORY_SEPARATOR.'globals'.DIRECTORY_SEPARATOR.$class_name.'.php',
'controller'.DIRECTORY_SEPARATOR.$class_name.'.php',
'..'.DIRECTORY_SEPARATOR.'libs'.DIRECTORY_SEPARATOR.$class_name.'.php',
'local'.DIRECTORY_SEPARATOR.$class_name.'.php'
);
foreach ($possibilities as $file) {
if(class_exists($class_name) != true) {
if (file_exists($file)) {
include_once($file);
}
}
}
}
?>
I have my project divided into subfolders wich represent the functionality, for example upload, myaccount and gallery.. in every subfolder there are also 2 other folders: controller and local. Controller is the class controlling this part (upload for example) and local is the folder where i am putting the local classes wich are needed. The controller class gets called from the index.php wich is located in the sub-project folder. "libs" and "global" are just projectwide classes, like database, user and so on.
This is an example of my folder structure:
www/index.php // main site
www/upload/index.php // calls the controller for upload and initializes the spl_autoload
www/upload/controller/indexcontroller.php // functionality for the upload
www/upload/local/processVideo.php // this is the conversion script.
I am fairly new to spl_autoload function. In my opinion the spl_autoload is not getting called if my script is calling: "php -f processVideo.php", isn't it?
PHP relative paths are calculated from the path where PHP binary is called.
I suggest you to use __DIR__ constant to avoid that behavior
http://php.net/manual/en/language.constants.predefined.php
I was actually able to resolve the issue. I had to include the spl_autoload_register function inside the conversion script so that it was able to locate the files. This was an issue because the conversion script is not build into my framework an so it isn't able to load the classes from the framework autoloader.
I'm pretty much newbie in Zend Framework action helpers and I am trying to use them with no success (I read a bunch of posts about action helpers, including http://devzone.zend.com/article/3350 and found no solution in like 8 hours). I used Zend Tool to setup my project and the name of the helper is Action_Helper_Common. No matter what I do, I get following error "Fatal error: Class 'Action_Helper_Common' not found". Currently, I have things set up like this:
zf version: 1.11.3
helper name: Action_Helper_Common
helpers location:
/application/controllers/helpers/Common.php
In Bootstrap.php i have following function:
protected function _initActionHelpers() {
Zend_Controller_Action_HelperBroker::addPath(APPLICATION_PATH . '/controllers/helpers', 'Action_Helper');
Zend_Controller_Action_HelperBroker::addHelper(
new Action_Helper_Common(null, $session)
);
}
I also tried this without success (it was defined in Bootstrap.php before _initActionHelpers):
protected function _initAutoloader() {
$moduleLoader = new Zend_Application_Module_Autoloader(array(
'namespace' => '',
'basePath' => APPLICATION_PATH . '/controllers/helpers'));
return $moduleLoader;
}
So what am I doing wrong?!?! PLZ help, I am desperate and about to give up :)
You got error because you haven't setup autoloader for Action_Helper_*
Resource autoloader
Helper broker uses plugin loader to load helpers based on paths and prefixes you specified to it. That is why ::getHelper() can find your helper
you dont need to do (so remove it)
Zend_Controller_Action_HelperBroker::addHelper(
new Action_Helper_Common(null, $session)
); ,
since you already did
Zend_Controller_Action_HelperBroker::addPath(APPLICATION_PATH . '/controllers/helpers', 'Action_Helper');
when you will do
$myhelper = $this->getHelper('Common');
in your controller zf will lookinto directory /controllers/helpers/ for class name Action_Helper_Common and create an instance for you and return it.
For some reason the following line didn't work for me as well:
Zend_Controller_Action_HelperBroker::addHelper( new Action_Helper_Common() );
I just keep getting a 'Class not found' error each time I'm creating a new helper object explicitly.
This is what works for me:
Zend_Controller_Action_HelperBroker::getHelper('Common');
In this case, new Action_Helper_Common object gets created and is registered with Helper Broker.
Not sure though if it works for you, since you have a parameterized constructor.
this is my third question so far on stackoverflow :D
i am defining files and their location on my first_run.php files,
the files that i define here is those files containing classes, helper functions
and any other files required
at early development, this first_run.php contains only a few lines of codes
but the line is increasing gradually as i add some new classes or new files to be included
and since i group the file's location inside a particular folder, i figure that maybe i can scan the folder, put the name of the files retrieved into an array and then loop the require_once, so that i dont have to edit first_run.php every time i add a new file inside the folder.
my fisrt approach is using scandir()
before:
defined('INC_PATH') ? null : define('INC_PATH', SITE_ROOT.DS.'includes');
defined('MEMBERS') ? null : define('MEMBERS', INC_PATH.DS.'models'.DS.'members');
require_once(MEMBERS.DS.'member.php');
require_once(MEMBERS.DS.'phone.php');
require_once(MEMBERS.DS.'profile.php');
require_once(MEMBERS.DS.'talent.php');
require_once(MEMBERS.DS.'profile_picture.php');
require_once(MEMBERS.DS.'audio.php');
require_once(MEMBERS.DS.'video.php');
require_once(MEMBERS.DS.'gallery.php');
require_once(MEMBERS.DS.'statistik.php');
require_once(MEMBERS.DS.'inbox.php');
require_once(MEMBERS.DS.'comment.php');
require_once(MEMBERS.DS.'picked_stat.php');
require_once(MEMBERS.DS.'log.php');
after is something like:
$member_files = scandir(MEMBERS);
foreach($member_files as $member_file):
require_once(MEMBERS.DS.$member_file);
endforeach;
i havent try the 'after' code though.
is this possible?? or is there any other approach?? or should i just leave it that way (keep adding the lines without scanning the files)
thanks in advance
Consider using Autoloading instead.
With autoloading, you do not have to bother with including files at all. Whenever you instantiate a new class that is not known to PHP at that point, PHP will trigger the registered autoload function. The function includes the required files then. This way, you only load what you need when you need it, which should increase performance.
Simple example with PHP5.3
spl_autoload_register(function($className) {
include "/path/to/lib/and/$className.php";
});
$foo = new Foo;
When you call new Foo, the registered autoload function will try to include the class from /path/to/lib/and/Foo.php. It is advisable to use a classname convention, like f.i. PEAR, to make finding files easier and to cut down on the amount of include_paths.
For additional security and speed, you can provide a more sophisticated Autoloader that uses an array to map from classname to filename, thus making sure only files that actually are part of your application can get included.
Further reading:
http://weierophinney.net/matthew/archives/245-Autoloading-Benchmarks.html
It's possible, but not recommended, like what if somebody could create a php file on that directory, you'll end up including it, besides, you can't predict the inclusion order.
Try this instead:
$includes=array(
'member',
'phone',
'profile',
'talent',
);
foreach($includes as $fname) {
require_once(MEMBERS.DS.$fname. '.php');
}
If you were using classes, consider using autoloading, as #Gordon suggested. And if you werent using classes, consider using them :)
At a first glance your code could work, although you have to ignore "." and ".." in the foreach loop. Plus I'd check, if the file ends with ".php":
$member_files = scandir(MEMBERS.DS);
foreach($member_files as $member_file) {
// Ignore non php files and thus ".." & "."
if (!preg_match('/\.php$/', $member_file) {
continue;
}
require_once(MEMBERS.DS.$member_file);
}
create 2 functions
function GetFiles($directory,$exempt = array('.','..','.ds_store','.svn'),&$files = array()) {
$handle = opendir($directory);
while(false !== ($resource = readdir($handle))){
if(!in_array(strtolower($resource),$exempt)){
if(is_dir($directory.$resource.'/'))
array_merge($files, self::GetFiles($directory.$resource.'/',$exempt,$files));
else
$files[] = $directory.$resource;
}
}
closedir($handle);
return $files;
}
function Autoload($includes = array()){
$files = array();
foreach($includes as $directory)
$files[] = self::GetFiles($directory);
foreach($files as $k=>$v){
foreach($v as $k1=>$v1)
require_once($v1);
}
}
to use it:
$includes = array(
'C:WWW/project/helpers/',
'C:WWW/project/lang/',
'C:WWW/project/lib/',
'C:WWW/project/mod/',
);
Autoload($includes);