Added by Jani Hartikainen, last edited by Jani Hartikainen on Dec 04, 2008  (view change)

Labels

 
(None)

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: 10)

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

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

In any case, I love the Doctrine adapter

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.

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.

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

Zend_Form_Model...?

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.

Sounds good so far, I can't wait to try it.

The class should be called Zend_Form_Model?

I really like this idea. 

I've changed the name to Zend_Form_Model + added another use case

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 =)

I've added some new unit tests and improved the classes a bit.

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

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.

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

Please share your thoughts on this matter.