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_Form generation from models Component Proposal

Proposed Component Name Zend_Form generation from models
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Form generation from models
Proposers Jani Hartikainen
Zend Liaison TBD
Revision 1.0 - 19 October 2008: Initial Draft. (wiki revision: 11)

Table of Contents

1. Overview

This proposal is for a class which can be used to generate Zend_Form-based forms from model classes, such as Zend_Db_Table or Doctrine_Record. Some of the basic ideas are taken from Django framework's modelform component.

For example, if the user has a model for a table with the following columns: firstname, lastname, address, email, creating a form and code for saving it would usually involve creating some kind of a zend_form object with the fields for the columns and then some logic in a controller to parse the fields from the form into a record and store the record.

This class automates the whole process. You can simply pass the model's name to the generator, and it will create a form with fields for each of the columns. You can then simply display the form to the user. When the user posts the form back, you use isValid(), like with "normal" zend_forms, and then you can simply call save() to store the new record with the values from the fields.

You can also use the generated forms for editing existing records. Simply fetch the record, and pass it to the form. When saving a form with an existing record, it will update the existing record instead of saving a new one.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component will generate forms based on models
  • Generated forms will utilize Zend_Form and its other functionality, such as validators
  • This component will be able to create new, or update old, models
  • This component will allow users to add support to other model types with an adapter
  • This component will be able to support relations

4. Dependencies on Other Framework Components

  • Zend_Form

5. Theory of Operation

The main generator class (Zend_Form_Model) will use the adapter to gather information on the model. It will also look at the parameters passed by the user, and generate a form field for each of the columns on the model. The generator class will also be able to parse data posted by the user to create new or update exsting records.

The generator's behavior can be customized in two ways:
You instanciate it directly and pass arguments to the constructor, and it will work similarily to instancing a Zend_Form class, except with some additional parameters.

You inherit the generator in a custom form class. This way you can provide the parameters in the class properties, and you can also hook custom functionality by overriding _preGenerate, _postGenerate and _postSave.

If the adapter provides support for relations in the model, the generator can provide a select box for choosing a "has one" related record, or a subform for creating/editing/deleting "has many" records. Relations can also be ignored by passing in parameters ignoring the columns.

Many-support with subforms

The many-relation support using subforms currently works by adding buttons to the form, which the user can use to add new related objects.

This works by the means of hooking isValid, and parsing the button responses from the passed data. Based on these, the form class can insert a new sub form for adding completely new records, or if the user had modified the data shown in one of the subforms, it can update the records already stored in the database.

It can also delete records if the user chooses the delete button visible on each subform.

6. Milestones / Tasks

  • Milestone 1: [DONE] Initial prototype
  • Milestone 2: [DONE] Unit tests for the generator
  • Milestone 3: Adapter interface finalized
  • Milestone 4: Unit tests for the adapters

7. Class Index

The class names are tentative. If you have a better name, feel free to suggest.

  • Zend_Form_Model
  • Zend_Form_Model_Adapter_Interface
  • Zend_Form_Model_Adapter_DbTable
  • Zend_Form_Model_Adapter_Doctrine

8. Use Cases

UC-01: Fast creation
UC-02: Settings
UC-03: Inheritance based forms

This class is from the unit tests, and is used to confirm the pre/post methods are called.

UC-04: Full example in a controller

This shows an exampel how you might use the form inside a controller

The view would simply output the form like normal. Note that when editing a record, the main difference is that you use setRecord to tell the form what record it's working with.

9. Class Skeletons

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

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

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Oct 20, 2008

    <p>Will we be able to modify the form after it has been generated from the models (preferably like we do with Zend_Form)?</p>

    <p>In any case, I love the Doctrine adapter <ac:emoticon ac:name="smile" /></p>

    1. Oct 20, 2008

      <p>Yes, this is possible by overriding _preGenerate and/or _postGenerate methods in the class. I've also been thinking about a possible way to attach event listeners (similar to how you'd attach event listener classes in, say, Doctrine) for these events, but since there is no standard way of doing it, I've put it off for now.</p>

      <p>Also, you'll have the full zend_form interface available to you, so you could manually attach new fields or such, even outside the _pre/_post methods.</p>

  2. Oct 21, 2008

    <p>Should the class names not be slightly the other way round and let it become part of Zend Form?</p>

    <p>Zend_Form_Model...?</p>

    <p>As long as we don't assume in the docs that a model is a Zend_Db_Table instance as this caused me a lot of confusion when I was first starting with the ZF. Use of the adapters seems like a good idea like the paginator class.</p>

    <p>Sounds good so far, I can't wait to try it.</p>

  3. Oct 21, 2008

    <p>The class should be called Zend_Form_Model?</p>

    <p>I really like this idea. 
    <br class="atl-forced-newline" /></p>

  4. Oct 21, 2008

    <p>I've changed the name to Zend_Form_Model + added another use case</p>

  5. Nov 27, 2008

    <p>Thought I'll drop a small status update.. I've been quite busy with other things and haven't had time to work on this, but I still intend to finish the dbtable adapter and proceed with the proposal process when I get the free time =)</p>

  6. Dec 04, 2008

    <p>I've added some new unit tests and improved the classes a bit. </p>

    <p>Now, I would like your feedback on the subform stuff I detailed in the proposals latest revision.</p>

    <p>Currently, it's quite automatic and kinda works, but I don't feel like it's optimal and very easy for the user to modify.</p>

    <p>I was thinking about an alternative way to do the same, by simply letting the user themselves use the addSubForm method to manually add or remove subforms, and process them themselves. It would allow for easier customization on the user's part, and possibly less confusion, as all the subform functionality currently depends on the fact that you must call isValid</p>

    <p>Please share your thoughts on this matter.</p>

  7. Jan 31, 2009

    <p>hello jani,</p>

    <p>the longer i think about it the more i want a form generator also to generate PHP code that describes a form based on a definition file. i think this approach is way more flexible since you could generate you a form code and extend that one to your need by overwriting the generated class. Whenever the underyling data source changes (which shouldn't be too often hence, one time generation may be more useful) you can regenerate the source code.</p>

    <p>This would make a perfect provider for Zend_Tool and CodeGenerator.</p>

  8. Apr 07, 2009

    <p>Would be useful to have also model working with I18n data.</p>

  9. Apr 07, 2009

    <p>Would be useful to have also model working with I18n data.</p>

  10. Apr 22, 2009

    <p>I definitely think this proposal scratches an itch more than a few devs have.</p>

    <p>Couple of thoughts:</p>

    <p>It'd be great to be able to generate forms from lots of different sources, rather than just orm-ish models. Unfortunately, the current adapter API is very database specific. Also, the class seems to be taking on a lot of responsibility; I don't feel 100% comfortable having a form object doing database writes. The overall saving process is indeed simpler but it's still necessary to create a certain amount of controller code to pipe the data in and out of the form generator. Lastly, it's all done inside an extended Zend_Form object so it's directly coupled with Zend_Form (because who knows when a Zend_Form2 or a compelling alternative will become available?).</p>

    <p>So, thought about a little bit, came up with a slightly different approach. It may be possible to split the actual form generation functionality off into a seperate Zend_Form_Generator* class, which uses a dual adapter approach; one for the source object (DbTable, Doctrine, etc) and one for the output object (stock/custom Zend_Form, Html_Quickform, etc).</p>

    <p>The source adapters would be in charge of formatting, say, Doctrine columns into small Generator_Element objects (terrible name, I know) which just contain the value, data type, field name, etc. The generator passes these to the output adapter which maps them to the form library of choice. Since mapping is off-loaded to this array of mini-elements then source adapter could be simple as a describe()/getParams()/setParams() scenario. In the end, the generator just returns a form object that can still be tweaked as necessary.</p>

    <p>That abstracts out the generation stuff from hard coded dependencies and lets people drop in their own adapters on both sides more easily. I do like the Zend_Form_Model mannerism though, so it'd still be possible to have a Zend_Form_Model extension that facades the normal generator classes and preloads the Zend_Form adapter.</p>

    <p>As for the actual saving bits, it's not directly related to this proposal but my preference would be to invert the placement and do the saving inside an extended controller that can offer not just saving, but also 80% guesses at normal actions like paginated list views (something like Zend_Controller_Action_Crud or more ambitiously, Zend_Admin_Controller? <ac:emoticon ac:name="wink" />. That centralizes my attempts at cutting down on boilerplate code and also means I can mix and match the actions I want, like overriding the list view, but keep the saving and add a new report page or something.</p>

    <p>Anyways, sorry if this is a bit long, I'm not sure if this should've been in a separate proposal but I didn't want to scatter the discussion too much. Thanks for all the work you've done on this one so far. <ac:emoticon ac:name="smile" />
    <br class="atl-forced-newline" /></p>

    <p> *I know there's an actual proposal with this name now, but I don't mean to reference it directly. The existing generator proposal is also very db-centric and requests changes to Zend_Db which I don't think can happen until 2.0?</p>

  11. Mar 04, 2010

    <p>First off, thanks for this class. After working with CakePHP I was really let down to find out, when I started my Zend Project, that no such functionality was built in to the framework.</p>

    <p>In the edit action of the controller,<br />
    instead of</p>

    <p>$record = $this->_getRecord($id);</p>

    <p>I was able to get it working like this:</p>

    <p>$records = Doctrine::getTable('FooModel')->findByDql('id = ?', (int)$id);<br />
    $record = $records[0];</p>

    <p>Obviously you'd want to include some error checking in there as well, in case there was no record matching the id. To include this in _getRecord:</p>

    <p>function _getRecord($id,$table)

    Unknown macro: {</p> <p>$records = Doctrine}

    </p>

    <p>and call it with: $this->_getRecord($id,'FooModel');</p>

  12. Sep 02, 2010

    <p>What do you think about fully functional CRUD interface with search, sort and pagination capabilities:<br />
    <a href="http://framework.zend.com/wiki/display/ZFPROP/Zend_Controller_Scaffolding+-+Alex+Oroshchuk">http://framework.zend.com/wiki/display/ZFPROP/Zend_Controller_Scaffolding+-+Alex+Oroshchuk</a></p>

  13. Sep 02, 2010

    <p>I think this is a ver useful proposal. I have seen this in other project. If you need help please tell me</p>

  14. Feb 08, 2011

    <p>Archiving this proposal, feel free to recover it when you want to work on it again. For more details see <a href="http://framework.zend.com/wiki/display/ZFDEV/Archiving+of+abandoned+proposals+(Feb+5+2011)">this email</a>.</p>