Ask your Symfony questions! Pay money and get answers fast! (more info)

Remove Blank Object from embed form if not filled out Symfony

  • SOLVED

So I have read http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms so please do not just post a link there.

I can ignore a blank object of another type in my embed form, but I have an interesting use case here I think.

I have a situation where I have a "contact" object (an individual), which may or may not be associated with an "account" (a company). An account has 1:n contacts, a contact has 0:1 accounts.

schema.yml
Account:
columns:
id: { type: integer(4), primary: true, autoincrement: true }
name: { type: string(75), notnull:true }
Contact:
columns:
id: { type: integer(4), primary: true, autoincrement: true }
account_id: { type: integer(4) }
first_name: { type: string(50), notnull: true}
relations:
Account: { local: account_id, foreign: id, foreignAlias: Contacts }


lib/form/doctrine/ContactAdvancedForm.class.php
<?php
class ContactAdvancedForm extends BaseContactForm
{
public function configure()
{
$account = new Account();
$this->getObject()->setAccount($account);
$accountForm = new AccountForm($account);
$this->embedForm('account', $accountForm);
$this->useFields(array('first_name', 'account'));

}
public function saveEmbeddedForms($con = null, $forms = null)
{
if (null === $forms)
{
$account = $this->getValue('account');
$forms = $this->embeddedForms;
if(!isset($account['name']) || strlen($account['name']==0))
{
unset($forms['account']);
}
}

return parent::saveEmbeddedForms($con, $forms);
}


I think this line is the problem
$this->getObject()->setAccount($account);

But I don't know how to unset it, and it's needed to associate the contact with the account in the event an account is created...

No matter what I do, a blank account is still created. Can you offer advice on how to not create a blank account object if the name is not filled out?

Answers (2)

2010-10-22

Gergely Szilagyi answers:

Hi!

First of all, the best way to avoid these problems, write less code.
I will post a full-worked and tested solution for this question, tested in sf1.4 with doctrine.

<strong>schema.yml : </strong>
<em>doctrine is very smart, auto-detect relations ( default one-many, like you need in these
case, and give auto-increment primary key, named "id"</em>

Account:
columns:
name: { type: string(75), notnull: true}


Contact:
columns:
account_id: integer
first_name: { type: string(50), notnull: true}
relations:
Account: { foreignAlias: Contacts }



<strong>Then the CommentForm in lib/form/doctrine/CommentForm.class.php only :
</strong>class ContactForm extends BaseContactForm
{
public function configure()
{
if( $this->isNew() || $this->getObject()->Account->getId() )
{
/*
* If this ContactForm is new OR the exist Contact object own an exist Account,
* then we need to embed relation.
*/
$this->embedRelation('Account');
$this->useFields(array('first_name', 'Account'));

if($this->isNew())
{
/*
* If it's new, we enable the empty field for Account name,
* to separate two case later in Model's overrided save action.
*/
$this->validatorSchema['Account']['name'] ->setOption('required', false );
}
}else {
/*
* This case we have an existed Contact object, without binded Account in DB.
*/
$this->useFields(array('first_name'));
}
}

}



<strong>Then the Account in lib/model/doctrine/Account.class.php :
</strong>
class Account extends BaseAccount
{
/**
* Need to know :
* - the (ContactForm)$form->save() call the (Concact)$object->save() , and this will call first the
* already parametherized (Account)$account modell's save method in background.
* - what does this mean:
* When this method return null, then the $contact->account_id catch null too... :)
*/
public function save(Doctrine_Connection $conn = null)
{
$this->setName(trim($this->getName()));
if($this->getName())
{
return parent::save();
}else {
return null;
}
}
}



Sentence : "<em>Write less, do more = symfony"</em> :D

Have a nice day!

2010-10-22

saki answers:

Hi there.

You have to create a Post Validator:
[[LINK href="http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms"]]http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms[[/LINK]]
Read the <strong>Creating a Custom Validator</strong> part.

As you can see, the example checks the caption and filename fields and gives error if one of them is missing. If both of them are missing, it removes the empty values. That's you need.

In your case:

// no name, remove the empty values
if (!$value['name'])
{
unset($values[$key]);
}


I hope this helps... Don't forget to add the post validator to the embed form...

ps: you can use the trim() function (in the post validator) to avoid whitespace in the name field


bmv82 comments:

If you'll look in the saveEmbedded forms, I do the unsetting. Please provide an exact code example if there is code beyond what I have posted that is required.

public function saveEmbeddedForms($con = null, $forms = null)
{
if (null === $forms)
{
$account = $this->getValue('account');

$forms = $this->embeddedForms;

if(!isset($account['name']) || strlen($account['name']==0))
{
unset($forms['account']);
}
}
return parent::saveEmbeddedForms($con, $forms);
}