I want to instantiate a class every time a page is loaded in CodeIgniter.
It looks like the /application/config/autoload.php is the place to do this. Is that correct?
I added this line to the package's autoload:
$autoload['packages'] = array('/application/third_party/Autoload.php');
Now I need this code to be executed on every page, where can I make this happen?
$bugsnag = new Bugsnag_Client("YOUR-API-KEY-HERE");
set_error_handler(array($bugsnag, "errorHandler"));
set_exception_handler(array($bugsnag, "exceptionHandler"));
To auto load a package (according to CI), you should put the package path/name in following array, like
$autoload['packages'] = array(APPPATH.'third_party', '/usr/local/shared');
But it doesn't execute any code automatically but makes your package available to use without explicitly loading it.
To make some code execute every time, you can put that code in your base controller's constructor function. Also, you can put the code in your config.php file. If you have an extended base controller, like application/core/MY_Controller.php
class MY_Controller extends CI_Controller {
//
}
Then you can use it's constructor function like
class MY_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
$this->bugsnag = new Bugsnag_Client("YOUR-API-KEY-HERE");
set_error_handler(array($bugsnag, "errorHandler"));
set_exception_handler(array($bugsnag, "exceptionHandler"));
}
}
Rest of your controllers will use/extend MY_Controller instead of CI_Controller.
But you can also use a hook in this case (to register custom exception handlers), in application/config/hooks.php file, put following code
$hook['pre_controller'][] = array(
'class' => 'CustomExceptionHook',
'function' => 'SetExceptionHandlers',
'filename' => 'CustomExceptionHook.php',
'filepath' => 'hooks'
);
Create a class in application/hooks/CustomExceptionHook.php folder, like
class CustomExceptionHook
{
public function SetExceptionHandlers()
{
// add package path (if not auto-loaded)
$this->load->add_package_path(APPPATH.'third_party/package_folder/');
// load package (if not auto-loaded)
$this->load->library('Bugsnag_Client');
set_error_handler(array($this->Bugsnag_Client, "errorHandler"));
set_exception_handler(array($this->Bugsnag_Client, "exceptionHandler"));
}
}
Well let me explain it how you can do it.
As you have autoloaded the package its fine now you need to do this.
Create a MY_Controller in application/core/ directory.
Class MY_Controller Extends CI_Controller{
public $bugsnag = '';
public function __construct(){
parent::__construct();
$this->bugsnag = new Bugsnag_Client("YOUR-API-KEY-HERE");
set_error_handler(array($bugsnag, "errorHandler"));
set_exception_handler(array($bugsnag, "exceptionHandler"));
}
}
Note $this->bugsnag contains the object now. When you need to access it in any page you can simply do it like this by extending the parent class
Class Test Extends MY_Controller{
public function __construct(){
parent::__construct();
}
public function index(){
echo '<pre>';
print_R($this->bugsnag);
}
}
Here is a version of MY_Controller.php
This is using BugSnag via composer install
Using this method exposes the $this->_bugsnag variable to the entire CI System
class MY_Controller extends CI_Controller {
// Application Version
public $_app_version;
// Bugsnag
public $_bugsnag = NULL;
/**
* Constructor
*/
public function __construct() {
parent::__construct();
// Dont print errors to screen
ini_set('display_errors', 0);
// Load configs
$this->load->config('appversion');
$this->load->config('bugsnag');
$this->_app_version = $this->config->item('app_version');
// INIT: bugsnag
// https://docs.bugsnag.com/platforms/php/other/configuration-options/
$this->_bugsnag = Bugsnag\Client::make( $this->config->item('bugsnagAPIKey') );
$this->_bugsnag->setErrorReportingLevel( E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED );
$this->_bugsnag->setNotifyReleaseStages( ['developement', 'testing', 'production'] );
$this->_bugsnag->setReleaseStage( ENVIRONMENT );
$this->_bugsnag->setAppType( 'API Server' );
$this->_bugsnag->setAppVersion( $this->_app_version );
$this->_bugsnag->setHostname( $_SERVER['HTTP_HOST'] );
$this->_bugsnag->setProjectRoot( realpath(APPPATH) );
$this->_bugsnag->setFilters( ['password'] );
Bugsnag\Handler::register( $this->_bugsnag );
// Load Helpers
// Load Libraries
// Load Languages
}
}
You can now access the BugSnag methods like this.
$this->_bugsnag->leaveBreadcrumb( 'Hello' );
$this->_bugsnag->notifyException( $e );
Create a MY_Controller & inherit all your controllers off that. You can find more on this by Googling "MY_Controller"
Related
I want to use dependency injection to pass an instance of Plates to my controllers with PHP-DI that is integrated with my routing system Simple Router.
I've tried to inject an instance of Plates, but I get this error:
<?php
namespace Controllers;
use \League\Plates\Engine;
use \League\Plates\Template\Template;
use \League\Plates\Extension\Asset;
class Controller {
public function __construct(\League\Plates\Engine $templates)
{
$this->templates = $templates;
}
?>
Uncaught LogicException: The template name "home" is not valid. The default directory has not been defined
How I can solve this issue? I need also to pass the assets path with the asset() method. Any help will be appreciated.
UPDATE
Thanks to the help of jcHache I've managed the injection of a Plates instance inside my base controller with this DI code:
<?php
// config.php
return [
League\Plates\Engine::class => DI\create()
->constructor(TEMPLATE_ROOT)
->method('loadExtension', DI\get('League\Plates\Extension\Asset')),
League\Plates\Extension\Asset::class => DI\create()
->constructor(APP_ROOT),
];
index.php file
<?php
use Pecee\SimpleRouter\SimpleRouter;
use DI\ContainerBuilder;
$container = (new \DI\ContainerBuilder())
->useAutowiring(true)
->addDefinitions('config.php')
->build();
SimpleRouter::enableDependencyInjection($container);
This is great but I'm facing a problem and I can't find a fix for it.
I get this error that is relative to the assets loader of plates, it seems that it's instantiated more than once. I've extended my controllers with my base controller where the asset loader is instantiated, but I don't think is this the problem? Is there a fix?
Uncaught Pecee\SimpleRouter\Exceptions\NotFoundHttpException: The template function name "asset" is already registered
Plates engine factory require a view folder parameter (see Plates doc):
so you have to add this creation in your PHP-DI configuration file:
For Plates V4:
// config.php
return [
// ...
\League\Plates\Engine::class => function(){
return League\Plates\Engine::create('/path/to/templates', 'phtml');
},
];
For Plates V3, I'll try:
// config.php
return [
// ...
\League\Plates\Engine::class => function(){
return new League\Plates\Engine('/path/to/templates');
},
];
or
// config.php
return [
// ...
\League\Plates\Engine::class => DI\create()
->constructor('/path/to/templates')
,
];
Design Note:
Personally, I won't use dependency injection for a template engine, I think it would be better to instantiate Plates engine in a base controller class.
namespace controllers;
use League\Plates\Engine;
abstract class BaseController
{
/**
* #var \League\Plates\Engine
*/
protected $templates;
public function __construct()
{
$this->templates=new Engine(\TEMPLATE_ROOT);
$this->templates->loadExtension(new \League\Plates\Extension\Asset(\APP_ROOT));
}
protected function renderView(string $viewname, array $variables=[])
{
return $this->templates->render($viewname,$variables);
}
}
For a child controller using Plates:
namespace controllers;
class MyController extends BaseController
{
public function index()
{
return $this->renderView('home');
}
}
I have created on hook to set current visiting URL to session. I have to use this URL later on. I have called session method of codeIgniter using $this->CI =& get_instance(); and then $this->CI->session->userdata but it is giving
Trying to get property of non-object on $this->CI->session->userdata line
I have done following things to enable hooks in CI
config.php
$config['enable_hooks'] = TRUE;
hooks.php
$hook['pre_controller'] = array(
'class' => 'Preclass',
'function' => 'checkreq',
'filename' => 'preclass.php',
'filepath' => 'hooks',
'params' => array()
);
preclass.php
class Preclass
{
private $CI;
public function __construct()
{
$this->CI =& get_instance();
}
public function checkreq($value='')
{
var_dump($this->CI->session->userdata);
die;
}
}
Note: Don't close this post as Duplicate of PHP errors. As I know about errors. This is in CodeIgniter and I want to check session before any controller method gets invoked.
From comment: "But I want it before controller methods invoke even before constructor"
To solve your issue, this is about the best you can do:
Make an MY_Controller.php in application/core:
class MY_Controller extends CI_Controller {
public function __construct() {
parent::__construct();
// class is just an alias for the controller name
if (!$this->user->is_allowed($this->router->class)) {
redirect('somepage');
}
}
}
Then have all your controllers extend MY_Controller:
class Somecontroller extends MY_Controller {
public function __construct() {
parent::__construct();
// nothing below the above line will be reached
// if the user isn't allowed
}
}
Whether or not you have a __construct() method in the class: nothing will happen so long as the user isn't allowed to access the page e.g. nothing after parent::__construct() will be called - even methods. Again, the fact that the parent constructor is called is implied if no constructor exists for the controller.
Note: if you autoload a model and do the same logic in the MY_Controller in the models __construct() the same results should be achieved. I just find this method cleaner.
This is not possible in Codeigniter as session itself a library and you are trying to call it pre_controller. When controllers not loaded yet how can you use it even in hook.
Solution
You may use post_controller_constructor instead what are using now
$hook['post_controller_constructor'] = array(
'class' => 'Preclass',
'function' => 'checkreq',
'filename' => 'preclass.php',
'filepath' => 'hooks',
'params' => array()
);
otherwise you may also use native session here
hope it help
I'm trying to create my custom driver using Codeigniter
Files structure:
/libraries
/Test_driver
/drivers
Test_driver_first_driver.php
Test_driver.php
Driver super class:
class Test_driver extends CI_Driver_Library
{
function __construct()
{
$this->valid_drivers = array('test_driver_first_driver');
}
}
Driver Subclass :
class Test_driver_first_driver extends CI_Driver
{
function index()
{
echo "Hello world!";
}
}
Testing code in welcome.php Controller :
$this->load->driver('test_driver');
$this->test_driver->test_driver_first_driver->index();
but the output was : "Invalid driver requested Test_driver.test_driver_first_driver".
Does any one have any idea, Unfortunately Codeigniter user guide does not contains steps for creating custom driver.
its best practice or i should say my thinking that i always avoid underscores in parent class for the driver
so for me the file structure is some what like this
/libraries
/Testdriver
/drivers
Testdriver_first_driver.php
Testdriver.php
Testdriver.php
<?php
class Testdriver extends CI_Driver_Library
{
function __construct()
{
$this->valid_drivers = array('testdriver_first_driver');
}
}
Testdriver_first_driver.php
<?php
class Testdriver_first_driver extends CI_Driver
{
public function index()
{
echo "Hello world!";
}
}
In controller
$this->load->driver('testdriver');
$this->testdriver->first_driver->index();
Note : even if you don't use ucfirst() it will still work
i.e. Folder testdriver
Files -
testdriver.php (class testdriver extends CI_Driver_Library)
and
testdriver_first_driver.php (class testdriver_first_driver extends CI_Driver)
hope it is helpful. :)
I tried Karan's answer but I removed the parent's name in valid_drivers' value:
<?php
class Testdriver extends CI_Driver_Library{
function __construct(){
$this->valid_drivers = array('first_driver');
}
}
?>
This worked for me, you might want to give it a try. Credits to Karan.
I have just grappled with this in CodeIgniter v2.2.0 so thought I'd chip in. The scant documentation on custom drivers isn't too helpful as the example does not show the complete setup. The existing core CodeIgniter drivers are not organised in a consistent way either, with the driver parent class files being in different directory locations to where the docs say they should be etc. so you have little to go by but to consult the core Driver Library code.
In your given situation, the driver is seen as invalid is because you are effectively adding on the parent class name twice when calling it. This:
$this->test_driver->test_driver_first_driver->index();
Should be changed to:
$this->test_driver->first_driver->index();
Looking at the core code that the driver parent class extends:
class CI_Driver_Library {
protected $valid_drivers = array();
protected $lib_name;
// The first time a child is used it won't exist, so we instantiate it
// subsequents calls will go straight to the proper child.
function __get($child) {
if (!isset($this->lib_name)) {
$this->lib_name = get_class($this);
}
// The class will be prefixed with the parent lib
$child_class = $this->lib_name . '_' . $child;
Note the last line there. Basically, CI was trying to load a driver class named "Test_driver_test_driver_first_driver", which of course didn't exist.
For codeignaiter 3 problem in core system libraries driver.php
testdriver_first_driver.php
class Testdriver_first_driver extends CI_Driver {
public function index()
{
echo "Hello world!";
}
}
testdriver.php
class Testdriver extends CI_Driver_Library{
function __construct(){
$this->valid_drivers = array('first_driver');
}
}
CodeIgniter SPL Autoloader
/*
|--------------------------------------------------------------------------
| Autoloader function
|--------------------------------------------------------------------------
|
| Add to the bottom of your ./application/config/config.php file.
|
| #author Brendan Rehman
| #param $class_name
| #return void
*/
function __autoloader($class_name)
{
// class directories
$directories = array(
APPPATH . 'core/',
// add more autoloading folders here� and you�re done.
);
// for each directory
foreach ($directories as $directory)
{
// see if the file exsists
if (file_exists($directory.$class_name.'.php'))
{
require_once($directory.$class_name.'.php');
// only require the class once, so quit after to save effort (if
you got more, then name them something else
return;
}
}
}
spl_autoload_register('__autoloader');
Hi i have issue here of calling another controller action to send an mail, here is my code:
user.php
public function followAction()
{
$follow_id = $this->_getParam('id');
$response = "<a href='javascript: void(0)' class='i-wrap ig-wrap-user_social i-follow_small-user_social-wrap'><i class='i i-follow_small-user_social ig-user_social'></i>Stop Following</a>";
notifyEmail() ------> need to call Notity Controller with notifyEmail() Action along with
params
$this->_helper->json($response); ----> return json response
}
NotifyController.php
<?php
class NotifyController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function index()
{
}
public function notifyEmailAction()
{
// rest of email code goes here
}
}
Thanks for help!
You have to move send mails functionality to another place,
and call it in both methods.
Check this thread
Calling member function of other controller in zend framework?
I suggest to create at the path /library a new folder 'My' and in it new file Utilities.php and in that file a new class where you can put all your help methods
class My_Utilities {
// put here your custom help methods
}
You need to auto-load that namespace.In configs/application.ini put
autoloaderNamespaces.my = "My_"
Then you can use namespace My_ and class My_Utilities.
In any case, you can call method form another controller:
include 'NotifyController.php';
$a = new NotifyController($this->_request, $this->_response);
$a->notifyEmailAction();
$this->action('action', 'controller', 'module', 'params')
That view helper walk through frontController and dispatch all plugins again.
I think is not the best solution keep in mind wasting resources
Please try this code
$this->action("action","controller","module")
In my module bootstrap:
<?php
class Api_Bootstrap extends Zend_Application_Module_Bootstrap
{
protected function _initAllowedMethods()
{
$front = Zend_Controller_Front::getInstance();
$front->setParam('api_allowedMethods', array('POST'));
}
protected function _initActionHelperBrokers()
{
Zend_Controller_Action_HelperBroker::addPath(APPLICATION_PATH . '/modules/api/controllers/helpers', 'Api_Controller_Action_Helper_');
Zend_Controller_Action_HelperBroker::addHelper(new Api_Controller_Action_Helper_Model());
}
}
There is a Api_Controller_Action_Helper_Model at /var/www/project/application/modules/api/controller/helpers/Model.php
But I get:
PHP Fatal error: Class 'Api_Controller_Action_Helper_Model' not found in /var/www/accounts.amh.localhost/application/modules/api/Bootstrap.php on line 15
As far as I can tell from the API and http://akrabat.com/zend-framework/using-action-helpers-in-zend-framework/ this should work.
I'm pretty sure this isn't a bootstrapping issue like I have had before, as I am specifically add the path/prefix right before trying to add the helper.
What else might I have missed?
The problem here is that the module autoloader does not know about controller action helper resources.
Try something like this in your module bootstrap
protected function _initResourceLoader()
{
$resourceLoader = $this->getResourceLoader();
$resourceLoader->addResourceType('actionhelper',
'controllers/helpers', 'Controller_Action_Helper');
}
All that being said, as your helper has an empty constructor, you could omit the addHelper() line and just let the broker automatically create it when requested in your controllers, eg
$helper = $this->getHelper('Model');