Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Model Component Proposal

Proposed Component Name Zend_Model
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Model
Proposers Jurriën Stutterheim
Revision 0.1 - 4 January 2008: Initial setup
0.9 - 8 July 2008: Major rewrite
0.10 - 9 July 2008: Added a few interfaces
0.11 - 27 July 2008: Major updates (wiki revision: 27)

Table of Contents

1. Overview

Zend Framework provides a powerful Model View Controller (MVC) implementation. The View and the Controller are very well featured in this implementation. However, the Model part is still left largely up to the developer. Unfortunately it is not clear for a lot of developers how the Model should be implemented. What exactly is its purpose? What are its responsibilities? What is a decent Model design? How can my Model make use of Zend_Db or a web service? How do I make my Model implementation flexible?

One (if not the most) important aspect of the Model implementation in Zend Framework should be documentation. The documentation should answer those (and probably more) questions for developers. It should give them a head start to explore a good application design for their models. This could be done by providing common use cases and possible implementations of those use cases.

To support this, Zend_Model provides some interfaces to identify a class as being a model. Additional interfaces could be used to identify common methods for models.

This proposal is also setup to provide a place for Model discussions. For the creation of the suggested documentation I would want to setup a focus group to come up with common use cases (and their implementations) for web applications.

There are a few topics related to models that aren't covered (fully) in this proposal yet. For these topics I would like some feedback from you all.

Relations
First off are relations between models. For example, a blog can have multiple posts, which in turn can contain multiple comments. Each post also has one author. A post belongs to a blog. You get the point These are relations that are actually quite common. For a blog post the following relations would be relevant: hasOne (author), hasMany (comments), belongsTo (blog). These relations are already supported by Zend_Db. Should they be supported by Zend_Model as well?

Multiple data sources
In some cases you might want multiple data sources for your model (e.g. multiple web services). The Data_Interface I'm currently suggesting doesn't cover this. Would an interface that supports multiple data sources be wanted? How would this look?

To/From array
Throughout the framework methods like toArray() and setFromArray() are used. It would be nice if there were an interface to indicate the presence of these methods. Would this have a place in Zend_Model?

Singleton
The same question goes for the Singleton interface. Does this have a place in Zend_Model? What would be a use-case where you want your Model to be a singleton? (the idea for this came from Agavi). Also, this interface could be used by other components with singleton classes. The name Model would probably cause confusion. What could be a better namespace for an interface that defines a singleton?

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component must provide a comprehensive documentation explaining the implementation of the M in MVC.
  • This component must provide a generic interface for models
  • This component must be independent of data source (e.g. database, web service, file system etc.)
  • This component must not discard functionality that current components provide

4. Dependencies on Other Framework Components

5. Theory of Operation

For this section the PHP 5.3 naming scheme will be used. (See Class Index)
Zend_Model consists of a few interfaces that can be implemented by your models.

Zend_Model_Interface
This is an empty interfaces, which serves only to indicate that the class is in fact a model. This serves no other reason other than making the Model aspect of ZF more tangible.

Zend_Model_Data_Interface
This provides the getDataSource() method, which would serve to fetch the data source from the model. This would only be useful for simple scenarios where the model does not have multiple data sources.

Zend_Model_Form_Interface
This provides a getForm() method. As the name indicates, this fetches the Zend_Form instance from the model, should it have one. Again, this might not be usable in every situation.

Zend_Model_Singleton_Interface
This provides a public static getInstance() method, which is the name which is commonly used to get singleton instances in the framework.

6. Milestones / Tasks

  • Milestone 1: [DONE] Working prototype
  • Milestone 2: [DONE] Finish first draft of this proposal
  • Milestone 3: [IN PROGRESS...] Collect & process feedback
  • Milestone 4: Component is incubated
  • Milestone 5: Documentation & Unit Tests
  • Milestone 6: Move to core

7. Class Index

Naming suggestions are welcome!

PHP < 5.3

  • Zend_Model_Interface
  • Zend_Model_Data_Interface
  • Zend_Model_Form_Interface
  • Zend_Model_Singleton_Interface

PHP >= 5.3

  • Zend::Model::IModel
  • Zend::Model::IData
  • Zend::Model::IForm
  • Zend::Model::ISingleton

8. Use Cases

9. Class Skeletons

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
model model Delete
zend_model zend_model Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Feb 14, 2008

    <p>I am currently working on my own Model component and stumbled upong your proposal. It would be a shame to let this idea die. The data access layer is surely one of the most used but least "supported" by the zend framework. To get this propsal maybe back on tracks, here is my feedback:</p>

    <p>It would be nice to know:</p>
    <ul>
    <li>What does Zend Model Set do?</li>
    <li>How do you load and setup your adapter you want to use with the model?</li>
    <li>Overall more information on how the classes interact with each other and how you setup and load your model with the specific adapater is needed.</li>
    </ul>

    <p>My ideas:</p>
    <ul>
    <li>For what is Zend Model Factory? I would prefer a Model Loader class.</li>
    <li>How about adding a validation component?</li>
    </ul>

  2. Feb 28, 2008

    <p>I am also working on a custom model factory, but it is one that does not directly tie into a database. It has very similar methods as database model (fetch, fetchAll, insert, delete, etc). I would also like to throw my support behind this component, seems odd that it wasn't included in version 1.</p>

  3. Apr 10, 2008

    <p>Why is this proposal archived? Any Idea?</p>

  4. Jul 08, 2008

    <p>Glad to see this one is still active. I know there have been some discussions previously that the 'Model' part of MVC is always application specific, but I do think there is some generic functionality that can be provided by such a component, and this one is going in the right direction.</p>

    <p>Tracking modified fields in the object is good, it might be worth looking at the 'dirty object' features that have recently been added to Rails (as of 2.1) - <a class="external-link" href="http://ryandaigle.com/articles/2008/3/31/what-s-new-in-edge-rails-dirty-objects">http://ryandaigle.com/articles/2008/3/31/what-s-new-in-edge-rails-dirty-objects</a> . I guess the $_data and $_cleanData arrays could be compared in order to track data changes as in the Rails examples, which provide some nice options for audit trails.</p>

    <p>Two big areas that I'd like to see considered in this component would be:</p>

    <p>1. Some way of handling associations with other objects (that would also extend Zend_Model*), i.e. some hasMany/belongsTo-type relationships.</p>

    <p>2. Some way of associating a form with a model (perhaps with a setter function that accepts an instance of Zend_Form as an argument)</p>

    1. Jul 08, 2008

      <p>I've added a few interfaces to the list. One of which contains the relations methods.<br />
      There are no setters for the relationships. It seemed better to leave that over to the actual implementation. The abstract model class already implements the interface, but the method bodies are empty at the moment.</p>

      <p>I will look in to the coupling of a form to a model. This was also suggested on the mailing list a while back.</p>

      1. Jul 10, 2008

        <p>I would hope that relations could use the same getters and setters as normal model data, so we end up with something like this:</p>

        <ac:macro ac:name="code"><ac:default-parameter>PHP</ac:default-parameter><ac:plain-text-body><![CDATA[
        class Group extends Zend_Model_Abstract
        {
        public function init()

        Unknown macro: { $this->hasMany('users', 'User'); }

        }

        class User extends Zend_Model_Abstract
        {
        public function init()

        Unknown macro: { $this->belongsTo('group', 'Group'); }

        }

        $salesGroup = new Group();
        $salesGroup->name = 'Sales';

        $user = new User();
        $user->name = 'Joe Bloggs';
        $user->group = $salesGroup;

        echo $salesGroup->users[0]->name; // would output 'Joe Bloggs'
        echo $user->group->name; // would output 'Sales'
        ]]></ac:plain-text-body></ac:macro>

        <p>As for form coupling, I guess the simplest solution would be to have a static variable in the model that holds the name of the equivalent Zend_Form class. Or perhaps an inflector method that the user could override to return the form class name based on their own coding preference. E.g. it could return the name of the current class with '_Form' appended.</p>

  5. Jul 09, 2008

    <p>Currently you have those two:</p>
    <ul>
    <li>Zend_Model_Abstract</li>
    <li>Zend_Model_Model</li>
    </ul>

    <p>First of all:<br />
    What is the benefit of having a concrete implentation of Zend_Model, versus having only an abstract model? One benefit could be that developers can easily do $model = new Zend_Model(), then set some properties on it and use it elsewhere.</p>

    <p>Okay, so what's the abstract class for then?<br />
    If the concrete model implementation does not add any functionality or properties to the abstract class, why don't just remove Zend_Model_Model, make Zend_Model_ModelAbstract non-abstract and rename it to Zend_Model_Model?</p>

    1. Jul 09, 2008

      <p>I actually asked myself the same question today.<br />
      In most usecases I think the model will be used as base class, so it can be abstract. However, there might be some situations where someone might want to instantiate a concrete Zend_Model. The concrete model is just provided as a convenience for this. Also, it can be used to do the unit testing.<br />
      Of course the abstract model could be renamed to the concrete model, but this somehow seemed more correct somehow.<br />
      In the end I don't really have a strong opinion on this. Either way works for me. If there are objections to using this setup, I'm open to combining the abstract and concrete model.</p>

  6. Jul 10, 2008

    <p>From IRC:</p>

    <p><DASPRiD> norm2782, i still told the doctrne developer<br />
    <DASPRiD> i dislike the idea of some base model<br />
    <DASPRiD> but well<br />
    <DASPRiD> in the way you implemented it<br />
    <DASPRiD> it looks okay<br />
    <norm2782> <ac:emoticon ac:name="smile" /><br />
    <norm2782> any feedback is welcome really<br />
    <norm2782> as long as it's commented<br />
    <DASPRiD> feedback: you got my ok<br />
    <norm2782> <a class="external-link" href="http://framework.zend.com/wiki/pages/viewpage.action?pageId=41564">http://framework.zend.com/wiki/pages/viewpage.action?pageId=41564</a><br />
    <norm2782> <ac:emoticon ac:name="wink" /><br />
    <DASPRiD> i post irc log again, ok? <ac:emoticon ac:name="cheeky" /><br />
    <norm2782> hehe<br />
    <norm2782> sure<br />
    <DASPRiD> making you look like a dikdik<br />
    <norm2782> <ac:emoticon ac:name="sad" /></p>

  7. Jul 12, 2008

    <p>Some of the interfaces could be extended by SPL classes/interfaces by default to give them a basic functionality (e.g. Zend_Model_Array_Interface: SeekableIterator, ArrayAccess, Countable).</p>

    1. Jul 12, 2008

      <p>Could you perhaps post the class skeletons you sent me? <ac:emoticon ac:name="smile" /></p>

      1. Jul 12, 2008

        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[interface Zend_Model_Interface {}

        interface Zend_Model_Array_Interface extends SeekableIterator, ArrayAccess, Countable, Zend_Model_Interface {
        public function toArray();
        public function setFromArray(array $array);
        }

        abstract class Zend_Model_Array_Abstract implements Zend_Model_Array_Interface {
        protected $_array;

        public function __construct(array $array = array()) {}
        public function toArray() {}
        public function setFromArray(array $array) {}
        public function count() {}
        public function current() {}
        public function key() {}
        public function next() {}
        public function offsetExists($offset) {}
        public function offsetGet($offset) {}
        public function offsetSet($offset, $value) {}
        public function offsetUnset($offset) {}
        public function rewind() {}
        public function valid() {}
        public function seek($index) {}
        }

        class Zend_Model_Array extends Zend_Model_Array_Abstract {}]]></ac:plain-text-body></ac:macro>

  8. Jul 14, 2008

    <p>This is looking fairly good. One big comment I have, however, has to do with how you obtain data from the model. To my thinking, there should be 'result' and 'resultset' interfaces as well.</p>

    <p>Also, can you show some use cases involving <em>consuming</em> a model?</p>

  9. Jul 14, 2008

    <p>I also like this proposal. I have thought about writing a similar interface for my own work. what about the idea of including a Zend_Model_Persistent_Interface with methods that would perform basic CRUD operations for the model regardless of persistence layer (db, web service, etc.) ?</p>

  10. Jul 14, 2008

    <blockquote>
    <p>PHP >= 5.3</p>

    <p>Zend::Model::IArrayModel<br />
    Zend::Model::IAttributeModel<br />
    Zend::Model::IModel<br />
    Zend::Model::IModifiable<br />
    Zend::Model::IReadOnlyModel<br />
    Zend::Model::IRelationModel<br />
    Zend::Model::Model<br />
    Zend::Model::ModelAbstract</p></blockquote>

    <p>I hope they just fix PHP instead of leaving a huge bug in it.</p>

  11. Jul 14, 2008

    <p>Somehow the approach appeals very limiting to me? If i understand the ZYM example properly the component can only be used in combination with Zend_Db_Table? What about users who only use Zend_Db_Select or how would a model class look like when i want to use another DB backend adapter or even a another data pattern?</p>

    <p>Imho the component shouldnt prescribe how the model should be structered or used, you cant create a model class which appeals to all cases. I would suggest sub components that are tailored to be used with specific patterns like Zend_Db_Table (As example Zend_Model_Table_Abstract). The user himself could decide then if he wants to use that as his baseclass for his models or not.</p>

    <p>Besides that i would rather provide "helpers" that can be used for managing the models like a loader, adapater manager, table name manager or validator and suggest a basic directory structure for the models.</p>

    <p>Like stated in my first post a few months ago i created my own model component that currently consist of the stated "helpers" except the validator part <ac:emoticon ac:name="wink" /> A "not-so-in-depth" description can be found here: <a href="http://ohne-ziel.de/model_component.txt">http://ohne-ziel.de/model_component.txt</a></p>

    1. Jul 18, 2008

      <p>I agree with Ota. Smaller, more focused components would be much more useful: provide specific components to solve specific, common model-layer problems. Trying to impose this specific structure on any generic thing that might be considered a "model" is tilting windmills.</p>

      <p>One of the great things I think the ZF has done is to stay away from trying to define the model layer. By definition, its structure should be defined by the application developer. Zend_Db_Table, for all it's shortcomings, is great because it is focused on delivering something very specific (a Table Data Gateway).</p>

      <p>That said, there's still plenty of opportunity for the framework to provide model-layer value to the application developer: by providing implementations of other common data source patterns such as Active Record and Data Mapper, and some adapter components to allow using various data source components with things such as Zend_Form. Then, "Zend_Model" (as mentioned on Bill Karwin's blog) should really be nothing more than good documentation and references on how these things can possibly be put together.</p>

  12. Jul 14, 2008

    <p>What is Zend_Model_IModifiable::isNew()? Something like this?</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[$model = new Zend_Model;
    $model->name = "Mr. X";
    $model->age = 25;
    var_dump($model->isNew()); // true]]></ac:plain-text-body></ac:macro>

    <p>Who decides whether an model is new or not?</p>

    <p>Why does Zend_Model_ModelAbstract::_throwException($message) not contain $code as parameter? I think you should add it.</p>

    1. Jul 18, 2008

      <p>I would imagine this would function like the method new_record? does in Rails, in which case a model is 'new' if it has not yet been saved/committed to a datasource (e.g. the database).</p>

      <p>If so:</p>

      <ac:macro ac:name="code"><ac:default-parameter>PHP</ac:default-parameter><ac:plain-text-body><![CDATA[
      $model = new Zend_Model();
      $model->name = 'Mr. X';
      var_dump($model->isNew()); // true

      $model->save();
      var_dump($model->isNew()); // false

      $user = $db->findByID(5); // loads from database
      var_dump($user->isNew()); // false
      ]]></ac:plain-text-body></ac:macro>

  13. Jul 14, 2008

    <p>In Bill Karwin blog there is a discussion about active record and models
    <a class="external-link" href="http://karwin.blogspot.com/2008/05/activerecord-does-not-suck.html">http://karwin.blogspot.com/2008/05/activerecord-does-not-suck.html</a></p>

    <p>And i have to agree with them , that it would be better to have a chapter in documentation<br />
    about models - Zend_model (what they are, best practices,start for beginners) , but not to have some base class. </p>

  14. Jul 14, 2008

    <p>I've been a proponent of the "no base Model class" concept, but it's largely because people to equate a Model with a database access class. If you have created a framework in which a Model can be designed independently of the database access, that's better. It can help to reinforce the distinction between the two mechanisms.</p>

    <p>Your design achieves its goal which is to provide a class structure for Models. But you don't talk about extensibility, which is an important aspect of a framework. Guide developers to create their own application-specific interfaces to supplement the generic ones you provide. This can be as simple as writing some explanation and examples in the documentation for Zend_Model.</p>

    <p>Requirements section needs more detail. For example, you created several separate interfaces – why? Do you need the flexibility to add one interface but not the other to any given Model class? Spell out this objective in the Requirements section. You should be able to explain why you made any given architecture decision by tying it back to the Requirements. </p>

    <p>IModifiable is strange. The name suggests it is merely the opposite of IReadOnly, but the explanation you give for it suggests it maps specifically to Zend_Db_Table_Row, and that class's state of being "dirty" and needing to be committed to the database. This is not a logical part of being a Model, it's an implementation detail of persistence. IModifiable is also the only interface that doesn't end with the word "Model" so it breaks the naming pattern you have established.</p>

    <p>I don't see the benefit of providing PHP 5.3 namespaces. If ZF is intended to remain compatible with PHP below 5.3, no component should use namespaces. This is an artificial requirement.</p>

    <p>You can use SPL interfaces for some things, but make sure to test with the minimum PHP version as well as the current PHP version. SPL grows in scope continuously, and its authors have neglected documentation, so it's hard to get details about what SPL interfaces are stable in which version of PHP. The only way to be sure is to test.</p>

    <p>Your use cases should show usage, not just the class definitions. You can leverage this work by developing some of your unit tests from the use cases.</p>

    <p>I don't think Zend_Model_Model needs that level of class depth. Why not just make it "abstract class Zend_Model"?</p>

    <p>If a Model can have an associated form, not all Models take a form object, so make that an interface. For instance, "IFormInputModel" and "IFormOutputModel". Define methods in this interface for setting and validating the form object. "IFormOutputModel" is for a model that prepares data to auto-fill a new form.</p>

    <p>Regarding the abstract class, you should use abstract functions where appropriate in abstract classes to force the implementer to provide the code body for those functions. What you have now allows a developer to extend the abstract class without overriding the default method. This is a problem because the functions will eat any parameters and do nothing with them, or will return nothing even though the function claims to return something.</p>

    <p>Spell "independent".</p>

  15. Jul 28, 2008

    <p>Second review after Jurriën made a significant rewrite.</p>

    <p>The requirements section is still too lean. You need to define a specific problem you're trying to solve, or else you can't know if you've solved it. You've just done a massive rewrite, but it's still not clear whether it's a good solution. Rewrites may continue, yet come no closer to a clear solution, until you have a more concrete definition of the goal.</p>

    <p>Use cases should show usage, not solely class definitions. Without showing usage, you have not shown that the interfaces you provide have anything to do with how people use Models. Instead of reviewing other frameworks and blog articles (including mine), you need to look at some of the ways people are using models. Several people on the mailing list have said they're working on their own Model component. What are they doing? What works and doesn't work?</p>

    <p>There is no apparent purpose to the example BlogPost Model class. It offers no value over using a Table class directly (except making the find method return a single Row object instead of a Rowset). This BlogPost class has a private member for a form object, but no code utilizing it.</p>

    <p>BlogPost seems to implement Zym* interfaces, not Zend* interfaces...?</p>

    <p>Despite rewriting a lot of the proposal, you have retained the misspelling of "independent."</p>

    1. Jul 28, 2008

      <p>Bill,</p>

      <p>Thanks for keeping track of this proposal. I've updated the overview section to make it more clear what I think the problem is.</p>

      <p>The research I'm doing on this is an ongoing process and I have to admit that my knowledge on the subject is still nowhere near where I want it to be. Because of this I see this proposal both as a partial solution to the problem and as a place to discuss and refine what exactly the problem is that needs to be tackled.</p>

      <p>References to Zym interfaces in the examples and the spelling error have been fixed : )</p>

  16. Sep 05, 2008

    <p>Hey, whats the status of the proposal? It seems that its dead again <ac:emoticon ac:name="smile" /></p>

    <p>Anywayn, the current information are, to be honest, even more shallow then the previous.<br />
    I dont think slaping some interfaces in our face and then waiting for us to give you some great feedback is the right way.</p>

    <p>What are the benefits of the interfaces? For me they are useless in their current state and i wouldnt know what todo them.</p>

    <p>As we allready discussed in the comments a model could be anything, so i think defining the containg data or how the data should be accessed is the wrong way because that idea would be to restrictive and unflexible.</p>

    <p>Maybe you should first define what do you want to achieve with the model component, how do you want to help the users and what do the users need.</p>

    <p>A first idea would be to gather the most often asked questions regarding the model part. A few would be:</p>
    <ul>
    <li>Where to i place my model files?</li>
    <li>What should they contain?</li>
    <li>How do i get the database connection into my model.</li>
    <li>Whats a "best practice" model?</li>
    <li>How do i link my controller and model together?</li>
    </ul>

    1. Sep 05, 2008

      <p>I wouldn't say it's "dead" – just that most of us, Jurrien included, have been busy getting the 1.6.0 release out the door. <ac:emoticon ac:name="smile" /></p>

      <p>Personally, I feel you're asking the wrong questions. Probably the most pertinent question to ask is: What kind of Model would Zend_Model be targetting: Domain Model? Table Module? ActiveRecord? Object Relation Mapping? Answering this question will better define the scope of this proposal, and what interfaces or abstract classes it should expose.</p>

      <p>"How do I get the database connection into my model" is a naive question – it ignores the fact that a model could have non-DB data sources, such as services, the filesystem, etc.</p>

      <p>Everything else – where to place model files, "best practices" in models, and linking models together – have nothing to do with modeling, but are questions that will be dealt with in our recommendations for project structure and in separate proposals such as the current ResourceLoader proposal.</p>

      1. Sep 06, 2008

        <blockquote>
        <p>I wouldn't say it's "dead" - just that most of us, Jurrien included, have been busy getting the 1.6.0 release out the door. </p></blockquote>
        <p>You never know if someone leaves a proposal be ...</p>
        <blockquote>
        <p>Personally, I feel you're asking the wrong questions. Probably the most pertinent question to ask is: What kind of Model would Zend_Model be targetting: Domain Model? Table Module? ActiveRecord? Object Relation Mapping? Answering this question will better define the scope of this proposal, and what interfaces or abstract classes it should expose.</p></blockquote>
        <p>I do not agree with this view. Why should Zend_Model focus and force the users one specific model pattern?</p>
        <blockquote>
        <p>"How do I get the database connection into my model" is a naive question - it ignores the fact that a model could have non-DB data sources, such as services, the filesystem, etc.</p></blockquote>
        <p>Its a naive question yes but its an often asked question by newcomers. And it was just a point that sprung into my mind to give Jurrien some ideas</p>