• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Autoloading Models PHP 5 Style

#1
[eluser]gcarrion[/eluser]
Hi,

I found this article posted over at Nettuts with pretty neat hacks:
http://net.tutsplus.com/tutorials/php/6-...e-masters/

I would like to use "hack" #1 (specially for the auto-complete feature in the IDE and the simplicity to call models), but is not working for me. I keep getting errors when running the page.

I added the required code to the end of application/config/config.php

Code:
function __autoload($class) {
    if (file_exists(APPPATH."models/".strtolower($class).EXT)) {
        include_once(APPPATH."models/".strtolower($class).EXT);
    } else if (file_exists(APPPATH."controllers/".strtolower($class).EXT)) {
        include_once(APPPATH."controllers/".strtolower($class).EXT);
    }
}


Then created a test controller: application/controllers/test.php

Code:
<?php
Class Test extends Controller {

    function index() {
        $test_model = New Test_model;
        $db_array = $test_model->getTest();
        print_r($db_array);
    }
}
?>

I then created a test model: application/models/test_model.php

Code:
<?php
class Test_model extends Model {

    function getTest() {
        $query = $this->db->query('select * from table where PostStatus = 1');

        if($query->num_rows() > 0) {

            foreach ($query->result() as $row) {
                $data[] = $row;
            }
        }
        return $data;
    }

}
?>

When I run the URL: mysite.com/test/
I get this message:

Quote:Fatal error: Class 'Model' not found in /path/to/web/application/models/test_model.php on line 2


Tried removing the "extends Model" from the test_model.php to be like this:
Code:
class Test_model {

Then ran it again and got this error:

Quote:A PHP Error was encountered
Severity: Notice
Message: Undefined property: Test_model::$db
Filename: models/test_model.php
Line Number: 5

Fatal error: Call to a member function query() on a non-object in /path/to/web/application/models/test_model.php on line 5


However, If I call the model the original way in the controller, it works fine.

Code:
$this->load->model('test_model');
$db_array = $this->test_model->getTest();


Any ideas of what I'm doing wrong?

Thanks!

#2
[eluser]gcarrion[/eluser]
It is also worth to mention if I change the model from this:
Code:
<?php
class Test_model extends Model {

    function getTest() {
        $query = $this->db->query('select * from table where PostStatus = 1');

        if($query->num_rows() > 0) {

            foreach ($query->result() as $row) {
                $data[] = $row;
            }
        }
        return $data;
    }

}
?>

To this:
Code:
<?php
class Test_model {

    function getTest() {
        $data = array ('test1','test2','test3');
        return $data;
    }

}
?>

To test just output a simple array, It works fine without any errors.

Any idea?

#3
[eluser]Ben Edmunds[/eluser]
Is the database library autoloaded?

Why are you foreaching through the result? You can simply return $query->result() or $query->result_array() depending on what you need.

#4
[eluser]gcarrion[/eluser]
Yes, the database library is autoloaded.

About the foreaching... just a test code I copied from other project I have... new ones I'm using result_array()

#5
[eluser]Ben Edmunds[/eluser]
I would think it would work as long as you're extending Model.

You could always use get_instance(). What is the point in autoloading though? You're going to lose performance by autoloading.

The simpliest solution is probably to use $this-load-model() in your autoload method.

#6
[eluser]umefarooq[/eluser]
i dont understand why you are autoloading controller and modules where in CI you can put moudels in autoload.php file which module you want to load and you can define your default controller in route.php file CI is already supporting that

#7
[eluser]Phil Sturgeon[/eluser]
I was just posting a comment on that article, point out how bad this (very old and commonly known) idea is.

Quote:1. The model when loaded will not be added to the CodeIgniter super-global unless you do $this->post = new Post; which will kill the shorter syntax.

2. The model will need to be loaded in each model, library or method it is used.

3. By not inheriting from Model you will have no access to loaded libraries without using $ci =& get_instance() which will make your models look ugly as sin.

And I share umefarooq's concern, if you ever need to call a controller directly you are doing something very wrong and the MVC Gods will punish you. Tongue

#8
[eluser]Chad Fulton[/eluser]
I'll bite on this.

1. I think that there's no reason that we should be encouraging people to never use local Model instances.

I agree that some model instances should be global, like maybe a User model, or a Page model, or whatever, but there are times when it makes more sense to deal with an object temporarily, in which case it doesn't need to be in the global scope and doing so would make that scope unnecessarily messy. That's the whole point of local scoping in PHP, personally I disagree with CodeIgniter's handling of Models, which makes it difficult to get around that.

The "hack" I use is to add an argument to the constructor of the MY_Model class (which all my models descend from) such that if the argument given is FALSE, it doesn't load the parent constructor (and so doesn't add it to the global scope, but, of course, this also means that you have to get any of the CI variables that you want):

Code:
public function __construct($model = true) {
        if($model) {
            parent::__construct();
        }
        else {
            $ci =& get_instance();
            $this->db =& $ci->db;
            // ...
        }
    }

2. Besides polluting the global space with things that should be left in the local space, I feel like there's an awful burden imposed by allowing only a single instance of a model (I know that you can use the second argument in the load function to assign the model instance to a different global variable, but that's only really helpful if you want 2 or 3 instances of a model). I want to be able to make an arbitrary number of model instances and assign them into an array and then manipulate them as a group:

Code:
foreach($objects as $object) {
  if($object->function()) {
    echo $object->property_1;
  }
  else {
    echo $object->property_2;
  }
}

Of course, none of this has to do with autoloading in particular (since it doesn't matter if you do a require('path/to/model') before the $model = new Model; or not), but is relevant to this case.

#9
[eluser]Phil Sturgeon[/eluser]
Sure, you are doing it with more care and attention to the effects that the author of this article. He suggests it as a "new" & "better" way, when it is entirely different. Using both methods together is smart, killing a fundamental part of CodeIgniter is ridiculous.

My main issue with it is where he tells people there is no need to inherit the Model class too. What is the point of that? You loose access to loaded libraries without gaining anything at all.

#10
[eluser]Thomas Lee Brewer Jr.[/eluser]
Try this for you __autoload function instead with you original code:

Code:
function __autoload($class) {
    if (file_exists(APPPATH.'models/'.strtolower($class).EXT)) {
        include_once(APPPATH.'models/'.strtolower($class).EXT);
    } else if (file_exists(APPPATH."controllers/".strtolower($class).EXT)) {
        include_once(APPPATH.'controllers/'.strtolower($class).EXT);
    } else if (file_exists(BASEPATH.'libraries/'.strtolower($class).EXT)) {
        include_once(BASEPATH.'libraries/'.strtolower($class).EXT);
    }
}


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2019 MyBB Group.