HMVC MX_Controller not loading CI' _output function - codeigniter

Normally, extending CI_Controller lets you use the function _output for rendering html outputs.
I'm using HMVC. MX_Controller doesn't load _output function.
I've tested it and run a couple of times.
Questions:
1 - Does MX_Controller inherits CI_Controller?
2 - How can I implement _output?

It seems like codeigniter-modular-extensions-hmvc does indeed break the _output() functionality. I can't figure out how to submit the bug on bitbucket: https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc
My workaround involved overriding the Output class & adding a hook to fire a custom output method. Here's what I did.
Overwrite the main Output class:
class MY_Output extends CI_Output
{
function __construct()
{
parent::__construct();
}
// Overwrite the output
public function my_output()
{
$content = $this->get_output();
// do stuff to $content here
$this->set_output($content);
$this->_display();
}
}
Then enable hooks in your config.
$config['enable_hooks'] = TRUE;
Then add this to your hooks config.
$hook['display_override'][] = array(
'class' => '',
'function' => 'custom_output',
'filename' => 'custom_output.php',
'filepath' => 'hooks'
);
Finally add the "custom_output.php" file to your hooks directory and add this.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
* Customize the output
*/
function custom_output()
{
$CI =& get_instance();
$CI->output->my_output();
}
If you don't need to access any class variables, you can just edit the output right in the custom_output() function and not worry about overriding the Output class.
Very hacky, but it works. :)

Related

pre_controller hook does not load base classes like docs state?

According to the Codeignitor docs here: http://ellislab.com/codeigniter/user-guide/general/hooks.html it states:
pre_controller
Called immediately prior to any of your controllers being called. All base classes, routing, and security checks have been done.
However, if I create a hook pre_controller hook with:
$hook['pre_controller'][] = array(
'class' => 'tester',
'function' => 'test',
'filename' => 'tester.php',
'filepath' => 'models',
//'params' => array('beer', 'wine', 'snacks')
);
and the file tester.php is:
class tester extends CI_Model
{
public function __construct()
{
parent::__construct();
$this->load->library('migration');
}
public function test()
{
echo "hi";
exit;
}
}
I get this error:
Fatal error: Class 'CI_Model' not found in ******.php
Why is it not loading CI_Model? If I put a require_once('system/core/Model.php'); in the hooks.php file above the pre_controller definition, I get this error:
Fatal error: Call to a member function library() on a non-object in ****.php
Since it's not actually loading the CI_Model, functions such as library() would not work. How can I force it to bootstrap the CI_Model.
The first person that says "Use post_controller_constructor" will be shot on sight as that does not answer the question. I need it to load BEFORE it runs any constructor functions from the controller classes. I need access to extend the CI_Model class from the pre_controller hook.
The short answer is that CodeIgniter doesn't work the way you want it to. At the stage that you're trying to access a model, CodeIgniter hasn't loaded the required classes and it isn't available. Depending on exactly what you're trying to achieve, there may be another way to achieve this - without using a hook/using a later hook?
Viewing /system/core/CodeIgniter.php will show when each hook is called and when other tasks are performed; loading routing, loading global functions etc.
If you insist on using this hook, then you could add this: load_class('Model', 'core'); at the top of your model file (before you declare the class), but this would be a very dirty fix.
Make sure your class names follow the correct naming convention - tester should be Tester.
Edit: as you want to run the same code on every call (assuming every controller call), this is a possible solution:
Extend the core controller, and use this new controller as a base controller for all other controllers (as they will be sharing the same functionality). In the constructor of this new base controller, add the functionality that you want to run on every call. The code in this constructor will be called before any other code in any of your controllers.
Create the following file, application/core/MY_Controller.php.
class MY_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
// Do whatever you want - load a model, call a function...
}
}
Extend every controller in application/controllers, with MY_Controller, rather than CI_Controller.
class Welcome extends MY_Controller {
function __construct()
{
parent::__construct();
}
// Your controllers other functions...
}
/*application/config/hooks.php*/
$hook['pre_controller'][] =
array(
'class' => 'MyClass',
'function' => 'Myfunction',
'filename' => 'Myclass.php',
'filepath' => 'hooks',
'params' => array('beer', 'wine', 'snacks')
);
/*application/config/config.php*/
$config['enable_hooks'] = TRUE;
/hooks/Myclass.php/

Data available for all views in codeigniter

I have a variable, contaning data that should be present in the entire site. Instead of passing this data to each view of each controller, I was wondering if there is a way to make this data available for every view in the site.
Pd. Storing this data as a session variable / ci session cookie is not an option.
Thanks so much.
Create a MY_Controller.php file and save it inside the application/core folder. In it, something like:
class MY_Controller extends CI_Controller {
public $site_data;
function __construct() {
parent::__construct();
$this->site_data = array('key' => 'value');
}
}
Throughout your controllers, views, $this->site_datais now available.
Note that for this to work, all your other controllers need to extend MY_Controllerinstead of CI_Controller.
You need to extend CI_Controller to create a Base Controller:
https://www.codeigniter.com/user_guide/general/core_classes.html
core/MY_Controller.php
<?php
class MY_Controller extend CI_Controller {
public function __construct() {
parent::__construct();
//get your data
$global_data = array('some_var'=>'some_data');
//Send the data into the current view
//http://ellislab.com/codeigniter/user-guide/libraries/loader.html
$this->load->vars($global_data);
}
}
controllers/welcome.php
class Welcome extend MY_Controller {
public function index() {
$this->load->view('welcome');
}
}
views/welcome.php
var_dump($some_var);
Note: to get this vars in your functions or controllers, you can use $this->load->get_var('some_var')
Set in application/config/autoload.php
$autoload['libraries'] = array('config_loader');
Create application/libraries/Config_loader.php
defined('BASEPATH') OR exit('No direct script access allowed.');
class Config_loader
{
protected $CI;
public function __construct()
{
$this->CI =& get_instance(); //read manual: create libraries
$dataX = array(); // set here all your vars to views
$dataX['titlePage'] = 'my app title';
$dataX['urlAssets'] = base_url().'assets/';
$dataX['urlBootstrap'] = $dataX['urlAssets'].'bootstrap-3.3.5-dist/';
$this->CI->load->vars($dataX);
}
}
on your views
<title><?php echo $titlePage; ?></title>
<!-- Bootstrap core CSS -->
<link href="<?php echo $urlBootstrap; ?>css/bootstrap.min.css" rel="stylesheet">
<!-- Bootstrap theme -->
<link href="<?php echo $urlBootstrap; ?>css/bootstrap-theme.min.css" rel="stylesheet">
If this is not an Variable(value keep changing) then I would suggest to create a constant in the constant.php file under the config directory in the apps directory, if it's an variable keep changing then I would suggest to create a custom controller in the core folder (if not exist, go ahead an create folder "core") under apps folder. Need to do some changes in other controller as mentioned here :
extend your new controller with the "CI_Controller" class. Example
open-php-tag if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class LD_Controller extends CI_Controller {
}
close-php-tag
Here LD_ is my custom keyword, if you want to change you can change it in config.php file under line# 112 as shown here : $config['subclass_prefix'] = 'LD_';
and extend this class in all your controllers as "class Mynewclass extends LD_Controller..
And in LD_controller you've to write the method in which you want to define the variable/array of values & call that array in all over the application as shown here :
defining variable :
var $data = array();
Method to get values from db through the Model class:
function getbooks()
{
$books = $this->mybooks_model->getbooks(); //array of records
$this->data = array('books'=>$books);
}
to call this variable in the views : print_r($this->data['books']);); you will get all the array values... here we've to make sure atleast one "$data" parameter needs to be passed if not no problem you can define this $data param into the view as shown here :
$this->load->view('mybookstore',$data);
then it works absolutely fine,,, love to share... have a fun working friends
you can use $this->load->vars('varname', $data);[ or load data at 1st view only] onse and use in any loaded views after this
Use sessions in your controllers
$this->session->set_userdata('data');
then display them in your view
$this->session->userdata('data');
Or include a page in base view file e.g index.php
include "page.php";
then in page.php,
add $this->session->userdata('data'); to any element or div
then this will show on all your views
I read all answers, but imho the best approch is via hook:
Create hook, let's get new messages for example:
class NewMessages {
public function contact()
{
// Get CI instance CI_Base::get_instance();
$CI = &get_instance(); // <-- this is contoller in the matter of fact
$CI->load->database();
// Is there new messages?
$CI->db->where(array('new' => 1));
$r = $CI->db->count_all_results('utf_contact_requests');
$CI->load->vars(array('new_message' => $r));
}
}
Attach it to some of the flow point, for example on 'post_controller_constructor'. This way, it will be loaded every time any of your controller is instantiated.
$hook['post_controller_constructor'][] = array(
'class' => 'NewMessages',
'function' => 'contact',
'filename' => 'NewMessages.php',
'filepath' => 'hooks',
'params' => array(),
);
Now, we can access to our variable $new_message in every view or template.
As easy as that :)
You could override the view loader with a MY_loader. I use it on a legacy system to add csrf tokens to the page where some of the forms in views don't use the builtin form generator. This way you don't have to retrospectively change all your controllers to call MY_Controller from CI_Controller.
Save the below as application/core/MY_Loader.php
<?php
class MY_Loader extends CI_Loader {
/**
* View Loader
*
* Overides the core view function to add csrf token hash into every page.
*
* #author Tony Dunlop
*
* #param string $view View name
* #param array $vars An associative array of data
* to be extracted for use in the view
* #param bool $return Whether to return the view output
* or leave it to the Output class
* #return object|string
*/
public function view($view, $vars = array(), $return = FALSE)
{
$CI =& get_instance();
$vars['csrf_token'] = $CI->security->get_csrf_hash();
return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_prepare_view_vars($vars), '_ci_return' => $return));
}
}

Autoload controller in CodeIgniter

I have question to you.
I try add to my page calendar and some events in this calendar. I know how I can load calendar in page, but I didn`t now how I can load this calendar on every page automatically.
Controller:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Calendar extends CI_Controller {
function index()
{
$data = array(
3 => 'Polska - Anglia',
);
$this->load->library('calendar');
$vars['calendar'] = $this->calendar->generate('', '', $data);
$this->load->view('main/calendar', $vars);
}
}
and In view I call:
<?php echo $calendar;?>
I use CodeIgniter 2.1.3
Instead of creating controller for calendar, create a library class and then add it to autoload configuration file
class MyCalendar{
public function get()
{
$CI =& get_instance();
$data = array(
3 => 'Polska - Anglia',
);
$CI->load->library('calendar');
return $CI->calendar->generate('', '', $data);
}
}
Add this library to autoload file and then you can call it anywhere you want by using this statement.
$data['calendar'] = $this->MyCalendar->get();
You can autoload your library by changing the application/config/autoload.php file.
Find :
$autoload['libraries'] = array();
Replace by :
$autoload['libraries'] = array('calendar');
To load the same calendar on all your pages, I suggest to build a parent controller in the application/core folder.
abstract class BaseController extends CI_Controller
{
protected $data;
public function __construct()
{
parent::__construct();
$this->data = array();
$calendarData = array(
3 => 'Polska - Anglia'
);
$this->data['calendar'] = $this->calendar->generate('', '', $calendarData);
}
}
You can then extend that BaseController class on all your controllers.
class Calendar extends BaseController {
function index()
{
$this->load->view('main/calendar', $this->data);
}
}
Be sure to always use $this->data to build on the protected member of your class.
Lastly, your BaseController will not be autoloaded, you probably don't want to include it everywhere. I suggest you to add the following method at the end of your autoload or config file.
/**
* Extra autoload function. Loads core classes automatically.
* #param type $class The class to load.
*/
function __autoload($class)
{
if (strpos($class, 'CI_') !== 0)
{
if (file_exists($file = APPPATH . 'core/' . $class . EXT))
{
include $file;
}
}
}
This will allow you to autoload any classes you have in your application/core folder. This solution might seems complex, but once it's setup. You can add functionality to your BaseController that is applicable for all pages, for example, header and footer stuff.
Hope this helps!

Create Codeigniter Helper -> undefined method

I created a helper "session_helper.php" in application/helpers/ folder
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if ( ! function_exists('is_login'))
{
function is_login()
{
$CI =& get_instance();
$is_logged_in = $CI->session->userdata('is_logged_in');
if (!isset($is_logged_in) || $is_logged_in != TRUE) {
redirect('login');
}
}
}
And "Configuracion" Controller:
class Configuracion extends CI_Controller {
function __construct()
{
parent::__construct();
$this->is_logged_in();
}
function is_logged_in()
{
$this->load->helper('session');
$this->is_login();
}
}
The problem is when I call the controller "http://localhost/proyect/configuracion" I get the following error:
Fatal error: Call to undefined method Configuracion::is_login() in C:...\application\controllers\configuracion.php on line 15
I read the manual and apparently everything is correct ... what is wrong?
"is_login" is a function, not a method. Just replace $this->is_login(); with is_login();.
Helpers are not methods, they are just simple function calls.
Take a look at helpers in the User Guide: http://codeigniter.com/user_guide/general/helpers.html
Loading a helper:
$this->load->helper('url');
using its helper functions:
<?php echo anchor('blog/comments', 'Click Here');?>
where anchor() is the function that is part of the loaded helper.
Also I would urge you to stay way from calling a helper 'session' make it something more descriptive, as it might become confusing later on. Just a suggestion, its entirely up to you.

Codeigniter: how to load constants, defined in a hook, in the constructor of my controller

The problem:
I've defined a few constants in my hook but I can't access them inside my sub-classed controller constructor.
The code:
A - the hook class:
class Settings extends CI_Hooks {
public function load_settings() {
$CI =& get_instance();
$CI->load->model('hooks/settings_model');
$data = $CI->settings_model->load_settings();
define('MEMBERS_PER_PAGE', $data['members_per_page']);
define('REGISTER_ENABLED', $data['register']);
define('SITE_ACCESS_ENABLED', $data['site_access']);
define('ADMIN_EMAIL', $data['admin_email']);
}
}
B - the hook config:
$hook['post_controller_constructor'] = array(
'class' => 'settings',
'function' => 'load_settings',
'filename' => 'settings.php',
'filepath' => 'hooks'
);
C - the controller
class MY_Controller extends CI_Controller
{
public function __construct()
{
parent::__construct();
defined('SITE_ACCESS_ENABLED') ? print SITE_ACCESS_ENABLED : print "NULL";
}
}
The way I understand *post_controller_constructor* is that it loads after the controller is initialized but before the constructor is executed. Apparently my defined constants don't work in any constructor while constants from config/constants.php do work.
Any help and insights are greatly appreciated as hooks are totally new to me.
Well, post_controller_constructor happens just then. After the constructor has finished constructing the controller :-).
You need to have it fire at pre_controller and manage the instantiation of the model on your own, or you will have to wait until the controller's method is called before you can access the values. Sorry.

Resources