Using a table without corresponding model

Published on and tagged with cakephp  model

I don’t know if the following is of any practical use, I was just curious whether it is possible to use a table without creating a corresponding model class for it. And yes, it is possible.

There are two possible ways: instantiating the Model class manually, or using the ClassRegistry. First the manual way, which requires a bit more work:

class ExamplesController extends AppController {
    public $uses = array();
	
    public function index() {
        App::import('Core', 'Model');
        $this->Month = new Model(false, 'months');
        $this->Month->alias = 'Month';
        $this->set('months', $this->Month->find('all'));
    }
}

In the example above we create an instance of the Model class which uses the “months” table (and we don’t set an ID, hence the “false” in the constructor). Then we have to specify the alias property (and not the name property as you may guess). Without defining this property, the result of the find statement would be as shown below (notice the “Model” key):

Array
(
    [0] => Array
        (
            [Model] => Array
                (
                    [id] => 1
                    [name] => January
                )
        )
    ...
)

The second approach uses the ClassRegistry to instantiate the Model class. The example from above can now be shortened to:

class ExamplesController extends AppController {
    public $uses = array();
	
    public function index() {
        $this->Month = ClassRegistry::init(array('class' => 'Model', 'table' => 'months', 'alias' => 'Month'));
        $this->set('months', $this->Month->find('all'));
    }
}

As I said at the beginning of this article, this was just an experiment, but maybe you come up with a practical use case for it ;-)

9 comments baked

  • Andy

    That’s great. I’ll use this for retrieving icons for a given mimetype.

  • Stepan Stolyarov

    I’ve noticed that CakePHP performs the same trick when you (accidentally) write something like

    class Foo extends AppModel {
      var $hasMany = array('Bars'); // note plural
    }

    Here, it instantiates AppModel to deal with bars table.

    Took me a few hours to determine why Bar::afterSave() is not called — it was not the class I needed! Still don’t know whether it’s a bug or a feature. :)

  • Bruno Bergher

    Considering what Stepan raises, shouldn’t the first example instantiate AppModel, in order to inherit app-specific functionality, instead of the vanilla core Model?

    This is pretty interesting by the way, thanks.

  • cakebaker

    @all: Thanks for your comments!

    @Stepan: At least according to Chris Hartjes’ article it is a feature.

    @Bruno: Yes, if you want to inherit app-specific functionality you have to instantiate the AppModel class. In that case you have to change the import statement of the first example to:
    App::import('Model', 'App');

  • Tim Koschuetzki

    @Adny: Please explain your model setup.

    Hrm seems like a hack to me. :) But if it gets the job done the client wont care much.

  • skiedr

    Solution with ClassRegistry looks more correct from ideology point of view.
    Code that used ClassRegistry::init still work correctly in test suite without any changes.

  • rafaelbandeira3

    @Tim Koschuetzki: I wouldn’t say “a hack” as it only works because Cake supports it, the already mentioned by hartjes: “dynamic models”, so, as commented about a feature in my blog: “a valid solution”.

  • rafaelbandeira3

    Now I was wondering, you could just use Controller::loadModel(), couldn’t you?

    $this->loadModel(‘Month’);
    $this->Month->find(‘all’);

    Cleaner and “cakisher”.

  • cakebaker

    @skiedr: Yeah, the solution using the ClassRegistry looks cleaner. But personally I’m not so happy about ClassRegistry::init(), as a) the method name is misnamed and b) I think this functionality should be somewhere else.

    @Rafael: Yes, you are right, that also works. I would have expected this method to fail in such a case, because there is no such model to load. Anyway, thanks for the hint!

Bake a comment




(for code please use <code>...</code> [no escaping necessary])

© daniel hofstetter. Licensed under a Creative Commons License