I'm building an application in Codigniter with HMVC. In it I call a module inside another controller. The problem I've run into is trying to pass/retrieve the data loaded into module. Specifically, I'm loading some javascript files that I would then like to pass to the calling controller.
Here is a simplified code:
public function module()
{
...
$this->data['js'] = $this->js_assets;
...
return $this->load->view('module_view', $this->data, true);
}
public function controller()
{
...
$this->load->module('module/module');
$this->data['module'] = $this->module->module();
...
}
I know that I can retrieve data['js'] in module_view as $js, but I wonder if I can just pass the data directly to the controller.
What I'd like to do is get data from the module to the calling controller
Yes, you can do that with HMVC.
In the calling module you can organise code like this (pseudocode):
class Someclass extends CI_Controller {
...
public function show_page()
{
$this->load->module("module");
$js_files = $this->module->get_js_files();
$this->load->view("header", array("js_files" => $js_files));
}
...
}
In the callee module you would write something along these lines:
class Module extends CI_Controller {
...
public function get_js_files()
{
$scripts = $this->frontend_model->get_scripts();
return $scripts;
}
....
}
(Although in this fantasy case it would be wiser to get data from model in the first place)
Another technique is, like #wolfgang1983 correctly mentioned, to call another module like this:
Modules::run('modulename/controller/function', $data);
and in order to get data from that controller you just have to assign returned data to a variable:
$data_received = Modules::run('modulename/controller/function', $data);
But in this case you can't get variables, only buffered output (like loaded and processed view files or echoed statements).
Related
I'm migrating an old app developed in Yii1 to Yii2.
I used to have a array in the controller that was storing all the variables that I would need to send to the frontend as a JavaScript:
public $jsVars;
public function toJSObject($params){
$this->jsVars = array_merge($this->jsVars, $params);
}
private function printJSVarsObject(){
//convert my php array into a js json object
}
When I needed a variable to be exposed in Javascript, I would just use $this->toJSObject, in the View or in the Controller.
Then, in the controller I also used to have:
public function beforeRender($view){
$this->printJSVarsObject();
}
In Yii2, I had to configure the View component with a custom View and then attach an event:
namespace app\classes;
use yii\base\Event;
use yii\helpers\Json;
Event::on(\yii\web\View::className(), \yii\web\View::EVENT_END_BODY, function($event) {
$event->sender->registerJSVars();
});
class View extends \yii\web\View {
public $jsVars = [];
public function addJsParam($param){
$this->jsVars = array_merge($this->jsVars, $param);
}
public function registerJSVars() {
$this->registerJs(
"var AppOptions= " . Json::htmlEncode($this->jsVars) . ";",
View::POS_END,
'acn_options'
);
}
}
But, having the event outside the class seems weird to me. Also, while I'm in the controller, I won't be able to use my former approach using this method.
Obviously, I'm missing something, or my approach is just incorrect.
How do you guys do that?
If you're trying to access properties of the controller from a view (see above comments!), you can use;
$this->context
to return an instance of the currently used controller from within the view file. So to access your beforeRender() method you would just use
$this->context->beforeRender()
So, lets say I have a global view and specific view.
In global view, the url may look like this (http://example.com/index.php/controller/method/)
Where when it come to the specific page view, the url will turn like this:
(http://example.com/index.php/controller/method/1989-03-25)
The difference between the global view and the specific page view is, if in the global view it shows the information in general, but in the specific page view it shows based on the detail or the date.
Of course, not only have different view, but also they will have different function of models.
The point is, I just want to make the url keep in order (which it mean there is no change in the name of the controller method).
How to do this. Thanks in advance.
You create just one param into your function. And set the param value is null. like this
class YOUR_CLASS extends CI_controller {
public function method($params=null) //null is Empty value
{
if($params)
{
//load your modal and view with your param
}
else
{
//load your modal and view
}
}
}
This method supports the following type of URL's without any issue.
http://example.com/index.php/YOUR_CLASS/method/
http://example.com/index.php/YOUR_CLASS/method/1989-03-25
Hope this will help you....
This class used to wrap CI_controller, my_base_controller will override CI_controller methods for depends to your project needs
class my_base_controller extends CI_controller {
}
You can load models by known states and define it in my_base_controller class.
class my_controller extends my_base_controller{
public function method($params=null) //null is option value
{
}
}
Good luck!
You can add additional parameter in your method like:
class Your_controller extends CI_controller {
public function method($params = null)
{
// Your Code Here with the condition for processing of the $params variable
}
}
in which that $params can be something in your URL like:
http://example.com/controller/method/your-dynamic-params
So if the $params is null you will call the model the views the general and if the $params has a specific value you can call other model by using if or switch conditional statements. Hope this helps...
Update with Example
you can use the $params variable like this:
if ($params == "1991") {
$this->load->view('general.html', $params);
} elseif ($params == "1992") {
$this->load->view('year_1992.html', $params);
} else {
$this->load->view('other_years.html', $params)
}
in this way you can use the $params as a conditional variable to load different views.
or using switch:
switch($params) {
case '1991':
$this->load->view('general.html', $params);
break;
case '1992':
$this->load->view('year_1992.html', $params);
break;
default:
$this->load->view('other_years.html', $params)
}
Note: Use a helper method so you can avoid fat controllers because it will be hard to test your methods if you have a several lines of codes in a function.
I've tried many solutions that had the same questions like mine. But didn't found a working solution.
I have a controller:
event.php
And two views:
event.phtml
eventList.phtml
I use eventList to get data via ajax call so I want to populate both views with a variable named "eventlist" for example.
Normally I use this code for sending a variable to the view:
$this->view->eventList = $events;
But this variable is only available in event.phtml.
How can I make this available for eventlist.phtml? (without adding a second controller)
Edit:
I get this error now
Call to undefined method Page_Event::render()
Function:
private $_event;
public function init(){
$dbTable = new Custom_Model_DbTable_Events();
//Get Events
$this->_event = $dbTable->getEntries($this->webuser->businessId);
$this->index();
}
public function indexAction(){
$this->eventList = $this->_event;
$this->render();
$this->render('eventlist');
}
If I use $this->view->render('event.phtml') and eventlist.phtml it won't pass the data
I'm using zend version 1
You can pass variables to other views using render()
public function fooAction()
{
// Renders my/foo.phtml
$this->render();
// Renders my/bar.phtml
$this->render('bar');
}
Copy and paste this in your controller and rename your controller from event.php to EventController.php
class EventController extends Zend_Controller_Action
{
private $_event;
public function init(){
$dbTable = new Custom_Model_DbTable_Events();
//Get Events
$this->_event = $dbTable->getEntries($this->webuser->businessId);
$this->index();
}
public function indexAction(){
// You're calling the index.phtml here.
$this->eventList = $this->_event;
$this->render('event');
$this->render('eventlist');
}
}
To specify that only written #Daan
In your action:
$this->view->eventList= $events;
$this->render('eventList'); // for call eventList.phtml
In you View use : $this->eventList
You could render it within the view itself (eventList.phtml), rather than within the controller, using the same line of code you used above:
$this->render('event[.phtml]');
I'm in the middle of cleaning up a web app written in CodeIgniter. Each main view has a sidebar that displays some common database driven data - recent updates, news, etc. I have the queries cached to help speed things up a bit but I'm also looking for a better way to make this happen.
Right now each controller loads the model, loads up the $data array and passes it to the view.
I've extended the main CI controller class and am not loading up the data in the constructor which has simplified the code a bit but I'm still left feeling like there should be a better way. Any suggestions?
not sure if that's what you're asking , but you can have a extra parent/base controller to load repetitive data like news , updates , etc...
class baseController extends CI_Controller {
public function __construct(){
parent::__construct();
}
function viwe($view = 'defualt' , $data = array()){
$data['updates'] = $this->db->get('updates');
$data['news'] = $this->db->get('news');
$this->load->view($view , $data );
}
}
another controller :
include "baseController.php";
class another extends baseController {
public function __construct(){
parent::__construct();
}
function index()
{
$data['thisData'] = $this->db->get('thisdata');
$this->view('thisView' , $data );
}
}
How can i forward to other action inside the same controller avoiding repeat all dispatch proccess ?
Example:
If i point to User Controller the default action is indexAction() inside this funciton i use _forwad('list') ... but all dispatch proccess are repeated.. and i dont that
Whats is the right way ?
Usually, you will install routes to redirect your users to the proper (default) action, instead of the index action (read how to redirect from a given route using Zend_Router). But you can do everything manually if you really want to (however this is called "writing hacker code to achieve something dirty") directly from the controller.
Change your "view script" to be rendered, then call your action method....
// inside your controller...
public function indexAction() {
$this->_helper->viewRenderer('foo'); // the name of the action to render instead
$this->fooAction(); // call foo action now
}
If you tend on using this "trick" often, perhaps you may write a base controller that you extend in your application, which can simply have a method like :
abstract class My_Controller_Action extends Zend_Controller_Action {
protected function _doAction($action) {
$method = $action . 'Action';
$this->_helper->viewRenderer($action);
return $this->$method(); // yes, this is valid PHP
}
}
Then call the method from your action...
class Default_Controller extends My_Controller_Action
public function indexAction() {
if ($someCondition) {
return $this->_doAction('foo');
}
// execute normal code here for index action
}
public function fooAction() {
// foo action goes here (you may even call _doAction() again...)
}
}
NOTE : this is not the official way to do it, but it is a solution.
We Can Also use this Helper To redirect
$this->_helper->redirector->gotoSimple($action, $controller, $module, $params);
$this->_helper->redirector->gotoSimple('edit'); // Example 1
$this->_helper->redirector->gotoSimple('edit', null, null, ['id'=>1]); // Example 2 With Params
If you don't want to re-dispatch there is no reason you can't simply call the action - it's just a function.
class Default_Controller extends My_Controller_Action
{
public function indexAction()
{
return $this->realAction();
}
public function realAction()
{
// ...
}
}
You could also create a route. For example I have in my /application/config/routes.ini a section:
; rss
routes.rss.route = rss
routes.rss.defaults.controller = rss
routes.rss.defaults.action = index
routes.rssfeed.route = rss/feed
routes.rssfeed.defaults.controller = rss
routes.rssfeed.defaults.action = index
Now you only need one action and that is index action but the requess rss/feed also goes there.
public function indexAction()
{
...
}