SlideShare a Scribd company logo
1 of 45
Download to read offline
Everything you always wanted 
to know about forms* 
*but were afraid to ask 
Andrea Giuliano 
@bit_shark 
SYMFONYDAY 2013
Tree 
Abstract Data Structure
Tree: Abstract data Type 
Andrea Giuliano @bit_shark 
… 
collection of nodes each of which has an associated 
value and a list of children connected to their parents by 
means of an edge
Symfony Forms are trees 
Andrea Giuliano @bit_shark 
Form 
Form Form Form 
Form
Example: a meeting form 
Andrea Giuliano @bit_shark
Let’s create it with Symfony 
namespace MyAppMyBundleForm;! 
! 
use SymfonyComponentFormAbstractType;! 
use SymfonyComponentFormFormBuilderInterface;! 
use SymfonyComponentOptionsResolverOptionsResolverInterface;! 
! 
class MeetingType extends AbstractType! 
{! 
public function buildForm(FormBuilderInterface $builder, array $option)! 
{! 
$builder->add('name', 'string');! 
$builder->add('when', 'date');! 
$builder->add('featured', 'checkbox');! 
}! 
! 
public function getName()! 
{! 
return 'meeting';! 
}! 
} 
Andrea Giuliano @bit_shark
Symfony’s point of view 
Andrea Giuliano @bit_shark 
Meeting 
form
Symfony’s point of view 
Andrea Giuliano @bit_shark 
Meeting 
form 
$builder->add('name', 'string') 
Name 
string
Andrea Giuliano @bit_shark 
$builder->add('when', 'date') 
Meeting 
form 
Name 
string 
Date 
date 
Month 
choice 
Day 
choice 
Year 
choice 
Symfony’s point of view
Andrea Giuliano @bit_shark 
Meeting 
form 
Name 
string 
Date 
date 
Month 
choice 
Day 
choice 
Year 
choice 
Symfony’s point of view 
$builder->add('featured', 'checkbox') 
Featured 
checkbox
Data format
Data format 
class Form implements IteratorAggregate, FormInterface! 
{! 
[...]! 
! 
/**! 
* The form data in model format! 
*/! 
private $modelData;! 
! 
/**! 
* The form data in normalized format! 
*/! 
private $normData;! 
! 
/**! 
* The form data in view format! 
*/! 
private $viewData;! 
} 
Andrea Giuliano @bit_shark
Data format 
Model 
Data 
Andrea Giuliano @bit_shark 
Norm 
Data 
How the information 
View 
Data 
is represented in the application model
Data format 
Model 
Data 
Andrea Giuliano @bit_shark 
Norm 
Data 
View 
Data 
How the information 
is represented in the view domain
Data format 
Model 
Data 
Andrea Giuliano @bit_shark 
Norm 
Data 
View 
Data 
???
Model Data and View Data 
$builder->add('when', 'date') 
Andrea Giuliano @bit_shark 
widget View Data 
choice array 
single_text string 
input Model Data 
string string 
datetime DateTime 
array array 
timestamp integer 
Meeting 
form 
Date 
date
Model Data and View Data 
Andrea Giuliano @bit_shark 
widget View Data 
choice array 
single_text string 
input Model Data 
string string 
datetime DateTime 
array array 
timestamp integer 
Meeting 
form 
Date 
date 
What $form->getData() will return?
Normalized Data 
Which format would you like to play with 
Andrea Giuliano @bit_shark 
in your application logic? 
$form->getNormData()
Data Transformers
Data transformers 
class BooleanToStringTransformer implements DataTransformerInterface! 
{! 
private $trueValue;! 
! 
public function __construct($trueValue)! 
{! 
$this->trueValue = $trueValue;! 
}! 
! 
public function transform($value)! 
{! 
if (null === $value) {! 
return null;! 
}! 
! 
if (!is_bool($value)) {! 
throw new TransformationFailedException('Expected a Boolean.');! 
}! 
! 
return $value ? $this->trueValue : null;! 
}! 
! 
public function reverseTransform($value)! 
{! 
if (null === $value) {! 
return false;! 
}! 
! 
if (!is_string($value)) {! 
throw new TransformationFailedException('Expected a string.');! 
}! 
! 
return true;! 
}! 
} 
Andrea Giuliano @bit_shark
Data transformers 
Model 
Data 
Andrea Giuliano @bit_shark 
Norm 
Data 
View 
Data 
transform() transform() 
Model Transformer View Transformer 
reverseTransform() reverseTransform()
Data transformers 
class MeetingType extends AbstractType! 
{! 
public function buildForm(FormBuilderInterface $builder, array $option)! 
{! 
$transformer = new MyDataTransformer();! 
! 
$builder->add('name', 'string');! 
$builder->add('when', 'date')->addModelTransformer($transformer);! 
$builder->add('featured', 'checkbox');! 
}! 
! 
public function getName()! 
{! 
return 'meeting';! 
}! 
}! 
Add a ModelTransformer or a ViewTransformer 
Andrea Giuliano @bit_shark
Data transformers 
class MeetingType extends AbstractType! 
{! 
public function buildForm(FormBuilderInterface $builder, array $option)! 
{! 
$transformer = new MyDataTransformer(/*AnAwesomeDependence*/);! 
! 
$builder->add('name', 'string');! 
$builder->add('when', 'date')->addModelTransformer($transformer);! 
$builder->add('featured', 'checkbox');! 
}! 
! 
public function getName()! 
{! 
return 'meeting';! 
}! 
}! 
Andrea Giuliano @bit_shark 
in case of dependencies?
Andrea Giuliano @bit_shark
Data transformers 
<service id="dnsee.type.my_text" ! 
class="DnseeMyBundleFormTypeMyTextType">! 
<argument type="service" id="dnsee.my_awesome_manager"/>! 
<tag name="form.type" alias="my_text" />! 
Andrea Giuliano @bit_shark 
Use it by creating your own type 
</service>
Data transformers 
class MyTextType extends AbstractType! 
{! 
private $myManager;! 
Andrea Giuliano @bit_shark 
Use it by creating your own type 
! 
public function __construct(MyManager $manager)! 
{! 
$this->myManager = $manager;! 
}! 
! 
public function buildForm(FormBuilderInterface $builder, array $options)! 
{! 
$transformer = new MyTransformer($this->manager);! 
$builder->addModelTransformer($transformer);! 
}! 
! 
public function getParent()! 
{! 
return 'text';! 
}! 
! 
public function getName()! 
{! 
return 'my_text';! 
}! 
}!
Data transformers 
class MeetingType extends AbstractType! 
{! 
public function buildForm(FormBuilderInterface $builder, array $option)! 
{! 
$builder->add('name', 'my_text');! 
$builder->add('when', 'date');! 
$builder->add('featured', 'checkbox');! 
}! 
! 
public function getName()! 
{! 
return 'meeting';! 
}! 
}! 
Andrea Giuliano @bit_shark 
use my_text as a standard type
Andrea Giuliano @bit_shark 
Remember 
Data Transformers transforms 
data representation 
Don’t use them to change 
data information
Events
Andrea Giuliano @bit_shark 
To change data information use 
form events 
Events
Events 
class FacebookSubscriber implements EventSubscriberInterface! 
{! 
public static function getSubscribedEvents()! 
{! 
return array(FormEvents::PRE_SET_DATA => 'preSetData');! 
}! 
! 
public function preSetData(FormEvent $event)! 
{! 
$data = $event->getData();! 
$form = $event->getForm();! 
! 
if (null === $data) {! 
Andrea Giuliano @bit_shark 
return;! 
}! 
! 
if (!$data->getFacebookId()) {! 
$form->add('username');! 
$form->add('password');! 
}! 
}! 
}
Events 
class RegistrationType extends AbstractType! 
{! 
public function buildForm(FormBuilderInterface $builder, array $options)! 
{! 
$builder->add('name');! 
$builder->add('surname');! 
! 
$builder->addEventSubscriber(new FacebookSubscriber());! 
}! 
! 
public function getName()! 
{! 
return 'registration';! 
}! 
! 
...! 
! 
} 
Andrea Giuliano @bit_shark 
add it to your type
Events 
class RegistrationForm extends AbstractType! 
{! 
public function buildForm(FormBuilderInterface $builder, array $options)! 
{! 
$builder->add('name');! 
$builder->add('surname');! 
! 
$builder->get('surname')->addEventListener(! 
Andrea Giuliano @bit_shark 
FormEvents::BIND,! 
function(FormEvent $event){! 
$event->setData(ucwords($event->getData()))! 
}! 
);! 
}! 
! 
public function getName()! 
{! 
return 'registration';! 
}! 
}
Events 
$form->setData($symfonyDay); 
PRE_SET_DATA 
Model Norm View 
Andrea Giuliano @bit_shark 
meeting [Form] 
POST_SET_DATA 
child
Events 
POST_BIND 
$form->handleRequest($request); 
Model Norm View 
Andrea Giuliano @bit_shark 
meeting [Form] 
child 
PRE_BIND 
BIND
Test
namespace AcmeTestBundleTestsFormType;! 
! 
use DnseeEventBundleFormTypeEventType;! 
use DnseeEventBundleModelEventObject;! 
use SymfonyComponentFormTestTypeTestCase;! 
! 
class MeetingTypeTest extends TypeTestCase! 
{! 
Andrea Giuliano @bit_shark 
public function testSubmitValidData()! 
{! 
$formData = array(! 
'name' => 'SymfonyDay',! 
'date' => '2013-10-18',! 
'featured' => true,! 
);! 
! 
$type = new TestedType();! 
$form = $this->factory->create($type);! 
! 
$object = new TestObject();! 
$object->fromArray($formData);! 
! 
// submit the data to the form directly! 
$form->submit($formData);! 
! 
$this->assertTrue($form->isSynchronized());! 
$this->assertEquals($object, $form->getData());! 
! 
$view = $form->createView();! 
$children = $view->children;! 
! 
foreach (array_keys($formData) as $key) {! 
$this->assertArrayHasKey($key, $children);! 
}! 
}! 
} 
Test
namespace AcmeTestBundleTestsFormType;! 
! 
use DnseeEventBundleFormTypeEventType;! 
use DnseeEventBundleModelEvent;! 
use SymfonyComponentFormTestTypeTestCase;! 
! 
class MeetingTypeTest extends TypeTestCase! 
{! 
public function testSubmitValidData()! 
{! 
$formData = array(! 
Andrea Giuliano @bit_shark 
'name' => 'SymfonyDay',! 
'when' => '2013-10-18',! 
'featured' => true,! 
);! 
! 
$type = new EventType();! 
$form = $this->factory->create($type);! 
! 
$event = new Event();! 
$event->fromArray($formData);! 
! 
[...]! 
Test 
decide the data 
to be submitted
Test 
namespace AcmeTestBundleTestsFormType;! 
! 
use DnseeEventBundleFormTypeEventType;! 
use DnseeEventBundleModelEventObject;! 
use SymfonyComponentFormTestTypeTestCase;! 
! 
class MeetingTypeTest extends TypeTestCase! 
{! 
public function testSubmitValidData()! 
{! 
! 
[...]! 
! 
$form->submit($formData);! 
! 
$this->assertTrue($form->isSynchronized());! 
$this->assertEquals($object, $form->getData());! 
! 
[...]! 
! 
Andrea Giuliano @bit_shark 
test data transformers
Test 
namespace AcmeTestBundleTestsFormType;! 
! 
use AcmeTestBundleFormTypeTestedType;! 
use AcmeTestBundleModelTestObject;! 
use SymfonyComponentFormTestTypeTestCase;! 
! 
class MeetingTypeTest extends TypeTestCase! 
{! 
public function testSubmitValidData()! 
{! 
! 
[...]! 
! 
$view = $form->createView();! 
$children = $view->children;! 
! 
foreach (array_keys($formData) as $key) {! 
Andrea Giuliano @bit_shark 
$this->assertArrayHasKey($key, $children);! 
}! 
}! 
}! 
test form view creation
Test 
namespace AcmeTestBundleTestsFormType;! 
! 
use DnseeEventBundleFormTypeEventType;! 
use DnseeEventBundleModelEventObject;! 
use SymfonyComponentFormTestTypeTestCase;! 
! 
class MeetingTypeTest extends TypeTestCase! 
{! 
protected function getExtensions()! 
{! 
$myCustomType = new MyCustomType();! 
return array(new PreloadedExtension(array(! 
Andrea Giuliano @bit_shark 
$myCustomType->getName() => $customType,! 
), array()));! 
}! 
! 
public function testSubmitValidData()! 
{! 
[...]! 
}! 
}
Test 
namespace AcmeTestBundleTestsFormType;! 
! 
use DnseeEventBundleFormTypeEventType;! 
use DnseeEventBundleModelEventObject;! 
use SymfonyComponentFormTestTypeTestCase;! 
! 
class MeetingTypeTest extends TypeTestCase! 
{! 
protected function getExtensions()! 
{! 
$myCustomType = new MyCustomType();! 
return array(new PreloadedExtension(array(! 
Andrea Giuliano @bit_shark 
$myCustomType->getName() => $customType,! 
), array()));! 
}! 
! 
public function testSubmitValidData()! 
{! 
[...]! 
}! 
} 
Test your custom type 
FIRST
?
http://joind.in/9784 
Andrea Giuliano 
@bit_shark
References 
https://speakerdeck.com/webmozart/symfony2-form-tricks 
http://www.flickr.com/photos/yahya/132963781/ 
http://www.flickr.com/photos/lutherankorean/2694858251/ 
http://www.flickr.com/photos/lauroroger/8808985531/ 
http://www.flickr.com/photos/gifake/4643253235/ 
http://www.flickr.com/photos/zorin-denu/5222189908/ 
http://www.flickr.com/photos/aigle_dore/10014783623/ 
http://www.flickr.com/photos/skosoris/4985591296/ 
http://www.flickr.com/photos/sharynmorrow/248647126/

More Related Content

What's hot

sfDay Cologne - Sonata Admin Bundle
sfDay Cologne - Sonata Admin BundlesfDay Cologne - Sonata Admin Bundle
sfDay Cologne - Sonata Admin Bundleth0masr
 
Disregard Inputs, Acquire Zend_Form
Disregard Inputs, Acquire Zend_FormDisregard Inputs, Acquire Zend_Form
Disregard Inputs, Acquire Zend_FormDaniel Cousineau
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにYuya Takeyama
 
Code moi une RH! (PHP tour 2017)
Code moi une RH! (PHP tour 2017)Code moi une RH! (PHP tour 2017)
Code moi une RH! (PHP tour 2017)Arnaud Langlade
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web servicesMichelangelo van Dam
 
Custom Signals for Uncoupled Design
Custom Signals for Uncoupled DesignCustom Signals for Uncoupled Design
Custom Signals for Uncoupled Designecomsmith
 
Web весна 2013 лекция 6
Web весна 2013 лекция 6Web весна 2013 лекция 6
Web весна 2013 лекция 6Technopark
 
Taming forms with React
Taming forms with ReactTaming forms with React
Taming forms with ReactGreeceJS
 
Form demoinplaywithmysql
Form demoinplaywithmysqlForm demoinplaywithmysql
Form demoinplaywithmysqlKnoldus Inc.
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneRafael Felix da Silva
 
Fields in Core: How to create a custom field
Fields in Core: How to create a custom fieldFields in Core: How to create a custom field
Fields in Core: How to create a custom fieldIvan Zugec
 
Javascript & jQuery: A pragmatic introduction
Javascript & jQuery: A pragmatic introductionJavascript & jQuery: A pragmatic introduction
Javascript & jQuery: A pragmatic introductionIban Martinez
 
Web осень 2012 лекция 6
Web осень 2012 лекция 6Web осень 2012 лекция 6
Web осень 2012 лекция 6Technopark
 
Data20161007
Data20161007Data20161007
Data20161007capegmail
 
Dealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsDealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsClinton Dreisbach
 

What's hot (20)

D8 Form api
D8 Form apiD8 Form api
D8 Form api
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
sfDay Cologne - Sonata Admin Bundle
sfDay Cologne - Sonata Admin BundlesfDay Cologne - Sonata Admin Bundle
sfDay Cologne - Sonata Admin Bundle
 
Disregard Inputs, Acquire Zend_Form
Disregard Inputs, Acquire Zend_FormDisregard Inputs, Acquire Zend_Form
Disregard Inputs, Acquire Zend_Form
 
Cyclejs introduction
Cyclejs introductionCyclejs introduction
Cyclejs introduction
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 
Code moi une RH! (PHP tour 2017)
Code moi une RH! (PHP tour 2017)Code moi une RH! (PHP tour 2017)
Code moi une RH! (PHP tour 2017)
 
Backbone - TDC 2011 Floripa
Backbone - TDC 2011 FloripaBackbone - TDC 2011 Floripa
Backbone - TDC 2011 Floripa
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web services
 
Custom Signals for Uncoupled Design
Custom Signals for Uncoupled DesignCustom Signals for Uncoupled Design
Custom Signals for Uncoupled Design
 
Ruby - Design patterns tdc2011
Ruby - Design patterns tdc2011Ruby - Design patterns tdc2011
Ruby - Design patterns tdc2011
 
Web весна 2013 лекция 6
Web весна 2013 лекция 6Web весна 2013 лекция 6
Web весна 2013 лекция 6
 
Taming forms with React
Taming forms with ReactTaming forms with React
Taming forms with React
 
Form demoinplaywithmysql
Form demoinplaywithmysqlForm demoinplaywithmysql
Form demoinplaywithmysql
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com Backbone
 
Fields in Core: How to create a custom field
Fields in Core: How to create a custom fieldFields in Core: How to create a custom field
Fields in Core: How to create a custom field
 
Javascript & jQuery: A pragmatic introduction
Javascript & jQuery: A pragmatic introductionJavascript & jQuery: A pragmatic introduction
Javascript & jQuery: A pragmatic introduction
 
Web осень 2012 лекция 6
Web осень 2012 лекция 6Web осень 2012 лекция 6
Web осень 2012 лекция 6
 
Data20161007
Data20161007Data20161007
Data20161007
 
Dealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsDealing with Legacy PHP Applications
Dealing with Legacy PHP Applications
 

Similar to Everything you always wanted to know about forms* *but were afraid to ask

Mikhail Kraynuk. Form api. Drupal 8
Mikhail Kraynuk. Form api. Drupal 8Mikhail Kraynuk. Form api. Drupal 8
Mikhail Kraynuk. Form api. Drupal 8i20 Group
 
Mikhail Kraynuk. Form api. Drupal 8
Mikhail Kraynuk. Form api. Drupal 8Mikhail Kraynuk. Form api. Drupal 8
Mikhail Kraynuk. Form api. Drupal 8DrupalSib
 
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and SimpleDrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and SimpleAlexander Varwijk
 
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXМихаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXDrupalSib
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgetsvelveeta_512
 
Crowdsourcing with Django
Crowdsourcing with DjangoCrowdsourcing with Django
Crowdsourcing with DjangoSimon Willison
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using CodeceptionJeroen van Dijk
 
Firebase & SwiftUI Workshop
Firebase & SwiftUI WorkshopFirebase & SwiftUI Workshop
Firebase & SwiftUI WorkshopPeter Friese
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful softwareJorn Oomen
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015Fernando Daciuk
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonKris Wallsmith
 

Similar to Everything you always wanted to know about forms* *but were afraid to ask (20)

Mikhail Kraynuk. Form api. Drupal 8
Mikhail Kraynuk. Form api. Drupal 8Mikhail Kraynuk. Form api. Drupal 8
Mikhail Kraynuk. Form api. Drupal 8
 
Mikhail Kraynuk. Form api. Drupal 8
Mikhail Kraynuk. Form api. Drupal 8Mikhail Kraynuk. Form api. Drupal 8
Mikhail Kraynuk. Form api. Drupal 8
 
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and SimpleDrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
 
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXМихаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
Symfony2. Form and Validation
Symfony2. Form and ValidationSymfony2. Form and Validation
Symfony2. Form and Validation
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
 
Crowdsourcing with Django
Crowdsourcing with DjangoCrowdsourcing with Django
Crowdsourcing with Django
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
Firebase & SwiftUI Workshop
Firebase & SwiftUI WorkshopFirebase & SwiftUI Workshop
Firebase & SwiftUI Workshop
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Unit testing UIView
Unit testing UIViewUnit testing UIView
Unit testing UIView
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
 

More from Andrea Giuliano

CQRS, ReactJS, Docker in a nutshell
CQRS, ReactJS, Docker in a nutshellCQRS, ReactJS, Docker in a nutshell
CQRS, ReactJS, Docker in a nutshellAndrea Giuliano
 
Go fast in a graph world
Go fast in a graph worldGo fast in a graph world
Go fast in a graph worldAndrea Giuliano
 
Concurrent test frameworks
Concurrent test frameworksConcurrent test frameworks
Concurrent test frameworksAndrea Giuliano
 
Index management in depth
Index management in depthIndex management in depth
Index management in depthAndrea Giuliano
 
Consistency, Availability, Partition: Make Your Choice
Consistency, Availability, Partition: Make Your ChoiceConsistency, Availability, Partition: Make Your Choice
Consistency, Availability, Partition: Make Your ChoiceAndrea Giuliano
 
Asynchronous data processing
Asynchronous data processingAsynchronous data processing
Asynchronous data processingAndrea Giuliano
 
Think horizontally @Codemotion
Think horizontally @CodemotionThink horizontally @Codemotion
Think horizontally @CodemotionAndrea Giuliano
 
Index management in shallow depth
Index management in shallow depthIndex management in shallow depth
Index management in shallow depthAndrea Giuliano
 

More from Andrea Giuliano (10)

CQRS, ReactJS, Docker in a nutshell
CQRS, ReactJS, Docker in a nutshellCQRS, ReactJS, Docker in a nutshell
CQRS, ReactJS, Docker in a nutshell
 
Go fast in a graph world
Go fast in a graph worldGo fast in a graph world
Go fast in a graph world
 
Concurrent test frameworks
Concurrent test frameworksConcurrent test frameworks
Concurrent test frameworks
 
Index management in depth
Index management in depthIndex management in depth
Index management in depth
 
Consistency, Availability, Partition: Make Your Choice
Consistency, Availability, Partition: Make Your ChoiceConsistency, Availability, Partition: Make Your Choice
Consistency, Availability, Partition: Make Your Choice
 
Asynchronous data processing
Asynchronous data processingAsynchronous data processing
Asynchronous data processing
 
Think horizontally @Codemotion
Think horizontally @CodemotionThink horizontally @Codemotion
Think horizontally @Codemotion
 
Index management in shallow depth
Index management in shallow depthIndex management in shallow depth
Index management in shallow depth
 
Stub you!
Stub you!Stub you!
Stub you!
 
Let's test!
Let's test!Let's test!
Let's test!
 

Recently uploaded

Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 

Recently uploaded (20)

Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 

Everything you always wanted to know about forms* *but were afraid to ask

  • 1. Everything you always wanted to know about forms* *but were afraid to ask Andrea Giuliano @bit_shark SYMFONYDAY 2013
  • 2. Tree Abstract Data Structure
  • 3. Tree: Abstract data Type Andrea Giuliano @bit_shark … collection of nodes each of which has an associated value and a list of children connected to their parents by means of an edge
  • 4. Symfony Forms are trees Andrea Giuliano @bit_shark Form Form Form Form Form
  • 5. Example: a meeting form Andrea Giuliano @bit_shark
  • 6. Let’s create it with Symfony namespace MyAppMyBundleForm;! ! use SymfonyComponentFormAbstractType;! use SymfonyComponentFormFormBuilderInterface;! use SymfonyComponentOptionsResolverOptionsResolverInterface;! ! class MeetingType extends AbstractType! {! public function buildForm(FormBuilderInterface $builder, array $option)! {! $builder->add('name', 'string');! $builder->add('when', 'date');! $builder->add('featured', 'checkbox');! }! ! public function getName()! {! return 'meeting';! }! } Andrea Giuliano @bit_shark
  • 7. Symfony’s point of view Andrea Giuliano @bit_shark Meeting form
  • 8. Symfony’s point of view Andrea Giuliano @bit_shark Meeting form $builder->add('name', 'string') Name string
  • 9. Andrea Giuliano @bit_shark $builder->add('when', 'date') Meeting form Name string Date date Month choice Day choice Year choice Symfony’s point of view
  • 10. Andrea Giuliano @bit_shark Meeting form Name string Date date Month choice Day choice Year choice Symfony’s point of view $builder->add('featured', 'checkbox') Featured checkbox
  • 12. Data format class Form implements IteratorAggregate, FormInterface! {! [...]! ! /**! * The form data in model format! */! private $modelData;! ! /**! * The form data in normalized format! */! private $normData;! ! /**! * The form data in view format! */! private $viewData;! } Andrea Giuliano @bit_shark
  • 13. Data format Model Data Andrea Giuliano @bit_shark Norm Data How the information View Data is represented in the application model
  • 14. Data format Model Data Andrea Giuliano @bit_shark Norm Data View Data How the information is represented in the view domain
  • 15. Data format Model Data Andrea Giuliano @bit_shark Norm Data View Data ???
  • 16. Model Data and View Data $builder->add('when', 'date') Andrea Giuliano @bit_shark widget View Data choice array single_text string input Model Data string string datetime DateTime array array timestamp integer Meeting form Date date
  • 17. Model Data and View Data Andrea Giuliano @bit_shark widget View Data choice array single_text string input Model Data string string datetime DateTime array array timestamp integer Meeting form Date date What $form->getData() will return?
  • 18. Normalized Data Which format would you like to play with Andrea Giuliano @bit_shark in your application logic? $form->getNormData()
  • 20. Data transformers class BooleanToStringTransformer implements DataTransformerInterface! {! private $trueValue;! ! public function __construct($trueValue)! {! $this->trueValue = $trueValue;! }! ! public function transform($value)! {! if (null === $value) {! return null;! }! ! if (!is_bool($value)) {! throw new TransformationFailedException('Expected a Boolean.');! }! ! return $value ? $this->trueValue : null;! }! ! public function reverseTransform($value)! {! if (null === $value) {! return false;! }! ! if (!is_string($value)) {! throw new TransformationFailedException('Expected a string.');! }! ! return true;! }! } Andrea Giuliano @bit_shark
  • 21. Data transformers Model Data Andrea Giuliano @bit_shark Norm Data View Data transform() transform() Model Transformer View Transformer reverseTransform() reverseTransform()
  • 22. Data transformers class MeetingType extends AbstractType! {! public function buildForm(FormBuilderInterface $builder, array $option)! {! $transformer = new MyDataTransformer();! ! $builder->add('name', 'string');! $builder->add('when', 'date')->addModelTransformer($transformer);! $builder->add('featured', 'checkbox');! }! ! public function getName()! {! return 'meeting';! }! }! Add a ModelTransformer or a ViewTransformer Andrea Giuliano @bit_shark
  • 23. Data transformers class MeetingType extends AbstractType! {! public function buildForm(FormBuilderInterface $builder, array $option)! {! $transformer = new MyDataTransformer(/*AnAwesomeDependence*/);! ! $builder->add('name', 'string');! $builder->add('when', 'date')->addModelTransformer($transformer);! $builder->add('featured', 'checkbox');! }! ! public function getName()! {! return 'meeting';! }! }! Andrea Giuliano @bit_shark in case of dependencies?
  • 25. Data transformers <service id="dnsee.type.my_text" ! class="DnseeMyBundleFormTypeMyTextType">! <argument type="service" id="dnsee.my_awesome_manager"/>! <tag name="form.type" alias="my_text" />! Andrea Giuliano @bit_shark Use it by creating your own type </service>
  • 26. Data transformers class MyTextType extends AbstractType! {! private $myManager;! Andrea Giuliano @bit_shark Use it by creating your own type ! public function __construct(MyManager $manager)! {! $this->myManager = $manager;! }! ! public function buildForm(FormBuilderInterface $builder, array $options)! {! $transformer = new MyTransformer($this->manager);! $builder->addModelTransformer($transformer);! }! ! public function getParent()! {! return 'text';! }! ! public function getName()! {! return 'my_text';! }! }!
  • 27. Data transformers class MeetingType extends AbstractType! {! public function buildForm(FormBuilderInterface $builder, array $option)! {! $builder->add('name', 'my_text');! $builder->add('when', 'date');! $builder->add('featured', 'checkbox');! }! ! public function getName()! {! return 'meeting';! }! }! Andrea Giuliano @bit_shark use my_text as a standard type
  • 28. Andrea Giuliano @bit_shark Remember Data Transformers transforms data representation Don’t use them to change data information
  • 30. Andrea Giuliano @bit_shark To change data information use form events Events
  • 31. Events class FacebookSubscriber implements EventSubscriberInterface! {! public static function getSubscribedEvents()! {! return array(FormEvents::PRE_SET_DATA => 'preSetData');! }! ! public function preSetData(FormEvent $event)! {! $data = $event->getData();! $form = $event->getForm();! ! if (null === $data) {! Andrea Giuliano @bit_shark return;! }! ! if (!$data->getFacebookId()) {! $form->add('username');! $form->add('password');! }! }! }
  • 32. Events class RegistrationType extends AbstractType! {! public function buildForm(FormBuilderInterface $builder, array $options)! {! $builder->add('name');! $builder->add('surname');! ! $builder->addEventSubscriber(new FacebookSubscriber());! }! ! public function getName()! {! return 'registration';! }! ! ...! ! } Andrea Giuliano @bit_shark add it to your type
  • 33. Events class RegistrationForm extends AbstractType! {! public function buildForm(FormBuilderInterface $builder, array $options)! {! $builder->add('name');! $builder->add('surname');! ! $builder->get('surname')->addEventListener(! Andrea Giuliano @bit_shark FormEvents::BIND,! function(FormEvent $event){! $event->setData(ucwords($event->getData()))! }! );! }! ! public function getName()! {! return 'registration';! }! }
  • 34. Events $form->setData($symfonyDay); PRE_SET_DATA Model Norm View Andrea Giuliano @bit_shark meeting [Form] POST_SET_DATA child
  • 35. Events POST_BIND $form->handleRequest($request); Model Norm View Andrea Giuliano @bit_shark meeting [Form] child PRE_BIND BIND
  • 36. Test
  • 37. namespace AcmeTestBundleTestsFormType;! ! use DnseeEventBundleFormTypeEventType;! use DnseeEventBundleModelEventObject;! use SymfonyComponentFormTestTypeTestCase;! ! class MeetingTypeTest extends TypeTestCase! {! Andrea Giuliano @bit_shark public function testSubmitValidData()! {! $formData = array(! 'name' => 'SymfonyDay',! 'date' => '2013-10-18',! 'featured' => true,! );! ! $type = new TestedType();! $form = $this->factory->create($type);! ! $object = new TestObject();! $object->fromArray($formData);! ! // submit the data to the form directly! $form->submit($formData);! ! $this->assertTrue($form->isSynchronized());! $this->assertEquals($object, $form->getData());! ! $view = $form->createView();! $children = $view->children;! ! foreach (array_keys($formData) as $key) {! $this->assertArrayHasKey($key, $children);! }! }! } Test
  • 38. namespace AcmeTestBundleTestsFormType;! ! use DnseeEventBundleFormTypeEventType;! use DnseeEventBundleModelEvent;! use SymfonyComponentFormTestTypeTestCase;! ! class MeetingTypeTest extends TypeTestCase! {! public function testSubmitValidData()! {! $formData = array(! Andrea Giuliano @bit_shark 'name' => 'SymfonyDay',! 'when' => '2013-10-18',! 'featured' => true,! );! ! $type = new EventType();! $form = $this->factory->create($type);! ! $event = new Event();! $event->fromArray($formData);! ! [...]! Test decide the data to be submitted
  • 39. Test namespace AcmeTestBundleTestsFormType;! ! use DnseeEventBundleFormTypeEventType;! use DnseeEventBundleModelEventObject;! use SymfonyComponentFormTestTypeTestCase;! ! class MeetingTypeTest extends TypeTestCase! {! public function testSubmitValidData()! {! ! [...]! ! $form->submit($formData);! ! $this->assertTrue($form->isSynchronized());! $this->assertEquals($object, $form->getData());! ! [...]! ! Andrea Giuliano @bit_shark test data transformers
  • 40. Test namespace AcmeTestBundleTestsFormType;! ! use AcmeTestBundleFormTypeTestedType;! use AcmeTestBundleModelTestObject;! use SymfonyComponentFormTestTypeTestCase;! ! class MeetingTypeTest extends TypeTestCase! {! public function testSubmitValidData()! {! ! [...]! ! $view = $form->createView();! $children = $view->children;! ! foreach (array_keys($formData) as $key) {! Andrea Giuliano @bit_shark $this->assertArrayHasKey($key, $children);! }! }! }! test form view creation
  • 41. Test namespace AcmeTestBundleTestsFormType;! ! use DnseeEventBundleFormTypeEventType;! use DnseeEventBundleModelEventObject;! use SymfonyComponentFormTestTypeTestCase;! ! class MeetingTypeTest extends TypeTestCase! {! protected function getExtensions()! {! $myCustomType = new MyCustomType();! return array(new PreloadedExtension(array(! Andrea Giuliano @bit_shark $myCustomType->getName() => $customType,! ), array()));! }! ! public function testSubmitValidData()! {! [...]! }! }
  • 42. Test namespace AcmeTestBundleTestsFormType;! ! use DnseeEventBundleFormTypeEventType;! use DnseeEventBundleModelEventObject;! use SymfonyComponentFormTestTypeTestCase;! ! class MeetingTypeTest extends TypeTestCase! {! protected function getExtensions()! {! $myCustomType = new MyCustomType();! return array(new PreloadedExtension(array(! Andrea Giuliano @bit_shark $myCustomType->getName() => $customType,! ), array()));! }! ! public function testSubmitValidData()! {! [...]! }! } Test your custom type FIRST
  • 43. ?
  • 45. References https://speakerdeck.com/webmozart/symfony2-form-tricks http://www.flickr.com/photos/yahya/132963781/ http://www.flickr.com/photos/lutherankorean/2694858251/ http://www.flickr.com/photos/lauroroger/8808985531/ http://www.flickr.com/photos/gifake/4643253235/ http://www.flickr.com/photos/zorin-denu/5222189908/ http://www.flickr.com/photos/aigle_dore/10014783623/ http://www.flickr.com/photos/skosoris/4985591296/ http://www.flickr.com/photos/sharynmorrow/248647126/