I written code using Codeigniter, I want to increase for load time when I open my page for first time. Actually when I written code I load all the model in my contruct like this:
public function __construct(){
parent::__construct();
$this->load->model('Fa_promo');
$this->load->model('Fa_project');
$this->load->model('Fa_inbox');
$this->load->model('Fa_quotes');
$this->data['keywords']=$this->Configuration->get_keyword();
$this->data['about'] = $this->Fa_menu->get__content_from__slug('about');
$this->data['menu']=$this->Fa_menu->list_menu_level1();
$this->Configuration->update_hits();
}
My question, how to do the best way to load the model to increase performance between above or like this?
public function __construct(){
parent::__construct();
}
public function a(){
$this->load->model('Fa_promo');
$this->Fa_promo->load();
}
public function (){
$this->load->model('Fa_project');
$this->Fa_project->load();
}
Thanks for your help :)
It will be faster to load them individually in each function as you can limit the number of calls made to load a model, but the difference is likely to be minimal
If you load them all in the constructor, then you can use them at any point in the controller from one load, which might be a little slower, but the benefit is they are loaded and ready. It could use more memory than needed for a single given function though.
If you want to save code for loading the models, you could always do the following in the constructor:
$this->load->model(['Fa_promo', 'Fa_project', 'Fa_inbox', 'Fa_quotes]);
This will load all of the models in one go. There's no real time benefit of this as passing an array causes the loader to call itself for each item, so it's the same as you currently have.
The codeigniter docs say: Your models will typically be loaded and called from within your controller methods.
The first approach has a great advantage: you can reuse it in all controller methods and don't have to type in each method over and over again.
concerning performance: I think it doesn't make any difference, the functions in the model might slow down things
Related
My sidebar has elements that are the same in all my views, so instead of calling them over and over in all my controllers, I created a MY_Controller class and make variables available from there. Problem is, the content from my variables come from a file, so now everytime my site is loaded I'm making a call to read the file. It was pointed out to the me that this is not too good.
So what I'm trying to do is read the file in a model, then store it in a variable and then pass that variable to MY_Controller. Problem is I'm facing the same issue only now instead of reading the file from MY_Controller I'm reading it from the model. So I tried to create in a different function a variable that would be available in my entire model, and then a function that returns that variable, but it is not working. Here is my code:
Model:
class My_model extends CI_Model {
public $report = null;
function read_file()
{
$this->report = file_get_contents('/path/to/file');
}
function get_file()
{
return $this->report;
}
}
MY_Controller:
class MY_Controller extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('My_model');
$report = $this->My_model->get_file();
...
}
}
Right now $reportis returning null.
The read_file() function should be called once a day, because the file is updated daily in the morning. Any tips pointing if it is possible to do what I'm trying, or if there is a better way would be greatly appreciated.
I'm not going to give you code, because it would take too long, but I will explain how Symfony2 does it. Heard of Twig? Well, regardless of whether you are familiar with it or not, the important part of it is how it compiles templates.
It compiles all template logic and text to PHP files filled with generated functions and strings. The first time the template is executed this compilation is performed. The second time, the compiled PHP is re-used.
The IO in effect still takes place, but only on the included PHP pages. You can eliminate this again by bootstraping your entire source into a single file (Symfony does this with libraries, but not templates).
So, in order to "cache" your content to PHP, you need to write a PHP dumper (or using an existing one), or use var_export on simple data structures to dump your pre-loaded data.
You should call read_file function before get_file, also there is no relation between calling the function read_file and the updating of the file.
Which one is better performance-wise? Loading all the models used in the controller in constructor or loading the model only in the needed function? Or is there any difference? If the model is needed only in one of the functions of a big controller, does it affect the performance if its loaded in the constructor?
class myController extends CI_Controller {
public function __construct() {
parent::__construct();
$this->load->model('loginmodel');
}
public function useLoginModel(){
$this->load->model('loginmodel');
$this->loginmodel->login();
}
}
If you only use it in that one function, then it is probably faster to load it only there. But this decreases mantainability. You always have to recheck if the model was loaded every time you want to use it somewhere. So I would stick with loading everything in the constructor (depends on the number of models obviously).
There is a simple rule for optimizations: If it isn't slow, don't optimize it. You gain very little from the above change, but encounter a severe hit in mantainability (or as symfony calls it "Developer Experience")
You can add it in autoload.php inside config folder.
$autoload['model'] = array('loginmodel');
Hope it helps.
I'm new to CodeIgniter and currently in my project I have several Models, loaded by several Controllers, which need to work with the database.
My question is - can I call $this->load->database() in just one place for the entire project, or should I do it in each method in my Models?
Thanks
In your autoload.php which is located in /application/config/autoload.php in which you see
$autoload['libraries'] array just add
$autoload['libraries'] = array('session', 'database','other_libraries');
If your project scope involves the database interaction you should use the autoload while including in each function would be a headache for you
Hope it makes sense
You have three choices (that I can think of).
If you require it almost everywhere in your project, use the
/application/config/autoload.php file, in which you'll find the
following statement:
$autoload['libraries'] = array();
which you can change to
$autoload['libraries'] = array('database');
This is the easiest method, but it does add overhead since the database class will be loaded even when you do not require it.
If you find that you need to use it for almost every method in a particular model you can call $this->load->database(); in the constructor of that particular model, for example:
class Forums_model extends CI_Model{
function __construct()
{
// Call the parent constructor
parent::__construct();
$this->load->database();
}
function get_records()
{
$this->db->get('table');
//this now works in every method in this model
}
}
which will make the database class available to every method in that model. This is a more efficient option than the second and not as tedious as the third, probably making it the most balanced option.
You can also, of course, choose to load it in every method that requires it using $this->load->database(); This adds the least overhead, theoretically making it the most efficient. However, doing this is very tedious.
All three will work, it's your choice whether you want it to be easy, or efficient. (My personal recommendation is choice 2)
If only some of your pages require database connectivity you can manually connect to your database by adding this line of code
$this->load->database();
in any function where it is needed, or in your class constructor to make the database available globally in that class.
The "auto connect" feature will load and instantiate the database class with every page.just
add the word 'database' to the library array, as indicated in the following file:
application/config/autoload.php
http://ellislab.com/codeigniter/user-guide/database/connecting.html
I know this is not the best of all methods, but since you are beginner.. you just call load data base $this->load->database() in that method just above the code where your database related query begins.. just suppose $this ->load->database(); is exactly the same thing for you as you were using include_once('connection.php') this script in you simple php script (without CI).
I need to call some library functions in order to correctly display some data in my header view - what is the best/correct way to approach this?
I take it I'm supposed to call this in all my controllers but it seems a bit redundant. Should I take this route? What sort of non 'hacky' method do you suggest?
Edit:
I have a view which outputs the header portion of the page. In this view I have a menu which varies depending whether you're logged in, have any favorites etc. To determine what to display in the menu, I must refer to some libraries, for example, an authentication and favorites library.
I tried calling the library from the view, but it gives me an error.
I suppose I could load the controller and pass the data to the view in every controller but I would have a lot of repetitive code. Is this the way to go?
Yes, manually assigning the same data to a partial view in every controller or method is redundant. You want to avoid this.
Any decent template library should be able to handle this for you. You can google up a solution or write your own.
Here, in mockup code, is what it may resemble:
class Template {
public $data = array();
function area($area_name)
{
$CI =& get_instance();
$data = isset($this->data[$area_name]) : $this->data[$area_name] ? NULL;
$CI->load->view('templates/'.$area_name, $data);
}
function set_data($area_name, $data)
{
$this->data[$area_name] = $data;
}
}
Then in the controller, something like this:
$this->template->set_data('header', $my_data);
Then in the view, something like this:
<header><?php echo $this->template->area('header'); ?></header>
<div><?php echo $this->template->area('content'); ?></div>
<footer><?php echo $this->template->area('footer'); ?></footer>
This is over-simplified, and there are a million ways to handle it, but I definitely suggest writing some kind of class to handle your templates rather than just using $this->load->view() for everything, even if it is just a wrapper for loading views.
To avoid manually setting that same data in every controller, use a MY_Controller, set it in the template class __construct(), or call it directly from the view file from whatever the source is (model, library, etc.). Father MVC may shed a tear, but sometimes this is easiest or even makes the most sense.
Quick example of how to use a controller extension:
// File: application/core/MY_Controller.php
class MY_Controller extends CI_Controller {
public function __construct()
{
parent::__construct();
$data['var_name'] = $this->some_lib->get_data();
$data['var_name2'] = $this->some_model->get_more_data();
$this->template->set_data('header', $data);
}
}
Then, all your controllers would extend MY_Controller rather than CI_Controller and the header data would already be loaded. This is just a simplified glimpse into another topic altogether, much much more is possible with this method.
I tried calling the library from the view, but it gives me an error.
This shouldn't happen if the library is loaded and you are calling it correctly. The syntax is $this->library_name->method().
In any case, I definitely recommend writing or borrowing some kind of Template class.
You don't have to follow the MVC model, but if you want to, the "correct" way is to call the functions in the controller, then pass the data to the view where it's printed out.
You should be able to just autoload the library or else load it in the controller before the view. Then you'll have access to the library methods in your views and can access them the same way you would in your controllers.
Here is a quick overview of the controllers functionality in most of the application:
controller loads a specific model, gets data from it, formats the data and passes the formatted data to the view.
Now there is a search page, which needs to do a search query over entire database (all models). It needs to show each type of data in its particular formatted output on a single page as a list.
The problem:
The search controller can do the search, dynamically load model for each record type, and get the data from model. Problem comes when the data needs to be formatted. I am trying to load the specific controller from the search controller, which is causing problems.
What to do?
PS: I tried using the 'Wick' library, but it fails when the controller's format function tries to use its own model and session object, giving errors about call to a member on a non-object.
After much refactoring and trial/error, It appears that the best way to achieve the above is this way:
Keep the format function in the base controller from which all other controllers are derived. The format options are passed to the function along with the data object as arguments.
Make a static function in each derived controller, which returns the formatting options of the data.
Inside the search controller (which is itself derived from the base controller), for each data object, call the static function of its particular controller which returns the data formatting options, then use that to format the object for the view.
I guess I can say I will stick to using the model only for interaction with the database, and let everything else be done by controller. If anyone has a better solution still, I am all ears.
It sounds like you want to use the Factory design pattern
Make this a library:
class MyModelFactory {
static public function Factory($data) {
$type = key($data);
return new $type($data);
}
}
now, in your controller, you can do something like this:
$model = MyModelFactory::Factory(array($_REQUEST['model'] => $_REQUEST));
and now you have an object of whatever model was specified in $_REQUEST['model']. Be sure to take any security precautions you may need for your application to assure the user has permissions to use the model that they request
Now, since you want to be using common methods and stuff, your models should probably be based off an abstract class / interface.. so instead of
class MyModelOne extends Model {
// stuff
}
You probably want something like this, to ensure your required methods will always be available:
abstract class MyAbstractModel extends Model {
protected $search_params;
public function __construct($data = array()) {
$search_params = $data['search_params'];
}
protected function GetSearchParameters() {
return $this->search_params;
}
abstract public function GetData();
abstract public function GetColumns();
abstract public function DefineViewOptions();
}
class MyModelOne extends MyAbstractModel {
public function GetData() {
$params = array();
$params[] = $this->db->escape_str($this->GetSearchParameters());
// return whatever data you want, given the search parameter(s)
}
public function GetColumns() {
// return some columns
}
public function DefineViewOptions() {
// return some configuration options
}
}
In general you can't load another controller from within a controller in CodeIgniter (although there are mods that allow you to do something like this).
I would try creating a class for formatting your data and add it to the application/library folder. Then load, use and re-use this class throughout your various controllers.
Here is a page from the CodeIgniter documentation Creating Your Own Libraries that explains the details and conventions.
Also, if a class is overkill, creating helper functions is an even lighter approach.
The difference between libraries and helpers in CodeIgniter is that libraries are classes, helpers are just a group of php functions.
Once you have formatted your data, you can load any view from any controller, so you should still have all the re-usability you need so you DRY (don't repeat yourself)
There are a few simple approaches based on the principle of what's simpler (versus what's perfectly DRY). Here's one alternative approach I use with CodeIgniter:
Instead of trying to load multiple controllers, reuse the view fragments from your search controller (or search route, depending which you're using). This requires using the same naming conventions for your data elements so the views are interchangeable, but you should be doing this anyway.
Instead of using multiple models for search, add a single Search model that knows about the things that can be searched on. If you want to prevent duplicate SQL, reuse the SQL between models (this can be done using constants, or loading SQL from disk).
Controllers are not great candidates for reuse from your own PHP code: they route actions and requests for resources to the things themselves. They are intended to be called via HTTP, using the URI interface you've come up with. Calling them from code is a coupling you want to avoid. That said, reusing controllers from JavaScript (or via cURL) is a great, decoupled way to reuse things in any web framework.