I assume that $this->data
is a property of a controller class defined like this.
class Some_controller extends CI_Controller
{
protected $data; //could be public or private too, not relevant to the discussion
function __construct()
{
//assign a value to the $data property
$this->data = $this->general_model->data_init();
}
If so, then the points about memory utilization in Mike's answer could be realized simply by using $this->data
directly in each controller method. Making a copy (i.e. $data = $this->data;
) is pointless because the property is already available to all controller methods. In other words, simply do this in any class method.
$this->data['page_title'] = 'example';
Then pass the class property ($data
) to the view load like this.
$this->load->view('templates/header', $this->data);
In the revised index()
below I have done a couple other things that probably amount to "micro-optimizations" but are worth considering. First, notice I only pass $this->data
to the first load->view()
call.
The documentation doesn't do a great job of pointing out that any data passed via load->view()
is cached and will be available to any subsequent views loaded. If you continually pass exactly the same data you are running many extra lines of code that simply overwrite the cached data with the exact same values. If you don't pass any data this pointless exercise is eliminated.
The second "micro-optimization" is the use of method chaining. load->view()
returns a CI_Loader
instance which is exactly the same memory location that $this->load
returns. Why make it look up that value again? And why do all the extra typing?
public function index()
{
$this->data['page_title'] = 'example';
$this->load
->view('templates/header', $this->data)
->view('page/example')
->view('templates/footer');
}
Now, with all that said, the thing that will help you the most with being DRY is to create a "base controller" that will extend CI_Controller
. This "base controller" is then used to create all the other controllers for the application. Refer to the CI documentation about Extending Native Libraries for details but the basic idea starts with creating the "base controller".
Create the file application/core/MY_Controller.php
class MY_Controller extends CI_Controller
{
protected $data;
public function __construct()
{
parent::__construct();
$this->load->model('general_model', '', TRUE);
$this->data = $this->general_model->data_init();
}
The property $data
will be available in any class that extends MY_Controller
so use it as the base class for all other application controllers.
Since you appear to use the same set of header and footer views all the time you can also DRY out view loading.
MY_Controller
continues with:
/**
* A template used for every page load
* @param string $view is the name of the view file to load
* @param array $view_data is data to be passed to view files.
* If no $view_data is passed then the class property $data is used
*/
public function render_page($view, $view_data = NULL)
{
//Uses a ternary to decide what "data" gets sent to view
$this->load
->view('templates/header', isset($view_data) ? $view_data : $this->data)
->view($view)
->view('templates/footer');
}
} //end of MY_Controller
The following uses the CI "Welcome" example modified by extending with MY_Controller
. It adds an "other_page" too.
This is the file application/controllers/Welcome.php
class Welcome extends MY_Controller
{
public function __construct()
{
parent::__construct();
//If desired you could set a default title for pages of this controller
$this->data["page_title"] = "Welcome";
}
public function index()
{
$this->render_page('welcome_message');
}
public function other_page()
{
//overwrite the default page title
$this->data["page_title"] = "Other Page";
$this->render_page('other_view');
}
}
Hopefully it is clear how this achieves the goals described in your question.
A couple last comments on what seems to be unnecessary work.
First, it appears you have set some session data that might look something like this. (Obviously, I'm making up keys and values.)
$_SESSION['session'] = array('id`=>$id, 'name'=>'Guy', 'logged_in'=>TRUE);
Putting an array in an array seems to me to be making more work than needed. Just set each item as a key in $_SESSION
directly.
$_SESSION['some_key'] = $some_value;
If you look at the source code for set_userdata()
the above is essentially what you will find. IMO, the best reason to use set_userdata()
is to set several items at once.
$this->session->set_userdata(array('id'=>$id, 'name'=>'Guy', 'logged_in'=> TRUE));
That line produces exactly the same thing as these lines.
$_SESSION['id'] = $id;
$_SESSION['name'] = 'Guy';
$_SESSION['logged_in'] = TRUE;
The second 'final comment' is about making a copy of session data in your model with this call.
$data['session'] = $this->session->userdata('session');
Clearly you have the session
library running and it contains previously set user data.
The session
class can be used directly in every controller method so why make a copy of its data? Making a copy uses more memory and forces you to dereference the copy in order to utilize it - for example:
$user_name = $this->data['session']['user_name'];
Why do something like that when, if you set the session data as suggested earlier, you could use any of the following in any controller method?
$user_name = $_SESSION['user_name']; //runs the risk of an "Undefined index" error
or
$user_name = $this->session->user_name; //using the "magic" getter - my prefered way to go
or
$user_name = $this->session->userdata('user_name'); // the "traditional" CI way
$this->data = $this->general_model->data_init();
in every constructor and$data = $this->data;
in every function. \$\endgroup\$CI_Model
? \$\endgroup\$CI_Model_Extended
class that extendsCI_Model
, and put your code there. Have your subsequent classes inheritCI_Model_Extended
instead ofCI_Model
. \$\endgroup\$