the new form framework

Post on 06-May-2015

12.315 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

Email

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?

top related