+ Reply to Thread
Page 1 of 2 1 2 LastLast
Results 1 to 10 of 12

Thread: Autoloading Models

  1. #1
    Mark^Bastard is offline Junior Member
    Join Date
    May 2007
    Posts
    15

    Default Autoloading Models

    I'm interested to find out how everyone else is loading / naming their model classes?

    There's a distinct lack of 'magic' in the framework for handling this. It seems you have to do one of the following.

    1 - Add your model directory(s) to the include path.
    2 - include/require your model class before using it.

    I'm using register autoload in my app so really want to avoid having to manually include model class files, but I also don't really like having to add my model directories to the include path, because I'm using modules and have many model directories.

    I'm almost tempted to just put them all in the library folder.

    I've considered writing my own loader class and registering it with Zend_Load but surely there's a better way?

  2. #2
    Piro is offline Junior Member
    Join Date
    Apr 2008
    Location
    Holland
    Posts
    8

    Default

    Option 1:

    I'm using the Zend_Loader::registerAutoloader() method and extending the include_path in the bootstrap file by scanning the module or controller directories for the folder 'models'. When it encounters one, it adds it to the include_path.

    This way I can use '$nodes = new Nodes();' in my projects to load a model without any hassle.

  3. #3
    Mark^Bastard is offline Junior Member
    Join Date
    May 2007
    Posts
    15

    Default

    That sounds good. So you have a base dir, and you wrote a function to scan all children dirs recursively and if one matches the name 'models', it's added to the include path?

    That definitely works for me.

    One other thing though, do you have any issue with giving your models names without a suffix or prefix?

    Shouldn't there be a better way than just new Nodes() for example? I like how controllers have a naming convention of NameController.

    I guess I should just use Model as a suffix and deal with the lack of magic.

    Ideally I'd like to have...

    (default module)

    NodeModel.php

    class NodeModel extends Zend_Db_Table_Abstract {}

    (news module)

    News_ArticleModel.php

    class News_ArticleModel

    If we kept things too generic there may be clashes of class names? Particularly amongst different modules if the idea is to make modules able to be placed in different applications.

  4. #4
    Piro is offline Junior Member
    Join Date
    Apr 2008
    Location
    Holland
    Posts
    8

    Default

    Quote Originally Posted by Mark^Bastard View Post
    That sounds good. So you have a base dir, and you wrote a function to scan all children dirs recursively and if one matches the name 'models', it's added to the include path?

    That definitely works for me.
    Exactly; in my bootstrap I have the following code (I'm using the modular structure of ZF):

    [php]$includePath = PATH_SEPARATOR . '../library';

    // Add model directories to include path
    if($dhApp = opendir('../application/modules'))
    {
    while(($dirApp = readdir($dhApp)) !== false)
    {
    if(substr($dirApp, 0, 1) != '.' && is_dir('../application/modules/' . $dirApp))
    {
    if($dhModule = opendir('../application/modules/' . $dirApp))
    {
    while(($dirModule = readdir($dhModule)) !== false)
    {
    if($dirModule == 'models' && is_dir('../application/modules/' . $dirApp . '/models'))
    {
    $includePath .= PATH_SEPARATOR . '../application/modules/' . $dirApp . '/models';
    }
    }
    closedir($dhModule);
    }
    }
    }
    closedir($dhApp);
    }

    // Change include_path to add Zend Frameowrk to the include path
    ini_set('include_path', ini_get('include_path') . $includePath);[/php]

    One other thing though, do you have any issue with giving your models names without a suffix or prefix?

    Shouldn't there be a better way than just new Nodes() for example? I like how controllers have a naming convention of NameController.

    <...snip...>

    If we kept things too generic there may be clashes of class names? Particularly amongst different modules if the idea is to make modules able to be placed in different applications.
    True, I've thought about this too but all Zend related classes have a prefix or suffix anyway. If you like to create a Node controller, you have to name the class NodeController anyway.

    The only conflict you might have is that an external lib is using the same classname. But using a suffix of Model isn't a bad idea anyway!

  5. #5
    Elemental's Avatar
    Elemental is offline Senior Member
    Join Date
    Jul 2007
    Posts
    122

    Default

    If you're using a conventional modular file hierarchy then a Controller_Plugin is a very quick an clean solution to this issue. Query the module being loaded and add that module's model path to the include. I can post some code if you want it.

  6. #6
    Mark^Bastard is offline Junior Member
    Join Date
    May 2007
    Posts
    15

    Default

    Quote Originally Posted by Elemental View Post
    If you're using a conventional modular file hierarchy then a Controller_Plugin is a very quick an clean solution to this issue. Query the module being loaded and add that module's model path to the include. I can post some code if you want it.
    I'd be interested in some code. Thanks.

  7. #7
    Elemental's Avatar
    Elemental is offline Senior Member
    Join Date
    Jul 2007
    Posts
    122

    Default

    The plugin:
    [php]
    <?php
    /**
    * ModelLoader.php
    * (library/MyApp/Controller/Plugin/ModelLoader.php)
    */

    require_once('Zend/Controller/Plugin/Abstract.php');

    class MyApp_Controller_Plugin_ModelLoader extends Zend_Controller_Plugin_Abstract
    {
    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
    $moduleName = $request->getModuleName();
    $rootDir = Zend_Registry::get('rootDir');
    set_include_path(get_include_path() .
    PATH_SEPARATOR . $rootDir . '/application/modules/' . $moduleName . '/models/');
    }
    }
    [/php]in your bootstrap:
    [php]
    ...
    $rootDir = dirname(dirname(__FILE__));
    ...
    Zend_Registry::set('rootDir',$rootDir);
    ...
    $frontController = Zend_Controller_Front::getInstance();
    ...
    $frontController->registerPlugin(new MyApp_Controller_Plugin_ModelLoader());
    ...
    $frontController->dispatch();
    [/php]

    This will allow any models in your <module>/models dir to be loaded with autoload by adding the modules model path to the include path based on the requested module. This will not allow models from non-requested modules to be loaded. I have a "global" model space in application/models that holds all models needed by the core system or more than one module.

  8. #8
    Mark^Bastard is offline Junior Member
    Join Date
    May 2007
    Posts
    15

    Default

    Thanks, that code looks very interesting.

    Last night I actually did something myself, completely different way though. I made my own loading class that extends Zend_Loader.

    [PHP]<?php

    class Lsdev_Loader extends Zend_Loader {

    public static function loadClass($class, $dirs = null)
    {
    if (substr($class, -5) == 'Model') {
    self::loadModel($class);
    }
    elseif (substr($class, -4) == 'Form') {
    self::loadForm($class);
    }
    else {
    parent::loadClass($class, $dirs);
    }
    }


    public static function loadModel($class)
    {
    self::loadCustom($class, 'models');
    }

    public static function loadForm($class)
    {
    self::loadCustom($class, 'forms');
    }

    public static function loadCustom($class, $type)
    {
    $basePath = '../application';

    $parts = self::__explodeCase($class);

    switch (count($parts)) {
    case 2 :
    parent::loadClass($class, "$basePath/$type/");
    break;

    case 3 :
    parent::loadClass($class, "$basePath/modules/{$parts[0]}/$type/");
    break;

    default :
    throw new Zend_Exception("Lsdev_Loader::loadCustom() Invalid class "
    . "name specified: <b>$class</b>");
    break;
    }
    }

    private static function __explodeCase($string, $lower = true)
    {
    $array = preg_split('/([A-Z][^A-Z]*)/', $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    if ($lower) {
    $array = array_map('strtolower', $array);
    }
    return $array;
    }

    public static function autoload($class)
    {
    try {
    self::loadClass($class);
    return $class;
    } catch (Exception $e) {
    return false;
    }
    }
    }[/PHP]

    I register it with my boot strapper using the following code.

    [PHP]// Enable autoloading of classes
    include 'Zend/Loader.php';
    Zend_Loader::registerAutoload('Lsdev_Loader');[/PHP]

    Now I can autoload models and also forms very easily based on their name.

    For example inside my IndexController I can do...

    $news = new NewsModel();

    It will automatically search for NewsModel.php in /application/models/

    If I want to use modules, I can just add the module name to the start.

    $news = new BlogNewsModel();

    It will automatically search for BlogNewsModel.php in /application/modules/blog/models/

    It's obviously based on camel casing. This is a working draft that could be improved upon by handling directories better.

    Note I used camel casing so as not to conflict with Zend's use of underscores to match directories.

    Interested in feedback.

  9. #9
    Elemental's Avatar
    Elemental is offline Senior Member
    Join Date
    Jul 2007
    Posts
    122

    Default

    I"d go ahead an put it in line with Zend's naming convention so you don't have to follow two conventions. There shouldn't be a conflict and if there is you should get your class to play nice with the ZF conventions. Just my two cents tho...
    Zend Framework Resources: Zend Webinars | Reference Manual | API Docs | Books | FreeNode: #zftalk
    Getting Started Tutorials: Getting started with ZF | Getting started with Zend Auth

  10. #10
    Mark^Bastard is offline Junior Member
    Join Date
    May 2007
    Posts
    15

    Default

    You're right. I only noticed yesterday that Zend treats module controllers as Module_NamedController

    Even though that obviously doesn't map to /modules/module/controllers/NamedController.php

    So I'll look at how they've done that, and apply the same to models and forms.

    Thanks.

+ Reply to Thread
Page 1 of 2 1 2 LastLast

Similar Threads

  1. Modules, models and autoloading...
    By ajlisowski in forum General Q&A on Zend Framework
    Replies: 3
    Last Post: 07-11-2010, 09:17 AM
  2. autoloading default modules models
    By saif in forum General Q&A on Zend Framework
    Replies: 0
    Last Post: 03-02-2010, 11:04 AM
  3. autoloading
    By chinaski in forum Core Infrastructure
    Replies: 3
    Last Post: 11-21-2009, 03:12 PM
  4. Autoloading models?
    By ArticSun in forum Model-View-Controller (MVC)
    Replies: 1
    Last Post: 11-16-2009, 07:41 AM
  5. Autoloading Models and DB_DataObjects
    By CreedFeed in forum Installation & Configuration
    Replies: 0
    Last Post: 06-10-2009, 12:46 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts