Slide 1

Slide 1 text

Bernhard Schussek @webmozart 1/96 Handling forms like a ninja with Symfony2 http://sanaril.deviantart.com/art/Unstealthiest-Ninja-276289913

Slide 2

Slide 2 text

Bernhard Schussek @webmozart 2/96 Bernhard Schussek

Slide 3

Slide 3 text

Bernhard Schussek @webmozart 3/96 Bernard "that Forms guy" @webmozart

Slide 4

Slide 4 text

Bernhard Schussek @webmozart 4/96 Austria

Slide 5

Slide 5 text

Bernhard Schussek @webmozart 5/96 http://upload.wikimedia.org/wikipedia/commons/b/b3/Blank_map_of_Europe.svg USA

Slide 6

Slide 6 text

http://collider.com/wp-content/uploads/Michael-Flatley-LORD-OF-THE-DANCE-1.jpg

Slide 7

Slide 7 text

Bernhard Schussek @webmozart 7/96 flag of Austria not the flag of Austria http://en.wikipedia.org/wiki/File:Flag_of_Austria.svg http://en.wikipedia.org/wiki/File:Zeichen_267.svg

Slide 8

Slide 8 text

Bernhard Schussek @webmozart 8/96 Ninjas http://askaninja.com

Slide 9

Slide 9 text

Bernhard Schussek @webmozart 9/96 Ninja … a covert agent in feudal Japan who specialized in unorthodox warfare … source: Wikipedia

Slide 10

Slide 10 text

Bernhard Schussek @webmozart 10/96 invisible

Slide 11

Slide 11 text

Bernhard Schussek @webmozart 11/96 super-human

Slide 12

Slide 12 text

Bernhard Schussek @webmozart 12/96 control the 5 elements

Slide 13

Slide 13 text

Bernhard Schussek @webmozart 13/96 tactics

Slide 14

Slide 14 text

Bernhard Schussek @webmozart 14/96 prepare innovate team up adapt

Slide 15

Slide 15 text

Bernhard Schussek @webmozart 15/96 2009 in a dark, dark age…

Slide 16

Slide 16 text

Bernhard Schussek @webmozart 16/96 I set out to become a ninja…

Slide 17

Slide 17 text

Bernhard Schussek @webmozart 17/96 prepare innovate team up adapt

Slide 18

Slide 18 text

Bernhard Schussek @webmozart 18/96 Step 1: Forge your weapons prepare innovate team up adapt

Slide 19

Slide 19 text

Bernhard Schussek @webmozart 19/96 Abstraction/Reuse application code 1. Abstract 2. Reuse A A A A

Slide 20

Slide 20 text

Bernhard Schussek @webmozart 20/96 Example: Choice Field

Slide 21

Slide 21 text

Bernhard Schussek @webmozart 21/96 Choices Example: Choice Field "1" "0" "" true false null User HTML/HTTP Application Yes No Don't know

Slide 22

Slide 22 text

Bernhard Schussek @webmozart 22/96 Application Form Logic View form submission string model type → render model type string → process/filter validate true "1" "0" false false false false "0" true default value submitted value lots of logic, lots of duplication!

Slide 23

Slide 23 text

Bernhard Schussek @webmozart 23/96 Application Form Logic View true choice field string model type → render model type string → process/filter validate true false default value submitted value create once, use often

Slide 24

Slide 24 text

Bernhard Schussek @webmozart 24/96 Coming from Rails, this is absurdly complicated. Why not leave this to what it is – a template level problem. Why do I need to create a new model just to render a form?! – Dave Pendejo source: http://webmozarts.com/2012/03/06/...

Slide 25

Slide 25 text

Bernhard Schussek @webmozart 25/96 Application Form Logic View form submission true "0" false true default value submitted value form helper render model type string → active record process/filter string model type → validate Rails dependency!

Slide 26

Slide 26 text

Bernhard Schussek @webmozart 26/96 Step 2: Combine forces abstract innovate team up adapt

Slide 27

Slide 27 text

Bernhard Schussek @webmozart 27/96 Composition 1. Compose 2. Reuse C C C A B C

Slide 28

Slide 28 text

Bernhard Schussek @webmozart 28/96 Example: Date Field date field choice field choice field choice field

Slide 29

Slide 29 text

Bernhard Schussek @webmozart 29/96 Recursive Composition choice field choice field choice field date field date field range field …

Slide 30

Slide 30 text

Bernhard Schussek @webmozart 30/96 Step 3: Expect innovation abstract innovate compose adapt

Slide 31

Slide 31 text

Bernhard Schussek @webmozart 31/96 Vertical Extension 1. Extend 2. Reuse B B B A B

Slide 32

Slide 32 text

Bernhard Schussek @webmozart 32/96 Example: DB Choice Field Specialized choice field that loads choices from a DB DB choice field db choice field

Slide 33

Slide 33 text

Bernhard Schussek @webmozart 33/96 Horizontal Extension 1. Reuse 2. Mix in A A A A A A A A + +

Slide 34

Slide 34 text

Bernhard Schussek @webmozart 34/96 Example: Mark Required Fields Add an asterisk to the label of all required fields base field add asterisk when required +

Slide 35

Slide 35 text

Bernhard Schussek @webmozart 35/96 Step 4: Change when needed abstract extend compose adapt

Slide 36

Slide 36 text

Bernhard Schussek @webmozart 36/96 Adaptiveness Server Browser form input/ DOM manipulation render submit adapt

Slide 37

Slide 37 text

Bernhard Schussek @webmozart 37/96 Example 1: Field Dependencies Render field depending on another field's selected value depends on

Slide 38

Slide 38 text

Bernhard Schussek @webmozart 38/96 Example 2: Collection Fields Submit lists of values by allowing to add/remove fields remove row add row

Slide 39

Slide 39 text

Bernhard Schussek @webmozart 39/96 four core principles abstract compose extend adapt

Slide 40

Slide 40 text

Bernhard Schussek @webmozart 40/96 2009 in a dark, dark age…

Slide 41

Slide 41 text

Bernhard Schussek @webmozart 41/96 In a dark, dark age… ● 2009 — symfony 1.2 forms — Zend_Form 1.10 — Zebra_Form 1.2 — HTML_QuickForm 3.2 — …

Slide 42

Slide 42 text

Bernhard Schussek @webmozart 42/96 abstract compose extend adapt ✓ ✗ ✗ ✗

Slide 43

Slide 43 text

Bernhard Schussek @webmozart 43/96 The master plan… ● The plan… — rebuild the symfony 1.2 forms ● The schedule… — a matter of months ● but the struggle should last for years…

Slide 44

Slide 44 text

Bernhard Schussek @webmozart 44/96 Symfony2 Form Component

Slide 45

Slide 45 text

Bernhard Schussek @webmozart 45/96 3+ years of development

Slide 46

Slide 46 text

Bernhard Schussek @webmozart 46/96 144+ contributors

Slide 47

Slide 47 text

Bernhard Schussek @webmozart 47/96 100+ open tickets

Slide 48

Slide 48 text

Bernhard Schussek @webmozart 48/96 500+ closed tickets

Slide 49

Slide 49 text

Bernhard Schussek @webmozart 49/96 Installation

Slide 50

Slide 50 text

Bernhard Schussek @webmozart 50/96 Installation via Composer { "require": { "symfony/form": "2.1.*", "symfony/validator": "2.1.*", "symfony/config": "2.1.*", "symfony/translation": "2.1.*", "symfony/twig-bridge": "2.1.*" } } composer.json https://github.com/bschussek/standalone-forms

Slide 51

Slide 51 text

Bernhard Schussek @webmozart 51/96 Bootstrapping ● Form Factory — creates forms — central object for registering types and extensions use Symfony\Component\Form\Forms; $factory = Forms::createFormFactoryBuilder() ->addType(...) ->addExtension(...) ->getFormFactory();

Slide 52

Slide 52 text

Bernhard Schussek @webmozart 52/96 Creating a Form

Slide 53

Slide 53 text

Bernhard Schussek @webmozart 53/96 Create a form

Slide 54

Slide 54 text

Bernhard Schussek @webmozart 54/96 Create a form $form = $factory->createBuilder() ->add('name', 'text') ->add('skill_level', 'choice', array( 'choices' => array(...) )) ->add('assassinations', 'number') ->getForm();

Slide 55

Slide 55 text

Bernhard Schussek @webmozart 55/96 Add validation constraints use Symfony\Component\Validator\Constraints as Assert; $form = $factory->createBuilder() ->add('name', 'text', array( 'constraints' => array( new Assert\NotBlank(), new Assert\MinLength(4), ) )) ... ->getForm();

Slide 56

Slide 56 text

Bernhard Schussek @webmozart 56/96 Use a form in the controller if (isset($_POST[$form->getName()])) { $form->bind($_POST[$form->getName()]); if ($form->isValid()) { print_r($form->getData()); } } // Array ( // [name] => Mei-Chi Lu // [skill_level] => elite // [assassinations] => 5 // )

Slide 57

Slide 57 text

Bernhard Schussek @webmozart 57/96 Render the form echo $twig->render('index.html.twig', array( 'form' => $form->createView(), )); index.html.twig {{ form_widget(form) }}

Slide 58

Slide 58 text

Bernhard Schussek @webmozart 58/96 Render the form

Slide 59

Slide 59 text

Bernhard Schussek @webmozart 59/96 The form tree name text skill_level choice assassin form assassinations number

Slide 60

Slide 60 text

Bernhard Schussek @webmozart 60/96 Composition assassinations number skill_level choice name text assassin form incident form …

Slide 61

Slide 61 text

Bernhard Schussek @webmozart 61/96 Composition assassinations number skill_level choice name text assassin form incident form … dynasty form …

Slide 62

Slide 62 text

Bernhard Schussek @webmozart 62/96 abstract compose extend adapt ✓

Slide 63

Slide 63 text

Bernhard Schussek @webmozart 63/96 Composition assassinations number skill_level choice name text assassin form incident form … form types $builder->add('name', 'text');

Slide 64

Slide 64 text

Bernhard Schussek @webmozart 64/96 Native types form checkbox file date hidden choice country language locale … …

Slide 65

Slide 65 text

Bernhard Schussek @webmozart 65/96 Creating a form type assassinations number skill_level choice name text assassin form incident form … ninja

Slide 66

Slide 66 text

Bernhard Schussek @webmozart 66/96 Creating a form type class NinjaType extends AbstractType { public function getName() { return 'ninja'; } ... }

Slide 67

Slide 67 text

Bernhard Schussek @webmozart 67/96 Creating a form type class NinjaType extends AbstractType { ... public function buildForm($builder, $options) { $builder->add('name', 'text') ->add('skill_level', 'choice', array( 'choices' => array(...) )) ->add('assassinations', 'number'); } }

Slide 68

Slide 68 text

Bernhard Schussek @webmozart 68/96 Registering a form type $factory = Forms::createFormFactoryBuilder() ->addType(new NinjaType()) ->getFormFactory(); $form = $factory->createBuilder() ->add('assassin', 'ninja') ... ->getForm(); Usage: $form = $factory->create('ninja');

Slide 69

Slide 69 text

Bernhard Schussek @webmozart 69/96 abstract compose extend adapt ✓ ✓

Slide 70

Slide 70 text

Bernhard Schussek @webmozart 70/96 Data transformation

Slide 71

Slide 71 text

Bernhard Schussek @webmozart 71/96 Data transformation date field DateTime DateTime form array/object array/object checkbox field boolean boolean

Slide 72

Slide 72 text

Bernhard Schussek @webmozart 72/96 Getting data into and out of the form $form->setData(array( 'name' => 'Mei-Chi Lu', 'skill_level' => 'elite', 'assassinations' => 5, )); print_r($form->getData()); // Array ( // [name] => Mei-Chi Lu // [skill_level] => elite // [assassinations] => 5 // )

Slide 73

Slide 73 text

Bernhard Schussek @webmozart 73/96 Getting data into and out of the form $form->setData(new Ninja('Mei-Chi Lu', 'elite', 5)); print_r($form->getData()); // Ninja Object ( // [name] => Mei-Chi Lu // [skill_level] => elite // [assassinations] => 5 // )

Slide 74

Slide 74 text

Bernhard Schussek @webmozart 74/96 Getting data into and out of the form $form->get('name')->setData('Mei-Chi Lu'); print_r($form->get('name')->getData()); // Mei-Chi Lu name text ninja form

Slide 75

Slide 75 text

Bernhard Schussek @webmozart 75/96 Theming

Slide 76

Slide 76 text

Bernhard Schussek @webmozart 76/96 Form theming form text choice url number … Form Logic View main template theme A include theme B

Slide 77

Slide 77 text

Bernhard Schussek @webmozart 77/96 Theming in the main template {% extends '::base.html.twig' %} {% form_theme form _self %} {% block content %} {{ form_widget(form.avg_kills) }} {% endblock %} {% block percent_widget %}
{{ parent() }}%
{% endblock %}

Slide 78

Slide 78 text

Bernhard Schussek @webmozart 78/96 Block names percent Type Template Section _widget _label _row Template Helper form_widget(form.field) form_label(form.field) form_row(form.field)

Slide 79

Slide 79 text

Bernhard Schussek @webmozart 79/96 Theming in separate templates {% extends '::base.html.twig' %} {% form_theme form 'NinjaBundle::theme.html.twig' %} {% block content %} {# render form... #} {% endblock %} {% block percent_widget %}
{{ parent() }}%
{% endblock %}

Slide 80

Slide 80 text

Bernhard Schussek @webmozart 80/96 abstract compose extend adapt ✓ ✓

Slide 81

Slide 81 text

Bernhard Schussek @webmozart 81/96 Extension concepts A B A A + vertical type inheritance horizontal type extensions packaging component extensions ext A B C + + …

Slide 82

Slide 82 text

Bernhard Schussek @webmozart 82/96 Vertical extension class NinjaType extends AbstractType { public function getParent() { return 'form'; } } form ninja "is a"

Slide 83

Slide 83 text

Bernhard Schussek @webmozart 83/96 Horizontal extension text strip HTML + class TextTypeStripHtmlExtension extends AbstractTypeExtension { public function getExtendedType() { return 'form'; } } "mix in"

Slide 84

Slide 84 text

Bernhard Schussek @webmozart 84/96 Mixed vertical/horizontal extension text strip HTML + search extensions are inherited

Slide 85

Slide 85 text

Bernhard Schussek @webmozart 85/96 Packaging class NinjaExtension extends AbstractExtension { protected function loadTypes() { return array(new NinjaType()); } protected function loadTypeExtensions() { return array(new TextTypeStripHtmlExtension()); } } ext ninja strip HTML +

Slide 86

Slide 86 text

Bernhard Schussek @webmozart 86/96 Extension based architecture Form Engine Foundation … … Extensions Templating Core ext Validation ext DI ext CSRF ext Doctrine ext Propel ext Zend_Filter ext jQuery ext Bootstrap ext Zend_Validator ext Twig ext PHP Templating ext Smarty ext

Slide 87

Slide 87 text

Bernhard Schussek @webmozart 87/96 Bootstrapping continued $formFactory = Forms::createFormFactoryBuilder() // extensions ->addExtension(new TwigExtension(...)) ->addExtension(new CsrfExtension(...)) ->addExtension(new ValidatorExtension(...)) // custom types ->addType(new NinjaType()) // custom type extensions ->addTypeExtension(new TextTypeStripHtmlExtension()) ->getFormFactory();

Slide 88

Slide 88 text

Bernhard Schussek @webmozart 88/96 abstract compose extend adapt ✓ ✓ ✓

Slide 89

Slide 89 text

Bernhard Schussek @webmozart 89/96 abstract compose extend adapt ✓ ✓ ✓

Slide 90

Slide 90 text

Bernhard Schussek @webmozart 90/96 Field dependencies depends on work in progress, not yet solved

Slide 91

Slide 91 text

Bernhard Schussek @webmozart 91/96 Collection fields $builder->add('victims', 'collection', array( 'type' => 'text', ));

Slide 92

Slide 92 text

Bernhard Schussek @webmozart 92/96 abstract compose extend adapt ✓ ✓ ✓ ~

Slide 93

Slide 93 text

Bernhard Schussek @webmozart 93/96 Bad News Form handling is incredibly complex

Slide 94

Slide 94 text

Bernhard Schussek @webmozart 94/96 Good News We do it for you! ;-)

Slide 95

Slide 95 text

Bernhard Schussek @webmozart 95/96 Where to get ● Symfony Form component: — https://github.com/symfony/Form ● Documentation: — http://symfony.com/doc/current/book/forms.html ● Standalone-usage sample: — https://github.com/bschussek/standalone-forms

Slide 96

Slide 96 text

Bernhard Schussek @webmozart 96/96 Questions? http://joind.in/talk/view/8023 Thank you! Bernhard Schussek @webmozart http://sanaril.deviantart.com/art/Unstealthiest-Ninja-III-309883920