Symfony 1.2 added a lot of new and exciting new features to an already great and powerful PHP framework. One of those features is the ability to embed a form into another. So what excatly does this mean?
First consider the model shown in the diagram below:

As shown in the above figure, there is a one-to-one relationship between the company and the contact model.
Here is the schema.yml:
propel:
_attributes:
package: lib.model
defaultIdMethod: native
company:
_attributes: { phpName: Company }
id: { type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
name: { type: VARCHAR, size: '255', required: true }
contact_id: { type: INTEGER, size: '11', required: false, foreignTable: contact, foreignReference: id, onDelete: SET NULL, onUpdate: RESTRICT }
_indexes: { company_FI_1: [contact_id] }
contact:
_attributes: { phpName: Contact }
id: { type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
first_name: { type: VARCHAR, size: '255', required: true }
last_name: { type: VARCHAR, size: '255', required: true }
company_id: { type: INTEGER, size: '11', required: false, foreignTable: company, foreignReference: id, onDelete: SET NULL, onUpdate: RESTRICT }
_indexes: { contact_FI_1: [company_id] }
Note that both foriegn keys are not required, that is a must for us to be able to embed the Contact form in the Company form.
Now that we have the schema ready, let us build the sql schema, models, forms, filters, and create the tables.
$ php symfony propel:build-sql $ php symfony propel:build-model $ php symfony propel:build-forms $ php symfony propel:build-filters $ php symfony propel:insert-sql --env=dev
Now let us generate a module using symfony’s admin generator and see how the generator will handle this relationship.
$ php symfony propel:generate-admin backend Company
By browsing to the category module we just created above we can see the below figure:

Now if we click on the “New” link we get the following screen:

Notice that the “contact_id” foreign column was interpreted by the admin generator as a drop down list. Of course that is not what we had in mind, we want to be able to add a new “Company” along with it’s “Contact”. Thanks to symfony 1.2 ability to embed forms, this can be done very easily.
First open “CompanyForm.class.php” file and edit the configure method to match the following:
public function configure() {
// get Contact model object
$contact = $this->getObject()->getContact();
// contact object is null
if (is_null($contact)) {
// create a new Contact object
$contact = new Contact();
// set the copmany of the newly created object to the current company
$contact->setCompany($this->getObject());
// set the contact of the current company
$this->getObject()->setContact($contact);
}
// create a new contact form
$contact_form = new ContactForm($contact);
// embed the contact form in the current company form
$this->embedForm('contact', $contact_form);
// remove the contact_id from the form
unset($this['contact_id']);
}
Next, open the ContactForm.class.php and edit as follows:
public function configure() {
unset($this['company_id']);
}
Now modify the Company.php model class to delete the contact while delete the company
public function delete(PropelPDO $con = null) {
$this->getContact()->delete($con);
parent::delete($con);
}
And last but not least, edit the generator.yml to match the following(this step is optional):
generator:
class: sfPropelGenerator
param:
model_class: Company
theme: admin
non_verbose_templates: true
with_show: false
singular: ~
plural: ~
route_prefix: company
with_propel_route: 1
config:
actions: ~
fields:
contact_id: { label: Company Contact }
list:
display: [=name, contact]
filter: ~
form: ~
edit: ~
new: ~
Now go to the add new “Company” screen and you should see the following:

Try adding, editing, and deleting some records now to make sure it’s working.


Comments So Far » (21 Comments). Add Yours
1. forganna
21 December, 2008
easyyy
hope keeping us up to date always using this easy explanation
2. Hebatollah Moaz
21 December, 2008
thanks for the article i find it easy to get and very helpfull…
3. NiKo
21 December, 2008
Nice tuto, kudos
4. jukea
22 December, 2008
great! but now, let’s do the same for a 1 to many relation … : My companies have many contacts, so that would be better for me!
5. Ahmed El.Hussaini
22 December, 2008
@jukea: The one-to-many relationship will automatically be implmemented by symfony’s admin generator in the form of a select many form elemeny. If you’d like more options, try reading this article
6. jukea
06 January, 2009
@ahmed : yes, but I’m more looking into something like in-place editing of contacts inside a company, like :
http://redotheoffice.com/?p=42
7. Ahmed El.Hussaini
07 January, 2009
@jukea: I see, I’ll look into it and update the article ASAP.
8. Gopal
23 January, 2009
thanks for the article i find it easy to get and very help full me …
9. Ahmed El.Hussaini
23 January, 2009
@Gopal: You’re most welcome, I’m glad that I can help. By he way if you need any help regarding symfony please don’t hesitate in contacting me.
10. John
23 January, 2009
Hi,
This is great and has helped me a lot, however I’m having one issue…
This line:
# // get Contact model object
# $contact = $this->getObject()->getContact();
Modified to call the model object I want, fails with the error Call to undefined method BaseCompany::getContact (I’ve modified names back to suit your example rather than my own code)…
If I just comment it out and the if structure following, leaving everything else, the form displays fine, validates, submits etc, but when you bring it back up, it can’t populate the embedded form with the data to math the parent form, presumably because the above, which I’ve commented out, is what controls this.
So how can you get it to call on a model outside of itself (ie call the Contact model from the Company model) when you’re using $this?? (There is probably just something I am missing / don’t understand :))
Thanks,
JM
11. John
23 January, 2009
Sorry I should add I am using it in a non admin-generated frontend, but I don’t believe for this problem it makes a difference?
12. Ahmed El.Hussaini
23 January, 2009
@John: I’m not quite sure what the problem is, but I think it has to to with your MySQL tables, are they MYISAM or InnoDB?
13. John
24 January, 2009
@Ahmed El.Hussaini: I had the model wrong, no foreign key from the main table to the ‘child’ table I wanted to embed… I thought I could do it without this (just a link back the other way) but obviously not! Thanks
14. roland
28 January, 2009
snip
Note that both foriegn keys are not required, that is a must for us to be able to embed the Contact form in the Company form.
/snip
should that be “foreign keys *are* required”?
15. Joao Correia
02 February, 2009
Hello !
Very nice tutorial. Hey by the way, can you give any tips on managing many-to-many relations on admin generator ?
I have
Portfolio
Tags
portfolio_tags
and want to manage the tags associated inside my portfolio form.
Thanks
Joao
16. Ahmed El.Hussaini
03 February, 2009
@Joao: Thanks, try this: http://www.symfony-project.org/blog/2008/10/14/new-in-symfony-1-2-make-your-choice
17. germana
04 May, 2009
Hi!!
I have the same problem that jhon:
“Call to undefined method BaseCompany::getContact”
But my tables are: Denuncia and Denunciado, i want to embed Denunciado into Denuncia, so my model have the foreing keys on each table, and the exact error is:
“Call to undefined method BaseDenuncia::getDenunciado”
and my tables are InnoDB..
What could be my problem???
18. ojie43
10 May, 2009
I get error when i add __toString function in lib/model/contac.php
Catchable fatal error: Method Contact::__toString() must return a string value in E:\Web\company\cache\backend\dev\modules\autoCompany\templates\_list_td_tabular.php on line 5
plese help this..
thanks
19. Ahmed El.Hussaini
10 May, 2009
@ojie43: Open lib/model/Contact.php and override the __toString() function.
ex:
public function __toString() { return $this->getFullName(); }20. ojie43
14 May, 2009
thanks…
now, I can use it to my form..
sory my english not good
Now, I have probel with year range ini my birdday field, I only get year range 2004- 2014..
why I can get more year range ?, example 1950-2000
please help me
thanks before
21. sudhir
29 June, 2009 (5 days ago)
Great tutorial, This is exactly what I was looking for since last two days. I was not able to save my embedded for.
You solved my problem.
Thanks