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

Reply via email to