Expanding forms with symfony 1.2 and Doctrine
I recently started learning how to use the forms system in symfony 1.2 and for the most part I was impressed with its simplicity and flexibility. Unfortunately I was thrown in the deep end somewhat when a project I was working on had a requirement for an “expanding” form – that is, one where a certain section of a form should be able to be repeated as many times as necessary to accommodate the user’s needs.
In the case of the project in question, the specific situation was an application form where the user could fill out any number of team members involved in their project. Each team member consisted of a name and a role, both free-form text fields. Team members were to be stored in the database, linked to the application in a one to many relationship.
Circumstances conspired that this must be achieved in a single form, so full of confidence in symfony’s design decisions regarding the forms system, a bit of light Googling revealed the answer – symfony’s embedded forms system. Great, so you just plonk in a few embedded forms and away you go, right? Wrong.
The good news is, I managed to find a solution that satisfied the requirements, eventually. The bad news is that it is not easy, elegant, or particularly reusable.
What follows is a loose guide to implementing such a system. Being a relative newcomer to symfony I cannot guarantee that this is the best way to do things, so tread with caution, and if you think of a better way to achieve the same outcome, please please let me know! Read on if you dare…
Introduction
I’m going to assume the following in this guide:
- You have a solid working knowledge of symfony, PHP and Doctrine.
- You have a blank symfony 1.2 project, set up to use Doctrine rather than Propel (although I’m sure the same could be achieved with Propel with a bit of tweaking).
- You have the symfony executable in your system path or in the root of your project.
- You are using a relational database such as MySQL to store your data.
- You have entered your database connection details into your config/databases.yml file and set up all the appropriate database permissions.
- You have completed any web server setup as required to access the project.
- You are aware that you need to clear the symfony cache (by running
symfony cc) when new classes are created and when configuration changes are made.
I’m also going to move fairly quickly as there is a lot to cover, so please feel free to ask for any clarification in the comments and I will update as necessary.
For help with installing and setting up symfony 1.2, check out Getting started with symfony. I chose to use Doctrine 1.1 for this tutorial, however the version that comes with symfony should also be fine. For instructions on upgrading to Doctrine 1.1 see Using Doctrine 1.1 with Symfony 1.2.
You can also see a live demo and get an idea of what we are trying to achieve by visiting http://expandingform.sf.ezzatron.com/.
Step 1: Setting up
Here is the Doctrine schema we will be using. I went for something a bit more cheery than the above situation, namely bands and band members:
columns:
name:
type: string(200)
notnull: true
notblank: true
formed: date
BandMember:
columns:
band_id:
type: integer
notnull: true
name:
type: string(200)
notnull: true
notblank: true
role: string(200)
relations:
Band:
foreignAlias: Members
onUpdate: cascade
onDelete: cascade
Place this in your config/doctrine/schema.yml file, and then create a data fixture so we have some test data to work with:
hnd:
name: Hesitate & Die
formed: '2006-06-06'
BandMember:
andrew:
name: Andrew
role: Guitar
Band: hnd
erin:
name: Erin
role: Bass
Band: hnd
richie:
name: Richie
role: Vocals
Band: hnd
rowan:
name: Rowan
role: Drums
Band: hnd
Place the above in data/fixtures/fixtures.yml and run:
This will generate all the model classes and forms we will need, create the database, and populate it with some test data for us. Next we need to create an application, and we’ll use the standard symfony app name “frontend”:
Replacing “randomstring” with whatever you like. Now let’s generate a module from our model classes as a base to start from:
Now if you visit http://<project url>/frontend_dev.php/band/edit/id/1 you should be presented with the following:

We now have a basic form for entering band details. Thus concludes step 1. Moving on to…
Step 2: Building the form
OK let’s dive right in. We are going to embed forms for editing band members inside of the band form itself. To add a single member form you would simply add:
to our lib/form/doctrine/BandForm.class.php‘s configure() method. But what we want is to structure the form in such a way that the form data, when posted to the update action, will contain an array of band members. The way to do so in the symfony forms system is to wrap the embedded forms in another form, then embed this wrapper form itself into the main form. Confused? Don’t worry, everything will become clearer once we actually create the forms.
Firstly, we need to make a small modification to the band member form to allow it to slot into our band form better. The generated form includes a field for the related band ID, which we will not need as all band members will relate to the band represented in the parent band form.
We could modify the BandMemberForm class itself, but it’s possible we may want to use the form outside of a band context, so let’s harness the power of the forms system and extend the form instead. Create a file at lib/form/doctrine/EmbeddedBandMemberForm.class.php with the following class definition (PHP opening tag excluded for brevity):
{
public function configure()
{
parent::configure();
unset($this['band_id']);
}
}
Next, let’s create the “container” form. Create a file at lib/form/doctrine/BandMembersForm.class.php containing the following class:
{
public function configure()
{
for ($i = 0; $i < 3; $i ++)
{
$this->embedForm($i, new EmbeddedBandMemberForm());
}
}
}
This creates three blank forms for inputting band members. Now to actually embed the container form into our main band form, it’s actually very simple. Simply edit lib/form/doctrine/BandForm.class.php so that it looks like the following:
{
public function configure()
{
$this->embedForm('members', new BandMembersForm());
}
}
Now when we reload our band form (did you remember to clear your cache?), we will see the following:

Looks promising, and that wasn’t too painful so far, right?
There next obvious step would be displaying the existing band members. We want to be able to see and edit the existing band members and still have the option of inputting new members also. To do this we need to pass the Band object to our container form so that it can access the existing members. Let’s update the container form so that it looks like:
{
protected $band;
public function __construct(Band $band)
{
$this->band = $band;
parent::__construct();
}
public function configure()
{
$i = 0;
foreach ($this->band->Members as $member)
{
$this->embedForm($i, new EmbeddedBandMemberForm($member));
$i ++;
}
for ($j = $i; $j < $i + 3; $j ++)
{
$this->embedForm($j, new EmbeddedBandMemberForm());
}
}
}
Now we have to change the main form so that we pass the Band object when we instantiate the container form:
{
public function configure()
{
$this->embedForm('members', new BandMembersForm($this->object));
}
}
Reloading the form should now show the existing members:

So now we have a form that can display the band with all of its members and still provide room for new ones. Time for the next step.
Step 3: Getting the form to save
Try saving the form without making any changes to the data. You should get validation errors because the band member name is a required field:

This won’t do at all because we want to be able to leave a band member blank and have the system ignore it. We also want to be able to delete an existing member by clearing their name and role. So let’s remove the requirement for now, and we’ll add it back in later. Edit your EmbeddedBandMemberForm class so that it looks like this:
{
public function configure()
{
parent::configure();
unset($this['band_id']);
$this->validatorSchema['name']->setOption('required', false);
}
}
Now when we try to save the form again, we get an exception thrown:

As you can see, Doctrine is not happy with us, but why? The answer is that symfony is trying to create new band members from the blank band member forms, but it has no idea which band the new members should belong to. We’ll deal with this issue shortly, but in the meantime let’s start by making symfony ignore any band member forms which are left blank.
Firstly, how do we decide if a band member form is “blank”? Let’s write a couple of custom methods in our form classes. Some of this functionality is reusable, so we’ll place the main body of the code in lib/form/doctrine/BaseFormDoctrine.class.php which is the base class for all of our generated forms:
{
public static function _formValuesAreBlank(array $fieldNames, array $values)
{
foreach ($fieldNames as $fieldName)
{
if (isset($values[$fieldName]) && !self::formValueIsBlank($values[$fieldName])) return false;
}
return true;
}
public static function formValueIsBlank($value)
{
if (is_array($value))
{
foreach ($value as $subValue)
{
if (!self::formValueIsBlank($subValue)) return false;
}
return true;
}
return $value ? false : true;
}
}
These two methods essentially traverse an array recursively looking for any non-blank values, and returns false as soon as one is found. The method needs to be recursive because some fields like dates are passed as an array. Now we can write a simple method in our EmbeddedBandMemberForm class to check whether the fields that constitute a band member have been filled out:
{
// ...
public static function formValuesAreBlank(array $values)
{
$fieldNames = array_diff(Doctrine::getTable('BandMember')->getFieldNames(), array(
'id',
'band_id',
));
return parent::_formValuesAreBlank($fieldNames, $values);
}
}
We are simply grabbing the field names directly from our model class, and excluding the ones we don’t care about. This is more robust that explicitly specifying name and role as the important fields, as it allows for further fields to be added to the band member form as requirements change.
Now we need to actually change the way the form is processed by overriding some methods in our main band form:
{
// ...
public function updateObjectEmbeddedForms($values, $forms = null)
{
if (is_array($forms))
{
foreach ($forms as $key => $form)
{
if ($form instanceof EmbeddedBandMemberForm)
{
$formValues = isset($values[$key]) ? $values[$key] : array();
if (EmbeddedBandMemberForm::formValuesAreBlank($formValues)) unset($forms[$key]);
}
}
}
return parent::updateObjectEmbeddedForms($values, $forms);
}
public function saveEmbeddedForms($con = null, $forms = null)
{
if (is_array($forms))
{
foreach ($forms as $key => $form)
{
if ($form instanceof EmbeddedBandMemberForm)
{
if (!$form->getObject()->isModified()) unset($forms[$key]);
}
}
}
return parent::saveEmbeddedForms($con, $forms);
}
}
These methods doubtless require some explanation. Firstly let’s look at updateObjectEmbeddedForms(). This method uses the custom method we wrote to check whether the band members passed to the form for processing are blank. If a blank band member is encountered, the related form is removed from the forms array to prevent symfony from attempting to update the related band member object.
The next method, saveEmbeddedForms() works in tandem with the above. It runs through each of the forms and checks whether the related object has been modified. If an unmodified object is encountered, the related form is once again removed from the forms array to prevent symfony from attempting to save an unmodified object.
OK so now we should be able to save our form without any validation warnings or exceptions cropping up. If you can’t, it’s probably time to double check everything, and perhaps clear your cache. On to the next step…
Step 4: Adding and deleting members
Our form now saves without errors, but what does it actually do? Not much at the moment. Let’s try adding another band member. Ladies and gentlemen, may I present Steven on second guitar!:

What happens when we save the form? Ah, it seems we have the same issue we encountered before:

As we found out in the previous step, this is caused by symfony not knowing to link our new band member to the band we are editing. We can fix this by making a simple change to our BandForm class, in the saveEmbeddedForms() method:
{
// ...
public function saveEmbeddedForms($con = null, $forms = null)
{
if (is_array($forms))
{
foreach ($forms as $key => $form)
{
if ($form instanceof EmbeddedBandMemberForm)
{
if ($form->getObject()->isModified())
{
$form->getObject()->Band = $this->object;
}
else
{
unset($forms[$key]);
}
}
}
}
return parent::saveEmbeddedForms($con, $forms);
}
}
Now when we try again, the new member is saved correctly and appears in the list of band members as expected:

Awesome! We now have 2 guitarists and all the glory that comes with duelling guitar solos. But wait; oh no! Steven has decided to get married and move to Norway! Well, it’s time to remove him from the band I guess, so let’s try setting his name and role to blank and see what happens when we save…
Oh dear, it seems Steven is not keen on leaving without a fight. He still appears in the list of band members. So what’s happening here? In short, we simply haven’t told Doctrine to dispose of the unwanted band member yet! Let’s go ahead and do that now by modifying the BandForm class’ updateObjectEmbeddedForms() method:
{
// ...
public function updateObjectEmbeddedForms($values, $forms = null)
{
if (is_array($forms))
{
foreach ($forms as $key => $form)
{
if ($form instanceof EmbeddedBandMemberForm)
{
$formValues = isset($values[$key]) ? $values[$key] : array();
if (EmbeddedBandMemberForm::formValuesAreBlank($formValues))
{
if ($id = $form->getObject()->getId())
{
$this->object->unlink('Members', $id);
$form->getObject()->delete();
}
unset($forms[$key]);
}
}
}
}
return parent::updateObjectEmbeddedForms($values, $forms);
}
// ...
}
Now we can try again to delete Steven, and it seems to have worked:

So now we have a fully functional form, which is great! But there are some important things we still need to consider, which leads us to the next step…
Step 5: Validation
That’s right, you forgot, didn’t you? Back in step 3 we disabled important validation for the band member form, which means, for example, if you try to enter a band member with a role but no name, you get this nasty validation exception:

NOTE: You may find that you do not encounter this exception, there seems to be a bug somewhere where the “notblank” validator we specified in the schema is being ignored. Nevertheless, we still need to prevent blank names from being entered.
We can’t leave things as they stand, so let’s create a custom wrapper for the validator schema that we can use to validate band members that have not been left blank. Create a file at lib/validator/EmbeddedBandMemberValidatorSchema.class.php and enter this class definition:
{
protected $validatorSchema;
public function __construct(sfValidatorSchema $validatorSchema)
{
$this->validatorSchema = $validatorSchema;
parent::__construct();
}
public function doClean($values)
{
if (!EmbeddedBandMemberForm::formValuesAreBlank($values))
{
return $this->validatorSchema->doClean($values);
}
return $values;
}
}
All this class does is check whether the passed values are considered “blank” before applying the existing validation rules. This increases robustness by allowing us to keep all of the validation rules defined in the BandMemberForm class, and freeing us from having to duplicate their logic in the EmbeddedBandMemberForm class.
Now it’s simply a matter of making a small change to the EmbeddedBandMemberForm class’ configure() method to allow us to take advantage of our new wrapper class:
{
public function configure()
{
parent::configure();
unset($this['band_id']);
$this->validatorSchema = new EmbeddedBandMemberValidatorSchema($this->validatorSchema);
}
// ...
}
With those changes made, we can try again to save a band member with only a role and this time we are presented with the appropriate form errors:

OK, that’s validation taken care of, let’s make some usability improvements.
Step 6: Usability
We’re going to add extra functionality to our form for users with JavaScript support, namely the ability to add additional spaces for band members without the need to save the form. What’s more we’re going to do it without preventing non-JavaScript enabled users from using the form. This is known as progressive enhancement and is generally considered a best-practice in web development.
The first thing we need to do is set up an action to render the additional band member forms so that we can fetch them via an AJAX call. Open up your apps/frontend/modules/band/actions/actions.class.php file and add the following method:
{
// ...
public function executeMemberForm(sfWebRequest $request)
{
$this->forward404Unless($request->isXmlHttpRequest());
$count = $request->getParameter('count', 0);
$form = new BandForm();
$form->setNumMembers($count + 1);
$this->member = $form['members'][$count];
$this->setLayout(false);
}
}
The template for this action is very simple. Create a file at apps/frontend/modules/band/templates/memberFormSuccess.php with the following contents:
You may have noticed the call to BandForm::setNumMembers() in the above action. We still need to add this method, so let’s do that now. Edit your BandForm class and add the following method definition:
{
// ...
public function setNumMembers($numMembers)
{
$this->embedForm('members', new BandMembersForm($this->object, $numMembers));
}
}
This in turn means a change to the BandMembersForm class, which should be edited to look like this:
{
protected $band;
protected $count;
public function __construct(Band $band, $count = null)
{
$this->band = $band;
$this->count = $count;
parent::__construct();
}
public function configure()
{
$i = 0;
foreach ($this->band->Members as $member)
{
$this->embedForm($i, new EmbeddedBandMemberForm($member));
$i ++;
}
$count = max($i + 3, $this->count);
for ($j = $i; $j < $count; $j ++)
{
$this->embedForm($j, new EmbeddedBandMemberForm());
}
}
}
What the above changes do are allow us to insert extra blank band members as we please. We then use this to recreate the “extra” band member form exactly as it would appear if it were rendered as part of the whole form.
All that is left to do is create the AJAX handler and some unobtrusive JavaScript to fetch and insert the new member form. Open apps/frontend/modules/band/templates/_form.php and update the contents to the following:
<?php include_stylesheets_for_form($form) ?>
<?php include_javascripts_for_form($form) ?>
<form action="<?php echo url_for('band/'.($form->getObject()->isNew() ? 'create' : 'update').(!$form->getObject()->isNew() ? '?id='.$form->getObject()->getId() : '')) ?>" method="post" <?php $form->isMultipart() and print 'enctype="multipart/form-data" ' ?>>
<?php if (!$form->getObject()->isNew()): ?>
<input type="hidden" name="sf_method" value="put" />
<?php endif; ?>
<table id="band">
<tfoot>
<tr>
<td colspan="2">
<noscript><p>
<strong>NOTE:</strong> To add more members, please save this form, and more spaces will be presented.
</p></noscript>
<a href="<?php echo url_for('band/index') ?>">Cancel</a>
<?php if (!$form->getObject()->isNew()): ?>
<?php echo link_to('Delete', 'band/delete?id='.$form->getObject()->getId(), array('method' => 'delete', 'confirm' => 'Are you sure?')) ?>
<?php endif; ?>
<input type="submit" value="Save" />
</td>
</tr>
</tfoot>
<tbody>
<?php echo $form ?>
</tbody>
</table>
</form>
<?php echo javascript_tag() ?>
$$('#band table').each(function(e)
{
if (e.select('table').length)
{
e.select('tbody')[0].id = 'band_members';
e.insert('<?php echo escape_javascript("
<tfoot><tr><td colspan=\"2\">".
button_to_remote('Add member', array(
'url' => 'band/memberForm',
'with' => "'count='+$$('#band_members table').length",
'update' => 'band_members',
'position' => 'bottom',
))
."</td></tr></tfoot>
") ?>');
}
});
<?php end_javascript_tag() ?>
It’s important to note that this code is somewhat ugly because I wanted to avoid manually changing the form’s layout. In a production situation you could implement a much more elegant solution by customising the form layout or writing a custom form renderer.
This point aside, your form should now look like the image below when JavaScript is enabled (when JavaScript is disabled a message will be displayed informing the user of how to add additional members):

We’re now able to add additional slots for new members dynamically using the “Add member” button. We’re facing one last hurdle unfortunately; when we add a new member slot and hit the save button we’re presented with a form error:

Thankfully this is fairly easy to remedy. The issue is that when the update action handles the posted data, it creates a fresh instance of BandForm which has no knowledge of our “extra” band member form. To fix this we can override the BandForm class’ bind() method to detect the number of band members passed and expand the form as needed:
{
// ...
public function bind(array $taintedValues = null, array $taintedFiles = null)
{
if (isset($taintedValues['members']) && is_array($taintedValues['members']))
{
$this->setNumMembers(count($taintedValues['members']));
}
return parent::bind($taintedValues, $taintedFiles);
}
}
And hey presto, our form now works perfectly!
Conclusion
If you got this far I’m sure you’ll agree that this was not by any means an easy exercise. The symfony forms system is powerful and flexible, but it seems like perhaps this type of situation was not really brought into consideration when it was designed. I would love to see the symfony architects consider ways that the implementation of expanding forms could be simplified, or at least better documented.
Once again if you have any suggestions on how to improve this implementation I’d really love to hear them. I’m sure there are aspects of the symfony forms system that I don’t understand fully which could make this whole exercise somewhat simpler, and that would certainly be valuable knowledge.
If you are interested, there is a guide to implementing a similar system here, however it seems to deal with the symfony admin generator specifically, and it also seems to have the disadvantage that the parent object must exist before child objects can be added.
Good luck with your own implementations, let me know how they go!
Source code
30 Comments »
RSS feed for comments on this post. TrackBack URL

Hi. Sorry for not answering before! I like this post, very comprehensive, going step by step and explaining everything. Good job!
Thanks, although I wish I had found your article before I started. It would have saved a lot of time!
[...] See also this post and this one about this [...]
Thank you for this! The bit in step 6 to address the “unexpected extra form field” issue is particularly helpful to me. In retrospect, it makes perfect sense, of course. Such is the process of learning how the Symfony framework works.
No worries, it’s good to know that someone actually found this useful!
Excellent and useful, thanks! One remark and a question:
– now with a “Ajax” button is existing to dynamically add member fields, It would be more nice not to have three empty fields in edition mode (except of course for the very first time, useful for band creation);
– question: what about pre-existing members (a man playing in several bands, at the same time, or to manage band history) ? How do you think it can be developped? Of course, the doctrine base schema must be updated (not difficult), but how to code an ergonomic form? allowing in a new band to add new members or to link existing ones… It seems to me to be usual need in middlesize bases… I have some ideas about possible GUI (for instance entering name pattern, searching in base (ajax), then propose the list of matching entries or propose to create a new one) but how to develop such a form?
Symfony is marvellous to create forms in a very fast way, but (like others framework I suppose) seems to became a nightmare to more complex (but usual) use case, like previous case or to develop something like a “wizard”…
The first point is easily fixed, you just need to write some JavaScript to remove the existing empty band members at the same time as you add the button. I’ve written some JavaScript to do this and left it commented out in the example at (http://expandingform.sf.ezzatron.com/). Just view the page source if you want to see how I did it.
I actually chose not to do this though, because most bands would have more than one member, and all that removing the empty forms does is force users with JavaScript to click the button extra times. Even with JavaScript enabled the empty forms are ignored so perhaps re-think whether you really want to do this?
The second point is a bit trickier. In general I’ve found, with symfony especially, you want to follow the KISS (Keep It Simple Stupid) principle as much as possible. Perhaps to start with you could get the user to create “musicians” first, with no band information, and then only present *existing* musicians in the band form? This makes things much, much simpler – you probably wouldn’t even need JavaScript at all. Then once this is working OK, perhaps add the option to create a new musician in the band form also.
If you really can’t avoid doing it the hard way, personally I would do the following:
* Add a separate multiple select field with options for all the existing band members that aren’t already in the band. This will work for users without JavaScript.
* When JavaScript is enabled, hide the above field and replace it with an autocomplete text field, a button for adding members, and a display area.
* You can probably use the sfFormExtraPlugin (http://www.symfony-project.org/plugins/sfFormExtraPlugin) to turn the text field into an autocomplete field.
* When a band member is selected using the above, find their ID in the hidden select field and set it to selected, then create some kind of display for the band member in the display area I mentioned in the second point.
* This band member display should also include an option to remove the band member, and you would need to write some JavaScript to un-select the appropriate ID in the hidden select field and remove the band member display when finished.
Thanks for your response.
A solution (to use existing entry or to create a new one in the same time) is proposed by Thibault Jouannic (Miximum blog), here : http://www.miximum.fr/tutos/466-symfony-form-pick-or-create
Hello. Excellent Post.
I want to know what changes I make in the code to work in propel?,
I mean the embedded form. to step 5
and what version of symfony it all work?
—-
Hola. excelente Post.
quisiera saber que cambios debo hacer en el código para funcione en propel?,
me refiero al formulario embebido. hasta el paso 5
y para que versión de symfony funciona todo esto?
Thanks for the comment, unfortunately I don’t have enough time at the moment to go through the whole thing in Propel, but if you know how to write a schema for Propel the changes would probably be very minor. Perhaps you could give it a go, and if you get stuck I can help you?
Theoretically, this would work for any version of symfony greater than 1.1, because that’s when the new forms system was first implemented, but I don’t know for sure, there might be some features I’ve used that didn’t exist till symfony 1.2. In any case, I used 1.2 for the example above.
If you are just starting a new project, I highly recommend you use Doctrine anyway, from symfony 1.3 onwards it is the default ORM.
Thanks for posting this very detailed tutorial. You could better implement disregarding blank values by writing a custom validator for your form.
The “More With Symfony 1.3 & 1.4″ book gives an advanced/embedding forms tutorial, very similar to what you showed here, that you and anyone who reads this will find useful: http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms
Thank you! That link looks very interesting and I will definitely read through when I have some time and make updates to this article. The embedRelation() method introduced in 1.3 looks very promising also.
If you have the patience, could you explain your custom validator idea to me in more detail? I’d love to implement it if it works well for this situation.
Hello, thank you very much for the tutorial!!!
Y followed the steps but I couldn’t show the ‘Add member’ button. There is no errors (I have installed sfProtoculousPlugin correctly).
The page code, in Firefox, contains the javascript code, almost the same as in http://expandingform.sf.ezzatron.com/, I said that because the code presented in the tutorial don’t produce the same page that http://expandingform.sf.ezzatron.com/, there are similars.
I have javascript enabled, thats why I can use http://expandingform.sf.ezzatron.com/.
Could you help me please to solve the problem?
Maybe you can send me the code of your demostration page.
Thanks in advance.
Guillermo
Did you try the source code at the end of the article?
There are links to the full source code of every file that I edited in the tutorial at the very bottom of the article, just before the comments.
That source code is not 100% the same as http://expandingform.sf.ezzatron.com/ but it does work, and it should help you figure out where the problem is.
Hello Erin!!
Yes I have tried with the code at the bottom of the tutorial.
The problem was that I didn’t write in my /templates/layout.php file. Now I have my functional page!!
Sorry about that, but I am very new in web development and last night I was very tired
Thank you very much Erin!!
Guillermo
Wonderful tutorial even for a symfony beginner. Learn a lot here. Many thanks.
Hello, how are you?
Again me
I want to save the number of members into the Band table. To do that, inmediately before save the band, I need to know the number of members will be saved.
I cannot obtaing the new number. I override the save method of Band class, to recover the members but I recover he old members. I did a new method that access to database, and it doesn’t work.
Could you give some hints to try to solve the problem?
Thanks a lot!!
Guillermo
Hello!!
I have solved the problem!!
In BandForm, I have declared a protected variable, I update it in updateObjectEmbeddedForms method (count non blanks members), and finally I have overrided updateObject method to update the number of members of the band.
Actually, I am using my own project but this solution is able to use with Band and Members.
Thanks a lot!!
Guillermo
Hi,
Thanks for this good tuto. But I tried to use it to add dynamic fields in my form but when I click on the “Save” Button, nothing happen. The Web Page is reloaded but there is no data saved into my database.
I compare all my files with your tutorial and they are extactly the same (except name of classes).
Could you please help me. And explain to me why data are not saved ?
Best regards.
Ok. I found. The problem was my table was timestample and i forgot $this->useFields() call in my main Form to precise only fields I wan’t use and let symfony manage other field itself.
very helpful reference.. thank you!!
Hi,
Thank’s for your tutorial, it helped me a lot!! I used it for multi upload, with two tables ‘message’ and ‘file’. But I have a problem using ajax at the end of the tutorial. The button doesn’t appear. There is an error in the source code:
”
$$(‘#message table’).each(function(e)
{
if (e.select(‘table’).length)
{
e.select(‘tbody’)[0].id = ‘fichiers’;
e.insert(‘
Fatal error: Call to undefined function button_to_remote() in C:\development\sfprojects\voice_forum\apps\forum\modules\message\templates\_form.php on line 50
I hope you will help me finding my error… and sorry for my bad english ^^
I think you might be missing:
< ?php use_helper('Javascript') ?>
at the top of your template. This line includes some helper functions for JavaScript and AJAX operations, like button_to_remote() and link_to_remote().
Remember that you can grab the full source code for each file at the bottom of the tutorial and compare it to your own. That’s probably the quickest way to find the problem.
Good luck!
I thank you very much for this tutorial well explained.
I followed all the steps but I couldn’t show the ‘Add member’ button. There is no errors.
knowing that I have made in the tempalte _form.php, and I added all the functions missed in my JavascriptBaseHttp.php
Could you help me please !
I want to say that i had already call the helper “use_helper(‘JavascriptBase’)” in my tempalte _form.php
Sorry, I don’t think I understand the problem you’re having.
As a first step, please try downloading the source code at the bottom of the article and (very carefully) comparing it to your own. It’s likely that you are just missing something simple.
Having said that, you should probably be using the ‘Javascript’ helper, not the ‘JavascriptBase’ helper.
Also, I’m not sure what ‘JavascriptBaseHttp.php’ is supposed to be. If you are trying to create a custom helper, it needs to end in ‘Helper.php’ and be placed in your ‘lib/helper’ directory, but really, you should just be using the standard ‘Javascript’ helper, not writing a custom one.
Are you using the development environment for testing? Make sure you are, otherwise you might be missing some important error messages.
Hope this helps.
First I thank you a lot for your quick answer, and I’m really sorry for my English, I try to do my best.
I already test your code, and my own problem is that the button “add member” in invisible in my form”
Whene I use the ‘Javascript’ helper, it generate the following error : “Unable to load “JavascriptHelper.php” helper in: SF_ROOT_DIR\apps\frontend\modules/band/lib/helper, SF_ROOT_DIR\apps\frontend\lib/helper, SF_ROOT_DIR\lib/helper, SF_ROOT_DIR\lib\symfony\lib/helper.”
I added all the functions missed in my JavascriptBaseHelper.php from this link http://trac.symfony-project.org/browser/branches/1.0/lib/helper/JavascriptHelper.php because they aren’t all in my JavascriptBaseHelper
I’m using WAMP SERVER to test my PHP pages and I’m using symfony 1.4
That is very strange.
First of all, the Javascript helper is not something you add to symfony manually, it is a core helper which already exists when you install symfony.
Secondly, this tutorial is for symfony 1.2 only. I have not checked this against symfony 1.4 and I don’t have the time to do that properly at the moment.
Thirdly, that link is for the Javascript helper for symfony 1.0, which is very old and probably not compatible with the version you are using.
I think there is something very wrong with your symfony setup. For that reason, and since (I assume) you are quite new to symfony, I suggest you use this tutorial to help you set up symfony correctly first:
http://www.symfony-project.org/getting-started/1_2/en/
It’s available in a number of languages, hopefully you’ll find your native language in the list, which should make it easier.
Once you have done this, just create a simple action to test that you can load the Javascript helper. If that works, then perhaps try this tutorial.
Good luck!
Thank you very much, I’ll follow your advice
nice tutorial… made it work with 1.4… thx a lot