6

I need to figure out a best practice for utilizing models efficiently in Zend Framework.

Currently, I have classes extending Zend_Db_Table_Abstract which handle my queries to each class' respective table.

When I need to access say 5 of those tables from a controller, I find myself creating 5 new instances of each specific Zend_Db_Table object. This is really ineffective.

I've thought about implementing a Factory pattern to create new instances (or provide existing static copy) but am not sure. Is this the best way to go about it?

What is the correct way to handle models ensuring speed without consuming excessive resources? Should lazy loading come into play here?

[EDIT] As an example, I have a class I use to handle getting details about a location from a raw search query and need these objects in order to parse the query:

// Initialize database object
$this->dbLocations = new Model_Locations;
$this->dbStates = new Model_States;
$this->dbZipcodes = new Model_Zipcodes;
$this->dbLookup = new Model_Lookup;

In another class, I may need to access those models again so I repeat the above code. Essentially reinitializing objects that could be static/singleton.

Jeremy Harris
  • 24,318
  • 13
  • 79
  • 133
  • 1
    Your question is quite wage, can you show an example of code where you actually create instances of 5 table classes and describe what you need them for. – markus Feb 21 '12 at 22:49
  • I understand your concerns but don't really follow. Creating multiple instances of a class and especially an abstract class is a given thing in OOP, I would say. Questioning this table model is a little like questioning OOP or inheritance altogether to me. – Adrian World Feb 22 '12 at 16:39
  • On a basic level, usage in this method is acceptable. I have a custom "handlers", for lack of a better word", which takes a query object, parses properties in it and passes it on to a location handler which gets all the location data for that query, then passes it on to a Tide data handler as well as a weather data handler. In many phases of this, I need to access various tables and end up initiating these objects a lot from various classes. See this for more info: http://stackoverflow.com/questions/9116838/data-encapsulation-and-data-flow-in-php – Jeremy Harris Feb 22 '12 at 17:30
  • Well, if you are so worried about creating too many objects you are free to use `$db->query('SELECT * FROM tide');` instead of Zend_Db_Table. That would leave you with just one object. – Adrian World Feb 22 '12 at 19:45

2 Answers2

3

I tend to work at the DbTable like you do. I've found it effective when I need to query multiple tables in a single action to create another layer of model above the dbTable. Similar to a service or domain layer. This way I only have to call a single model but I still have the functionality I need.

Here is a simple example that may eventually interact with 5 DbTable classes and most likely a couple of Row classes as well:

<?php

class Application_Model_TrackInfo
{


    protected $_track;
    protected $_bidLocation;
    protected $_weekend;
    protected $_shift;
    protected $_station;

    public function __construct() {
        //assign DbTable models to properties for convience
        $this->_track = new Application_Model_DbTable_Track();

    }

    /**
     *
     * @param type $trackId
     * @return type object
     */
    public function getByTrackId($trackId) {

        $trackData = $this->_track->fetchRow($trackId);
        //getAllInfo() Application_Model_Row_TRack
        $result = $trackData->getAllInfo();
        //returns std object reflecting data from 3 DbTable classes
        return $result;
    }

    /**
     *Get Station from trackid through bidlocationid
     *
     * @param type $trackId
     * @return type object
     */
    public function getStation($trackId){

        $data = $this->_track->fetchRow($trackId);
        //This a Application_Model_Row_Track method
        $result= $data->getStationFromBidLocation();

        return $result;
    }

} 

I hope this helps.

[EDIT] Since I wrote this answer I have learned the benefits of Domain Models and Data Mappers. Wow what a difference in my app. Not a magic bullet, but a huge improvement.
Thanks to
Alejandro Gervasio over at PHPMaster.com
Rob Allen at Akrabat.com
and
Pádraic Brady at Surviving The Deepend

for all their help in understanding this pattern.

RockyFord
  • 8,529
  • 1
  • 15
  • 21
  • Everytime you use the Application_Model_TrackInfo class, it does what I have an issue with. Creates dbTable object(s) which may or may not be used, then it gets deleted, and your next use of it creates this all over again. Should these dbTable connections be generated in a factory paradigm or is multiple concurrent instances an acceptable overhead to have to deal with? – Jeremy Harris Feb 22 '12 at 10:15
  • @cillosis It sounds like you might be better off looking at caching strategies so you can minimize your Db queries. An ORM (with some data persistence) solution might be appropriate as well. – RockyFord Feb 23 '12 at 06:39
1

You seem to be in a possition where you require efficient data management with features that the current Zend framework does not come with. Zend does not have a built in engine for working with databases of any sort, it simply has a wrapper classes which help you write your queries.

What you need is an object relational model (ORM) which is a must-have in a professional framework. As I understand it, ORM is a framework by itself, it has patterns and strongly defined ways of "doing things", supports lazy loading (it takes the most of it) and optimizes your queries to the fullest. When you use ORM you don't even write SQL, instead you need to change your interpretation of data storage, you need to forget about tables and focus on Objects. In Doctrine for example each type (table) is specified by a Class and each record (row) as a class instance where you have access to different methods and properties. It supports event listeners and crazy cascading rellations.

No more need to extract rows from related tables when you delete records (it is automatic), no more need to write complex and chaotic scripts to ensure filesystem synchronisation, you can migrate to almost any db engine at any time (mysql, postgresql, simplesql..) and more..

I've been using Doctrine 2 in conjunction with Symfony 2 framework and I have to say I wouldn't go back to Zend for anything. Yes, it is complex and heavy, but really the ultimate solution. When you come to a moment when you need to manage hundreds of tables with millions of records total - then you will see the difference.

So, final summation: ORM is what you need, there are many solutions, I know of two really good: Doctrine 1 or 2 and Propel.

P.S.: ORM is an independant part of your system, so you don't really need to use a specific framework, Zend can be configured to work with Doctrine wonderfully :)

Tony Bogdanov
  • 7,436
  • 10
  • 49
  • 80
  • 4
    Zend_Db IS by itself an implementation of the ORM pattern. Your answer does not address the real problem of the OP, it only tells him to change tool based on your personal oppinion. Your first paragraph is completely wrong which suggests you're talking about things you don't actually know. – markus Feb 21 '12 at 22:47
  • I didn't write any, because for the moment, there is not enough information in the question to write an answer to it. – markus Feb 21 '12 at 22:53
  • And it is probably going to stay like that, at least mine is a working solution, even if not exactly what the OP has asked. – Tony Bogdanov Feb 21 '12 at 22:55
  • @tony consider to give an answer to this question http://stackoverflow.com/questions/9061640/zend-ormtdg-vs-doctrine – tasmaniski Feb 22 '12 at 08:52
  • I don't currently need the overhead of an ORM. But, for future research on SO, this answer and comments may provide some useful insight. – Jeremy Harris Feb 22 '12 at 10:10
  • @cillosis - how about a singleton dbTable-container, lazy-loading needed models and returning them? `$this->dbLocations = My_DbContainer::getInstance()->getDbLocations()` and so on. Never done this, just asking. – bububaba Feb 22 '12 at 11:19
  • @bububaba Thats kind of what I am thinking at this moment. I really had hoped there was standard way people manage this sort of thing in ZF. – Jeremy Harris Feb 22 '12 at 12:09