Merge branch '3.4' into 4.2

* 3.4:
  [Form] various minor fixes
  bugfix: the terminal state was wrong and not reseted
  [Console] Fix inconsistent result for choice questions in non-interactive mode
  Define null return type for Constraint::getDefaultOption()
  [HttpKernel] Fix DebugHandlersListener constructor docblock
  Skip Glob brace test when GLOB_BRACE is unavailable
  bumped Symfony version to 3.4.25
  updated VERSION for 3.4.24
  update CONTRIBUTORS for 3.4.24
  updated CHANGELOG for 3.4.24
  [EventDispatcher] cleanup
This commit is contained in:
Fabien Potencier 2019-04-06 15:51:08 +02:00
commit fa44efe90c
33 changed files with 473 additions and 371 deletions

View File

@ -15,21 +15,21 @@ Symfony is the result of the work of many people who made the code better
- Victor Berchet (victor)
- Kévin Dunglas (dunglas)
- Maxime Steinhausser (ogizanagi)
- Ryan Weaver (weaverryan)
- Jakub Zalas (jakubzalas)
- Johannes S (johannes)
- Javier Eguiluz (javier.eguiluz)
- Ryan Weaver (weaverryan)
- Kris Wallsmith (kriswallsmith)
- Roland Franssen (ro0)
- Grégoire Pineau (lyrixx)
- Roland Franssen (ro0)
- Hugo Hamon (hhamon)
- Abdellatif Ait boudad (aitboudad)
- Romain Neutron (romain)
- Pascal Borreli (pborreli)
- Wouter De Jong (wouterj)
- Samuel ROZE (sroze)
- Joseph Bielawski (stloyd)
- Karma Dordrak (drak)
- Samuel ROZE (sroze)
- Lukas Kahwe Smith (lsmith)
- Martin Hasoň (hason)
- Jeremy Mikola (jmikola)
@ -42,8 +42,8 @@ Symfony is the result of the work of many people who made the code better
- Guilhem Niot (energetick)
- Sarah Khalil (saro0h)
- Jonathan Wage (jwage)
- Hamza Amrouche (simperfit)
- Tobias Nyholm (tobias)
- Hamza Amrouche (simperfit)
- Diego Saint Esteben (dosten)
- Iltar van der Berg (kjarli)
- Alexandre Salomé (alexandresalome)
@ -54,8 +54,8 @@ Symfony is the result of the work of many people who made the code better
- stealth35 (stealth35)
- Alexander Mols (asm89)
- Bulat Shakirzyanov (avalanche123)
- Matthias Pigulla (mpdude)
- Jérémy DERUSSÉ (jderusse)
- Matthias Pigulla (mpdude)
- Saša Stamenković (umpirsky)
- Peter Rehm (rpet)
- Kevin Bond (kbond)
@ -69,23 +69,24 @@ Symfony is the result of the work of many people who made the code better
- Mathieu Piot (mpiot)
- Florin Patan (florinpatan)
- Gábor Egyed (1ed)
- Gabriel Ostrolucký (gadelat)
- Titouan Galopin (tgalopin)
- Vladimir Reznichenko (kalessil)
- Jáchym Toušek (enumag)
- David Maicher (dmaicher)
- Michel Weimerskirch (mweimerskirch)
- Andrej Hudec (pulzarraider)
- Konstantin Myakshin (koc)
- Eric Clemmons (ericclemmons)
- Charles Sarrazin (csarrazi)
- David Maicher (dmaicher)
- Christian Raue
- Issei Murasawa (issei_m)
- Valentin Udaltsov (vudaltsov)
- Arnout Boks (aboks)
- Deni
- Grégoire Paris (greg0ire)
- Henrik Westphal (snc)
- Dariusz Górecki (canni)
- Valentin Udaltsov (vudaltsov)
- Douglas Greenshields (shieldo)
- Dariusz Ruminski
- Lee McDermott
@ -99,7 +100,6 @@ Symfony is the result of the work of many people who made the code better
- Jérôme Tamarelle (gromnan)
- John Wards (johnwards)
- Fran Moreno (franmomu)
- gadelat (gadelat)
- Antoine Hérault (herzult)
- Paráda József (paradajozsef)
- Arnaud Le Blanc (arnaud-lb)
@ -108,13 +108,14 @@ Symfony is the result of the work of many people who made the code better
- Tim Nagel (merk)
- Brice BERNARD (brikou)
- Baptiste Clavié (talus)
- Chris Wilkinson (thewilkybarkid)
- marc.weistroff
- Tomáš Votruba (tomas_votruba)
- David Buchmann (dbu)
- lenar
- Alexander Schwenn (xelaris)
- Włodzimierz Gajda (gajdaw)
- Chris Wilkinson (thewilkybarkid)
- Thomas Calvet (fancyweb)
- Jérôme Vasseur (jvasseur)
- Peter Kokot (maastermedia)
- Jacob Dreesen (jdreesen)
@ -125,11 +126,10 @@ Symfony is the result of the work of many people who made the code better
- Daniel Wehner (dawehner)
- excelwebzone
- Gordon Franke (gimler)
- Thomas Calvet (fancyweb)
- Sebastiaan Stok (sstok)
- Javier Spagnoletti (phansys)
- Fabien Pennequin (fabienpennequin)
- Eric GELOEN (gelo)
- Sebastiaan Stok (sstok)
- Lars Strojny (lstrojny)
- Tugdual Saunier (tucksaun)
- Théo FIDRY (theofidry)
@ -140,14 +140,18 @@ Symfony is the result of the work of many people who made the code better
- Alex Pott
- Vincent AUBERT (vincent)
- Juti Noppornpitak (shiroyuki)
- Anthony MARTIN (xurudragon)
- Oskar Stark (oskarstark)
- Tigran Azatyan (tigranazatyan)
- Sebastian Hörl (blogsh)
- Daniel Gomes (danielcsgomes)
- Joel Wurtz (brouznouf)
- Gabriel Caruso
- Hidenori Goto (hidenorigoto)
- Arnaud Kleinpeter (nanocom)
- Jannik Zschiesche (apfelbox)
- Guilherme Blanco (guilhermeblanco)
- Teoh Han Hui (teohhanhui)
- Pablo Godel (pgodel)
- Jérémie Augustin (jaugustin)
- Andréia Bohner (andreia)
@ -155,9 +159,7 @@ Symfony is the result of the work of many people who made the code better
- Julien Falque (julienfalque)
- Rafael Dohms (rdohms)
- jwdeitch
- Teoh Han Hui (teohhanhui)
- Mikael Pajunen
- Joel Wurtz (brouznouf)
- Oleg Voronkovich
- Vyacheslav Pavlov
- Richard van Laak (rvanlaak)
@ -172,7 +174,6 @@ Symfony is the result of the work of many people who made the code better
- Matthieu Ouellette-Vachon (maoueh)
- Michał Pipa (michal.pipa)
- Dawid Nowak
- Gabriel Ostrolucký
- Amal Raghav (kertz)
- Jonathan Ingram (jonathaningram)
- Artur Kotyrba
@ -181,12 +182,12 @@ Symfony is the result of the work of many people who made the code better
- SpacePossum
- jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent)
- James Halsall (jaitsu)
- Anthony MARTIN (xurudragon)
- Matthieu Napoli (mnapoli)
- Florent Mata (fmata)
- Warnar Boekkooi (boekkooi)
- Dmitrii Chekaliuk (lazyhammer)
- Clément JOBEILI (dator)
- Marek Štípek (maryo)
- Daniel Espendiller
- Possum
- Dorian Villet (gnutix)
@ -196,7 +197,7 @@ Symfony is the result of the work of many people who made the code better
- Mario A. Alvarez Garcia (nomack84)
- Dennis Benkert (denderello)
- DQNEO
- Oskar Stark (oskarstark)
- Samuel NELA (snela)
- Benjamin Dulau (dbenjamin)
- François-Xavier de Guillebon (de-gui_f)
- Mathieu Lemoine (lemoinem)
@ -205,7 +206,6 @@ Symfony is the result of the work of many people who made the code better
- Tom Van Looy (tvlooy)
- Noel Guilbert (noel)
- Yanick Witschi (toflar)
- Marek Štípek (maryo)
- Stepan Anchugov (kix)
- bronze1man
- sun (sun)
@ -217,24 +217,28 @@ Symfony is the result of the work of many people who made the code better
- apetitpa
- Matthieu Bontemps (mbontemps)
- apetitpa
- Samuel NELA (snela)
- Pierre Minnieur (pminnieur)
- fivestar
- Dominique Bongiraud
- Jeremy Livingston (jeremylivingston)
- Michael Lee (zerustech)
- Matthieu Auger (matthieuauger)
- Gregor Harlan (gharlan)
- Leszek Prabucki (l3l0)
- Fabien Bourigault (fbourigault)
- François Zaninotto (fzaninotto)
- Dustin Whittle (dustinwhittle)
- jeff
- John Kary (johnkary)
- Andreas Schempp (aschempp)
- Justin Hileman (bobthecow)
- Blanchon Vincent (blanchonvincent)
- Michele Orselli (orso)
- Sven Paulus (subsven)
- Maxime Veber (nek-)
- Gary PEGEOT (gary-p)
- Rui Marinho (ruimarinho)
- Massimiliano Arione (garak)
- Eugene Wissner
- Pascal Montoya
- Julien Brochet (mewt)
@ -242,15 +246,17 @@ Symfony is the result of the work of many people who made the code better
- Tristan Darricau (nicofuma)
- Marcel Beerta (mazen)
- Pavel Batanov (scaytrase)
- Mantis Development
- Loïc Faugeron
- Hidde Wieringa (hiddewie)
- Marco Pivetta (ocramius)
- Jan Schädlich (jschaedl)
- Rob Frawley 2nd (robfrawley)
- julien pauli (jpauli)
- Lorenz Schori
- Sébastien Lavoie (lavoiesl)
- Gregor Harlan (gharlan)
- Dariusz
- Michael Babker (mbabker)
- Francois Zaninotto
- Alexander Kotynia (olden)
- Daniel Tschinder
@ -265,7 +271,6 @@ Symfony is the result of the work of many people who made the code better
- Roman Marintšenko (inori)
- Xavier Montaña Carreras (xmontana)
- Mickaël Andrieu (mickaelandrieu)
- Maxime Veber (nek-)
- Xavier Perez
- Arjen Brouwer (arjenjb)
- Katsuhiro OGAWA
@ -277,6 +282,7 @@ Symfony is the result of the work of many people who made the code better
- Baptiste Lafontaine (magnetik)
- Jakub Kucharovic (jkucharovic)
- Edi Modrić (emodric)
- Alexander Schranz (alexander-schranz)
- Uwe Jäger (uwej711)
- Eugene Leonovich (rybakit)
- Filippo Tessarotto
@ -290,10 +296,9 @@ Symfony is the result of the work of many people who made the code better
- Viktor Bocharskyi (bocharsky_bw)
- Jhonny Lidfors (jhonne)
- Diego Agulló (aeoris)
- Andreas Schempp (aschempp)
- jdhoek
- Massimiliano Arione (garak)
- Bob den Otter (bopp)
- Thomas Schulz (king2500)
- Frank de Jonge (frenkynet)
- Nikita Konstantinov
- Wodor Wodorski
@ -301,7 +306,7 @@ Symfony is the result of the work of many people who made the code better
- mcfedr (mcfedr)
- Colin O'Dell (colinodell)
- Giorgio Premi
- Jan Schädlich (jschaedl)
- Alex Rock (pierstoval)
- Ben Davies (bendavies)
- Beau Simensen (simensen)
- Michael Hirschler (mvhirsch)
@ -309,9 +314,9 @@ Symfony is the result of the work of many people who made the code better
- Roumen Damianoff (roumen)
- Antonio J. García Lagar (ajgarlag)
- Kim Hemsø Rasmussen (kimhemsoe)
- Pascal Luna (skalpa)
- Wouter Van Hecke
- Jérôme Parmentier (lctrs)
- Michael Babker (mbabker)
- Peter Kruithof (pkruithof)
- Michael Holm (hollo)
- Remon van de Kamp (rpkamp)
@ -319,14 +324,13 @@ Symfony is the result of the work of many people who made the code better
- Marc Weistroff (futurecat)
- Christian Schmidt
- MatTheCat
- Alexander Schranz (alexander-schranz)
- Chad Sikorra (chadsikorra)
- Chris Smith (cs278)
- Florian Klein (docteurklein)
- Gary PEGEOT (gary-p)
- Manuel Kiessling (manuelkiessling)
- Atsuhiro KUBO (iteman)
- rudy onfroy (ronfroy)
- Serkan Yildiz (srknyldz)
- Andrew Moore (finewolf)
- Bertrand Zuchuat (garfield-fr)
- Sullivan SENECHAL (soullivaneuh)
@ -347,14 +351,16 @@ Symfony is the result of the work of many people who made the code better
- Hidde Boomsma (hboomsma)
- John Bafford (jbafford)
- Raul Fraile (raulfraile)
- David Prévot
- Adrian Rudnik (kreischweide)
- Francesc Rosàs (frosas)
- Romain Pierre (romain-pierre)
- Julien Galenski (ruian)
- Bongiraud Dominique
- janschoenherr
- Thomas Schulz (king2500)
- Emanuele Gaspari (inmarelibero)
- Dariusz Rumiński
- Vincent Touzet (vincenttouzet)
- Berny Cantos (xphere81)
- Thierry Thuon (lepiaf)
- Ricard Clau (ricardclau)
@ -367,8 +373,9 @@ Symfony is the result of the work of many people who made the code better
- Zan Baldwin (zanderbaldwin)
- Thomas Royer (cydonia7)
- alquerci
- Mateusz Sip (mateusz_sip)
- Andre Rømcke (andrerom)
- Francesco Levorato
- Pascal Luna (skalpa)
- Dmitrii Poddubnyi (karser)
- Vitaliy Zakharov (zakharovvi)
- Tobias Sjösten (tobiassjosten)
@ -384,6 +391,7 @@ Symfony is the result of the work of many people who made the code better
- Yaroslav Kiliba
- Terje Bråten
- Robbert Klarenbeek (robbertkl)
- Eric Masoero (eric-masoero)
- JhonnyL
- David Badura (davidbadura)
- hossein zolfi (ocean)
@ -394,6 +402,7 @@ Symfony is the result of the work of many people who made the code better
- ShinDarth
- Stéphane PY (steph_py)
- Philipp Kräutli (pkraeutli)
- Anton Chernikov (anton_ch1989)
- Grzegorz (Greg) Zdanowski (kiler129)
- Iker Ibarguren (ikerib)
- Kirill chEbba Chebunin (chebba)
@ -414,10 +423,10 @@ Symfony is the result of the work of many people who made the code better
- Tobias Naumann (tna)
- Daniel Beyer
- Shein Alexey
- Alex Rock Ancelet (pierstoval)
- Romain Gautier (mykiwi)
- Joe Lencioni
- Daniel Tschinder
- Emmanuel BORGES (eborges78)
- vladimir.reznichenko
- Kai
- Lee Rowlands
@ -427,7 +436,6 @@ Symfony is the result of the work of many people who made the code better
- Karoly Negyesi (chx)
- Ivan Kurnosov
- Xavier HAUSHERR
- David Prévot
- Albert Jessurum (ajessu)
- Laszlo Korte
- Miha Vrhovnik
@ -440,7 +448,6 @@ Symfony is the result of the work of many people who made the code better
- Karel Souffriau
- Christophe L. (christophelau)
- Anthon Pang (robocoder)
- Emanuele Gaspari (inmarelibero)
- Sébastien Santoro (dereckson)
- Brian King
- Michel Salib (michelsalib)
@ -461,7 +468,7 @@ Symfony is the result of the work of many people who made the code better
- Olivier Dolbeau (odolbeau)
- Jan Rosier (rosier)
- Alessandro Lai (jean85)
- Andre Rømcke (andrerom)
- Nicolas LEFEVRE (nicoweb)
- Arturs Vonda
- Josip Kruslin
- Asmir Mustafic (goetas)
@ -473,7 +480,6 @@ Symfony is the result of the work of many people who made the code better
- Vlad Gregurco (vgregurco)
- Boris Vujicic (boris.vujicic)
- Chris Sedlmayr (catchamonkey)
- Mateusz Sip (mateusz_sip)
- Kamil Kokot (pamil)
- Seb Koelen
- Christoph Mewes (xrstf)
@ -528,6 +534,7 @@ Symfony is the result of the work of many people who made the code better
- ondrowan
- Barry vd. Heuvel (barryvdh)
- Craig Duncan (duncan3dc)
- Patrick Landolt (scube)
- Sébastien Alfaiate (seb33300)
- Evan S Kaufman (evanskaufman)
- mcben
@ -603,6 +610,7 @@ Symfony is the result of the work of many people who made the code better
- Jan Behrens
- Mantas Var (mvar)
- Sebastian Krebs
- Piotr Stankowski
- Baptiste Leduc (bleduc)
- Laurent VOULLEMIER (lvo)
- Jean-Christophe Cuvelier [Artack]
@ -617,6 +625,7 @@ Symfony is the result of the work of many people who made the code better
- Renan
- Ricky Su (ricky)
- Gildas Quéméner (gquemener)
- Kyle Evans (kevans91)
- Charles-Henri Bruyand
- Max Rath (drak3)
- Stéphane Escandell (sescandell)
@ -625,6 +634,8 @@ Symfony is the result of the work of many people who made the code better
- Sinan Eldem
- Alexandre Dupuy (satchette)
- Malte Blättermann
- Kévin THERAGE (kevin_therage)
- Simeon Kolev (simeon_kolev9)
- Nahuel Cuesta (ncuesta)
- Chris Boden (cboden)
- Christophe Villeger (seragan)
@ -649,11 +660,13 @@ Symfony is the result of the work of many people who made the code better
- Sebastian Marek (proofek)
- Guilhem N (guilhemn)
- Erkhembayar Gantulga (erheme318)
- zenmate
- Michal Trojanowski
- David Fuhr
- Max Grigorian (maxakawizard)
- DerManoMann
- Rostyslav Kinash
- Dennis Fridrich (dfridrich)
- Maciej Malarz (malarzm)
- Daisuke Ohata
- Vincent Simonin
@ -707,6 +720,7 @@ Symfony is the result of the work of many people who made the code better
- Paweł Wacławczyk (pwc)
- Oleg Zinchenko (cystbear)
- Baptiste Meyer (meyerbaptiste)
- Tales Santos (tsantos84)
- Johannes Klauss (cloppy)
- Evan Villemez
- fzerorubigd
@ -720,6 +734,7 @@ Symfony is the result of the work of many people who made the code better
- flip111
- Greg Anderson
- VJ
- RJ Garcia
- Delf Tonder (leberknecht)
- Mark Sonnabaum
- Massimiliano Braglia (massimilianobraglia)
@ -738,15 +753,14 @@ Symfony is the result of the work of many people who made the code better
- Julien DIDIER (juliendidier)
- Dominik Ritter (dritter)
- Sebastian Grodzicki (sgrodzicki)
- Serkan Yildiz (srknyldz)
- Jeroen van den Enden (stoefke)
- nikos.sotiropoulos
- Pascal Helfenstein
- Anthony GRASSIOT (antograssiot)
- Baldur Rensch (brensch)
- Pierre Rineau
- Vladyslav Petrovych
- Alex Xandra Albert Sim
- Patrick Landolt (scube)
- Carson Full
- Sergey Yastrebov
- Trent Steel (trsteel88)
@ -761,6 +775,7 @@ Symfony is the result of the work of many people who made the code better
- Dave Marshall (davedevelopment)
- Jakub Kulhan (jakubkulhan)
- avorobiev
- Grégoire Penverne (gpenverne)
- Venu
- Lars Vierbergen
- Jonatan Männchen
@ -774,6 +789,7 @@ Symfony is the result of the work of many people who made the code better
- Jordan Deitch
- Casper Valdemar Poulsen
- Josiah (josiah)
- Greg ORIOL
- Joschi Kuphal
- John Bohn (jbohn)
- Marc Morera (mmoreram)
@ -922,6 +938,7 @@ Symfony is the result of the work of many people who made the code better
- Stéphane Delprat
- Brian Freytag (brianfreytag)
- Samuele Lilli (doncallisto)
- Marko Kaznovac (kaznovac)
- Brunet Laurent (lbrunet)
- Florent Viel (luxifer)
- Mikhail Yurasov (mym)
@ -937,15 +954,17 @@ Symfony is the result of the work of many people who made the code better
- Kyle
- Daniel Alejandro Castro Arellano (lexcast)
- sensio
- Thomas Jarrand
- Sebastien Morel (plopix)
- Patrick Kaufmann
- Piotr Stankowski
- Anton Dyshkant
- Reece Fowell (reecefowell)
- Mátyás Somfai (smatyas)
- stefan.r
- Valérian Galliat
- d-ph
- Renan Taranto (renan-taranto)
- Thomas Talbot (ioni)
- Rikijs Murgs
- Ben Ramsey (ramsey)
- Amaury Leroux de Lens (amo__)
@ -954,12 +973,14 @@ Symfony is the result of the work of many people who made the code better
- The Whole Life to Learn
- ergiegonzaga
- Farhad Safarov
- Alexis Lefebvre
- Liverbool (liverbool)
- Sam Malone
- Phan Thanh Ha (haphan)
- Chris Jones (leek)
- xaav
- Mahmoud Mostafa (mahmoud)
- Ahmed Abdou
- Pieter
- Michael Tibben
- Billie Thompson
@ -992,21 +1013,23 @@ Symfony is the result of the work of many people who made the code better
- Irmantas Šiupšinskas (irmantas)
- Danilo Silva
- Arnaud PETITPAS (apetitpa)
- Ken Stanley
- Zachary Tong (polyfractal)
- Ashura
- Hryhorii Hrebiniuk
- johnstevenson
- Dennis Fridrich (dfridrich)
- hamza
- dantleech
- Bastien DURAND (deamon)
- Xavier Leune
- Rudy Onfroy
- Tero Alén (tero)
- Stanislav Kocanda
- DerManoMann
- Guillaume Royer
- Artem (digi)
- boite
- Silvio Ginter
- MGDSoft
- Vadim Tyukov (vatson)
- David Wolter (davewww)
@ -1015,6 +1038,7 @@ Symfony is the result of the work of many people who made the code better
- Wojciech Sznapka
- Gavin Staniforth
- Ariel J. Birnbaum
- Danijel Obradović
- Pablo Borowicz
- Mathieu Santostefano
- Arjan Keeman
@ -1065,7 +1089,6 @@ Symfony is the result of the work of many people who made the code better
- Jean-Guilhem Rouel (jean-gui)
- jfcixmedia
- Dominic Tubach
- Tales Santos (tsantos84)
- Nikita Konstantinov
- Martijn Evers
- Vitaliy Ryaboy (vitaliy)
@ -1094,6 +1117,7 @@ Symfony is the result of the work of many people who made the code better
- Tadas Gliaubicas (tadcka)
- Thanos Polymeneas (thanos)
- Benoit Garret
- Maximilian Ruta (deltachaos)
- Jakub Sacha
- Olaf Klischat
- orlovv
@ -1131,7 +1155,6 @@ Symfony is the result of the work of many people who made the code better
- rpg600
- Péter Buri (burci)
- kaiwa
- RJ Garcia
- Charles Sanquer (csanquer)
- Albert Ganiev (helios-ag)
- Neil Katin
@ -1148,7 +1171,6 @@ Symfony is the result of the work of many people who made the code better
- rchoquet
- gitlost
- Taras Girnyk
- nikos.sotiropoulos
- Eduardo García Sanz (coma)
- Sergio (deverad)
- James Gilliland
@ -1207,7 +1229,6 @@ Symfony is the result of the work of many people who made the code better
- Mario Young
- Ilia (aliance)
- Chris McCafferty (cilefen)
- Grégoire Penverne (gpenverne)
- Mo Di (modi)
- Pablo Schläpfer
- Gert de Pagter
@ -1215,6 +1236,7 @@ Symfony is the result of the work of many people who made the code better
- Quique Porta (quiqueporta)
- stoccc
- Tomasz Szymczyk (karion)
- Alex Vasilchenko
- Xavier Coureau
- ConneXNL
- Aharon Perkel
@ -1232,8 +1254,10 @@ Symfony is the result of the work of many people who made the code better
- Sebastian Göttschkes (sgoettschkes)
- Tatsuya Tsuruoka
- Ross Tuck
- Andreas Erhard
- Kévin Gomez (kevin)
- Mihai Nica (redecs)
- Soufian EZ-ZANTAR (soezz)
- Andrei Igna
- azine
- Dawid Sajdak
@ -1249,6 +1273,7 @@ Symfony is the result of the work of many people who made the code better
- Saem Ghani
- Clément LEFEBVRE
- Conrad Kleinespel
- Matthias Althaus
- Zacharias Luiten
- Sebastian Utz
- Adrien Gallou (agallou)
@ -1288,6 +1313,7 @@ Symfony is the result of the work of many people who made the code better
- Markus Fasselt (digilist)
- Vašek Purchart (vasek-purchart)
- Janusz Jabłoński (yanoosh)
- Fleuv
- Sandro Hopf
- Łukasz Makuch
- George Giannoulopoulos
@ -1311,11 +1337,11 @@ Symfony is the result of the work of many people who made the code better
- Daniel Kay (danielkay-cp)
- Matt Daum (daum)
- Alberto Pirovano (geezmo)
- Nicolas LEFEVRE (nicoweb)
- Pete Mitchell (peterjmit)
- Tom Corrigan (tomcorrigan)
- Luis Galeas
- Martin Pärtel
- Frédéric Bouchery (fbouchery)
- Patrick Daley (padrig)
- Xavier Briand (xavierbriand)
- Max Summe
@ -1336,6 +1362,7 @@ Symfony is the result of the work of many people who made the code better
- Emmanuel Vella (emmanuel.vella)
- Guillaume BRETOU (guiguiboy)
- Jonathan Johnson (jrjohnson)
- Dāvis Zālītis (k0d3r1s)
- Carsten Nielsen (phreaknerd)
- Roger Guasch (rogerguasch)
- Mathieu Rochette
@ -1371,6 +1398,7 @@ Symfony is the result of the work of many people who made the code better
- mlively
- Amine Matmati
- caalholm
- Nouhail AL FIDI (alfidi)
- Fabian Steiner (fabstei)
- Felipy Tavares Amorim (felipyamorim)
- Klaus Silveira (klaussilveira)
@ -1420,7 +1448,6 @@ Symfony is the result of the work of many people who made the code better
- Hoffmann András
- LubenZA
- Olivier
- Anton Chernikov
- Cyril PASCAL
- pscheit
- Wybren Koelmans
@ -1432,6 +1459,7 @@ Symfony is the result of the work of many people who made the code better
- Antonio Peric-Mazar (antonioperic)
- César Suárez (csuarez)
- Bjorn Twachtmann (dotbjorn)
- Tobias Genberg (lorceroth)
- Luis Tacón (lutacon)
- Nicolas Badey (nico-b)
- Shane Preece (shane)
@ -1465,10 +1493,9 @@ Symfony is the result of the work of many people who made the code better
- Przemysław Piechota (kibao)
- Leonid Terentyev (li0n)
- Martynas Sudintas (martiis)
- Gabriel Ostrolucký
- ryunosuke
- zenmate
- victoria
- Dmytro Borysovskyi (dmytr0)
- Francisco Facioni (fran6co)
- Iwan van Staveren (istaveren)
- Povilas S. (povilas)
@ -1488,6 +1515,7 @@ Symfony is the result of the work of many people who made the code better
- Ikhsan Agustian
- Arnau González (arnaugm)
- Simon Bouland (bouland)
- Jibé Barth (jibbarth)
- Matthew Foster (mfoster)
- Reyo Stallenberg (reyostallenberg)
- Paul Seiffert (seiffert)
@ -1531,7 +1559,6 @@ Symfony is the result of the work of many people who made the code better
- Gunther Konig
- Mickael GOETZ
- Maciej Schmidt
- Greg ORIOL
- Dennis Væversted
- nuncanada
- flack
@ -1652,6 +1679,7 @@ Symfony is the result of the work of many people who made the code better
- Trevor Suarez
- gedrox
- Alan Bondarchuk
- Joe Bennett
- dropfen
- Andrey Chernykh
- Edvinas Klovas
@ -1671,6 +1699,7 @@ Symfony is the result of the work of many people who made the code better
- AmsTaFF (amstaff)
- Simon Müller (boscho)
- Yannick Bensacq (cibou)
- Damien (damien_vauchel)
- Frédéric G. Marand (fgm)
- Freek Van der Herten (freekmurze)
- Luca Genuzio (genuzio)
@ -1735,6 +1764,7 @@ Symfony is the result of the work of many people who made the code better
- timaschew
- Jochen Mandl
- Marin Nicolae
- soyuka
- Alessandro Loffredo
- Ian Phillips
- Marco Lipparini
@ -1810,6 +1840,7 @@ Symfony is the result of the work of many people who made the code better
- Kevin Verschaeve (keversc)
- Kevin Herrera (kherge)
- Luis Ramón López López (lrlopez)
- Mehdi Mabrouk (mehdidev)
- Bart Reunes (metalarend)
- Muriel (metalmumu)
- Michael Pohlers (mick_the_big)
@ -1861,6 +1892,7 @@ Symfony is the result of the work of many people who made the code better
- Ramon Henrique Ornelas (ramonornela)
- Ricardo de Vries (ricknox)
- Markus S. (staabm)
- Thomas Dutrion (theocrite)
- Till Klampaeckel (till)
- Tobias Weinert (tweini)
- Ulf Reimers (ureimers)
@ -2011,7 +2043,6 @@ Symfony is the result of the work of many people who made the code better
- phc
- Дмитрий Пацура
- ilyes kooli
- Marko Kaznovac
- Matthias Althaus
- Michaël VEROUX
- Julia
@ -2073,6 +2104,7 @@ Symfony is the result of the work of many people who made the code better
- samuel laulhau (lalop)
- Laurent Bachelier (laurentb)
- Luís Cobucci (lcobucci)
- Marcos Gómez Vilches (markitosgv)
- Matthieu Mota (matthieumota)
- Matthieu Moquet (mattketmo)
- Moritz Borgmann (mborgmann)

View File

@ -49,7 +49,13 @@ class QuestionHelper extends Helper
if (!$input->isInteractive()) {
$default = $question->getDefault();
if (null !== $default && $question instanceof ChoiceQuestion) {
if (null === $default) {
return $default;
}
if ($validator = $question->getValidator()) {
return \call_user_func($question->getValidator(), $default);
} elseif ($question instanceof ChoiceQuestion) {
$choices = $question->getChoices();
if (!$question->isMultiselect()) {
@ -215,6 +221,7 @@ class QuestionHelper extends Helper
// as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false.
if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) {
shell_exec(sprintf('stty %s', $sttyMode));
throw new RuntimeException('Aborted.');
} elseif ("\177" === $c) { // Backspace Character
if (0 === $numMatches && 0 !== $i) {

View File

@ -137,6 +137,9 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
$question->setMultiselect(true);
$this->assertNull($questionHelper->ask($this->createStreamableInputInterfaceMock($inputStream, false), $this->createOutputInterface(), $question));
$question = new ChoiceQuestion('Who are your favorite superheros?', ['a' => 'Batman', 'b' => 'Superman'], 'a');
$this->assertSame('a', $questionHelper->ask($this->createStreamableInputInterfaceMock('', false), $this->createOutputInterface(), $question), 'ChoiceQuestion validator returns the key if it\'s a string');
try {
$question = new ChoiceQuestion('Who are your favorite superheros?', $heroes, '');
$question->setMultiselect(true);

View File

@ -304,10 +304,6 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
if (null !== $this->logger) {
$this->logger->debug('Notified event "{event}" to listener "{listener}".', $context);
}
if (!isset($this->called[$eventName])) {
$this->called[$eventName] = new \SplObjectStorage();
}
} else {
$this->callStack->detach($listener);
}

View File

@ -883,6 +883,10 @@ class FinderTest extends Iterator\RealIteratorTestCase
public function testInWithGlobBrace()
{
if (!\defined('GLOB_BRACE')) {
$this->markTestSkipped('Glob brace is not supported on this system.');
}
$finder = $this->buildFinder();
$finder->in([__DIR__.'/Fixtures/{A,copy/A}/B/C'])->getIterator();

View File

@ -36,7 +36,7 @@ abstract class AbstractExtension implements FormExtensionInterface
/**
* The type guesser provided by this extension.
*
* @var FormTypeGuesserInterface
* @var FormTypeGuesserInterface|null
*/
private $typeGuesser;
@ -136,7 +136,7 @@ abstract class AbstractExtension implements FormExtensionInterface
/**
* Registers the type guesser.
*
* @return FormTypeGuesserInterface|null A type guesser
* @return FormTypeGuesserInterface|null
*/
protected function loadTypeGuesser()
{

View File

@ -131,7 +131,7 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface
* resource
* @param FormView $view The form view for finding the applying
* themes
* @param array $blockNameHierarchy The block hierarchy, with the most
* @param string[] $blockNameHierarchy The block hierarchy, with the most
* specific block name at the end
* @param int $hierarchyLevel The level in the block hierarchy that
* should be loaded

View File

@ -22,7 +22,7 @@ use Symfony\Component\Form\Exception\BadMethodCallException;
class Button implements \IteratorAggregate, FormInterface
{
/**
* @var FormInterface|null
* @var FormInterface
*/
private $parent;
@ -111,6 +111,8 @@ class Button implements \IteratorAggregate, FormInterface
}
$this->parent = $parent;
return $this;
}
/**
@ -199,11 +201,13 @@ class Button implements \IteratorAggregate, FormInterface
* This method should not be invoked.
*
* @param mixed $modelData
*
* @return $this
*/
public function setData($modelData)
{
// called during initialization of the form tree
// noop
// no-op, called during initialization of the form tree
return $this;
}
/**
@ -211,6 +215,7 @@ class Button implements \IteratorAggregate, FormInterface
*/
public function getData()
{
return null;
}
/**
@ -218,6 +223,7 @@ class Button implements \IteratorAggregate, FormInterface
*/
public function getNormData()
{
return null;
}
/**
@ -225,6 +231,7 @@ class Button implements \IteratorAggregate, FormInterface
*/
public function getViewData()
{
return null;
}
/**
@ -240,7 +247,7 @@ class Button implements \IteratorAggregate, FormInterface
/**
* Returns the button's configuration.
*
* @return FormConfigInterface The configuration
* @return FormConfigInterface The configuration instance
*/
public function getConfig()
{
@ -272,6 +279,7 @@ class Button implements \IteratorAggregate, FormInterface
*/
public function getPropertyPath()
{
return null;
}
/**
@ -309,11 +317,11 @@ class Button implements \IteratorAggregate, FormInterface
*/
public function isDisabled()
{
if (null === $this->parent || !$this->parent->isDisabled()) {
return $this->config->getDisabled();
if ($this->parent && $this->parent->isDisabled()) {
return true;
}
return true;
return $this->config->getDisabled();
}
/**
@ -341,6 +349,7 @@ class Button implements \IteratorAggregate, FormInterface
*/
public function getTransformationFailure()
{
return null;
}
/**
@ -368,7 +377,7 @@ class Button implements \IteratorAggregate, FormInterface
/**
* Submits data to the button.
*
* @param string|null $submittedData The data
* @param string|null $submittedData Not used
* @param bool $clearMissing Not used
*
* @return $this

View File

@ -22,9 +22,6 @@ use Symfony\Component\Form\Exception\InvalidArgumentException;
*/
class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
{
/**
* @var bool
*/
protected $locked = false;
/**
@ -518,6 +515,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getEventDispatcher()
{
return null;
}
/**
@ -533,6 +531,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getPropertyPath()
{
return null;
}
/**
@ -600,6 +599,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getDataMapper()
{
return null;
}
/**
@ -637,6 +637,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getEmptyData()
{
return null;
}
/**
@ -679,6 +680,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getData()
{
return null;
}
/**
@ -686,6 +688,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getDataClass()
{
return null;
}
/**
@ -703,6 +706,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getFormFactory()
{
throw new BadMethodCallException('Buttons do not support adding children.');
}
/**
@ -710,6 +714,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getAction()
{
return null;
}
/**
@ -717,6 +722,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getMethod()
{
return null;
}
/**
@ -724,6 +730,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
*/
public function getRequestHandler()
{
return null;
}
/**

View File

@ -11,9 +11,6 @@
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
class CallbackTransformer implements DataTransformerInterface
{
private $transform;
@ -30,14 +27,7 @@ class CallbackTransformer implements DataTransformerInterface
}
/**
* Transforms a value from the original representation to a transformed representation.
*
* @param mixed $data The value in the original representation
*
* @return mixed The value in the transformed representation
*
* @throws UnexpectedTypeException when the argument is not of the expected type
* @throws TransformationFailedException when the transformation fails
* {@inheritdoc}
*/
public function transform($data)
{
@ -45,15 +35,7 @@ class CallbackTransformer implements DataTransformerInterface
}
/**
* Transforms a value from the transformed representation to its original
* representation.
*
* @param mixed $data The value in the transformed representation
*
* @return mixed The value in the original representation
*
* @throws UnexpectedTypeException when the argument is not of the expected type
* @throws TransformationFailedException when the transformation fails
* {@inheritdoc}
*/
public function reverseTransform($data)
{

View File

@ -17,22 +17,46 @@ namespace Symfony\Component\Form;
interface DataMapperInterface
{
/**
* Maps properties of some data to a list of forms.
* Maps the view data of a compound form to its children.
*
* @param mixed $data Structured data
* @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances
* The method is responsible for calling {@link FormInterface::setData()}
* on the children of compound forms, defining their underlying model data.
*
* @param mixed $viewData View data of the compound form being initialized
* @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances
*
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported
*/
public function mapDataToForms($data, $forms);
public function mapDataToForms($viewData, $forms);
/**
* Maps the data of a list of forms into the properties of some data.
* Maps the model data of a list of children forms into the view data of their parent.
*
* @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances
* @param mixed $data Structured data
* This is the internal cascade call of FormInterface::submit for compound forms, since they
* cannot be bound to any input nor the request as scalar, but their children may:
*
* $compoundForm->submit($arrayOfChildrenViewData)
* // inside:
* $childForm->submit($childViewData);
* // for each entry, do the same and/or reverse transform
* $this->dataMapper->mapFormsToData($compoundForm, $compoundInitialViewData)
* // then reverse transform
*
* When a simple form is submitted the following is happening:
*
* $simpleForm->submit($submittedViewData)
* // inside:
* $this->viewData = $submittedViewData
* // then reverse transform
*
* The model data can be an array or an object, so this second argument is always passed
* by reference.
*
* @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances
* @param mixed $viewData The compound form's view data that get mapped
* its children model data
*
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported
*/
public function mapFormsToData($forms, &$data);
public function mapFormsToData($forms, &$viewData);
}

View File

@ -23,23 +23,35 @@ interface DataTransformerInterface
/**
* Transforms a value from the original representation to a transformed representation.
*
* This method is called on two occasions inside a form field:
* This method is called when the form field is initialized with its default data, on
* two occasions for two types of transformers:
*
* 1. When the form field is initialized with the data attached from the datasource (object or array).
* 2. When data from a request is submitted using {@link Form::submit()} to transform the new input data
* back into the renderable format. For example if you have a date field and submit '2009-10-10'
* you might accept this value because its easily parsed, but the transformer still writes back
* "2009/10/10" onto the form field (for further displaying or other purposes).
* 1. Model transformers which normalize the model data.
* This is mainly useful when the same form type (the same configuration)
* has to handle different kind of underlying data, e.g The DateType can
* deal with strings or \DateTime objects as input.
*
* 2. View transformers which adapt the normalized data to the view format.
* a/ When the form is simple, the value returned by convention is used
* directly in the view and thus can only be a string or an array. In
* this case the data class should be null.
*
* b/ When the form is compound the returned value should be an array or
* an object to be mapped to the children. Each property of the compound
* data will be used as model data by each child and will be transformed
* too. In this case data class should be the class of the object, or null
* when it is an array.
*
* All transformers are called in a configured order from model data to view value.
* At the end of this chain the view data will be validated against the data class
* setting.
*
* This method must be able to deal with empty values. Usually this will
* be NULL, but depending on your implementation other empty values are
* possible as well (such as empty strings). The reasoning behind this is
* that value transformers must be chainable. If the transform() method
* of the first value transformer outputs NULL, the second value transformer
* must be able to process that value.
*
* By convention, transform() should return an empty string if NULL is
* passed.
* that data transformers must be chainable. If the transform() method
* of the first data transformer outputs NULL, the second must be able to
* process that value.
*
* @param mixed $value The value in the original representation
*
@ -54,7 +66,10 @@ interface DataTransformerInterface
* representation.
*
* This method is called when {@link Form::submit()} is called to transform the requests tainted data
* into an acceptable format for your data processing/model layer.
* into an acceptable format.
*
* The same transformers are called in the reverse order so the responsibility is to
* return one of the types that would be expected as input of transform().
*
* This method must be able to deal with empty values. Usually this will
* be an empty string, but depending on your implementation other empty

View File

@ -43,8 +43,6 @@ class ButtonType extends BaseType implements ButtonTypeInterface
{
parent::configureOptions($resolver);
$resolver->setDefaults([
'auto_initialize' => false,
]);
$resolver->setDefault('auto_initialize', false);
}
}

View File

@ -311,8 +311,8 @@ class ChoiceType extends AbstractType
'placeholder' => $placeholderDefault,
'error_bubbling' => false,
'compound' => $compound,
// The view data is always a string, even if the "data" option
// is manually set to an object.
// The view data is always a string or an array of strings,
// even if the "data" option is manually set to an object.
// See https://github.com/symfony/symfony/pull/5582
'data_class' => null,
'choice_translation_domain' => true,

View File

@ -21,6 +21,7 @@ use Symfony\Component\Form\Util\FormUtil;
use Symfony\Component\Form\Util\InheritDataAwareIterator;
use Symfony\Component\Form\Util\OrderedHashMap;
use Symfony\Component\PropertyAccess\PropertyPath;
use Symfony\Component\PropertyAccess\PropertyPathInterface;
/**
* Form represents a form.
@ -63,79 +64,57 @@ use Symfony\Component\PropertyAccess\PropertyPath;
class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterface
{
/**
* The form's configuration.
*
* @var FormConfigInterface
*/
private $config;
/**
* The parent of this form.
*
* @var FormInterface
* @var FormInterface|null
*/
private $parent;
/**
* The children of this form.
*
* @var FormInterface[] A map of FormInterface instances
* @var FormInterface[]|OrderedHashMap A map of FormInterface instances
*/
private $children;
/**
* The errors of this form.
*
* @var FormError[] An array of FormError instances
*/
private $errors = [];
/**
* Whether this form was submitted.
*
* @var bool
*/
private $submitted = false;
/**
* The button that was used to submit the form.
*
* @var Button
* @var ClickableInterface|null The button that was used to submit the form
*/
private $clickedButton;
/**
* The form data in model format.
*
* @var mixed
*/
private $modelData;
/**
* The form data in normalized format.
*
* @var mixed
*/
private $normData;
/**
* The form data in view format.
*
* @var mixed
*/
private $viewData;
/**
* The submitted values that don't belong to any children.
*
* @var array
* @var array The submitted values that don't belong to any children
*/
private $extraData = [];
/**
* Returns the transformation failure generated during submission, if any.
*
* @var TransformationFailedException|null
* @var TransformationFailedException|null The transformation failure generated during submission, if any
*/
private $transformationFailure;
@ -161,8 +140,21 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
private $lockSetData = false;
/**
* Creates a new form based on the given configuration.
*
* @var string|int|null
*/
private $name;
/**
* @var bool Whether the form inherits its underlying data from its parent
*/
private $inheritData;
/**
* @var PropertyPathInterface|null
*/
private $propertyPath;
/**
* @throws LogicException if a data mapper is not provided for a compound form
*/
public function __construct(FormConfigInterface $config)
@ -176,12 +168,13 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
// If the form inherits the data from its parent, it is not necessary
// to call setData() with the default data.
if ($config->getInheritData()) {
if ($this->inheritData = $config->getInheritData()) {
$this->defaultDataSet = true;
}
$this->config = $config;
$this->children = new OrderedHashMap();
$this->name = $config->getName();
}
public function __clone()
@ -206,7 +199,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
*/
public function getName()
{
return $this->config->getName();
return $this->name;
}
/**
@ -214,11 +207,11 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
*/
public function getPropertyPath()
{
if (null !== $this->config->getPropertyPath()) {
return $this->config->getPropertyPath();
if ($this->propertyPath || $this->propertyPath = $this->config->getPropertyPath()) {
return $this->propertyPath;
}
if (null === $this->getName() || '' === $this->getName()) {
if (null === $this->name || '' === $this->name) {
return null;
}
@ -229,10 +222,12 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
}
if ($parent && null === $parent->getConfig()->getDataClass()) {
return new PropertyPath('['.$this->getName().']');
$this->propertyPath = new PropertyPath('['.$this->name.']');
} else {
$this->propertyPath = new PropertyPath($this->name);
}
return new PropertyPath($this->getName());
return $this->propertyPath;
}
/**
@ -268,7 +263,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
throw new AlreadySubmittedException('You cannot set the parent of a submitted form');
}
if (null !== $parent && '' === $this->config->getName()) {
if (null !== $parent && '' === $this->name) {
throw new LogicException('A form with an empty name cannot have a parent form.');
}
@ -315,7 +310,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
// If the form inherits its parent's data, disallow data setting to
// prevent merge conflicts
if ($this->config->getInheritData()) {
if ($this->inheritData) {
throw new RuntimeException('You cannot change the data of a form inheriting its parent data.');
}
@ -335,7 +330,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
$this->lockSetData = true;
$dispatcher = $this->config->getEventDispatcher();
// Hook to change content of the data
// Hook to change content of the model data before transformation and mapping children
if ($dispatcher->hasListeners(FormEvents::PRE_SET_DATA)) {
$event = new FormEvent($this, $modelData);
$dispatcher->dispatch(FormEvents::PRE_SET_DATA, $event);
@ -348,6 +343,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
}
// Synchronize representations - must not change the content!
// Transformation exceptions are not caught on initialization
$normData = $this->modelToNorm($modelData);
$viewData = $this->normToView($normData);
@ -370,13 +366,10 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
$this->defaultDataSet = true;
$this->lockSetData = false;
// It is not necessary to invoke this method if the form doesn't have children,
// even if the form is compound.
// Compound forms don't need to invoke this method if they don't have children
if (\count($this->children) > 0) {
// Update child forms from the data
$iterator = new InheritDataAwareIterator($this->children);
$iterator = new \RecursiveIteratorIterator($iterator);
$this->config->getDataMapper()->mapDataToForms($viewData, $iterator);
// Update child forms from the data (unless their config data is locked)
$this->config->getDataMapper()->mapDataToForms($viewData, new \RecursiveIteratorIterator(new InheritDataAwareIterator($this->children)));
}
if ($dispatcher->hasListeners(FormEvents::POST_SET_DATA)) {
@ -392,7 +385,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
*/
public function getData()
{
if ($this->config->getInheritData()) {
if ($this->inheritData) {
if (!$this->parent) {
throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
}
@ -416,7 +409,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
*/
public function getNormData()
{
if ($this->config->getInheritData()) {
if ($this->inheritData) {
if (!$this->parent) {
throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
}
@ -440,7 +433,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
*/
public function getViewData()
{
if ($this->config->getInheritData()) {
if ($this->inheritData) {
if (!$this->parent) {
throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
}
@ -505,8 +498,8 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
throw new AlreadySubmittedException('A form can only be submitted once');
}
// Initialize errors in the very beginning so that we don't lose any
// errors added during listeners
// Initialize errors in the very beginning so we're sure
// they are collectable during submission only
$this->errors = [];
// Obviously, a disabled form should not change its data upon submission.
@ -605,18 +598,16 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
// changes in the grandchildren (i.e. children of the form that inherits
// its parent's data) into account.
// (see InheritDataAwareIterator below)
if (!$this->config->getInheritData()) {
// If the form is compound, the default data in view format
// is reused. The data of the children is merged into this
// default data using the data mapper.
// If the form is not compound, the submitted data is also the data in view format.
if (!$this->inheritData) {
// If the form is compound, the view data is merged with the data
// of the children using the data mapper.
// If the form is not compound, the view data is assigned to the submitted data.
$viewData = $this->config->getCompound() ? $this->viewData : $submittedData;
if (FormUtil::isEmpty($viewData)) {
$emptyData = $this->config->getEmptyData();
if ($emptyData instanceof \Closure) {
/* @var \Closure $emptyData */
$emptyData = $emptyData($this, $viewData);
}
@ -631,9 +622,10 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
// descendants that inherit this form's data.
// These descendants will not be submitted normally (see the check
// for $this->config->getInheritData() above)
$childrenIterator = new InheritDataAwareIterator($this->children);
$childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
$this->config->getDataMapper()->mapFormsToData($childrenIterator, $viewData);
$this->config->getDataMapper()->mapFormsToData(
new \RecursiveIteratorIterator(new InheritDataAwareIterator($this->children)),
$viewData
);
}
// Normalize data to unified representation
@ -658,7 +650,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
// the erroneous data is accessible on the form.
// Forms that inherit data never set any data, because the getters
// forward to the parent form's getters anyway.
if (null === $viewData && !$this->config->getInheritData()) {
if (null === $viewData && !$this->inheritData) {
$viewData = $submittedData;
}
}
@ -755,8 +747,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
/**
* Returns the button that was used to submit the form.
*
* @return Button|null The clicked button or NULL if the form was not
* submitted
* @return ClickableInterface|null
*/
public function getClickedButton()
{
@ -845,29 +836,6 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
throw new LogicException('You cannot add children to a simple form. Maybe you should set the option "compound" to true?');
}
// Obtain the view data
$viewData = null;
// If setData() is currently being called, there is no need to call
// mapDataToForms() here, as mapDataToForms() is called at the end
// of setData() anyway. Not doing this check leads to an endless
// recursion when initializing the form lazily and an event listener
// (such as ResizeFormListener) adds fields depending on the data:
//
// * setData() is called, the form is not initialized yet
// * add() is called by the listener (setData() is not complete, so
// the form is still not initialized)
// * getViewData() is called
// * setData() is called since the form is not initialized yet
// * ... endless recursion ...
//
// Also skip data mapping if setData() has not been called yet.
// setData() will be called upon form initialization and data mapping
// will take place by then.
if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
$viewData = $this->getViewData();
}
if (!$child instanceof FormInterface) {
if (!\is_string($child) && !\is_int($child)) {
throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormInterface');
@ -897,10 +865,28 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
$child->setParent($this);
if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
$iterator = new InheritDataAwareIterator(new \ArrayIterator([$child->getName() => $child]));
$iterator = new \RecursiveIteratorIterator($iterator);
$this->config->getDataMapper()->mapDataToForms($viewData, $iterator);
// If setData() is currently being called, there is no need to call
// mapDataToForms() here, as mapDataToForms() is called at the end
// of setData() anyway. Not doing this check leads to an endless
// recursion when initializing the form lazily and an event listener
// (such as ResizeFormListener) adds fields depending on the data:
//
// * setData() is called, the form is not initialized yet
// * add() is called by the listener (setData() is not complete, so
// the form is still not initialized)
// * getViewData() is called
// * setData() is called since the form is not initialized yet
// * ... endless recursion ...
//
// Also skip data mapping if setData() has not been called yet.
// setData() will be called upon form initialization and data mapping
// will take place by then.
if (!$this->lockSetData && $this->defaultDataSet && !$this->inheritData) {
$viewData = $this->getViewData();
$this->config->getDataMapper()->mapDataToForms(
$viewData,
new \RecursiveIteratorIterator(new InheritDataAwareIterator(new \ArrayIterator([$child->getName() => $child])))
);
}
return $this;
@ -1049,13 +1035,13 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
}
/**
* Normalizes the value if a model transformer is set.
* Normalizes the underlying data if a model transformer is set.
*
* @param mixed $value The value to transform
*
* @return mixed
*
* @throws TransformationFailedException If the value cannot be transformed to "normalized" format
* @throws TransformationFailedException If the underlying data cannot be transformed to "normalized" format
*/
private function modelToNorm($value)
{
@ -1064,7 +1050,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
$value = $transformer->transform($value);
}
} catch (TransformationFailedException $exception) {
throw new TransformationFailedException('Unable to transform value for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception);
throw new TransformationFailedException('Unable to transform data for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception);
}
return $value;
@ -1101,7 +1087,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
*
* @return mixed
*
* @throws TransformationFailedException If the value cannot be transformed to "view" format
* @throws TransformationFailedException If the normalized value cannot be transformed to "view" format
*/
private function normToView($value)
{
@ -1110,12 +1096,12 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
// Only do this for simple forms, as the resulting value in
// compound forms is passed to the data mapper and thus should
// not be converted to a string before.
if (!$this->config->getViewTransformers() && !$this->config->getCompound()) {
if (!($transformers = $this->config->getViewTransformers()) && !$this->config->getCompound()) {
return null === $value || is_scalar($value) ? (string) $value : $value;
}
try {
foreach ($this->config->getViewTransformers() as $transformer) {
foreach ($transformers as $transformer) {
$value = $transformer->transform($value);
}
} catch (TransformationFailedException $exception) {
@ -1132,13 +1118,11 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
*
* @return mixed
*
* @throws TransformationFailedException If the value cannot be transformed to "normalized" format
* @throws TransformationFailedException If the submitted value cannot be transformed to "normalized" format
*/
private function viewToNorm($value)
{
$transformers = $this->config->getViewTransformers();
if (!$transformers) {
if (!$transformers = $this->config->getViewTransformers()) {
return '' === $value ? null : $value;
}

View File

@ -72,10 +72,7 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB
// Add to "children" to maintain order
$this->children[$child] = null;
$this->unresolvedChildren[$child] = [
'type' => $type,
'options' => $options,
];
$this->unresolvedChildren[$child] = [$type, $options];
return $this;
}
@ -143,15 +140,7 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
if (isset($this->unresolvedChildren[$name])) {
return true;
}
if (isset($this->children[$name])) {
return true;
}
return false;
return isset($this->unresolvedChildren[$name]) || isset($this->children[$name]);
}
/**
@ -223,7 +212,7 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB
/**
* {@inheritdoc}
*
* @return FormBuilderInterface[]
* @return FormBuilderInterface[]|\Traversable
*/
public function getIterator()
{
@ -239,12 +228,11 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB
*/
private function resolveChild(string $name): FormBuilderInterface
{
$info = $this->unresolvedChildren[$name];
$child = $this->create($name, $info['type'], $info['options']);
$this->children[$name] = $child;
list($type, $options) = $this->unresolvedChildren[$name];
unset($this->unresolvedChildren[$name]);
return $child;
return $this->children[$name] = $this->create($name, $type, $options);
}
/**
@ -253,7 +241,7 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB
private function resolveChildren()
{
foreach ($this->unresolvedChildren as $name => $info) {
$this->children[$name] = $this->create($name, $info['type'], $info['options']);
$this->children[$name] = $this->create($name, $info[0], $info[1]);
}
$this->unresolvedChildren = [];

View File

@ -37,41 +37,18 @@ class FormConfigBuilder implements FormConfigBuilderInterface
/**
* @var bool
*/
protected $locked = false;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/**
* @var string
*/
private $name;
/**
* @var PropertyPathInterface
* @var PropertyPathInterface|string|null
*/
private $propertyPath;
/**
* @var bool
*/
private $mapped = true;
/**
* @var bool
*/
private $byReference = true;
/**
* @var bool
*/
private $inheritData = false;
/**
* @var bool
*/
private $compound = false;
/**
@ -79,34 +56,16 @@ class FormConfigBuilder implements FormConfigBuilderInterface
*/
private $type;
/**
* @var array
*/
private $viewTransformers = [];
/**
* @var array
*/
private $modelTransformers = [];
/**
* @var DataMapperInterface
* @var DataMapperInterface|null
*/
private $dataMapper;
/**
* @var bool
*/
private $required = true;
/**
* @var bool
*/
private $disabled = false;
/**
* @var bool
*/
private $errorBubbling = false;
/**
@ -114,9 +73,6 @@ class FormConfigBuilder implements FormConfigBuilderInterface
*/
private $emptyData;
/**
* @var array
*/
private $attributes = [];
/**
@ -129,39 +85,26 @@ class FormConfigBuilder implements FormConfigBuilderInterface
*/
private $dataClass;
/**
* @var bool
*/
private $dataLocked;
private $dataLocked = false;
/**
* @var FormFactoryInterface
* @var FormFactoryInterface|null
*/
private $formFactory;
/**
* @var string
* @var string|null
*/
private $action;
/**
* @var string
*/
private $method = 'POST';
/**
* @var RequestHandlerInterface
* @var RequestHandlerInterface|null
*/
private $requestHandler;
/**
* @var bool
*/
private $autoInitialize = false;
/**
* @var array
*/
private $options;
/**
@ -603,7 +546,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->errorBubbling = null === $errorBubbling ? null : (bool) $errorBubbling;
$this->errorBubbling = (bool) $errorBubbling;
return $this;
}
@ -649,7 +592,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->mapped = $mapped;
$this->mapped = (bool) $mapped;
return $this;
}
@ -663,7 +606,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->byReference = $byReference;
$this->byReference = (bool) $byReference;
return $this;
}
@ -677,7 +620,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->inheritData = $inheritData;
$this->inheritData = (bool) $inheritData;
return $this;
}
@ -691,7 +634,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->compound = $compound;
$this->compound = (bool) $compound;
return $this;
}
@ -733,7 +676,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->dataLocked = $locked;
$this->dataLocked = (bool) $locked;
return $this;
}
@ -761,7 +704,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
throw new BadMethodCallException('The config builder cannot be modified anymore.');
}
$this->action = $action;
$this->action = (string) $action;
return $this;
}
@ -827,7 +770,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
/**
* Validates whether the given variable is a valid form name.
*
* @param string|int $name The tested form name
* @param string|int|null $name The tested form name
*
* @throws UnexpectedTypeException if the name is not a string or an integer
* @throws InvalidArgumentException if the name contains invalid characters
@ -853,7 +796,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
* * contains only letters, digits, numbers, underscores ("_"),
* hyphens ("-") and colons (":")
*
* @param string $name The tested form name
* @param string|null $name The tested form name
*
* @return bool Whether the name is valid
*/

View File

@ -108,7 +108,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface
public function setDataMapper(DataMapperInterface $dataMapper = null);
/**
* Set whether the form is disabled.
* Sets whether the form is disabled.
*
* @param bool $disabled Whether the form is disabled
*
@ -166,8 +166,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface
/**
* Sets whether the form's data should be modified by reference.
*
* @param bool $byReference Whether the data should be
* modified by reference
* @param bool $byReference Whether the data should be modified by reference
*
* @return $this The configuration object
*/
@ -194,7 +193,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface
public function setCompound($compound);
/**
* Set the types.
* Sets the resolved type.
*
* @return $this The configuration object
*/
@ -203,7 +202,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface
/**
* Sets the initial data of the form.
*
* @param mixed $data The data of the form in application format
* @param mixed $data The data of the form in model format
*
* @return $this The configuration object
*/
@ -214,9 +213,12 @@ interface FormConfigBuilderInterface extends FormConfigInterface
*
* A form with locked data is restricted to the data passed in
* this configuration. The data can only be modified then by
* submitting the form.
* submitting the form or using PRE_SET_DATA event.
*
* @param bool $locked Whether to lock the default data
* It means data passed to a factory method or mapped from the
* parent will be ignored.
*
* @param bool $locked Whether to lock the default configured data
*
* @return $this The configuration object
*/

View File

@ -70,15 +70,17 @@ interface FormConfigInterface
* This property is independent of whether the form actually has
* children. A form can be compound and have no children at all, like
* for example an empty collection form.
* The contrary is not possible, a form which is not compound
* cannot have any children.
*
* @return bool Whether the form is compound
*/
public function getCompound();
/**
* Returns the form types used to construct the form.
* Returns the resolved form type used to construct the form.
*
* @return ResolvedFormTypeInterface The form's type
* @return ResolvedFormTypeInterface The form's resolved type
*/
public function getType();
@ -97,7 +99,7 @@ interface FormConfigInterface
public function getModelTransformers();
/**
* Returns the data mapper of the form.
* Returns the data mapper of the compound form or null for a simple form.
*
* @return DataMapperInterface|null The data mapper
*/
@ -125,9 +127,15 @@ interface FormConfigInterface
public function getErrorBubbling();
/**
* Returns the data that should be returned when the form is empty.
* Used when the view data is empty on submission.
*
* @return mixed The data returned if the form is empty
* When the form is compound it will also be used to map the
* children data.
*
* The empty data must match the view format as it will passed to the first view transformer's
* "reverseTransform" method.
*
* @return mixed The data used when the submitted form is initially empty
*/
public function getEmptyData();
@ -165,7 +173,7 @@ interface FormConfigInterface
public function getData();
/**
* Returns the class of the form data or null if the data is scalar or an array.
* Returns the class of the view data or null if the data is scalar or an array.
*
* @return string|null The data class or null
*/

View File

@ -49,7 +49,7 @@ class FormError implements \Serializable
*/
public function __construct(?string $message, string $messageTemplate = null, array $messageParameters = [], int $messagePluralization = null, $cause = null)
{
$this->message = $message;
$this->message = (string) $message;
$this->messageTemplate = $messageTemplate ?: $message;
$this->messageParameters = $messageParameters;
$this->messagePluralization = $messagePluralization;

View File

@ -39,10 +39,9 @@ class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \Array
private $errors;
/**
* Creates a new iterator.
*
* @param FormInterface $form The erroneous form
* @param FormError[]|FormErrorIterator[] $errors The form errors
* @param FormInterface $form The erroneous form
* @param FormError[]|self[] $errors An array of form errors and instances
* of FormErrorIterator
*
* @throws InvalidArgumentException If the errors are invalid
*/
@ -71,7 +70,7 @@ class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \Array
if ($error instanceof FormError) {
$string .= 'ERROR: '.$error->getMessage()."\n";
} else {
/* @var $error FormErrorIterator */
/** @var self $error */
$string .= $error->form->getName().":\n";
$string .= self::indent((string) $error);
}
@ -93,8 +92,7 @@ class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \Array
/**
* Returns the current element of the iterator.
*
* @return FormError|FormErrorIterator an error or an iterator containing
* nested errors
* @return FormError|self An error or an iterator containing nested errors
*/
public function current()
{

View File

@ -21,6 +21,10 @@ class FormEvent extends Event
private $form;
protected $data;
/**
* @param FormInterface $form The associated form
* @param mixed $data The data
*/
public function __construct(FormInterface $form, $data)
{
$this->form = $form;

View File

@ -34,21 +34,35 @@ final class FormEvents
const PRE_SUBMIT = 'form.pre_submit';
/**
* The SUBMIT event is dispatched just before the Form::submit() method
* transforms back the normalized data to the model and view data.
* The SUBMIT event is dispatched after the Form::submit() method
* has changed the view data by the request data, or submitted and mapped
* the children if the form is compound, and after reverse transformation
* to normalized representation.
*
* It can be used to change data from the normalized representation of the data.
* It's also dispatched just before the Form::submit() method transforms back
* the normalized data to the model and view data.
*
* So at this stage children of compound forms are submitted and synchronized, unless
* their transformation failed, but a parent would still be at the PRE_SUBMIT level.
*
* Since the current form is not synchronized yet, it is still possible to add and
* remove fields.
*
* @Event("Symfony\Component\Form\FormEvent")
*/
const SUBMIT = 'form.submit';
/**
* The FormEvents::POST_SUBMIT event is dispatched after the Form::submit()
* once the model and view data have been denormalized.
* The FormEvents::POST_SUBMIT event is dispatched at the very end of the Form::submit().
*
* It this stage the model and view data may have been denormalized. Otherwise the form
* is desynchronized because transformation failed during submission.
*
* It can be used to fetch data after denormalization.
*
* The event attaches the current view data. To know whether this is the renormalized data
* or the invalid request data, call Form::isSynchronized() first.
*
* @Event("Symfony\Component\Form\FormEvent")
*/
const POST_SUBMIT = 'form.post_submit';
@ -58,7 +72,7 @@ final class FormEvents
*
* It can be used to:
* - Modify the data given during pre-population;
* - Modify a form depending on the pre-populated data (adding or removing fields dynamically).
* - Keep synchronized the form depending on the data (adding or removing fields dynamically).
*
* @Event("Symfony\Component\Form\FormEvent")
*/
@ -67,7 +81,8 @@ final class FormEvents
/**
* The FormEvents::POST_SET_DATA event is dispatched at the end of the Form::setData() method.
*
* This event is mostly here for reading data after having pre-populated the form.
* This event can be used to modify the form depending on the final state of the underlying data
* accessible in every representation: model, normalized and view.
*
* @Event("Symfony\Component\Form\FormEvent")
*/

View File

@ -11,7 +11,7 @@
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\PropertyAccess\PropertyPathInterface;
/**
* A form group bundling multiple forms in a hierarchical structure.
@ -23,7 +23,9 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
/**
* Sets the parent form.
*
* @return self
* @param FormInterface|null $parent The parent form or null if it's the root
*
* @return $this
*
* @throws Exception\AlreadySubmittedException if the form has already been submitted
* @throws Exception\LogicException when trying to set a parent for a form with
@ -45,7 +47,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
* @param string|null $type The child's type, if a name was passed
* @param array $options The child's options, if a name was passed
*
* @return self
* @return $this
*
* @throws Exception\AlreadySubmittedException if the form has already been submitted
* @throws Exception\LogicException when trying to add a child to a non-compound form
@ -104,44 +106,70 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
public function getErrors($deep = false, $flatten = true);
/**
* Updates the form with default data.
* Updates the form with default model data.
*
* @param mixed $modelData The data formatted as expected for the underlying object
*
* @return $this
*
* @throws Exception\AlreadySubmittedException if the form has already been submitted
* @throws Exception\LogicException If listeners try to call setData in a cycle. Or if
* the view data does not match the expected type
* according to {@link FormConfigInterface::getDataClass}.
* @throws Exception\AlreadySubmittedException If the form has already been submitted
* @throws Exception\LogicException If the view data does not match the expected type
* according to {@link FormConfigInterface::getDataClass}.
* @throws Exception\RuntimeException If listeners try to call setData in a cycle or if
* the form inherits data from its parent
* @throws Exception\TransformationFailedException If the synchronization failed.
*/
public function setData($modelData);
/**
* Returns the data in the format needed for the underlying object.
* Returns the model data in the format needed for the underlying object.
*
* @return mixed
* @return mixed When the field is not submitted, the default data is returned.
* When the field is submitted, the default data has been bound
* to the submitted view data.
*
* @throws Exception\RuntimeException If the form inherits data but has no parent
*/
public function getData();
/**
* Returns the normalized data of the field.
* Returns the normalized data of the field, used as internal bridge
* between model data and view data.
*
* @return mixed When the field is not submitted, the default data is returned.
* When the field is submitted, the normalized submitted data is
* returned if the field is valid, null otherwise.
* When the field is submitted, the normalized submitted data
* is returned if the field is synchronized with the view data,
* null otherwise.
*
* @throws Exception\RuntimeException If the form inherits data but has no parent
*/
public function getNormData();
/**
* Returns the data transformed by the value transformer.
* Returns the view data of the field.
*
* It may be defined by {@link FormConfigInterface::getDataClass}.
*
* There are two cases:
*
* - When the form is compound the view data is mapped to the children.
* Each child will use its mapped data as model data.
* It can be an array, an object or null.
*
* - When the form is simple its view data is used to be bound
* to the submitted data.
* It can be a string or an array.
*
* In both cases the view data is the actual altered data on submission.
*
* @return mixed
*
* @throws Exception\RuntimeException If the form inherits data but has no parent
*/
public function getViewData();
/**
* Returns the extra data.
* Returns the extra submitted data.
*
* @return array The submitted data which do not belong to a child
*/
@ -150,7 +178,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
/**
* Returns the form's configuration.
*
* @return FormConfigInterface The configuration
* @return FormConfigInterface The configuration instance
*/
public function getConfig();
@ -164,6 +192,8 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
/**
* Returns the name by which the form is identified in forms.
*
* Only root forms are allowed to have an empty name.
*
* @return string The name of the form
*/
public function getName();
@ -171,7 +201,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
/**
* Returns the property path that the form is mapped to.
*
* @return \Symfony\Component\PropertyAccess\PropertyPathInterface|null The property path
* @return PropertyPathInterface|null The property path instance
*/
public function getPropertyPath();
@ -230,14 +260,16 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
* If the data is not synchronized, you can get the transformation failure
* by calling {@link getTransformationFailure()}.
*
* If the form is not submitted, this method always returns true.
*
* @return bool
*/
public function isSynchronized();
/**
* Returns the data transformation failure, if any.
* Returns the data transformation failure, if any, during submission.
*
* @return TransformationFailedException|null The transformation failure
* @return Exception\TransformationFailedException|null The transformation failure or null
*/
public function getTransformationFailure();
@ -247,6 +279,8 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
* Should be called on the root form after constructing the tree.
*
* @return $this
*
* @throws Exception\RuntimeException If the form is not the root
*/
public function initialize();
@ -265,11 +299,13 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
public function handleRequest($request = null);
/**
* Submits data to the form, transforms and validates it.
* Submits data to the form.
*
* @param mixed $submittedData The submitted data
* @param bool $clearMissing Whether to set fields to NULL when they
* are missing in the submitted data
* @param string|array|null $submittedData The submitted data
* @param bool $clearMissing Whether to set fields to NULL
* when they are missing in the
* submitted data. This argument
* is only used in compound form
*
* @return $this
*
@ -280,7 +316,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
/**
* Returns the root of the form tree.
*
* @return self The root of the tree
* @return self The root of the tree, may be the instance itself
*/
public function getRoot();
@ -292,8 +328,6 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
public function isRoot();
/**
* Creates a view.
*
* @return FormView The view
*/
public function createView(FormView $parent = null);

View File

@ -26,7 +26,7 @@ class FormRegistry implements FormRegistryInterface
/**
* Extensions.
*
* @var FormExtensionInterface[] An array of FormExtensionInterface
* @var FormExtensionInterface[]
*/
private $extensions = [];

View File

@ -74,7 +74,7 @@ interface FormRendererEngineInterface
* First the themes attached directly to
* the view with {@link setTheme()} are
* considered, then the ones of its parent etc.
* @param array $blockNameHierarchy The block name hierarchy, with the root block
* @param string[] $blockNameHierarchy The block name hierarchy, with the root block
* at the beginning
* @param int $hierarchyLevel The level in the hierarchy at which to start
* looking. Level 0 indicates the root block, i.e.
@ -112,7 +112,7 @@ interface FormRendererEngineInterface
* First the themes attached directly to
* the view with {@link setTheme()} are
* considered, then the ones of its parent etc.
* @param array $blockNameHierarchy The block name hierarchy, with the root block
* @param string[] $blockNameHierarchy The block name hierarchy, with the root block
* at the beginning
* @param int $hierarchyLevel The level in the hierarchy at which to start
* looking. Level 0 indicates the root block, i.e.

View File

@ -19,7 +19,7 @@ class FormTypeGuesserChain implements FormTypeGuesserInterface
private $guessers = [];
/**
* @param FormTypeGuesserInterface[] $guessers Guessers as instances of FormTypeGuesserInterface
* @param FormTypeGuesserInterface[] $guessers
*
* @throws UnexpectedTypeException if any guesser does not implement FormTypeGuesserInterface
*/

View File

@ -49,8 +49,8 @@ interface FormTypeGuesserInterface
/**
* Returns a guess about the field's pattern.
*
* - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below
* - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess.
* - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE)
* - Then line below, if this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess.
* Example:
* You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5)
*

View File

@ -41,6 +41,8 @@ class NativeRequestHandler implements RequestHandlerInterface
/**
* {@inheritdoc}
*
* @throws Exception\UnexpectedTypeException If the $request is not null
*/
public function handleRequest(FormInterface $form, $request = null)
{

View File

@ -450,6 +450,31 @@ class CompoundFormTest extends AbstractFormTest
$form->setData('foo');
}
public function testSetDataDoesNotMapViewDataToChildrenWithLockedSetData()
{
$mapper = new PropertyPathMapper();
$viewData = [
'firstName' => 'Fabien',
'lastName' => 'Pot',
];
$form = $this->getBuilder()
->setCompound(true)
->setDataMapper($mapper)
->addViewTransformer(new FixedDataTransformer([
'' => '',
'foo' => $viewData,
]))
->getForm();
$form->add($child1 = $this->getBuilder('firstName')->getForm());
$form->add($child2 = $this->getBuilder('lastName')->setData('Potencier')->setDataLocked(true)->getForm());
$form->setData('foo');
$this->assertSame('Fabien', $form->get('firstName')->getData());
$this->assertSame('Potencier', $form->get('lastName')->getData());
}
public function testSubmitSupportsDynamicAdditionAndRemovalOfChildren()
{
$form = $this->form;

View File

@ -54,6 +54,26 @@ class SimpleFormTest_Traversable implements \IteratorAggregate
class SimpleFormTest extends AbstractFormTest
{
/**
* @dataProvider provideFormNames
*/
public function testGetPropertyPath($name, $propertyPath)
{
$config = new FormConfigBuilder($name, null, $this->dispatcher);
$form = new Form($config);
$this->assertEquals(new PropertyPath($propertyPath), $form->getPropertyPath());
}
public function provideFormNames()
{
yield [null, null];
yield ['', null];
yield ['0', '0'];
yield [0, '0'];
yield ['name', 'name'];
}
public function testDataIsInitializedToConfiguredValue()
{
$model = new FixedDataTransformer([
@ -76,7 +96,7 @@ class SimpleFormTest extends AbstractFormTest
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage Unable to transform value for property path "name": No mapping for value "arg"
* @expectedExceptionMessage Unable to transform data for property path "name": No mapping for value "arg"
*/
public function testDataTransformationFailure()
{

View File

@ -19,6 +19,7 @@ use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
use Symfony\Component\HttpKernel\Event\KernelEvent;
use Symfony\Component\HttpKernel\KernelEvents;
@ -40,13 +41,13 @@ class DebugHandlersListener implements EventSubscriberInterface
private $hasTerminatedWithException;
/**
* @param callable|null $exceptionHandler A handler that will be called on Exception
* @param LoggerInterface|null $logger A PSR-3 logger
* @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants
* @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value
* @param bool $scream Enables/disables screaming mode, where even silenced errors are logged
* @param string|array $fileLinkFormat The format for links to source files
* @param bool $scope Enables/disables scoping mode
* @param callable|null $exceptionHandler A handler that will be called on Exception
* @param LoggerInterface|null $logger A PSR-3 logger
* @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants
* @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value
* @param bool $scream Enables/disables screaming mode, where even silenced errors are logged
* @param string|FileLinkFormatter|null $fileLinkFormat The format for links to source files
* @param bool $scope Enables/disables scoping mode
*/
public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = E_ALL, ?int $throwAt = E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true)
{

View File

@ -232,12 +232,13 @@ abstract class Constraint
*
* Override this method to define a default option.
*
* @return string
* @return string|null
*
* @see __construct()
*/
public function getDefaultOption()
{
return null;
}
/**