Merge branch '4.4' into 5.1

* 4.4:
  Fix parameter order
  [DependencyInjection] Fix circular in DI with lazy + byContruct loop
  adjust Client::getProfile() typehint
  fix: resolving pt translation issues
  Update VERSION for 3.4.47
  Update CONTRIBUTORS for 3.4.47
  Update CHANGELOG for 3.4.47
  Add Romanian missing translations
  [DependencyInjection][Translator] Silent deprecation triggered by libxml_disable_entity_loader
  fix lexing strings containing escaped quotation characters
  prevent duplicated error message for file upload limits
  ignore the pattern attribute for textareas
  fix: solving pt-br translation issues
This commit is contained in:
Alexander M. Turek 2020-11-28 11:57:20 +01:00
commit e70ccfe55d
29 changed files with 797 additions and 126 deletions

View File

@ -12,9 +12,10 @@ Symfony is the result of the work of many people who made the code better
- Robin Chalas (chalas_r)
- Christophe Coevoet (stof)
- Kévin Dunglas (dunglas)
- Jordi Boggiano (seldaek)
- Maxime Steinhausser (ogizanagi)
- Jordi Boggiano (seldaek)
- Victor Berchet (victor)
- Alexander M. Turek (derrabus)
- Grégoire Pineau (lyrixx)
- Ryan Weaver (weaverryan)
- Javier Eguiluz (javier.eguiluz)
@ -22,33 +23,32 @@ Symfony is the result of the work of many people who made the code better
- Jakub Zalas (jakubzalas)
- Johannes S (johannes)
- Kris Wallsmith (kriswallsmith)
- Alexander M. Turek (derrabus)
- Wouter de Jong (wouterj)
- Yonel Ceruto (yonelceruto)
- Thomas Calvet (fancyweb)
- Hugo Hamon (hhamon)
- Jérémy DERUSSÉ (jderusse)
- Abdellatif Ait boudad (aitboudad)
- Samuel ROZE (sroze)
- Romain Neutron (romain)
- Pascal Borreli (pborreli)
- Jérémy DERUSSÉ (jderusse)
- Joseph Bielawski (stloyd)
- Karma Dordrak (drak)
- Jules Pietri (heah)
- Lukas Kahwe Smith (lsmith)
- Martin Hasoň (hason)
- Hamza Amrouche (simperfit)
- Tobias Nyholm (tobias)
- Jeremy Mikola (jmikola)
- Jean-François Simon (jfsimon)
- Benjamin Eberlei (beberlei)
- Igor Wiedler (igorw)
- Tobias Nyholm (tobias)
- Eriksen Costa (eriksencosta)
- Guilhem Niot (energetick)
- Sarah Khalil (saro0h)
- Jonathan Wage (jwage)
- Lynn van der Berg (kjarli)
- Jan Schädlich (jschaedl)
- Lynn van der Berg (kjarli)
- Matthias Pigulla (mpdude)
- Diego Saint Esteben (dosten)
- Pierre du Plessis (pierredup)
@ -56,13 +56,13 @@ Symfony is the result of the work of many people who made the code better
- William Durand (couac)
- Valentin Udaltsov (vudaltsov)
- ornicar
- Grégoire Paris (greg0ire)
- Dany Maillard (maidmaid)
- Francis Besset (francisbesset)
- stealth35 (stealth35)
- Alexander Mols (asm89)
- Kevin Bond (kbond)
- Konstantin Myakshin (koc)
- Grégoire Paris (greg0ire)
- Bulat Shakirzyanov (avalanche123)
- Saša Stamenković (umpirsky)
- Peter Rehm (rpet)
@ -116,17 +116,17 @@ Symfony is the result of the work of many people who made the code better
- Tim Nagel (merk)
- Chris Wilkinson (thewilkybarkid)
- Brice BERNARD (brikou)
- Alexander Schranz (alexander-schranz)
- marc.weistroff
- Tomáš Votruba (tomas_votruba)
- Peter Kokot (maastermedia)
- Lars Strojny (lstrojny)
- lenar
- Alexander Schwenn (xelaris)
- Massimiliano Arione (garak)
- Włodzimierz Gajda (gajdaw)
- Alexander Schranz (alexander-schranz)
- Oskar Stark (oskarstark)
- Adrien Brault (adrienbrault)
- Massimiliano Arione (garak)
- Jacob Dreesen (jdreesen)
- Florian Voutzinos (florianv)
- Teoh Han Hui (teohhanhui)
@ -139,11 +139,11 @@ Symfony is the result of the work of many people who made the code better
- excelwebzone
- Gordon Franke (gimler)
- Joel Wurtz (brouznouf)
- Antoine Makdessi (amakdessi)
- Fabien Pennequin (fabienpennequin)
- Julien Falque (julienfalque)
- Théo FIDRY (theofidry)
- Eric GELOEN (gelo)
- Antoine Makdessi (amakdessi)
- Jannik Zschiesche (apfelbox)
- jeremyFreeAgent (jeremyfreeagent)
- Robert Schönthal (digitalkaoz)
@ -166,6 +166,7 @@ Symfony is the result of the work of many people who made the code better
- Guilherme Blanco (guilhermeblanco)
- SpacePossum
- Pablo Godel (pgodel)
- Andreas Braun
- Matthieu Napoli (mnapoli)
- Richard van Laak (rvanlaak)
- Jérémie Augustin (jaugustin)
@ -175,7 +176,6 @@ Symfony is the result of the work of many people who made the code better
- Rafael Dohms (rdohms)
- jwdeitch
- Ahmed TAILOULOUTE (ahmedtai)
- Andreas Braun
- Mikael Pajunen
- Arman Hosseini (arman)
- Niels Keurentjes (curry684)
@ -295,7 +295,9 @@ Symfony is the result of the work of many people who made the code better
- Lorenz Schori
- Sébastien Lavoie (lavoiesl)
- Dariusz
- Farhad Safarov (safarov)
- Michael Babker (mbabker)
- Thomas Lallement (raziel057)
- Francois Zaninotto
- Colin O'Dell (colinodell)
- Alexander Kotynia (olden)
@ -307,21 +309,25 @@ Symfony is the result of the work of many people who made the code better
- Danny Berger (dpb587)
- zairig imad (zairigimad)
- Antonio J. García Lagar (ajgarlag)
- Alessandro Lai (jean85)
- Adam Prager (padam87)
- Benoît Burnichon (bburnichon)
- Maciej Malarz (malarzm)
- Roman Marintšenko (inori)
- Xavier Montaña Carreras (xmontana)
- Timothée Barray (tyx)
- Mickaël Andrieu (mickaelandrieu)
- Xavier Perez
- Arjen Brouwer (arjenjb)
- Katsuhiro OGAWA
- Patrick McDougle (patrick-mcdougle)
- Rokas Mikalkėnas (rokasm)
- Marc Weistroff (futurecat)
- Alif Rachmawadi
- Anton Chernikov (anton_ch1989)
- Kristen Gilden (kgilden)
- Pierre-Yves LEBECQ (pylebecq)
- Benjamin Leveque (benji07)
- Jordan Samouh (jordansamouh)
- Jakub Kucharovic (jkucharovic)
- Loick Piera (pyrech)
@ -337,6 +343,7 @@ Symfony is the result of the work of many people who made the code better
- Ray
- Chekote
- Thomas Adam
- Chi-teck
- Jhonny Lidfors (jhonne)
- Diego Agulló (aeoris)
- jdhoek
@ -348,7 +355,6 @@ Symfony is the result of the work of many people who made the code better
- Wodor Wodorski
- Timo Bakx (timobakx)
- Joe Bennett (kralos)
- Thomas Lallement (raziel057)
- soyuka
- Giorgio Premi
- renanbr
@ -362,7 +368,6 @@ Symfony is the result of the work of many people who made the code better
- Alexander Menshchikov (zmey_kk)
- Emanuele Panzeri (thepanz)
- Kim Hemsø Rasmussen (kimhemsoe)
- Alessandro Lai (jean85)
- Langlet Vincent (deviling)
- Pascal Luna (skalpa)
- Wouter Van Hecke
@ -375,6 +380,7 @@ Symfony is the result of the work of many people who made the code better
- Christian Schmidt
- Patrick Landolt (scube)
- MatTheCat
- Denis Brumann (dbrumann)
- Bohan Yang (brentybh)
- Vilius Grigaliūnas
- David Badura (davidbadura)
@ -383,8 +389,6 @@ Symfony is the result of the work of many people who made the code better
- Chris Smith (cs278)
- Thomas Bisignani (toma)
- Florian Klein (docteurklein)
- Timothée Barray (tyx)
- Benjamin Leveque (benji07)
- Manuel Kiessling (manuelkiessling)
- Alexey Kopytko (sanmai)
- Atsuhiro KUBO (iteman)
@ -404,7 +408,6 @@ Symfony is the result of the work of many people who made the code better
- Emmanuel BORGES (eborges78)
- Aurelijus Valeiša (aurelijus)
- Jan Decavele (jandc)
- Chi-teck
- Gustavo Piltcher
- Jesse Rushlow (geeshoe)
- Stepan Tanasiychuk (stfalcon)
@ -459,19 +462,22 @@ Symfony is the result of the work of many people who made the code better
- Thomas Perez (scullwm)
- Felix Labrecque
- Yaroslav Kiliba
- Ben Hakim
- Terje Bråten
- Gonzalo Vilaseca (gonzalovilaseca)
- Marco Petersen (ocrampete16)
- Markus Fasselt (digilist)
- Daniel STANCU
- Robbert Klarenbeek (robbertkl)
- Eric Masoero (eric-masoero)
- Ion Bazan (ionbazan)
- Denis Brumann (dbrumann)
- Vitalii Ekert (comrade42)
- JhonnyL
- Clara van Miert
- Haralan Dobrev (hkdobrev)
- hossein zolfi (ocean)
- Clément Gautier (clementgautier)
- Jeroen Noten (jeroennoten)
- Bastien Jaillot (bastnic)
- Dāvis Zālītis (k0d3r1s)
- Sanpi
@ -485,7 +491,6 @@ Symfony is the result of the work of many people who made the code better
- Dimitri Gritsajuk (ottaviano)
- Kirill chEbba Chebunin (chebba)
-
- Rokas Mikalkėnas (rokasm)
- Greg Thornton (xdissent)
- Alex Bowers
- Philipp Cordes
@ -551,7 +556,6 @@ Symfony is the result of the work of many people who made the code better
- Nate Wiebe (natewiebe13)
- Marcin Szepczynski (czepol)
- Mohammad Emran Hasan (phpfour)
- Farhad Safarov
- Dmitriy Mamontov (mamontovdmitriy)
- Jan Schumann
- Niklas Fiekas
@ -600,18 +604,20 @@ Symfony is the result of the work of many people who made the code better
- Arkadius Stefanski (arkadius)
- Tim Goudriaan (codedmonkey)
- Jonas Flodén (flojon)
- AnneKir
- Soner Sayakci
- Tobias Weichart
- Miro Michalicka
- Tarmo Leppänen (tarlepp)
- Marcin Sikoń (marphi)
- M. Vondano
- Dominik Zogg (dominik.zogg)
- Marek Pietrzak
- Tavo Nieves J
- Luc Vieillescazes (iamluc)
- Lukáš Holeczy (holicz)
- franek (franek)
- Raulnet
- Marco Petersen (ocrampete16)
- Christian Wahler
- Giso Stallenberg (gisostallenberg)
- Gintautas Miselis
@ -660,6 +666,7 @@ Symfony is the result of the work of many people who made the code better
- Roy Van Ginneken (rvanginneken)
- ondrowan
- Barry vd. Heuvel (barryvdh)
- Michael Voříšek
- Evan S Kaufman (evanskaufman)
- mcben
- Jérôme Vieilledent (lolautruche)
@ -758,6 +765,7 @@ Symfony is the result of the work of many people who made the code better
- Fred Cox
- vitaliytv
- Philippe Segatori
- fd6130 (fdtvui)
- Dalibor Karlović (dkarlovi)
- Andrey Sevastianov
- Sebastian Blum
@ -803,8 +811,10 @@ Symfony is the result of the work of many people who made the code better
- Jérôme Tamarelle (jtamarelle-prismamedia)
- Geoffrey Brier (geoffrey-brier)
- Alexandre Parent
- Roger Guasch (rogerguasch)
- Vladimir Tsykun
- Dustin Dobervich (dustin10)
- Luis Tacón (lutacon)
- dantleech
- Philipp Kolesnikov
- Anne-Sophie Bachelard (annesophie)
@ -828,6 +838,7 @@ Symfony is the result of the work of many people who made the code better
- Stefan Warman
- Tristan Maindron (tmaindron)
- Behnoush Norouzali (behnoush)
- Marko H. Tamminen (gzumba)
- Wesley Lancel
- Xavier Briand (xavierbriand)
- Ke WANG (yktd26)
@ -853,8 +864,10 @@ Symfony is the result of the work of many people who made the code better
- Michael Devery (mickadoo)
- Antoine Corcy
- Ahmed Ashraf (ahmedash95)
- Luca Saba (lucasaba)
- Sascha Grossenbacher
- Szijarto Tamas
- Thomas P
- Robin Lehrmann (robinlehrmann)
- Catalin Dan
- Jaroslav Kuba
@ -918,6 +931,7 @@ Symfony is the result of the work of many people who made the code better
- Peter Ward
- Davide Borsatto (davide.borsatto)
- Julien DIDIER (juliendidier)
- Randy Geraads
- Dominik Ritter (dritter)
- Andreas Leathley (iquito)
- Sebastian Grodzicki (sgrodzicki)
@ -927,7 +941,6 @@ Symfony is the result of the work of many people who made the code better
- Baldur Rensch (brensch)
- Pierre Rineau
- Fritz Michael Gschwantner
- Jeroen Noten (jeroennoten)
- Vladyslav Petrovych
- Alex Xandra Albert Sim
- Carson Full
@ -1045,12 +1058,10 @@ Symfony is the result of the work of many people who made the code better
- Daniel Gorgan
- Tony Malzhacker
- Mathieu MARCHOIS
- Tavo Nieves J
- Cyril Quintin (cyqui)
- Gerard van Helden (drm)
- flack (flack)
- Johnny Peck (johnnypeck)
- Michael Voříšek
- Stefan Kruppa
- Ivan Menshykov
- David Romaní
@ -1058,6 +1069,7 @@ Symfony is the result of the work of many people who made the code better
- Gustavo Falco (gfalco)
- Matt Robinson (inanimatt)
- Kristof Van Cauwenbergh (kristofvc)
- Marco Lipparini (liarco)
- Peter Bowyer (pbowyer)
- Aleksey Podskrebyshev
- Calin Mihai Pristavu
@ -1095,6 +1107,7 @@ Symfony is the result of the work of many people who made the code better
- Don Pinkster
- Maksim Muruev
- Emil Einarsson
- Anderson Müller
- 243083df
- Thibault Duplessis
- Rimas Kudelis
@ -1195,7 +1208,9 @@ Symfony is the result of the work of many people who made the code better
- Pieter
- Michael Tibben
- Hallison Boaventura (hallisonboaventura)
- Mas Iting
- Billie Thompson
- Albion Bame (abame)
- Ganesh Chandrasekaran
- Sander Marechal
- Franz Wilding (killerpoke)
@ -1216,11 +1231,15 @@ Symfony is the result of the work of many people who made the code better
- Nicolas Martin (cocorambo)
- Tom Panier (neemzy)
- Fred Cox
- luffy1727
- Luciano Mammino (loige)
- fabios
- Sander Coolen (scoolen)
- Amirreza Shafaat (amirrezashafaat)
- Laurent Clouet
- Adoni Pavlakis (adoni)
- Nicolas Le Goff (nlegoff)
- Ahmed EBEN HASSINE (famas23)
- Ben Oman
- Chris de Kok
- Eduard Bulava (nonanerz)
@ -1229,6 +1248,7 @@ Symfony is the result of the work of many people who made the code better
- Guillaume (guill)
- Igor Timoshenko (igor.timoshenko)
- Manuele Menozzi
- “teerasak”
- Anton Babenko (antonbabenko)
- Irmantas Šiupšinskas (irmantas)
- Benoit Mallo
@ -1238,6 +1258,7 @@ Symfony is the result of the work of many people who made the code better
- pizzaminded
- Arnaud PETITPAS (apetitpa)
- Ken Stanley
- ivan
- Zachary Tong (polyfractal)
- linh
- Guilherme Augusto Henschel
@ -1279,8 +1300,10 @@ Symfony is the result of the work of many people who made the code better
- Danijel Obradović
- Pablo Borowicz
- Arjan Keeman
- Bruno Rodrigues de Araujo (brunosinister)
- Máximo Cuadros (mcuadros)
- Lukas Mencl
- Jacek Wilczyński (jacekwilczynski)
- tamirvs
- gauss
- julien.galenski
@ -1342,7 +1365,6 @@ Symfony is the result of the work of many people who made the code better
- Martijn Evers
- Philipp Fritsche
- tarlepp
- Luca Saba (lucasaba)
- Benjamin Paap (benjaminpaap)
- Claus Due (namelesscoder)
- Christian
@ -1449,6 +1471,7 @@ Symfony is the result of the work of many people who made the code better
- Makdessi Alex
- James Gilliland
- fduch (fduch)
- Juan Miguel Besada Vidal (soutlink)
- Stuart Fyfe
- David de Boer (ddeboer)
- Eno Mullaraj (emullaraj)
@ -1677,7 +1700,6 @@ Symfony is the result of the work of many people who made the code better
- WedgeSama
- Hugo Sales
- Felds Liscia
- Randy Geraads
- Chihiro Adachi (chihiro-adachi)
- Raphaëll Roussel
- Tadcka
@ -1693,7 +1715,6 @@ Symfony is the result of the work of many people who made the code better
- Emmanuel Vella (emmanuel.vella)
- Guillaume BRETOU (guiguiboy)
- Carsten Nielsen (phreaknerd)
- Roger Guasch (rogerguasch)
- Jay Severson
- Benny Born
- Emirald Mateli
@ -1727,6 +1748,7 @@ Symfony is the result of the work of many people who made the code better
- Michael Dowling (mtdowling)
- Karlos Presumido (oneko)
- Tony Vermeiren (tony)
- Bart Wach
- Jos Elstgeest
- Thomas Counsell
- BilgeXA
@ -1772,7 +1794,6 @@ Symfony is the result of the work of many people who made the code better
- Pablo Ogando Ferreira
- Thomas Ploch
- Simon Neidhold
- Ben Hakim
- Valentin VALCIU
- Jeremiah VALERIE
- Julien Menth
@ -1826,8 +1847,8 @@ 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)
- Marek Víger (freezy)
- Tobias Genberg (lorceroth)
- Luis Tacón (lutacon)
- Nicolas Badey (nico-b)
- Shane Preece (shane)
- Johannes Goslar
@ -1996,6 +2017,7 @@ Symfony is the result of the work of many people who made the code better
- Felix Marezki
- Normunds
- Luiz “Felds” Liscia
- Johan
- Thomas Rothe
- Adrien Wilmet
- Martin
@ -2095,6 +2117,8 @@ Symfony is the result of the work of many people who made the code better
- Ali Tavafi
- Trevor Suarez
- gedrox
- hugovms
- Viet Pham
- Alan Bondarchuk
- Pchol
- dropfen
@ -2200,7 +2224,6 @@ Symfony is the result of the work of many people who made the code better
- Marin Nicolae
- Alessandro Loffredo
- Ian Phillips
- Marco Lipparini
- Haritz
- Matthieu Prat
- Grummfy
@ -2246,7 +2269,6 @@ Symfony is the result of the work of many people who made the code better
- Gyula Szucs
- Tomas Liubinas
- Alex
- Thomas P
- Jan Hort
- Klaas Naaijkens
- Daniel González Cerviño
@ -2410,8 +2432,10 @@ Symfony is the result of the work of many people who made the code better
- Daniel Bannert
- Karim Miladi
- Michael Genereux
- Wojciech Kania
- patrick-mcdougle
- Dariusz Czech
- Bruno Baguette
- Jack Wright
- MrNicodemuz
- Anonymous User
@ -2430,7 +2454,6 @@ Symfony is the result of the work of many people who made the code better
- n-aleha
- Talha Zekeriya Durmuş
- Anatol Belski
- Anderson Müller
- Şəhriyar İmanov
- Alexis BOYER
- Kaipi Yann
@ -2485,6 +2508,7 @@ Symfony is the result of the work of many people who made the code better
- Alex Nostadt
- Michael Squires
- Egor Gorbachev
- Fabien Villepinte
- Derek Stephen McLean
- Norman Soetbeer
- zorn

View File

@ -2393,7 +2393,7 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
$this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']],
'/textarea
[@name="name"]
[@pattern="foo"]
[not(@pattern)]
[@class="my&class form-control"]
[.="foo&bar"]
'

View File

@ -26,7 +26,7 @@
"symfony/asset": "^4.4|^5.0",
"symfony/dependency-injection": "^4.4|^5.0",
"symfony/finder": "^4.4|^5.0",
"symfony/form": "^5.1",
"symfony/form": "^5.1.9",
"symfony/http-foundation": "^4.4|^5.0",
"symfony/http-kernel": "^4.4|^5.0",
"symfony/mime": "^4.4|^5.0",

View File

@ -25,10 +25,10 @@ class TrimmedBufferOutput extends Output
private $buffer = '';
public function __construct(
int $maxLength,
?int $verbosity = self::VERBOSITY_NORMAL,
bool $decorated = false,
OutputFormatterInterface $formatter = null,
int $maxLength
OutputFormatterInterface $formatter = null
) {
if ($maxLength <= 0) {
throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));

View File

@ -46,7 +46,7 @@ class SymfonyStyle extends OutputStyle
public function __construct(InputInterface $input, OutputInterface $output)
{
$this->input = $input;
$this->bufferedOutput = new TrimmedBufferOutput($output->getVerbosity(), false, clone $output->getFormatter(), \DIRECTORY_SEPARATOR === '\\' ? 4 : 2);
$this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter());
// Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
$width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
$this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
@ -35,6 +36,7 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass
private $hasProxyDumper;
private $lazy;
private $byConstructor;
private $byFactory;
private $definitions;
private $aliases;
@ -58,6 +60,7 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass
$this->graph->clear();
$this->lazy = false;
$this->byConstructor = false;
$this->byFactory = false;
$this->definitions = $container->getDefinitions();
$this->aliases = $container->getAliases();
@ -79,7 +82,7 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass
$inExpression = $this->inExpression();
if ($value instanceof ArgumentInterface) {
$this->lazy = true;
$this->lazy = !$this->byFactory || !$value instanceof IteratorArgument;
parent::processValue($value->getValues());
$this->lazy = $lazy;
@ -129,7 +132,11 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass
$byConstructor = $this->byConstructor;
$this->byConstructor = $isRoot || $byConstructor;
$byFactory = $this->byFactory;
$this->byFactory = true;
$this->processValue($value->getFactory());
$this->byFactory = $byFactory;
$this->processValue($value->getArguments());
$properties = $value->getProperties();

View File

@ -440,7 +440,7 @@ EOF;
foreach ($edges as $edge) {
$node = $edge->getDestNode();
$id = $node->getId();
if (!($definition = $node->getValue()) instanceof Definition || $sourceId === $id || ($edge->isLazy() && ($this->proxyDumper ?? $this->getProxyDumper())->isProxyCandidate($definition)) || $edge->isWeak()) {
if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isLazy() || $edge->isWeak()) {
continue;
}

View File

@ -624,14 +624,13 @@ $imports
EOF
;
if (\LIBXML_VERSION < 20900) {
if ($this->shouldEnableEntityLoader()) {
$disableEntities = libxml_disable_entity_loader(false);
$valid = @$dom->schemaValidateSource($source);
libxml_disable_entity_loader($disableEntities);
} else {
$valid = @$dom->schemaValidateSource($source);
}
foreach ($tmpfiles as $tmpfile) {
@unlink($tmpfile);
}
@ -639,6 +638,36 @@ EOF
return $valid;
}
private function shouldEnableEntityLoader(): bool
{
// Version prior to 8.0 can be enabled without deprecation
if (\PHP_VERSION_ID < 80000) {
return true;
}
static $dom, $schema;
if (null === $dom) {
$dom = new \DOMDocument();
$dom->loadXML('<?xml version="1.0"?><test/>');
$tmpfile = tempnam(sys_get_temp_dir(), 'symfony');
register_shutdown_function(static function () use ($tmpfile) {
@unlink($tmpfile);
});
$schema = '<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:include schemaLocation="file:///'.str_replace('\\', '/', $tmpfile).'" />
</xsd:schema>';
file_put_contents($tmpfile, '<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="test" type="testType" />
<xsd:complexType name="testType"/>
</xsd:schema>');
}
return !@$dom->schemaValidateSource($schema);
}
private function validateAlias(\DOMElement $alias, string $file)
{
foreach ($alias->attributes as $name => $node) {

View File

@ -1397,12 +1397,18 @@ class ContainerBuilderTest extends TestCase
$container = include __DIR__.'/Fixtures/containers/container_almost_circular.php';
$container->compile();
$entityManager = $container->get('doctrine.entity_manager');
$this->assertEquals(new \stdClass(), $entityManager);
$pA = $container->get('pA');
$this->assertEquals(new \stdClass(), $pA);
$logger = $container->get('monolog.logger');
$this->assertEquals(new \stdClass(), $logger->handler);
$logger_inline = $container->get('monolog_inline.logger');
$this->assertEquals(new \stdClass(), $logger_inline->handler);
$foo = $container->get('foo');
$this->assertSame($foo, $foo->bar->foobar->foo);

View File

@ -1061,12 +1061,18 @@ class PhpDumperTest extends TestCase
$container = new $container();
$entityManager = $container->get('doctrine.entity_manager');
$this->assertEquals(new \stdClass(), $entityManager);
$pA = $container->get('pA');
$this->assertEquals(new \stdClass(), $pA);
$logger = $container->get('monolog.logger');
$this->assertEquals(new \stdClass(), $logger->handler);
$logger_inline = $container->get('monolog_inline.logger');
$this->assertEquals(new \stdClass(), $logger_inline->handler);
$foo = $container->get('foo');
$this->assertSame($foo, $foo->bar->foobar->foo);

View File

@ -1,5 +1,6 @@
<?php
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
@ -9,6 +10,20 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\FooForCircularWithAddCa
$public = 'public' === $visibility;
$container = new ContainerBuilder();
// factory with lazy injection
$container->register('doctrine.config', 'stdClass')->setPublic(false)
->setProperty('resolver', new Reference('doctrine.entity_listener_resolver'))
->setProperty('flag', 'ok');
$container->register('doctrine.entity_manager', 'stdClass')->setPublic(true)
->setFactory([FactoryChecker::class, 'create'])
->addArgument(new Reference('doctrine.config'));
$container->register('doctrine.entity_listener_resolver', 'stdClass')->setPublic($public)
->addArgument(new IteratorArgument([new Reference('doctrine.listener')]));
$container->register('doctrine.listener', 'stdClass')->setPublic($public)
->addArgument(new Reference('doctrine.entity_manager'));
// multiple path detection
$container->register('pA', 'stdClass')->setPublic(true)
@ -42,6 +57,27 @@ $container->register('mailer.transport_factory.amazon', 'stdClass')->setPublic($
$container->register('monolog.logger_2', 'stdClass')->setPublic($public)
->setProperty('handler', new Reference('mailer.transport'));
// monolog-like + handler that require monolog with inlined factory
$container->register('monolog_inline.logger', 'stdClass')->setPublic(true)
->setProperty('handler', new Reference('mailer_inline.mailer'));
$container->register('mailer_inline.mailer', 'stdClass')->setPublic(false)
->addArgument(
(new Definition('stdClass'))
->setFactory([new Reference('mailer_inline.transport_factory'), 'create'])
);
$container->register('mailer_inline.transport_factory', FactoryCircular::class)->setPublic($public)
->addArgument(new TaggedIteratorArgument('mailer_inline.transport'));
$container->register('mailer_inline.transport_factory.amazon', 'stdClass')->setPublic($public)
->addArgument(new Reference('monolog_inline.logger_2'))
->addTag('mailer.transport');
$container->register('monolog_inline.logger_2', 'stdClass')->setPublic($public)
->setProperty('handler', new Reference('mailer_inline.mailer'));
// same visibility for deps
$container->register('foo', FooCircular::class)->setPublic(true)

View File

@ -128,6 +128,18 @@ class FactoryCircular
}
}
class FactoryChecker
{
public static function create($config)
{
if (!isset($config->flag)) {
throw new \LogicException('The injected config must contain a "flag" property.');
}
return new stdClass();
}
}
class FoobarCircular
{
public function __construct(FooCircular $foo)

View File

@ -25,6 +25,7 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
'baz6' => 'getBaz6Service',
'connection' => 'getConnectionService',
'connection2' => 'getConnection2Service',
'doctrine.entity_manager' => 'getDoctrine_EntityManagerService',
'foo' => 'getFooService',
'foo2' => 'getFoo2Service',
'foo5' => 'getFoo5Service',
@ -37,6 +38,7 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
'manager2' => 'getManager2Service',
'manager3' => 'getManager3Service',
'monolog.logger' => 'getMonolog_LoggerService',
'monolog_inline.logger' => 'getMonologInline_LoggerService',
'pA' => 'getPAService',
'root' => 'getRootService',
'subscriber' => 'getSubscriberService',
@ -69,6 +71,9 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
'connection4' => true,
'dispatcher' => true,
'dispatcher2' => true,
'doctrine.config' => true,
'doctrine.entity_listener_resolver' => true,
'doctrine.listener' => true,
'foo4' => true,
'foobar' => true,
'foobar2' => true,
@ -82,8 +87,12 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
'mailer.transport' => true,
'mailer.transport_factory' => true,
'mailer.transport_factory.amazon' => true,
'mailer_inline.mailer' => true,
'mailer_inline.transport_factory' => true,
'mailer_inline.transport_factory.amazon' => true,
'manager4' => true,
'monolog.logger_2' => true,
'monolog_inline.logger_2' => true,
'multiuse1' => true,
'pB' => true,
'pC' => true,
@ -182,6 +191,22 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
return $instance;
}
/**
* Gets the public 'doctrine.entity_manager' shared service.
*
* @return \stdClass
*/
protected function getDoctrine_EntityManagerService()
{
$a = new \stdClass();
$a->resolver = new \stdClass(new RewindableGenerator(function () {
yield 0 => ($this->privates['doctrine.listener'] ?? $this->getDoctrine_ListenerService());
}, 1));
$a->flag = 'ok';
return $this->services['doctrine.entity_manager'] = \FactoryChecker::create($a);
}
/**
* Gets the public 'foo' shared service.
*
@ -375,6 +400,20 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
return $instance;
}
/**
* Gets the public 'monolog_inline.logger' shared service.
*
* @return \stdClass
*/
protected function getMonologInline_LoggerService()
{
$this->services['monolog_inline.logger'] = $instance = new \stdClass();
$instance->handler = ($this->privates['mailer_inline.mailer'] ?? $this->getMailerInline_MailerService());
return $instance;
}
/**
* Gets the public 'pA' shared service.
*
@ -445,6 +484,16 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
return $this->privates['bar6'] = new \stdClass($a);
}
/**
* Gets the private 'doctrine.listener' shared service.
*
* @return \stdClass
*/
protected function getDoctrine_ListenerService()
{
return $this->privates['doctrine.listener'] = new \stdClass(($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService()));
}
/**
* Gets the private 'level5' shared service.
*
@ -470,7 +519,8 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
{
return $this->privates['mailer.transport'] = (new \FactoryCircular(new RewindableGenerator(function () {
yield 0 => ($this->privates['mailer.transport_factory.amazon'] ?? $this->getMailer_TransportFactory_AmazonService());
}, 1)))->create();
yield 1 => $this->getMailerInline_TransportFactory_AmazonService();
}, 2)))->create();
}
/**
@ -489,6 +539,31 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
return $instance;
}
/**
* Gets the private 'mailer_inline.mailer' shared service.
*
* @return \stdClass
*/
protected function getMailerInline_MailerService()
{
return $this->privates['mailer_inline.mailer'] = new \stdClass((new \FactoryCircular(new RewindableGenerator(function () {
return new \EmptyIterator();
}, 0)))->create());
}
/**
* Gets the private 'mailer_inline.transport_factory.amazon' shared service.
*
* @return \stdClass
*/
protected function getMailerInline_TransportFactory_AmazonService()
{
$a = new \stdClass();
$a->handler = ($this->privates['mailer_inline.mailer'] ?? $this->getMailerInline_MailerService());
return new \stdClass($a);
}
/**
* Gets the private 'manager4' shared service.
*

View File

@ -30,6 +30,9 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
'connection4' => 'getConnection4Service',
'dispatcher' => 'getDispatcherService',
'dispatcher2' => 'getDispatcher2Service',
'doctrine.entity_listener_resolver' => 'getDoctrine_EntityListenerResolverService',
'doctrine.entity_manager' => 'getDoctrine_EntityManagerService',
'doctrine.listener' => 'getDoctrine_ListenerService',
'foo' => 'getFooService',
'foo2' => 'getFoo2Service',
'foo4' => 'getFoo4Service',
@ -45,11 +48,15 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
'mailer.transport' => 'getMailer_TransportService',
'mailer.transport_factory' => 'getMailer_TransportFactoryService',
'mailer.transport_factory.amazon' => 'getMailer_TransportFactory_AmazonService',
'mailer_inline.transport_factory' => 'getMailerInline_TransportFactoryService',
'mailer_inline.transport_factory.amazon' => 'getMailerInline_TransportFactory_AmazonService',
'manager' => 'getManagerService',
'manager2' => 'getManager2Service',
'manager3' => 'getManager3Service',
'monolog.logger' => 'getMonolog_LoggerService',
'monolog.logger_2' => 'getMonolog_Logger2Service',
'monolog_inline.logger' => 'getMonologInline_LoggerService',
'monolog_inline.logger_2' => 'getMonologInline_Logger2Service',
'pA' => 'getPAService',
'pB' => 'getPBService',
'pC' => 'getPCService',
@ -80,12 +87,14 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
'bar6' => true,
'config' => true,
'config2' => true,
'doctrine.config' => true,
'level2' => true,
'level3' => true,
'level4' => true,
'level5' => true,
'level6' => true,
'logger2' => true,
'mailer_inline.mailer' => true,
'manager4' => true,
'multiuse1' => true,
'subscriber2' => true,
@ -257,6 +266,42 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
return $instance;
}
/**
* Gets the public 'doctrine.entity_listener_resolver' shared service.
*
* @return \stdClass
*/
protected function getDoctrine_EntityListenerResolverService()
{
return $this->services['doctrine.entity_listener_resolver'] = new \stdClass(new RewindableGenerator(function () {
yield 0 => ($this->services['doctrine.listener'] ?? $this->getDoctrine_ListenerService());
}, 1));
}
/**
* Gets the public 'doctrine.entity_manager' shared service.
*
* @return \stdClass
*/
protected function getDoctrine_EntityManagerService()
{
$a = new \stdClass();
$a->resolver = ($this->services['doctrine.entity_listener_resolver'] ?? $this->getDoctrine_EntityListenerResolverService());
$a->flag = 'ok';
return $this->services['doctrine.entity_manager'] = \FactoryChecker::create($a);
}
/**
* Gets the public 'doctrine.listener' shared service.
*
* @return \stdClass
*/
protected function getDoctrine_ListenerService()
{
return $this->services['doctrine.listener'] = new \stdClass(($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService()));
}
/**
* Gets the public 'foo' shared service.
*
@ -450,13 +495,7 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
*/
protected function getMailer_TransportService()
{
$a = ($this->services['mailer.transport_factory'] ?? $this->getMailer_TransportFactoryService());
if (isset($this->services['mailer.transport'])) {
return $this->services['mailer.transport'];
}
return $this->services['mailer.transport'] = $a->create();
return $this->services['mailer.transport'] = ($this->services['mailer.transport_factory'] ?? $this->getMailer_TransportFactoryService())->create();
}
/**
@ -468,7 +507,8 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
{
return $this->services['mailer.transport_factory'] = new \FactoryCircular(new RewindableGenerator(function () {
yield 0 => ($this->services['mailer.transport_factory.amazon'] ?? $this->getMailer_TransportFactory_AmazonService());
}, 1));
yield 1 => ($this->services['mailer_inline.transport_factory.amazon'] ?? $this->getMailerInline_TransportFactory_AmazonService());
}, 2));
}
/**
@ -478,13 +518,29 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
*/
protected function getMailer_TransportFactory_AmazonService()
{
$a = ($this->services['monolog.logger_2'] ?? $this->getMonolog_Logger2Service());
return $this->services['mailer.transport_factory.amazon'] = new \stdClass(($this->services['monolog.logger_2'] ?? $this->getMonolog_Logger2Service()));
}
if (isset($this->services['mailer.transport_factory.amazon'])) {
return $this->services['mailer.transport_factory.amazon'];
}
/**
* Gets the public 'mailer_inline.transport_factory' shared service.
*
* @return \FactoryCircular
*/
protected function getMailerInline_TransportFactoryService()
{
return $this->services['mailer_inline.transport_factory'] = new \FactoryCircular(new RewindableGenerator(function () {
return new \EmptyIterator();
}, 0));
}
return $this->services['mailer.transport_factory.amazon'] = new \stdClass($a);
/**
* Gets the public 'mailer_inline.transport_factory.amazon' shared service.
*
* @return \stdClass
*/
protected function getMailerInline_TransportFactory_AmazonService()
{
return $this->services['mailer_inline.transport_factory.amazon'] = new \stdClass(($this->services['monolog_inline.logger_2'] ?? $this->getMonologInline_Logger2Service()));
}
/**
@ -563,6 +619,34 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
return $instance;
}
/**
* Gets the public 'monolog_inline.logger' shared service.
*
* @return \stdClass
*/
protected function getMonologInline_LoggerService()
{
$this->services['monolog_inline.logger'] = $instance = new \stdClass();
$instance->handler = ($this->privates['mailer_inline.mailer'] ?? $this->getMailerInline_MailerService());
return $instance;
}
/**
* Gets the public 'monolog_inline.logger_2' shared service.
*
* @return \stdClass
*/
protected function getMonologInline_Logger2Service()
{
$this->services['monolog_inline.logger_2'] = $instance = new \stdClass();
$instance->handler = ($this->privates['mailer_inline.mailer'] ?? $this->getMailerInline_MailerService());
return $instance;
}
/**
* Gets the public 'pA' shared service.
*
@ -692,6 +776,16 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
return $instance;
}
/**
* Gets the private 'mailer_inline.mailer' shared service.
*
* @return \stdClass
*/
protected function getMailerInline_MailerService()
{
return $this->privates['mailer_inline.mailer'] = new \stdClass(($this->services['mailer_inline.transport_factory'] ?? $this->getMailerInline_TransportFactoryService())->create());
}
/**
* Gets the private 'manager4' shared service.
*

View File

@ -12,8 +12,8 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FileUploadError;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
@ -164,7 +164,7 @@ class FileType extends AbstractType
$message = strtr($messageTemplate, $messageParameters);
}
return new FormError($message, $messageTemplate, $messageParameters);
return new FileUploadError($message, $messageTemplate, $messageParameters);
}
/**

View File

@ -23,6 +23,7 @@ class TextareaType extends AbstractType
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['pattern'] = null;
unset($view->vars['attr']['pattern']);
}
/**

View File

@ -11,12 +11,14 @@
namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
use Symfony\Component\Form\FileUploadError;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Util\InheritDataAwareIterator;
use Symfony\Component\PropertyAccess\PropertyPathBuilder;
use Symfony\Component\PropertyAccess\PropertyPathIterator;
use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface;
use Symfony\Component\Validator\Constraints\File;
use Symfony\Component\Validator\ConstraintViolation;
/**
@ -124,6 +126,23 @@ class ViolationMapper implements ViolationMapperInterface
// Only add the error if the form is synchronized
if ($this->acceptsErrors($scope)) {
if ($violation->getConstraint() instanceof File && (string) \UPLOAD_ERR_INI_SIZE === $violation->getCode()) {
$errorsTarget = $scope;
while (null !== $errorsTarget->getParent() && $errorsTarget->getConfig()->getErrorBubbling()) {
$errorsTarget = $errorsTarget->getParent();
}
$errors = $errorsTarget->getErrors();
$errorsTarget->clearErrors();
foreach ($errors as $error) {
if (!$error instanceof FileUploadError) {
$errorsTarget->addError($error);
}
}
}
$scope->addError(new FormError(
$violation->getMessage(),
$violation->getMessageTemplate(),

View File

@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* @internal
*/
class FileUploadError extends FormError
{
}

View File

@ -4,7 +4,7 @@
<body>
<trans-unit id="28">
<source>This form should not contain extra fields.</source>
<target>Aceast formular nu ar trebui să conțină câmpuri suplimentare.</target>
<target>Acest formular nu ar trebui să conțină câmpuri suplimentare.</target>
</trans-unit>
<trans-unit id="29">
<source>The uploaded file was too large. Please try to upload a smaller file.</source>
@ -12,8 +12,128 @@
</trans-unit>
<trans-unit id="30">
<source>The CSRF token is invalid. Please try to resubmit the form.</source>
<target>Token-ul CSRF este invalid. Vă rugăm să trimiteți formularul incă o dată.</target>
<target>Token-ul CSRF este invalid. Vă rugăm să retrimiteți formularul.</target>
</trans-unit>
<trans-unit id="99">
<source>This value is not a valid HTML5 color.</source>
<target>Această valoare nu este un cod de culoare HTML5 valid.</target>
</trans-unit>
<trans-unit id="100">
<source>Please enter a valid birthdate.</source>
<target>Vă rugăm să introduceți o dată de naștere validă.</target>
</trans-unit>
<trans-unit id="101">
<source>The selected choice is invalid.</source>
<target>Valoarea selectată este invalidă.</target>
</trans-unit>
<trans-unit id="102">
<source>The collection is invalid.</source>
<target>Colecția nu este validă.</target>
</trans-unit>
<trans-unit id="103">
<source>Please select a valid color.</source>
<target>Vă rugăm să selectați o culoare validă.</target>
</trans-unit>
<trans-unit id="104">
<source>Please select a valid country.</source>
<target>Vă rugăm să selectați o țară validă.</target>
</trans-unit>
<trans-unit id="105">
<source>Please select a valid currency.</source>
<target>Vă rugăm să selectați o monedă validă.</target>
</trans-unit>
<trans-unit id="106">
<source>Please choose a valid date interval.</source>
<target>Vă rugăm să selectați un interval de zile valid.</target>
</trans-unit>
<trans-unit id="107">
<source>Please enter a valid date and time.</source>
<target>Vă rugăm să introduceți o dată și o oră validă.</target>
</trans-unit>
<trans-unit id="108">
<source>Please enter a valid date.</source>
<target>Vă rugăm să introduceți o dată validă.</target>
</trans-unit>
<trans-unit id="109">
<source>Please select a valid file.</source>
<target>Vă rugăm să selectați un fișier valid.</target>
</trans-unit>
<trans-unit id="110">
<source>The hidden field is invalid.</source>
<target>Câmpul ascuns este invalid.</target>
</trans-unit>
<trans-unit id="111">
<source>Please enter an integer.</source>
<target>Vă rugăm să introduceți un număr întreg.</target>
</trans-unit>
<trans-unit id="112">
<source>Please select a valid language.</source>
<target>Vă rugăm să selectați o limbă validă.</target>
</trans-unit>
<trans-unit id="113">
<source>Please select a valid locale.</source>
<target>Vă rugăm să selectați o setare locală validă.</target>
</trans-unit>
<trans-unit id="114">
<source>Please enter a valid money amount.</source>
<target>Vă rugăm să introduceți o valoare monetară corectă.</target>
</trans-unit>
<trans-unit id="115">
<source>Please enter a number.</source>
<target>Vă rugăm să introduceți un număr.</target>
</trans-unit>
<trans-unit id="116">
<source>The password is invalid.</source>
<target>Parola nu este validă.</target>
</trans-unit>
<trans-unit id="117">
<source>Please enter a percentage value.</source>
<target>Vă rugăm să introduceți o valoare procentuală.</target>
</trans-unit>
<trans-unit id="118">
<source>The values do not match.</source>
<target>Valorile nu coincid.</target>
</trans-unit>
<trans-unit id="119">
<source>Please enter a valid time.</source>
<target>Vă rugăm să introduceți o oră validă.</target>
</trans-unit>
<trans-unit id="120">
<source>Please select a valid timezone.</source>
<target>Vă rugăm să selectați un fus orar valid.</target>
</trans-unit>
<trans-unit id="121">
<source>Please enter a valid URL.</source>
<target>Vă rugăm să introduceți un URL valid.</target>
</trans-unit>
<trans-unit id="122">
<source>Please enter a valid search term.</source>
<target>Vă rugăm să introduceți un termen de căutare valid.</target>
</trans-unit>
<trans-unit id="123">
<source>Please provide a valid phone number.</source>
<target>Vă rugăm să introduceți un număr de telefon valid.</target>
</trans-unit>
<trans-unit id="124">
<source>The checkbox has an invalid value.</source>
<target>Bifa nu are o valoare validă.</target>
</trans-unit>
<trans-unit id="125">
<source>Please enter a valid email address.</source>
<target>Vă rugăm să introduceți o adresă de email validă.</target>
</trans-unit>
<trans-unit id="126">
<source>Please select a valid option.</source>
<target>Vă rugăm să selectați o opțiune validă.</target>
</trans-unit>
<trans-unit id="127">
<source>Please select a valid range.</source>
<target>Vă rugăm să selectați un interval valid.</target>
</trans-unit>
<trans-unit id="128">
<source>Please enter a valid week.</source>
<target>Vă rugăm să introduceți o săptămână validă.</target>
</trans-unit>
</body>
</file>
</xliff>
</xliff>

View File

@ -2045,7 +2045,7 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
$this->assertWidgetMatchesXpath($form->createView(), [],
'/textarea
[@name="name"]
[@pattern="foo"]
[not(@pattern)]
[.="foo&bar"]
'
);

View File

@ -18,12 +18,14 @@ use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
use Symfony\Component\Form\FileUploadError;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormConfigBuilder;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper\Fixtures\Issue;
use Symfony\Component\PropertyAccess\PropertyPath;
use Symfony\Component\Validator\Constraints\File;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationInterface;
@ -81,6 +83,7 @@ class ViolationMapperTest extends TestCase
$config->setPropertyPath($propertyPath);
$config->setCompound(true);
$config->setDataMapper(new PropertyPathMapper());
$config->setErrorBubbling($options['error_bubbling'] ?? false);
if (!$synchronized) {
$config->addViewTransformer(new CallbackTransformer(
@ -1590,4 +1593,93 @@ class ViolationMapperTest extends TestCase
$this->assertEquals([$this->getFormError($violation2, $grandChild2)], iterator_to_array($grandChild2->getErrors()), $grandChild2->getName().' should have an error, but has none');
$this->assertEquals([$this->getFormError($violation3, $grandChild3)], iterator_to_array($grandChild3->getErrors()), $grandChild3->getName().' should have an error, but has none');
}
public function testFileUploadErrorIsNotRemovedIfNoFileSizeConstraintViolationWasRaised()
{
$form = $this->getForm('form');
$form->addError(new FileUploadError(
'The file is too large. Allowed maximum size is 2 MB.',
'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.',
[
'{{ limit }}' => '2',
'{{ suffix }}' => 'MB',
]
));
$this->mapper->mapViolation($this->getConstraintViolation('data'), $form);
$this->assertCount(2, $form->getErrors());
}
public function testFileUploadErrorIsRemovedIfFileSizeConstraintViolationWasRaised()
{
$form = $this->getForm('form');
$form->addError(new FileUploadError(
'The file is too large. Allowed maximum size is 2 MB.',
'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.',
[
'{{ limit }}' => '2',
'{{ suffix }}' => 'MB',
]
));
$violation = new ConstraintViolation(
'The file is too large (3 MB). Allowed maximum size is 2 MB.',
'The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.',
[
'{{ limit }}' => '2',
'{{ size }}' => '3',
'{{ suffix }}' => 'MB',
],
'',
'data',
null,
null,
(string) \UPLOAD_ERR_INI_SIZE,
new File()
);
$this->mapper->mapViolation($this->getConstraintViolation('data'), $form);
$this->mapper->mapViolation($violation, $form);
$this->assertCount(2, $form->getErrors());
}
public function testFileUploadErrorIsRemovedIfFileSizeConstraintViolationWasRaisedOnFieldWithErrorBubbling()
{
$parent = $this->getForm('parent');
$child = $this->getForm('child', 'file', null, [], false, true, [
'error_bubbling' => true,
]);
$parent->add($child);
$child->addError(new FileUploadError(
'The file is too large. Allowed maximum size is 2 MB.',
'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.',
[
'{{ limit }}' => '2',
'{{ suffix }}' => 'MB',
]
));
$violation = new ConstraintViolation(
'The file is too large (3 MB). Allowed maximum size is 2 MB.',
'The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.',
[
'{{ limit }}' => '2',
'{{ size }}' => '3',
'{{ suffix }}' => 'MB',
],
null,
'data.file',
null,
null,
(string) \UPLOAD_ERR_INI_SIZE,
new File()
);
$this->mapper->mapViolation($this->getConstraintViolation('data'), $parent);
$this->mapper->mapViolation($this->getConstraintViolation('data.file'), $parent);
$this->mapper->mapViolation($violation, $parent);
$this->assertCount(3, $parent->getErrors());
$this->assertCount(0, $child->getErrors());
}
}

View File

@ -29,6 +29,21 @@ class TranslationFilesTest extends TestCase
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
}
/**
* @dataProvider provideTranslationFiles
* @group Legacy
*/
public function testTranslationFileIsValidWithoutEntityLoader($filePath)
{
$document = new \DOMDocument();
$document->loadXML(file_get_contents($filePath));
libxml_disable_entity_loader(true);
$errors = XliffUtils::validateSchema($document);
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
}
public function provideTranslationFiles()
{
return array_map(

View File

@ -62,6 +62,14 @@
<source>Account is locked.</source>
<target>Contul este blocat.</target>
</trans-unit>
<trans-unit id="17">
<source>Too many failed login attempts, please try again later.</source>
<target>Prea multe încercări de autentificare eșuate, vă rugăm să încercați mai târziu.</target>
</trans-unit>
<trans-unit id="18">
<source>Invalid or expired login link.</source>
<target>Link de autentificare invalid sau expirat.</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -29,6 +29,20 @@ class TranslationFilesTest extends TestCase
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
}
/**
* @dataProvider provideTranslationFiles
*/
public function testTranslationFileIsValidWithoutEntityLoader($filePath)
{
$document = new \DOMDocument();
$document->loadXML(file_get_contents($filePath));
libxml_disable_entity_loader(true);
$errors = XliffUtils::validateSchema($document);
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
}
public function provideTranslationFiles()
{
return array_map(

View File

@ -61,21 +61,18 @@ class XliffUtils
{
$xliffVersion = static::getVersionNumber($dom);
$internalErrors = libxml_use_internal_errors(true);
if (\LIBXML_VERSION < 20900) {
if ($shouldEnable = self::shouldEnableEntityLoader()) {
$disableEntities = libxml_disable_entity_loader(false);
}
$isValid = @$dom->schemaValidateSource(self::getSchema($xliffVersion));
if (!$isValid) {
if (\LIBXML_VERSION < 20900) {
try {
$isValid = @$dom->schemaValidateSource(self::getSchema($xliffVersion));
if (!$isValid) {
return self::getXmlErrors($internalErrors);
}
} finally {
if ($shouldEnable) {
libxml_disable_entity_loader($disableEntities);
}
return self::getXmlErrors($internalErrors);
}
if (\LIBXML_VERSION < 20900) {
libxml_disable_entity_loader($disableEntities);
}
$dom->normalizeDocument();
@ -86,6 +83,36 @@ class XliffUtils
return [];
}
private static function shouldEnableEntityLoader(): bool
{
// Version prior to 8.0 can be enabled without deprecation
if (\PHP_VERSION_ID < 80000) {
return true;
}
static $dom, $schema;
if (null === $dom) {
$dom = new \DOMDocument();
$dom->loadXML('<?xml version="1.0"?><test/>');
$tmpfile = tempnam(sys_get_temp_dir(), 'symfony');
register_shutdown_function(static function () use ($tmpfile) {
@unlink($tmpfile);
});
$schema = '<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:include schemaLocation="file:///'.str_replace('\\', '/', $tmpfile).'" />
</xsd:schema>';
file_put_contents($tmpfile, '<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="test" type="testType" />
<xsd:complexType name="testType"/>
</xsd:schema>');
}
return !@$dom->schemaValidateSource($schema);
}
public static function getErrorsAsString(array $xmlErrors): string
{
$errorsAsString = '';

View File

@ -128,7 +128,7 @@
</trans-unit>
<trans-unit id="35">
<source>This value should be a valid number.</source>
<target>Este valor deveria de ser um número válido.</target>
<target>Este valor deveria ser um número válido.</target>
</trans-unit>
<trans-unit id="36">
<source>This file is not a valid image.</source>
@ -176,27 +176,27 @@
</trans-unit>
<trans-unit id="47">
<source>This value should be the user's current password.</source>
<target>Este valor deveria de ser a password atual do utilizador.</target>
<target>Este valor deveria ser a senha atual do usuário.</target>
</trans-unit>
<trans-unit id="48">
<source>This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.</source>
<target>Este valor tem de ter exatamente {{ limit }} carateres.</target>
<target>Este valor deve possuir exatamente {{ limit }} caracteres.</target>
</trans-unit>
<trans-unit id="49">
<source>The file was only partially uploaded.</source>
<target>Só foi enviado parte do ficheiro.</target>
<target>Só foi enviada uma parte do arquivo.</target>
</trans-unit>
<trans-unit id="50">
<source>No file was uploaded.</source>
<target>Nenhum ficheiro foi enviado.</target>
<target>Nenhum arquivo foi enviado.</target>
</trans-unit>
<trans-unit id="51">
<source>No temporary folder was configured in php.ini.</source>
<target>Não existe nenhum directório temporária configurado no ficheiro php.ini.</target>
<target>Não existe uma pasta temporária configurada no arquivo php.ini.</target>
</trans-unit>
<trans-unit id="52">
<source>Cannot write temporary file to disk.</source>
<target>Não foi possível escrever ficheiros temporários no disco.</target>
<target>Não foi possível escrever os arquivos temporários no disco.</target>
</trans-unit>
<trans-unit id="53">
<source>A PHP extension caused the upload to fail.</source>
@ -292,15 +292,15 @@
</trans-unit>
<trans-unit id="76">
<source>The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed.</source>
<target>A imagem está orientada à paisagem ({{ width }}x{{ height }}px). Imagens orientadas à paisagem não são permitidas.</target>
<target>A imagem está em orientação de paisagem ({{ width }}x{{ height }}px). Imagens orientadas em paisagem não são permitidas.</target>
</trans-unit>
<trans-unit id="77">
<source>The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed.</source>
<target>A imagem está orientada ao retrato ({{ width }}x{{ height }}px). Imagens orientadas ao retrato não são permitidas.</target>
<target>A imagem está em orientação de retrato ({{ width }}x{{ height }}px). Imagens orientadas em retrato não são permitidas.</target>
</trans-unit>
<trans-unit id="78">
<source>An empty file is not allowed.</source>
<target>Ficheiro vazio não é permitido.</target>
<target>Um arquivo vazio não é permitido.</target>
</trans-unit>
<trans-unit id="79">
<source>The host could not be resolved.</source>

View File

@ -29,6 +29,20 @@ class TranslationFilesTest extends TestCase
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
}
/**
* @dataProvider provideTranslationFiles
*/
public function testTranslationFileIsValidWithoutEntityLoader($filePath)
{
$document = new \DOMDocument();
$document->loadXML(file_get_contents($filePath));
libxml_disable_entity_loader(true);
$errors = XliffUtils::validateSchema($document);
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
}
public function provideTranslationFiles()
{
return array_map(

View File

@ -758,54 +758,54 @@ class Parser
return Inline::parse($this->lexInlineSequence($cursor), $flags, $this->refs);
}
$quotation = '' !== $value && ('"' === $value[0] || "'" === $value[0]) ? $value[0] : null;
switch ($value[0] ?? '') {
case '"':
case "'":
$cursor = \strlen($this->currentLine) - \strlen($value);
$parsedValue = Inline::parse($this->lexInlineQuotedString($cursor), $flags, $this->refs);
// do not take following lines into account when the current line is a quoted single line value
if (null !== $quotation && self::preg_match('/^'.$quotation.'.*'.$quotation.'(\s*#.*)?$/', $value)) {
return Inline::parse($value, $flags, $this->refs);
if (isset($this->currentLine[$cursor]) && preg_replace('/\s*#.*$/A', '', substr($this->currentLine, $cursor))) {
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($this->currentLine, $cursor)));
}
return $parsedValue;
default:
$lines = [];
while ($this->moveToNextLine()) {
// unquoted strings end before the first unindented line
if (0 === $this->getCurrentLineIndentation()) {
$this->moveToPreviousLine();
break;
}
$lines[] = trim($this->currentLine);
}
for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) {
if ('' === $lines[$i]) {
$value .= "\n";
$previousLineBlank = true;
} elseif ($previousLineBlank) {
$value .= $lines[$i];
$previousLineBlank = false;
} else {
$value .= ' '.$lines[$i];
$previousLineBlank = false;
}
}
Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
$parsedValue = Inline::parse($value, $flags, $this->refs);
if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename);
}
return $parsedValue;
}
$lines = [];
while ($this->moveToNextLine()) {
// unquoted strings end before the first unindented line
if (null === $quotation && 0 === $this->getCurrentLineIndentation()) {
$this->moveToPreviousLine();
break;
}
$lines[] = trim($this->currentLine);
// quoted string values end with a line that is terminated with the quotation character
$escapedLine = str_replace(['\\\\', '\\"'], '', $this->currentLine);
if ('' !== $escapedLine && $escapedLine[-1] === $quotation) {
break;
}
}
for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) {
if ('' === $lines[$i]) {
$value .= "\n";
$previousLineBlank = true;
} elseif ($previousLineBlank) {
$value .= $lines[$i];
$previousLineBlank = false;
} else {
$value .= ' '.$lines[$i];
$previousLineBlank = false;
}
}
Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
$parsedValue = Inline::parse($value, $flags, $this->refs);
if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename);
}
return $parsedValue;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
@ -1162,8 +1162,13 @@ class Parser
$previousLineWasNewline = true;
$previousLineWasTerminatedWithBackslash = false;
$lineNumber = 0;
do {
if (++$lineNumber > 1) {
$cursor += strspn($this->currentLine, ' ', $cursor);
}
if ($this->isCurrentLineBlank()) {
$value .= "\n";
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {

View File

@ -1569,6 +1569,54 @@ EOT;
$this->assertSame(['foo' => 'bar baz foobar foo', 'bar' => 'baz'], $this->parser->parse($yaml));
}
/**
* @dataProvider escapedQuotationCharactersInQuotedStrings
*/
public function testParseQuotedStringContainingEscapedQuotationCharacters(string $yaml, array $expected)
{
$this->assertSame($expected, $this->parser->parse($yaml));
}
public function escapedQuotationCharactersInQuotedStrings()
{
return [
'single quoted string' => [
<<<YAML
entries:
- message: 'No emails received before timeout - Address: ''test@testemail.company.com''
Keyword: ''Your Order confirmation'' ttl: 50'
outcome: failed
YAML
,
[
'entries' => [
[
'message' => 'No emails received before timeout - Address: \'test@testemail.company.com\' Keyword: \'Your Order confirmation\' ttl: 50',
'outcome' => 'failed',
],
],
],
],
'double quoted string' => [
<<<YAML
entries:
- message: "No emails received before timeout - Address: \"test@testemail.company.com\"
Keyword: \"Your Order confirmation\" ttl: 50"
outcome: failed
YAML
,
[
'entries' => [
[
'message' => 'No emails received before timeout - Address: "test@testemail.company.com" Keyword: "Your Order confirmation" ttl: 50',
'outcome' => 'failed',
],
],
],
],
];
}
public function testParseMultiLineString()
{
$this->assertEquals("foo bar\nbaz", $this->parser->parse("foo\nbar\n\nbaz"));