CodeIgniter: Load controller within controller
I have a home
controller with an index
action that displays a set of开发者_C百科 featured products. However, the products are managed through a product
controller including a proprietary model and views.
How do I access product
information from within the index
action in the home
controller? Instancing product
won't work as the class isn't loaded at runtime and CodeIgniter doesn't provide a way to dynamically load controllers. Putting the product
class into a library file doesn't really work, either.
To be precise, I need the product views (filled with data processed by the product
controller) inserted in the index view. I'm running CodeIgniter 2.0.2.
Load it like this
$this->load->library('../controllers/instructor');
and call the following method:
$this->instructor->functioname()
This works for CodeIgniter 2.x.
If you're interested, there's a well-established package out there that you can add to your Codeigniter project that will handle this:
https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc/
Modular Extensions makes the CodeIgniter PHP framework modular. Modules are groups of independent components, typically model, controller and view, arranged in an application modules sub-directory, that can be dropped into other CodeIgniter applications.
OK, so the big change is that now you'd be using a modular structure - but to me this is desirable. I have used CI for about 3 years now, and can't imagine life without Modular Extensions.
Now, here's the part that deals with directly calling controllers for rendering view partials:
// Using a Module as a view partial from within a view is as easy as writing:
<?php echo modules::run('module/controller/method', $param1, $params2); ?>
That's all there is to it. I typically use this for loading little "widgets" like:
- Event calendars
- List of latest news articles
- Newsletter signup forms
- Polls
Typically I build a "widget" controller for each module and use it only for this purpose.
In this cases you can try some old school php.
// insert at the beggining of home.php controller
require_once(dirname(__FILE__)."/product.php"); // the controller route.
Then, you'll have something like:
Class Home extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->product = new Product();
...
}
...
// usage example
public function addProduct($data)
{
$this->product->add($data);
}
}
And then just use the controller's methods as you like.
Just to add more information to what Zain Abbas said:
Load the controller that way, and use it like he said:
$this->load->library('../controllers/instructor');
$this->instructor->functioname();
Or you can create an object and use it this way:
$this->load->library('../controllers/your_controller');
$obj = new $this->your_controller();
$obj->your_function();
Based on @Joaquin Astelarra response, I have managed to write this little helper named load_controller_helper.php:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if (!function_exists('load_controller'))
{
function load_controller($controller, $method = 'index')
{
require_once(FCPATH . APPPATH . 'controllers/' . $controller . '.php');
$controller = new $controller();
return $controller->$method();
}
}
You can use/call it like this:
$this->load->helper('load_controller');
load_controller('homepage', 'not_found');
Note: The second argument is not mandatory, as it will run the method named index, like CodeIgniter would.
Now you will be able to load a controller inside another controller without using HMVC.
Later Edit: Be aware that this method might have unexpected results. Always test it!
With the following code you can load the controller classes and execute the methods.
This code was written for codeigniter 2.1
First add a new file MY_Loader.php
in your application/core directory. Add the following code to your newly created MY_Loader.php
file:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
// written by AJ sirderno@yahoo.com
class MY_Loader extends CI_Loader
{
protected $_my_controller_paths = array();
protected $_my_controllers = array();
public function __construct()
{
parent::__construct();
$this->_my_controller_paths = array(APPPATH);
}
public function controller($controller, $name = '', $db_conn = FALSE)
{
if (is_array($controller))
{
foreach ($controller as $babe)
{
$this->controller($babe);
}
return;
}
if ($controller == '')
{
return;
}
$path = '';
// Is the controller in a sub-folder? If so, parse out the filename and path.
if (($last_slash = strrpos($controller, '/')) !== FALSE)
{
// The path is in front of the last slash
$path = substr($controller, 0, $last_slash + 1);
// And the controller name behind it
$controller = substr($controller, $last_slash + 1);
}
if ($name == '')
{
$name = $controller;
}
if (in_array($name, $this->_my_controllers, TRUE))
{
return;
}
$CI =& get_instance();
if (isset($CI->$name))
{
show_error('The controller name you are loading is the name of a resource that is already being used: '.$name);
}
$controller = strtolower($controller);
foreach ($this->_my_controller_paths as $mod_path)
{
if ( ! file_exists($mod_path.'controllers/'.$path.$controller.'.php'))
{
continue;
}
if ($db_conn !== FALSE AND ! class_exists('CI_DB'))
{
if ($db_conn === TRUE)
{
$db_conn = '';
}
$CI->load->database($db_conn, FALSE, TRUE);
}
if ( ! class_exists('CI_Controller'))
{
load_class('Controller', 'core');
}
require_once($mod_path.'controllers/'.$path.$controller.'.php');
$controller = ucfirst($controller);
$CI->$name = new $controller();
$this->_my_controllers[] = $name;
return;
}
// couldn't find the controller
show_error('Unable to locate the controller you have specified: '.$controller);
}
}
Now you can load all the controllers in your application/controllers directory. for example:
load the controller class Invoice and execute the function test()
$this->load->controller('invoice','invoice_controller');
$this->invoice_controller->test();
or when the class is within a dir
$this->load->controller('/dir/invoice','invoice_controller');
$this->invoice_controller->test();
It just works the same like loading a model
According to this blog post you can load controller within another controller in codeigniter.
http://www.techsirius.com/2013/01/load-controller-within-another.html
First of all you need to extend CI_Loader
<?php
class MY_Loader extends CI_Loader {
public function __construct() {
parent::__construct();
}
public function controller($file_name) {
$CI = & get_instance();
$file_path = APPPATH.'controllers/' . $file_name . '.php';
$object_name = $file_name;
$class_name = ucfirst($file_name);
if (file_exists($file_path)) {
require $file_path;
$CI->$object_name = new $class_name();
}
else {
show_error('Unable to load the requested controller class: ' . $class_name);
}
}
}
then load controller within another controller.
There are plenty of good answers given here for loading controllers within controllers, but for me, this contradicts the mvc pattern.
The sentence that worries me is;
(filled with data processed by the product controller)
The models are there for processing and returning data. If you put this logic into your product model then you can call it from any controller you like without having to try to pervert the framework.
Once of the most helpful quotes I read was that the controller was like the 'traffic cop', there to route requests and responses between models and views.
I know this is old, but should anyone find it more recently, I would suggest creating a separate class file in the controllers folder. Pass in the existing controller object into the class constructor and then you can access the functions from anywhere and it doesn't conflict with CI's setup and handling.
You can use this:
self::index();
精彩评论