Date post: | 06-May-2015 |
Category: |
Technology |
Upload: | bernhard-schussek |
View: | 12,314 times |
Download: | 4 times |
The new form frameworkBernhard Schussek
What is different in the new form framework?
Domain Model
sfForm
User
symfony 1.x
Controller
Domain Model
sfForm
User
symfony 1.x
Controller Business Logic
Domain Model
sfForm
User
Controller Business Logic
unit testable!!
symfony 1.x
Domain Model
sfFormDoctrine / sfFormPropel
User
symfony 1.x
function configure(){ unset($this['foo']); unset($this['bar']); unset($this['moo']); unset($this['comeon!']); ...
New architecture
Simplicity and Reusability
Embrace your domain model
Domain Model
Form
User
Symfony 2
Domain Model
Form
User
Symfony 2
Presentation
Business Logic
designed by you™
class Customer{
public $name = 'Default';
public getGender();
public setGender($gender);
}
Business Logic
Business Logic Presentation
class Customer{
public $name = 'Default';
public getGender();
public setGender($gender);
}
Form
TextField
ChoiceField
$form = new Form('customer', $customer, ...);
$form->add(new TextField('name'));
$form->add(new ChoiceField('gender', array( 'choices' => array('male', 'female'),)));
$form = new Form('customer', $customer, ...);
...
if (isset($_POST['customer'])){ $form->bind($_POST['customer']);}
Business Logic Presentation
class Customer{
public $address;
}
Form
FieldGroupto-one relations
$group = new FieldGroup('address');
$group->add(...);$group->add(...);$group->add(...);
$form->add($group);
Business Logic Presentation
class Customer{
public $emails;
}
Form
CollectionField
FieldGroup
FieldGroup
to-many relations
$group = new FieldGroup('emails');
$group->add(...);$group->add(...);
$form->add(new CollectionField($group));
TextField
TextareaField
CheckboxField
ChoiceField
PasswordField
HiddenField
NumberField
IntegerField
PercentField
MoneyField
DateField
BirthdayField
TimeField
TimezoneField
DateTimeField
RepeatedField
CollectionField
FieldGroup
Default Localized
Special
CheckboxField CheckboxField
ChoiceField ChoiceField
DateField
?
● Field groups— light-weight subforms— compose other fields or field groups
Form Rendering
<?php echo $form->renderFormTag('url') ?>
<?php echo $form->renderErrors() ?> <?php echo $form->render() ?>
<input type="submit" value="Submit" />
</form>
<label for="<?php echo $form['name']->getId() ?>"> Enter a name</label>
<?php echo $form['name']->renderErrors() ?><?php echo $form['name']->render() ?>
<?php echo $form['date']['day']->render() ?><?php echo $form['date']['month']->render() ?><?php echo $form['date']['year']->render() ?>
Validation
symfony 1.x
sfForm
sfValidator
Domain Model
Doctrine_Validator
Controller
symfony 1.x
sfForm
sfValidator
Domain Model
Doctrine_Validator
Controller Duplicate validationlogic
Failed validationleads to 505 errors
Symfony 2
Form
Domain Model
Symfony 2
Form
Domain Model
Validator
Symfony 2
Form
Domain Model
Validator
Validation Metadata
"how shall the domain model be validated?"
Customer: properties: name: - MinLength: 6 birthday: - Date: ~ gender: - Choice: [male, female]
<class name="Customer"> <property name="name"> <constraint name="MinLength">6</constraint> </property> <property name="birthday"> <constraint name="Date" /> </property> <property name="gender"> <constraint name="Choice"> <value>male</value> <value>female</value> </constraint> </property></class>
class Customer{ /** @Validation({ @MinLength(6) }) */ public $name;
/** @Validation({ @Choice({"male", "female"}) }) */ public function getGender();
/** @Validation({ @Valid }) */ public $gender;}
AssertTrue
AssertFalse
Blank
Null
Blank
NotBlank
NotNull
AssertType
Choice
Valid
Collection
Date
DateTime
Time
File
Min
MaxMaxLength Max
MinLength
Regex
Url
Type Check String Other
● Constraints can be put on— Classes— Properties— Methods with a "get" or "is" prefix
$validator = $container->getService('validator');
$validator->validate($customer);
Independent from Symfony 2
Doctrine 2Zend Propel
How does all this fit into the form framework?
$form = new Form('customer', $customer, $this->container->getService('validator'));
$form->bind($_POST['customer']);
if ($form->isValid()){ // do something with $customer}
● The validation is launched automatically upon submission
Common Questions
Q: What if my form does not translate 1:1 to a domain model?
A: Then the domain model doesn't exist yet ;-)
● Use Case— Extend our form for a checkbox to accept terms
and conditions— Should not be stored as field in the Customer
class
class Registration { /** @Validation({ @Valid }) */ public $customer;
/** * @Validation({ * @AssertTrue(message="Please accept") * }) */ public $termsAccepted = false;
public function process() { // save $customer, send emails etc. }}
$form->add(new CheckboxField('termsAccepted'));
$group = new FieldGroup('customer');$group->add(new TextField('name'));...
$form->add($group);
if ($form->isValid()){ $registration->process();}
● The Registration class— can be reused (XML requests, …)— can be unit tested
Q: What if I don't want to validate all attributes of an object?
A: Use Constraint groups
● Use Case— Administrators should be able to create
Customers with empty names— Normal users not
class Customer{ /** * @Validation({ * @NotBlank(groups="User") * }) */ public $name;
...}
$validator->validate($customer, 'User');
$form->setValidationGroups('User');$form->bind($_POST('customer'));
if ($form->isValid()){ ...}
● Constraint groups can be sequenced— first validate group "Fast"— then, if "Fast" was valid, validate group "Slow"
Questions?