I'm trying to understand how $this->load->view() works inside of a view file in CodeIgniter.
The core/Controller.php is calling core/Loader.php which then calls _ci_load() which in turn does an include('/path/to/view');
Shouldn't $this refer to the Loader class at that point? How is $this referring to the controller?
By my understanding, you should have to call $this->view() inside of a view file. Not $this->load->view() because the load() function is not accessible inside of the Loader. It's a class variable of the Controller base class. i.e, $this->load =& load_class('Loader');
Please note: I'm trying to understand the CodeIgniter internals. I know perfectly well how to embed view files in other view files as a CodeIgniter user. Please do not leave answers explaining how to use $this->load().
To simplify the understanding of what $this refers to in a view, since a view is "loaded" by a controller method, the view is still run in the same scope as that method, meaning $this can have a different context depending on which class loaded it.
For example:
class Controller1 extends CI_Controller {}
In any view file loaded in this example controller, $this refers specifically to the Controller1 class, which can access CI_Controller public and protected properties/methods as well (like the Loader or Input classes, which are assigned to the load and input properties of CI_Controller) since it extends that class.
Controllers are still just plain old PHP classes. If I were to do this:
class Controller1 extends CI_Controller {
$this->foobar = 'Hello';
}
class Controller2 extends CI_Controller {
$this->foobar = 'World';
}
...if we load the same view file in any method of either of these controllers, using $this->foobar in that view file will return a different value.
Last time I checked, $this was of class CI_Loader, try var_dump($this); inside a view.
Check out:
https://github.com/EllisLab/CodeIgniter/blob/develop/system/core/Controller.php
is_loaded(); returns an array with the already loaded classnames and their aliases from the main container.
$this->load is then an instance of CI_Loader inside the controller.
Check:
https://github.com/EllisLab/CodeIgniter/blob/develop/system/core/Loader.php
Line 778
Related
Im current trying to learn more about the core of OpenCart and how its classes actually work. Im also trying to advance my OOP skills in general as Im still learning in that area, so perhaps theres something obvious that Im not seeing.
Im wondering how a controller file knows how to find the cart class (for example).
E.g.
In catalog/controller/checkout cart there is (obviously with code removed)
class ControllerCheckoutCart extends Controller {
public function index() {
$this->cart->update();
}
}
The Controller class can be found in system/engine/controller.php
update() can be found system/library/cart.
I assumed that in the controller.php there would be a link to the cart class, or an object made from it. (Im basing that on the use of $this->).
So how is the cart class actually found from the controller?
Thank you
Firstly, your ControllerCheckoutCart extends the Controller class, so this is the class we need to focus on. You can find this class in /system/engine/controller.php.
Inside this class, there are two magic methods we are interested in. The first is the __construct, where the "registry" class is loaded (found in /system/engine/registry.php if you're interested in picking that apart - it's very simplistic).
You can think of this as a lookup of all the classes the store uses, such as model files, library files and so on. In the construct, the registry is passed to the controller so it has a reference to it
public function __construct($registry) {
$this->registry = $registry;
}
The second and more important magic method is the __get method. This is called when a classes property doesn't exist, for you to handle it yourself if you wish to do so. OpenCart uses this to try and get the class with that key from the registry
public function __get($key) {
return $this->registry->get($key);
}
So $this->cart in any controller would try to get the object with the key cart from the registry. If you look at the index.php file you will see this is allocated in there
// Cart
$registry->set('cart', new Cart($registry));
ControllerCheckoutCart extends Controller, which means it inherits all the code in Controller which you are not seeing here. Some code in Controller, likely in Controller::__construct, is creating the $this->cart object. Example:
class Controller {
public function __construct() {
$this->cart = new Cart;
}
}
Since this constructor is inherited by all child classes, they construct their own $this->cart as well and have access to it in their own methods.
As mentioned by Jay Gilford, you need to register your newly added library class file in the index.php and/or admin/index.php (depending on if you are using it in catalog or admin)
$registry->set('yourlibraryclass', new YourLibraryClass());
so that upon system loading, Opencart knows that your class exists, then you can call all its functions by:
$this->yourlibraryfilename->function();
Please note that your library file name is normally the same as your class name, hence it is used in the example here.
After the change has been done in the index.php files, you need to logout and login again to see the changes.
I call a CodeIgniter controller method -imgupload- from jquery ajax. This controller extends my custom front controller.
class newad extends My_Controller{
public function __construct() {
parent::__construct();
}
public function imageupload() {
$this->load->library("uploadhandler");
}
The imgupload method calls the uploadhandler class which extends from newad.
class uploadhandler extends newad {
The functionality of that class works properly, except for one thing, I cant access the properties of the My_Controller class, even though they are declared protected.
The inheritance chain looks like this: My_Controller->newad->uploadhandler.
Any idea why I cant access those properties?
In short the answer is you do not need to extend Controller class here. You can just pass the value to your library as a parameter.
$params = array('user_ud' => $this->userID, 'otehr' => 'other');
$this->load->library('uploadhandler', $params);
//Now from your library
class uploadhandler{
public function __construct($params)
{
// Do something with $params
}
//.. Your code...//
}
Now about your question:
The functionality of that class works properly, except for one thing, I cant access the properties of the My_Controller class, even though they are declared protected. The inheritance chain looks like this: My_Controller->newad->uploadhandler. Any idea why I cant access those properties?
As inheritance chain are ok, you can access property of My_Controller from your library but not the value of the Current controller, because these two are different object.
So here is my answer how can we access the value? One way I have already mentioned. That will be enough if you need to share some property with the library. But what if you need to access all the Controller instance. There is a function to get the reference of controller instance get_instance(). You can use this function anywhere and get access of all public property controller. If you need to access any private property of controller the define a geter function to access that.
Explanation
First of all you need to learn basic about OOP. Learn about Class, Object, Inheritance..
When I said property of My_controller is different from the same property the you accessed from uploadhandler, it may confused you if you are not familiar with class and object. Here is two instance(object) of different class.
For short let say you have some classes like: Vehicle, Car, Machine and Person. All they have common attributes say name, weight ..
So, can we just inherit Any of these class from other??
Simple answer is no. We can't(!) define a Person class extending from Others. So how can we decide which incoherence would legal. If you can say Foo is a Bar you can write Foo class extending from Bar. Now from your case, It is obvious uploadhandler is not a controller. So Never Extend a anything from something that is not something.
NB: The answer is generic. If you need any specific clarification, just ask, I can update my answer
In my laravel application I am using a Base_Controller class and then extend this class in other controller.
In my app there is a variable which I need to use in all my controller and templates.
This is why I tried to use in my base controller.
$this->layout->myVar = 'stuff'
But when I try use $myVar in my view I am getting an error:
Creating default object from empty value
My base class constructor is something like this:
public function __constructor()
{
parent::__construct();
$this->layout->menu = 'stuff';
}
Does anyone have any idea on what is the best way to approach this?
You must have $this->layout defined in your controller class or else $this->layout must be assigned an instance of View::make().
$this->layout->menu may also require having the #section('menu') #endsection in it.
I have a list of constants (I'm using them as an enum), some are define statements, and some are just global variables.
Where am I suppose to put them in the MVC framework so I can use them for both my model and my controller that needs to reference it?
I'd rather not stick it into config/constants.php since they shouldn't be called except for by this model and the controllers that use it.
Edit 1: Clarification
To be more specific, I have my message_model model and it has a bunch of constants that I need that are stored in message_model_constants.php. Where should I put message_model_constants.php and is there a way to have it automatically included by the controller that loads message_model when message_model is not (and I don't want it to be) auto-loaded.
Edit 2:
I really don't want to have the constants auto-loaded except for when I use the model
Go to application/config/constants.php and define your constant their and you can use your constants on Model-View-Controller of CI not include "Helper" and "Library"
But in your case I prefer you to create a php file that has your constants and rename it to something like my_constants_helper.php.
In your model or controller __construct just
$this->load->helper('my_constants');
And hooray you can access them =)
You can choose to load a particular config file when you load a particular model in the controller. For instance in your file:
application/controllers/messages.php
You would use a line like this:
$this->config->load('messages');
If you include it at the top of your controller like this
function __construct() {
$this->config->load('messages');
$this->load->model('message_model');
}
Then all of those constants will be available to all the functions and methods in the given controller. You then call each config constant like:
$this->config->item('item name')
And you can name protected $variables; in the construct as well for shorter syntax.
If you are using these config constants and the message model in multiple different controllers you may want make a "Library" file that then loads both the config and the model and declares all variables there.
extending Brennan Novak answer, you can simplify your code by loading your config file in the model constructor. That way, you only have to load the model in your controllers and everything else is done automatically.
Model
class Message_model extends Model {
function __construct()
{
parent::Model();
$this->load->config('message_model_constants');
}
...
}
Controller
class Some_controller extends Controller {
function __construct()
{
parent::Controller();
$this->load->model('message_model');
}
...
}
As already stated, your config files should be application/config/message_model_constants.php
For global configs, add to the config/config.php or create a config/application.php and then load the config, then the item.
$this->config->load('application'); // or autoload this - $autoload['config'] = array('application');
$this->config->item('item name');
Have you considered just adding your constants to your Message_Model Class? You'll then reference them by self::ConstantName inside the Class and Message_Model::ConstantName outside the class. This would also prevent name space collision.
I am building a series of forms, and I am trying to inherit the functionality of a parent Form class into all the forms. For example,
LeaveForm extends Form (Model)
LeaveFormController extends FormController
I am handling all the leave form specific stuff in LeaveFormController and LeaveForm.
In LeaveFormController constructor, I simply call the parent class constructor, then load the LeaveForm Model. And in FormController constructor, I load Form model.
My problem is, I get an error,
Cannot redeclare class form in Form.php
Have I got my architecture wrong? How do I handle this ?
check if the class has already been initialized like this:
if (!class_exists('classname'))
{
// ok fine create new instance now
}
Possibly when you $this->load->model('Form'), you manually included the models/form.php file?
In your leaveform.php model file, make sure you load the superclass model you extend using codeigniter's model loading mechanism instead of require or include. Codeigniter has a loader that keeps track of already-loaded files to avoid redeclaring classes, but you need to use $this->load to use it. It won't know about files loaded directly with include or require.
So at the top of leaveform.php, use this:
$CI =& get_instance(); $CI->load->model('Form');
This is not related, but you will have pain unless you namespace your CodeIgniter model classes the same way you namespace Controller classes.
Try using FormModel extends CI_Model {}; Instead of Form extends CI_Model {};