Here's the solution I came up with to allow sfDoctrineActAsKeyValueStorePlugin to hydrate default values when injecting objects with the KeyValueStore behavior, and also to save form values to the key/value store after the form is submitted and validated.
It should be fairly easy to add support for this to the plugin itself, if Tom so sees fit. Hopefully the rest of this email can be used as this feature's documentation. There are two steps: 1. Change BaseFormDoctrine to extend KeyValueStoreForm, and create ./lib/form/KeyValueStoreForm.class.php with the following code: https://gist.github.com/1023053 <?php /** * Allows key-value store values from objects with the ActAsKeyValueStore Doctrine * behavior to be populated into form value defaults and also assigned/persisted * to with the object using the form. * * @author John Kary <johnk...@ku.edu> */ abstract class KeyValueStoreForm extends sfFormDoctrine { /** * Gets object property values and KeyValueStore values. * * @return array */ protected function getObjectValues() { $values = $this->getObject()->toArray(false) + $this->getObjectKeyValueStoreValues(); return $values; } /** * Gets object values for fields representing values presisted using * Doctrine behavior KeyValueStore. * * Customize for each form using an object with KeyValueStore behavior. * * @return array */ protected function getObjectKeyValueStoreValues() { return array(); } /** * Updates the default values of the form with the current values of the * current object. * * Added support for defaults that come from Doctrine behavior KeyValueStore. */ protected functio n updateDefaultsFromObject() { $defaults = $this->getDefaults(); // update defaults for the main object if ($this->isNew()) { $defaults = $defaults + $this->getObjectValues(); } else { $defaults = $this->getObjectValues() + $defaults; } foreach ($this->embeddedForms as $name => $form) { if ($form instanceof sfFormDoctrine) { $form->updateDefaultsFromObject(); $defaults[$name] = $form->getDefaults(); } } $this->setDefaults($defaults); } /** * Updates the values of the object with the cleaned up values. * * Overrides default Doctrine implementation to add storage of KeyValueStore * * @param array $values An array of values * @return mixed The current updated object */ public function updateObject($values = null) { if (null === $values) { $values = $this->values; } $values = $this->processValues($values); $this->doUpdateObject($values); //Store form values that are not object properties as key-value store data $this->updateObjectKeyValueStoreValues($values); // embedded forms $this->upd ateObjectEmbeddedForms($values); return $this->getObject(); } /** * Sets object values for fields representing values persisted using * Doctrine behavior KeyValueStore. * * Customize for each form using an object with KeyValueStore behavior. * * @param array $values */ protected function updateObjectKeyValueStoreValues(array $values) { } } 2. Now we can create a form called "MyForm". In my example, we'll use an InputText widget with the name "tenure_years" to modify a key-value store value of the same name: https://gist.github.com/1023061 <?php class MyForm extends BaseDoctrineForm { public function setup() { //tenure_years, integer $this->widgetSchema['tenure_years'] = new sfWidgetFormInputText(); $this->validatorSchema['tenure_years'] = new sfValidatorInteger(array('required' => false)); } /** * @see KeyValueStoreForm */ protected function getObjectKeyValueStoreValues() { $values = array(); $values['tenure_years'] = $this->getObject()->aGet('tenure_years'); return $values; } /** * @see KeyValueStoreForm */ protected function updateObjectKeyValueStoreValues(array $values) { $this->getObject()->aSet('tenure_years', $values['tenure_years']); } } Notice our widgets are created exactly as they would be using any other form. Each of your forms using a key-value store object must overriding getObjectKeyValueStoreValues() and tell the form how to map the key-value store value to the form widget. This will take key-value store values and populate the form widgets with default values. Each of your forms using a key-value store object must also override updateObjectKeyValueStoreValues(). This does the opposite of the above method, and maps your form widget values to the key-value store after the form is submitted and validated. That's it! Fairly painless. Enjoy! John Kary On Thursday, June 2, 2011 at 6:26 AM, Tom Boutell wrote: > Sounds like you'll be overriding the form's updateObject() method to > deal with your custom form fields by calling aSet and aGet on the > object. > > On Wed, Jun 1, 2011 at 11:38 PM, John Kary <johnk...@gmail.com > (mailto:johnk...@gmail.com)> wrote: > > I are doing a project where we our client runs ~15 competitions each > > year, but the application form the user is required to fill out for > > each form vary in the exact fields/questions they ask. And of course, > > they run these same competitions year-after-year, but often add or > > remove a custom field or two. > > > > About half of the fields across all applications are common (Name, > > Email, Address, Phone, etc.) but they also ask different questions on > > each form that vary from simple integer values, to boolean (yes/no) > > values, to several paragraphs of freeform text. > > > > So I created a basic Application model, then am using Doctrine's > > column-aggregate inheritance to create each concrete Application > > class. Here's my abbreviated schema: > > > > Application: > > actAs: > > KeyValueStore: ~ > > columns: > > id: > > type: integer > > primary: true > > autoincrement: true > > full_name: > > type: string(255) > > email: > > type: string(255) > > office_address: > > type: string(255) > > home_address: > > type: string(255) > > telephone: > > type: string(25) > > > > IronManApplication2011: > > inheritance: > > extends: Application > > type: column_aggregation > > keyField: object_type > > keyValue: iron_man2011 > > > > So I came across Tom Boutell/P'unk Ave's plugin > > sfDoctrineActAsKeyValueStorePlugin. It allows you to persist any > > number of varying key => value pairs with your Doctrine object. It > > serializes the various key/value pairs and throws them into a blob > > field. Perfect! I can create my base Application form and create a > > concrete form for each custom Application object. > > > > Since I never ORDER BY or query against these values, I figure this > > approach will work for me. This isn't a high performant site, so a > > slight hit during serialization/unserialization will be OK. > > > > You can read more about the plugin here: > > http://trac.apostrophenow.org/wiki/sfDoctrineActAsKeyValueStorePlugin > > > > Now has anyone used this plugin and taken form fields and stored them > > as the key/value pairs? It would be great if the form fields could > > auto-save onto the object, and auto-repopulate the form fields when > > passing the object into the form constructor. I feel like there will > > be some form save() overriding in my future? > > > > Thanks to anyone who has any ideas! > > > > John Kary > > > > -- > Tom Boutell > P'unk Avenue > 215 755 1330 > punkave.com (http://punkave.com) > window.punkave.com (http://window.punkave.com) -- If you want to report a vulnerability issue on symfony, please send it to security at symfony-project.com You received this message because you are subscribed to the Google Groups "symfony users" group. To post to this group, send email to symfony-users@googlegroups.com To unsubscribe from this group, send email to symfony-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/symfony-users?hl=en