Ok, so in my base controller (page.php) I have the following code which works fine:
$this->load->library('Siteclass');
$mysite = new site_model();
The siteclass library references a model named site_model and instantiates based on data received from that model. All is good.
Now I want to load another library so that I can instantiate another object as well. So I add this to page.php:
$this->load->library('Memberclass');
$mysite = new member_model();
But now I get the following error:
Message: Undefined property: Memberclass::$site_model
Filename: libraries/Loader.php
Line Number: 1035
From what I can tell, it seems that the loader class, when being applied to the Memberclass, is somehow still referencing the site_model instead of the member_model. I've checked my code and I am definitely calling the correct files.
Here's what Siteclass.php looks like:
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Siteclass extends Controller {
function __construct() {
parent::Controller();
$this->load->model('Site_model');
$data = $this->Site_model->load_site_data();
// etc etc
and here's what Memberclass.php looks like:
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Memberclass extends Controller {
function __construct() {
parent::Controller();
$this->load->model('Member_model');
$data = $this->Member_model->load_member_data();
// etc etc
Thanks in advance for any help!
Gary
I think you're confused about how MVC works in CodeIgniter. Why are you using the loader class to create a controller? Why are you creating a stand-alone instance of your model outside of your controller class?
In CodeIgniter, your URLs represent paths to your controllers' methods. That means that your "base controller" should automatically be instantiated if you go to:
www.example.com/memberclass
Or perhaps more to the point, if you have a link like this:
www.example.com/page
You should have a file in your /application/controllers directory called page.php which looks like this:
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Page extends Controller {
function __construct() {
parent::Controller();
// etc etc
Furthermore, unless you're loading data from your model to be used every single time you call this controller, you'll want to put your model calls inside a non-constructor method of this class. Something like:
class Page extends Controller {
function __construct() {
parent::Controller();
}
function index() {
$this->load->model('Member_model');
$data = $this->Member_model->load_member_data();
$this->load->view('myview', array('data'=>$data));
}
}
So again...not entirely sure what context you're doing this all in, but it seems like you're not standing firmly within the framework. There's basically no reason you should be using the loader class to load controllers, and furthermore there's no reason you should be creating stand-alone instances of model classes using PHP's new keyword.
Related
in codeigniter I have my main controller:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Main extends CI_Controller
{
public function index()
{
$this->load->library('../controllers/forum');
$obj = new $this->forum();
$obj->test();
}
}
And the controller I'm trying to access:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Forum extends CI_Controller
{
function __construct()
{
echo "testing1";
$this->load->library('session');
parent::__construct();
$this->load->database();
$this->load->model('model_forum');
}
public function index(){
}
public function test(){
echo "testing2";
$this->data['forums'] = $this->model_forum->getForums();
$this->load->view('homepage', $this->data);
}
}
Everything is fine with my model_forum.php file, because it works if I put all the code in Main controller. But if I'm trying to access Forum controller, nothing works, only "testing1" echo goes through. Picture of error:
Anyone has any idea what I'm doing wrong? I'm new to PHP and codeigniter so I'm struggling a little bit. Thanks in advance.
You can't load a controller from a controller in CI - unless you use HMVC or something.
You should think about your architecture a bit. If you need to call a controller method from another controller, then you should probably abstract that code out to a helper or library and call it from both controllers.
UPDATE
After reading your question again, I realize that your end goal is not necessarily HMVC, but URI manipulation. Correct me if I'm wrong, but it seems like you're trying to accomplish URLs with the first section being the method name and leave out the controller name altogether.
If this is the case, you'd get a cleaner solution by getting creative with your routes.
For a really basic example, say you have two controllers, controller1 and controller2. Controller1 has a method method_1 - and controller2 has a method method_2.
You can set up routes like this:
$route['method_1'] = "controller1/method_1";
$route['method_2'] = "controller2/method_2";
Then, you can call method 1 with a URL like http://example.com/method_1 and method 2 with http://example.com/method_2.
Albeit, this is a hard-coded, very basic, example - but it could get you to where you need to be if all you need to do is remove the controller from the URL.
You could also go with remapping your controllers.
From the docs: "If your controller contains a function named _remap(), it will always get called regardless of what your URI contains.":
public function _remap($method)
{
if ($method == 'some_method')
{
$this->$method();
}
else
{
$this->default_method();
}
}
Okay. So I have been stumping myself on where I have gone wrong with this. I am not-so-new to PHP but I am also no expert, although I am getting more and more used to OOP. I have recently got into CodeIgniter 3. I like it, I use it, it's pretty simple to grasp in the beginning.
However, I am in the learning stage where I cannot successfully pass dynamic data, from the database into the controller using a Model.
And just as an FYI: I am using MY_Controller as my Base Controller, and have set a $data object to pass variables application wide. I know my problem is not due to the use of MY_Controller, because when I use static $this->data['KEY'] = 'VALUE'; or $this->data array('KEY' => 'VALUE');, my variables get passed into my views. So MY_Controller is functional.
My problem resides in creating a Settings_model. Its sole purpose is to take data from a database table settings and extrapolate certain columns of data, such a/an: application title, background color, etc.
So. On to my question/s, and what I have tried to do to fix this.
First, here is my MY_Controller:
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Controller extends CI_Controller
{
public $data;
public function __construct() {
parent::__construct();
$this->data = array(
'app_title' => $this->settings_model->get_title('$title'),
'meta_author' => APP_AUTHOR
);
}
}
And here is my Settings_model:
defined('BASEPATH') OR exit('No direct script access allowed');
class Settings_model extends CI_Model
{
public $title = '';
public function __construct() {
$this->load->database();
}
public function get_title($title) {
$this->db->select('app_title');
$this->db->from->('settings');
$this->db-where('app_title', $title);
return $this->db->get()->row('app_title');
}
}
My Problem
When using the sytnax above. i am able to see my applications output in the browser. Everything is rendered properly, all the static variables I've assigned in MY_Controller work. Everything is good ... except, the $app_title variable (which is in my views, and assigned in MY_Controller) does not load the data from the database, as the model instructed. As well as does not produce any error, warning or notice.
What I've tried
Man i tell you I have tried everything. i have tried inserting the query into MY_Controller directly and not using a Model (which I know is not proper MVC, but I wanted to try), like so:
MY_Controller Using Straigh Query, no model
$this->data = array(
'app_title' => $this->db->query('GET app_title FROM settings'),
'meta_author' => APP_AUTHOR
);
And the one time i got somewhere, error/notice wise was when i altered the Settings_Model, like so:
Altered Settings Model
defined('BASEPATH') OR exit('No direct script access allowed');
class Settings_model extends CI_Model
{
public $title = '';
public function __construct() {
$this->load->database();
}
public function get_title($title) {
$this->db->select('app_title');
$this->db->from->('settings');
$this->db-where('app_title', $title);
// Before it was this:
return $this->db->get->row('app-title');
// But I changed it to this
return $this->db->get()->row()->app_title;
}
}
But that syntax above gave me the error in this Image of a non Object Error
I do not know what I am doing wrong.
Now the question/s
Why when i use the first approach of the settings_model, using return $this->db->get()->row('app_title'); does it show all of my applications output in the browser, but everywhere the $app_title variable is called, it itself displays no value from the database, via MY_Controller and Settings_model?
Why when i use the second approach of the settings_model, using return $this->db->get()->row()->app_title; does it produce the Trying to get property of Non Object error in the image i linked to above?
What on earth am I doing wrong? I know I am still on the early learning stages of OOP, and Models, etc. But I must be missing something, I know something is not right.
Any and all help is greatly appreciated and welcomed. I thank everyone for their input.
EDIT 1: Thanks to #Mirceac21 for asking. I am autoloading the settings_model in config/autoload.php.
EDIT 2: I have now switched the var $data to public $data in MY_Controller as #Mirceac21 suggested. Still the same error but he is correct about not using var there.
Okay, so I figured it out. With the help of #Mirceac21. I change the var $data to public $data in MY_Controller.
Then in the Settings_model, I took out the WHERE clause and it worked. Here is the new working code below:
MY_Controller
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Controller extends CI_Controller
{
// $data object used for $this->data
public $data;
public function __construct() {
parent::__construct();
/*
* The $data array('KEY' => 'VALUE') variable sets are used
* in other Controller Classes that extend MY_Controller.
*/
$this->data = array(
'app_title' => $this->settings_model->get_title('$title'),
'meta_author' => APP_AUTHOR
);
}
}
Then in the Settings_model I made the following changes, remove ->where('app-title', $title);. Like so:
defined('BASEPATH') OR exit('No direct script access allowed');
class Settings_model extends CI_Model
{
public $title = '';
public function __construct() {
$this->load->database();
}
public function get_title($title) {
$this->db->select('app_title');
$this->db->from->('settings');
// I removed the following where->(); and it now loads the dynamic data
// $this->db-where('app_title', $title);
return $this->db->get()->row('app_title');
}
}
Now everything works as planned. I knew it was something simple and stupid 9for lack of better words). Thank you to #Mirceac21 for your input.
I'd like to know if it's possible to extend my own controllers. I've been working on web-based applications for a while and I'm now starting to find each customer that wishes to use the application has different requirements of how it should work. My thoughts are that if I generate a base structure and then extend the controllers to override any of the functions that the customers require to work differently.
First of all, could you tell me if I'm on the correct track, and secondly, how do I go about extending my own controllers (if I can)? I've tried the usual:
Class Reports2 extends Reports { }
This doesn't work but I'm guessing it has something to do with the location of the file I'm trying to extend. My file structure is as follows:
Application
--->controllers
-------->control_panel
------------>reports.php
If I am not mistaken then you should be able to easily do this:
reports2.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
require_once(APPPATH.'controllers/control_panel/reports.php');
Class Reports2 extends Reports {
public function __construct(){
parent::_construct();
}
public function index(){
}
}
Hi I'd like to add a public variable ($this->data[]) to all instances of CI_Controllers, that way I can store some base rules for outputting a page (css/js, etc) then have each controller append to this array to add its own requirements (more css/js). I have a core library with custom view functions that take those arrays and inject them into the head tag of the page template.
The options I've thought of;
Edit CI_Controller and add it there... guessing that's a bad idea.
Create a shell controller that extends CI_Controller, add the var to that, then have every other controller extend the shell controller.
Any other clever ways?
I've only been using CI for about a month and I've tried reading through the docs but I can't find any built in ways to do something like this? Has anyone encountered this before and if so how did you solve it?
Thanks!
[edit] Using PHP 5.3.x [/edit]
http://ellislab.com/codeigniter/user-guide/general/creating_libraries.html
You can extend CI_Controller to have the functionality you want.
application/core/MY_Controller.php:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Controller extends CI_Controller {
public function __construct()
{
parent::__construct();
}
public function my_function()
{
return "Cool return from my_function";
}
}
controllers/welcome.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Welcome extends MY_Controller {
public function index()
{
echo $this->my_function();//echo's "Cool return from my_function"
}
}
You simply define the functionality you want in MY_Controller. Then in your controllers, use extends MY_Controller instead of extends CI_Controller and you can call the functions anywhere inside those controllers.
I think what you want can be easily achieved using traits. Check here: PHP: Traits
More specifically -> Example #11 Defining Properties.
The only limitation is it's PHP 5.4+
You can create your own a base controller file to inherit basic page load methods from in \application\core\MY_Controller.php as such:
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Controller extends CI_Controller {
public function __construct()
{
parent::__construct();
}
protected function loadPage($path, $data = array())
{
$this->load->view('common/head'); // Assuming you will use a folder for page parts
$this->load->view($path, $data);
$this->load->view('common/foot');
}
}
Afterwards in your page controller you can call upon the same methods much more easily:
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class User extends MY_Controller {
public function index()
{
$data = array(); // get data from model
$this->loadPage('user/view', $data); // Assuming you will use folders for sets of views
}
public function edit()
{
$data = array(); // get data from model
$this->loadPage('user/edit', $data);
}
}
I am unable to load my custom class which doesnot extend from any core class.
I have placed my custom class in a subfolder inside application/libraries.
So here is my folder structure
application
|_ libraries
|_ cgh
|_ cgh_asset.php
|_ cgh_article.php
|_ cgh_asettype.php
|_ controllers
|_ welcome.php
Class Cgh_article is a subclass of Cgh_asset
Cgh_asset.php :
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
abstract class Cgh_asset
{
public $id;
public $type;
public $title;
public $content;
public $user;
abstract public function generate_url();
function __construct()
{
$this->generate_url();
}
}
?>
Cgh_article.php :
<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Cgh_article extends Cgh_asset
{
function __construct()
{
parent::__construct();
$this->type=Cgh_assettype::article;
}
function generate_url()
{
$this->url="Article_URL";
}
}
?>
Cgh_assettype.php:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Cgh_assettype
{
const type1="type1";
const type2="type2";
const article="article";
}
?>
Controller welcome.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Welcome extends CI_Controller {
public function index()
{
$this->load->library('cgh/Cgh_assettype','cgh/Cgh_asset','cgh/Cgh_article');
$this->load->view('welcome_message');
}
}
The error I get is :
Unable to load the requested class: Cgh_assettype
I must have tried all possible upper and lower case combinations of classnames, filenames, but the error is always the same.
After going through some answers, I think probably I should add one basic question here - Is it at all possible to have my own custom object types within codeigniter ... types that should be quite obvious from my question ?
This seems to work for me, so here is what I will be doing ... at least till something breaks :
In the constructor of my controller, I use require_once for my classes ... and good thing is I can combine all my classes into a single file -- my classes initially were in a single file anyways --This is my controller after the changes, and this works :
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Welcome extends CI_Controller {
public $cgh_assettype;
public $cgh_asset;
public $cgh_article;
function __construct()
{
parent::__construct();
//$this->load->library(array('cgh/cgh_assettype','cgh/cgh_asset','cgh/cgh_article'));
echo "Including CGH<br />";
echo "<p>Apppath is ". APPPATH. "</p>";
require_once(APPPATH.'libraries/cgh/Cgh_assettype.php');
require_once(APPPATH.'libraries/cgh/Cgh_asset.php');
require_once(APPPATH.'libraries/cgh/Cgh_article.php');
}
public function index()
{
$iCgh_article=new Cgh_article();
echo "<p>$iCgh_article->url</p>";
$this->load->view('welcome_message');
}
}
You need to call $this->load->library for each library.
$this->load->library('cgh/Cgh_assettype');
$this->load->library('cgh/Cgh_asset');
$this->load->library('cgh/Cgh_article');
$this->load->library takes 3 parameters.
File to load
(optional) $config array
(optional) String to rename library to ($this->Renamed_library)
If you want to load multiple libraries on one line, use an array as the 1st parameter.
$this->load->library(array('cgh/Cgh_assettype','cgh/Cgh_asset','cgh/Cgh_article'));
Are you library file names capitalized? (Your submitted folder structure says they are not).
I don't know about having libraries within sub-directories, but I know the file names need to be capitalized.
http://codeigniter.com/user_guide/general/creating_libraries.html
Naming Conventions
File names must be capitalized. For example: Myclass.php
Class declarations must be capitalized. For example: class Myclass
Class names and file names must match.
You should load library or whatever only once. If you're loading for second time, you get that error.