Leveraging Symfony2 Forms
-
Upload
bernhard-schussek -
Category
Entertainment & Humor
-
view
40.004 -
download
0
description
Transcript of Leveraging Symfony2 Forms
![Page 1: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/1.jpg)
Bernhard Schussek
Leveraging Symfony2 Forms
Symfony Live Conference, March 03rd 2011
![Page 2: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/2.jpg)
About myself
Software Architect in Vienna
Student of Software Engineering
Symfony since 2006
Outdoor and music junkie
![Page 3: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/3.jpg)
Agenda
Introductory example
The Form Config class
Form processing
Fields
Useful features
![Page 4: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/4.jpg)
The Symfony2 Form component
![Page 5: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/5.jpg)
The Symfony2 Form component
Evolution of symfony1 sfForm
2.5 years development
Fixes most of its problems
Reusable widgets
Embedded forms
![Page 6: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/6.jpg)
Why 2.5 years?
![Page 7: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/7.jpg)
"It takes a long time to make somthing complicated simple, but if you do, it will work without problems for a long time."
– F. Andy Seidl, http://faseidl.com
![Page 8: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/8.jpg)
Service Oriented Architecture
Applications provide services
Services are exchangable
These services can be consumed by different actors
Humans
Machines
![Page 9: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/9.jpg)
Forms don't contain business logic
![Page 10: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/10.jpg)
Services do
![Page 11: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/11.jpg)
Example: Online sausage shop
![Page 12: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/12.jpg)
Example: Online sausage shop
You
Request
Response
![Page 13: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/13.jpg)
Example: Online sausage shop
Request
Response
YouConsumer Service
![Page 14: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/14.jpg)
Example: Online sausage shop
Request
Response
Consumer Service
![Page 15: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/15.jpg)
Example: Online sausage shop
Request
Response
Consumer Service
![Page 16: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/16.jpg)
Service implementation
class Order{ function setName($name);
function setAddress($address);
function setSausage($sausage);
function setAmount($amount);}
![Page 17: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/17.jpg)
Flow of information
I am Max!
![Page 18: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/18.jpg)
Flow of information
I am Max!
$order->setName('Max')
![Page 19: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/19.jpg)
Flow of information
Sensio Labs,Paris
Address:
MaxName:
BratwurstSausage:
5Amount:
Order form
![Page 20: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/20.jpg)
Flow of information
Sensio Labs,Paris
Address:
MaxName:
BratwurstSausage:
5Amount:
$order->setName('Max')
->setAddress( 'Sensio Labs, Paris')
->setSausage( 'Bratwurst')->setAmount(5);
Order form
![Page 21: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/21.jpg)
Flow of information
$order->getName()
->getAddress()
->getSausage()
->getAmount();
Liip OfficeZurich
Address:
BobName:
CervelatSausage:
10Amount:
Existing order
![Page 22: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/22.jpg)
The Form Config class
![Page 23: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/23.jpg)
class OrderFormConfig extends AbstractConfig{ public function configure( FieldInterface $form, array $options) {
}}
PHP class
Form definition
![Page 24: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/24.jpg)
class OrderFormConfig extends AbstractConfig{ public function configure( FieldInterface $form, array $options) { $form->add('text', 'name') ->add('text', 'address') ->add('text', 'sausage') ->add('integer', 'amount'); }}
PHP class
Form definition
![Page 25: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/25.jpg)
class OrderFormConfig extends AbstractConfig{
...
public function getIdentifier() { return 'form.order'; }}
PHP class
Form definition
![Page 26: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/26.jpg)
Why not a simple OrderForm class?
![Page 27: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/27.jpg)
Why we need Config classes
OrderForm cannot be put into the Dependency Injection Container ...
... but OrderFormConfig can!
![Page 28: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/28.jpg)
Dependency Injection Container
<service id="form.order" class="OrderFormConfig"> <tag name="form.config" alias="form.order" /> <argument type="service" id="form.factory" /></service>
public function getIdentifier(){ return 'form.order';}
Tag alias == form identifier
![Page 29: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/29.jpg)
Form processing
![Page 30: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/30.jpg)
Form processing
$factory = $this->get('form.factory');$form = $factory->getInstance('form.order');
$form->setData($order);
if ($request->getMethod() === 'POST') { $form->bindRequest($request);
if ($form->isValid()) { $order->send(); return new RedirectResponse(...); }}
Form identifier
![Page 31: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/31.jpg)
Form processing
$factory = $this->get('form.factory');$form = $factory->getInstance('form.order');
$form->setData($order);
if ($request->getMethod() === 'POST') { $form->bindRequest($request);
if ($form->isValid()) { $order->send(); return new RedirectResponse(...); }}
Service object
![Page 32: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/32.jpg)
Form processing
$factory = $this->get('form.factory');$form = $factory->getInstance('form.order');
$form->setData($order);
if ($request->getMethod() === 'POST') { $form->bindRequest($request);
if ($form->isValid()) { $order->send(); return new RedirectResponse(...); }}
Calls setters
![Page 33: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/33.jpg)
Form processing
$factory = $this->get('form.factory');$form = $factory->getInstance('form.order');
$form->setData($order);
if ($request->getMethod() === 'POST') { $form->bindRequest($request);
if ($form->isValid()) { $order->send(); return new RedirectResponse(...); }} $order now contains submitted data!
![Page 34: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/34.jpg)
Form rendering
In the action
return $this->render( 'HelloBundle:Hello:index.twig.html', array('form' => $form->getRenderer()));
Contains view variables and methods
![Page 35: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/35.jpg)
Form rendering
In the template
<form action="#" method="post"> {{ form.widget }}</form>
"widget" is a view method
![Page 36: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/36.jpg)
Form rendering
<form action="#" method="post"> {{ form.errors }} {% for field in form.vars.fields %} {{ field.errors }} {{ field.label }} {{ field.widget }} {% endfor %} {{ form.rest }}</form>
"fields" is a view variable
![Page 37: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/37.jpg)
Form rendering
<form action="#" method="post"> {{ form.errors }} {{ form.name.errors }} {{ form.name.label }} {{ form.name.widget }} {{ form.rest }}</form>
![Page 38: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/38.jpg)
Form rendering
Renders all fields that weren't rendered before
... fields that you forgot to render manually
... hidden fields
{{ form.rest }}
![Page 39: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/39.jpg)
What about validation?
![Page 40: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/40.jpg)
Form validation
uses the Symfony2 Validator
"Constraints" are put onto your PHP classes (services, entities etc.)
![Page 41: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/41.jpg)
Validation constraints
class Order{ /** * @check:NotNull * @check:AssertType("string") * @check:MaxLength(50, message= * "Long name, dude...") */ private $name;}
![Page 42: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/42.jpg)
Fields
![Page 43: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/43.jpg)
Text input
$form->add('text', 'title');
Title:
![Page 44: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/44.jpg)
Textarea
$form->add('textarea', 'content');
Content:
![Page 45: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/45.jpg)
Date selector
$form->add('date', 'publishAt');
Publish at:
Mmmh localized!
![Page 46: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/46.jpg)
Country selector
$form->add('country', 'nationality');
Nationality:
Localized too! Yummy!Localized too! Yummy!
![Page 47: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/47.jpg)
File upload
$form->add('file', 'profilePicture');
Profile picture:
Remembers uploaded files on errors!
![Page 48: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/48.jpg)
Repeated input
$form->add('repeated', 'email');
Email:
Email (again):
![Page 49: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/49.jpg)
Core fieldsbirthday
checkbox
choice
collection
country
date
datetime
entity
file
hidden
integer
language
locale
money
number
password
percent
repeated
textarea
text
timezone
url
![Page 50: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/50.jpg)
Field architecture
Filters
Value transformers
![Page 51: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/51.jpg)
Filters
modify a value
unidirectional
Example: FixUrlProtocolFilter
symfony-project.com http://symfony-project.com
![Page 52: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/52.jpg)
Value Transformers
convert values between two representations
bidirectional
Example: DateTimeToArrayTransformer
array( 'year' => 2011, 'month' => 5, 'day' => 1,)
object(DateTime)
![Page 53: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/53.jpg)
Example: Entity fieldThe user sees:
Entity field
Checkbox"0"
Checkbox"1"
Checkbox"2"
Checkbox"3"
Symfony sees:
Tag IDs
![Page 54: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/54.jpg)
Checkbox"0"
Checkbox"1"
Checkbox"2"
Checkbox"3"
array("0" => "0", "1" => "1", "2" => "1", ...)
"0" "1" "0" "0"
Tag IDs
![Page 55: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/55.jpg)
Checkbox"0"
Checkbox"1"
Checkbox"2"
Checkbox"3"
array("0" => "0", "1" => "1", "2" => "1", ...)
"0" "1" "0" "0"
Tag IDs
![Page 56: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/56.jpg)
Checkbox"0"
Checkbox"1"
Checkbox"2"
Checkbox"3"
false true true false
array("0" => false, "1" => true, "2" => true, ...)
ArrayCollection($securityTag, $validatorTag)
![Page 57: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/57.jpg)
Checkbox"0"
Checkbox"1"
Checkbox"2"
Checkbox"3"
false true true false
array("0" => false, "1" => true, "2" => true, ...)
ArrayCollection($securityTag, $validatorTag)
ChoicesToArrayTransformer
![Page 58: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/58.jpg)
Checkbox"0"
Checkbox"1"
Checkbox"2"
Checkbox"3"
false true true false
array("0" => false, "1" => true, "2" => true, ...)
ArrayCollection($securityTag, $validatorTag)
ArrayToEntitiesTransformer
![Page 59: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/59.jpg)
CSRF protection
CrossSite Request Forgery
A form is submitted using the session of another person
All kinds of misuse
Builtin protection in Symfony2
![Page 60: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/60.jpg)
CSRF protection
app/config/config.yml
framework: csrf_protection: enabled: true secret: 30665e19ef0010d5620553
![Page 61: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/61.jpg)
Field creation
Manual
Automatic
Symfony2 looks at metadata of the domain class to "guess" the correct field type and settings
E.g. Validator metadata, Doctrine2 metadata
![Page 62: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/62.jpg)
Manual field creation
public function configure( FieldInterface $form, array $options){ $form->add('entity', 'sausage', array( 'class' => 'Sausage', ));}
but Doctrine already knows, that "sausage" is a ToOne relationship to the Sausage class!
![Page 63: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/63.jpg)
Automatic field creation
public function configure( FieldInterface $form, array $options){ $form->setDataClass('Order');
$form->add('sausage');}
![Page 64: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/64.jpg)
Automatic with options overriding
public function configure( FieldInterface $form, array $options){ $form->setDataClass('Order') ->add('sausage', array( 'required' => false, ));}
![Page 65: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/65.jpg)
Embedded forms
Symfony2 allows to embed forms into another very easily
Fields and forms implement FieldInterface
"A form is a field"
![Page 66: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/66.jpg)
Embedded toone forms
public function configure( FieldInterface $form, array $options){ $form->add('form.sausage', 'sausage');}
Identifier of SausageFormConfig
![Page 67: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/67.jpg)
Embedded tomany forms
public function configure( FieldInterface $form, array $options){ $form->add('collection', 'sausages', array( 'identifier' => 'form.sausage' ));}
Identifier of SausageFormConfig
![Page 68: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/68.jpg)
Config options
class ConcealedFieldConfig extends Abstract..{ public function getDefaultOptions($options) { return array( 'concealed' => true, ); }}
Options for influencing the field's/form's creation
![Page 69: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/69.jpg)
Config inheritance
class ConcealedFieldConfig extends Abstract..{ public function getParent(array $options) { return $options['concealed'] ? 'password' : 'text'; }}
Dynamic inheritance from other forms/fields
![Page 70: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/70.jpg)
Form themes
Are normal Twig templates
Blocks for each field type
{% block textarea__widget %} <textarea {{ block('attributes') }}> {{ value }} </textarea>{% endblock textarea__widget %}
![Page 71: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/71.jpg)
Form themes
Can specify widget, errors, label and row templates for specific field types
{% block textarea__row %} <tr><td colspan="2"> {{ this.errors }} {{ this.widget }} </td></tr>{% endblock textarea__row %}
![Page 72: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/72.jpg)
Form themes
Core themes:
TwigBundle::div_layout.html.twig
TwigBundle::table_layout.html.twig
Configuration in the DI parameter "form.theme.template"
More flexible configuration options coming soon
![Page 73: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/73.jpg)
Questions?
Thanks for listening!
Code can currently be found onhttps://github.com/bschussek/symfony/tree/experimental
Bernhard SchussekTwitter: @webmozart
![Page 74: Leveraging Symfony2 Forms](https://reader034.fdocuments.in/reader034/viewer/2022052315/554f3d33b4c90572088b5094/html5/thumbnails/74.jpg)
The End
Copyright
"dog window" by Larry Wentzelhttp://www.flickr.com/photos/wentzelepsy
"Symfony Live 2011 Logo" by Sensio Labshttp://www.sensiolabs.com