diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ac82d7063d015..426b55def0001 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,20 +1,21 @@ | Q | A | ------------- | --- -| Branch? | master for features / 3.4 up to 4.2 for bug fixes +| Branch? | master for features / 3.4, 4.2 or 4.3 for bug fixes | Bug fix? | yes/no -| New feature? | yes/no +| New feature? | yes/no | BC breaks? | no -| Deprecations? | yes/no +| Deprecations? | yes/no | Tests pass? | yes | Fixed tickets | #... | License | MIT | Doc PR | symfony/symfony-docs#... diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000000000..60990950bf039 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,10 @@ +Security Policy +=============== + +If you found any issues that might have security implications, +please send a report to security[at]symfony.com +DO NOT PUBLISH SECURITY REPORTS PUBLICLY. + +The full [Security Policy][1] is described in the official documentation. + + [1]: https://symfony.com/security diff --git a/.travis.yml b/.travis.yml index 2e2de052182e2..ed27e7a505280 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: php -dist: trusty +dist: xenial git: depth: 2 @@ -13,6 +13,7 @@ addons: - slapd - zookeeperd - libzookeeper-mt-dev + - rabbitmq-server env: global: diff --git a/CHANGELOG-4.2.md b/CHANGELOG-4.2.md index f45e7e7273ab4..7c7c018037c6d 100644 --- a/CHANGELOG-4.2.md +++ b/CHANGELOG-4.2.md @@ -7,6 +7,35 @@ in 4.2 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.2.0...v4.2.1 +* 4.2.9 (2019-05-28) + + * bug #31584 [Workflow] Do not trigger extra guards (lyrixx) + * bug #31632 [Messenger] Use "real" memory usage to honor --memory-limit (chalasr) + * bug #31599 [Translation] Fixed issue with new vs old TranslatorInterface in TranslationDataCollector (althaus) + * bug #31349 [WebProfilerBundle] Use absolute URL for profiler links (Alumbrados) + * bug #31541 [DI] fix using bindings with locators of service subscribers (nicolas-grekas) + * bug #31568 [Process] Fix infinite waiting for stopped process (mshavliuk) + * bug #31551 [ProxyManager] isProxyCandidate() does not take into account interfaces (andrerom) + * bug #31335 [Doctrine] Respect parent class contract in ContainerAwareEventManager (Koc) + * bug #31421 [Routing][AnnotationClassLoader] fix utf-8 encoding in default route name (przemyslaw-bogusz) + * bug #31510 Use the current working dir as default first arg in 'link' binary (lyrixx) + * bug #31524 [HttpFoundation] prevent deprecation when filesize matches error code (xabbuh) + * bug #31535 [Debug] Wrap call to require_once in a try/catch (lyrixx) + * bug #31477 [PropertyAccess] Add missing property to PropertyAccessor (vudaltsov) + * bug #31479 [Cache] fix saving unrelated keys in recursive callback calls (nicolas-grekas) + * bug #31438 [Serializer] Fix denormalization of object with variadic constructor typed argument (ajgarlag) + * bug #31445 [Messenger] Making cache rebuild correctly when message subscribers change (weaverryan) + * bug #31442 [Validator] Fix finding translator parent definition in compiler pass (deguif) + * bug #31475 [HttpFoundation] Allow set 'None' on samesite cookie flag (markitosgv) + * bug #31456 Remove deprecated usage of some Twig features (fabpot) + * bug #31207 [Routing] Fixed unexpected 404 NoConfigurationException (yceruto) + * bug #31261 [Console] Commands with an alias should not be recognized as ambiguous when using register (Simperfit) + * bug #31371 [DI] Removes number of elements information in debug mode (jschaedl) + * bug #31418 [FrameworkBundle] clarify the possible class/interface of the cache (xabbuh) + * bug #31411 [Intl] Fix root fallback locale (ro0NL) + * bug #31377 [Console] Fix auto-complete for ChoiceQuestion (multi-select answers) (battye) + * bug #31380 [WebProfilerBundle] Don't filter submitted IP values (javiereguiluz) + * 4.2.8 (2019-05-01) * bug #31338 Revert "bug #30620 [FrameworkBundle][HttpFoundation] make session service resettable (dmaicher)" (nicolas-grekas) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 146b9822ffdce..fddccc428e7c9 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -20,12 +20,12 @@ Symfony is the result of the work of many people who made the code better - Johannes S (johannes) - Javier Eguiluz (javier.eguiluz) - Kris Wallsmith (kriswallsmith) - - Grégoire Pineau (lyrixx) - Roland Franssen (ro0) + - Grégoire Pineau (lyrixx) - Hugo Hamon (hhamon) - Abdellatif Ait boudad (aitboudad) - - Romain Neutron (romain) - Samuel ROZE (sroze) + - Romain Neutron (romain) - Pascal Borreli (pborreli) - Wouter De Jong (wouterj) - Joseph Bielawski (stloyd) @@ -39,9 +39,9 @@ Symfony is the result of the work of many people who made the code better - Benjamin Eberlei (beberlei) - Igor Wiedler (igorw) - Eriksen Costa (eriksencosta) + - Hamza Amrouche (simperfit) - Guilhem Niot (energetick) - Sarah Khalil (saro0h) - - Hamza Amrouche (simperfit) - Jonathan Wage (jwage) - Tobias Nyholm (tobias) - Lynn van der Berg (kjarli) @@ -66,28 +66,29 @@ Symfony is the result of the work of many people who made the code better - Diego Saint Esteben (dii3g0) - Konstantin Kudryashov (everzet) - Gábor Egyed (1ed) + - Grégoire Paris (greg0ire) - Bilal Amarni (bamarni) - Titouan Galopin (tgalopin) - Mathieu Piot (mpiot) - David Maicher (dmaicher) - Florin Patan (florinpatan) - - Grégoire Paris (greg0ire) - - Gabriel Ostrolucký (gadelat) - Valentin Udaltsov (vudaltsov) + - Konstantin Myakshin (koc) + - Gabriel Ostrolucký (gadelat) - Vladimir Reznichenko (kalessil) - Jáchym Toušek (enumag) - - Konstantin Myakshin (koc) - Michel Weimerskirch (mweimerskirch) - Andrej Hudec (pulzarraider) + - Issei Murasawa (issei_m) - Eric Clemmons (ericclemmons) - Charles Sarrazin (csarrazi) - Christian Raue - - Issei Murasawa (issei_m) - Arnout Boks (aboks) - Deni - Henrik Westphal (snc) - Dariusz Górecki (canni) - Douglas Greenshields (shieldo) + - David Buchmann (dbu) - Dariusz Ruminski - Lee McDermott - Brandon Turner @@ -101,16 +102,15 @@ Symfony is the result of the work of many people who made the code better - John Wards (johnwards) - Thomas Calvet (fancyweb) - Fran Moreno (franmomu) - - David Buchmann (dbu) - Antoine Hérault (herzult) - Paráda József (paradajozsef) - Arnaud Le Blanc (arnaud-lb) - Maxime STEINHAUSSER - Michal Piotrowski (eventhorizon) - Tim Nagel (merk) + - Chris Wilkinson (thewilkybarkid) - Brice BERNARD (brikou) - Baptiste Clavié (talus) - - Chris Wilkinson (thewilkybarkid) - marc.weistroff - Tomáš Votruba (tomas_votruba) - lenar @@ -142,6 +142,7 @@ Symfony is the result of the work of many people who made the code better - Alex Pott - Vincent AUBERT (vincent) - Juti Noppornpitak (shiroyuki) + - Teoh Han Hui (teohhanhui) - Anthony MARTIN (xurudragon) - Tigran Azatyan (tigranazatyan) - Sebastian Hörl (blogsh) @@ -151,7 +152,7 @@ Symfony is the result of the work of many people who made the code better - Arnaud Kleinpeter (nanocom) - Jannik Zschiesche (apfelbox) - Guilherme Blanco (guilhermeblanco) - - Teoh Han Hui (teohhanhui) + - Jan Schädlich (jschaedl) - SpacePossum - Pablo Godel (pgodel) - Jérémie Augustin (jaugustin) @@ -162,13 +163,13 @@ Symfony is the result of the work of many people who made the code better - Rafael Dohms (rdohms) - jwdeitch - Mikael Pajunen + - François-Xavier de Guillebon (de-gui_f) - Niels Keurentjes (curry684) - Vyacheslav Pavlov - Richard van Laak (rvanlaak) - Richard Shank (iampersistent) - Thomas Rabaix (rande) - Rouven Weßling (realityking) - - François-Xavier de Guillebon (de-gui_f) - Clemens Tolboom - Helmer Aaviksoo - Alessandro Chitolina (alekitto) @@ -181,6 +182,7 @@ Symfony is the result of the work of many people who made the code better - Artur Kotyrba - Tyson Andre - GDIBass + - Alexander Schranz (alexander-schranz) - jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent) - James Halsall (jaitsu) - Matthieu Napoli (mnapoli) @@ -192,6 +194,7 @@ Symfony is the result of the work of many people who made the code better - Daniel Espendiller - Possum - Dorian Villet (gnutix) + - George Mponos (gmponos) - Sergey Linnik (linniksa) - Richard Miller (mr_r_miller) - Albert Casademont (acasademont) @@ -199,6 +202,7 @@ Symfony is the result of the work of many people who made the code better - Dennis Benkert (denderello) - DQNEO - Samuel NELA (snela) + - Vincent Touzet (vincenttouzet) - Gregor Harlan (gharlan) - Gary PEGEOT (gary-p) - Ruben Gonzalez (rubenrua) @@ -213,7 +217,6 @@ Symfony is the result of the work of many people who made the code better - bronze1man - sun (sun) - Larry Garfield (crell) - - George Mponos (gmponos) - Michaël Perrin (michael.perrin) - Nikolay Labinskiy (e-moe) - Martin Schuhfuß (usefulthink) @@ -224,8 +227,6 @@ Symfony is the result of the work of many people who made the code better - fivestar - Dominique Bongiraud - Jeremy Livingston (jeremylivingston) - - Vincent Touzet (vincenttouzet) - - Jan Schädlich (jschaedl) - Michael Lee (zerustech) - Matthieu Auger (matthieuauger) - Leszek Prabucki (l3l0) @@ -237,7 +238,6 @@ Symfony is the result of the work of many people who made the code better - Andreas Schempp (aschempp) - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) - - Alexander Schranz (alexander-schranz) - Michele Orselli (orso) - Sven Paulus (subsven) - Maxime Veber (nek-) @@ -253,6 +253,7 @@ Symfony is the result of the work of many people who made the code better - Mantis Development - Loïc Faugeron - Hidde Wieringa (hiddewie) + - Andre Rømcke (andrerom) - Marco Pivetta (ocramius) - Rob Frawley 2nd (robfrawley) - julien pauli (jpauli) @@ -268,7 +269,9 @@ Symfony is the result of the work of many people who made the code better - Elnur Abdurrakhimov (elnur) - Manuel Reinhard (sprain) - Danny Berger (dpb587) + - Antonio J. García Lagar (ajgarlag) - Adam Prager (padam87) + - Przemysław Bogusz (przemyslaw-bogusz) - Benoît Burnichon (bburnichon) - Roman Marintšenko (inori) - Xavier Montaña Carreras (xmontana) @@ -295,11 +298,13 @@ Symfony is the result of the work of many people who made the code better - Jan Sorgalla (jsor) - Ray - Chekote + - Antoine Makdessi (amakdessi) - Thomas Adam - Viktor Bocharskyi (bocharsky_bw) - Jhonny Lidfors (jhonne) - Diego Agulló (aeoris) - jdhoek + - David Prévot - Bob den Otter (bopp) - Thomas Schulz (king2500) - Frank de Jonge (frenkynet) @@ -309,6 +314,7 @@ Symfony is the result of the work of many people who made the code better - mcfedr (mcfedr) - Colin O'Dell (colinodell) - Giorgio Premi + - renanbr - Alex Rock (pierstoval) - Ben Davies (bendavies) - Beau Simensen (simensen) @@ -316,9 +322,7 @@ Symfony is the result of the work of many people who made the code better - Robert Kiss (kepten) - Zan Baldwin (zanderbaldwin) - Roumen Damianoff (roumen) - - Antonio J. García Lagar (ajgarlag) - Kim Hemsø Rasmussen (kimhemsoe) - - Przemysław Bogusz (przemyslaw-bogusz) - Pascal Luna (skalpa) - Wouter Van Hecke - Jérôme Parmentier (lctrs) @@ -332,8 +336,10 @@ Symfony is the result of the work of many people who made the code better - Chad Sikorra (chadsikorra) - Chris Smith (cs278) - Florian Klein (docteurklein) + - Stadly - Manuel Kiessling (manuelkiessling) - Atsuhiro KUBO (iteman) + - Quynh Xuan Nguyen (xuanquynh) - rudy onfroy (ronfroy) - Serkan Yildiz (srknyldz) - Andrew Moore (finewolf) @@ -357,7 +363,6 @@ 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) @@ -371,7 +376,6 @@ Symfony is the result of the work of many people who made the code better - Ricard Clau (ricardclau) - Mark Challoner (markchalloner) - Gennady Telegin (gtelegin) - - renanbr - Erin Millard - Artur Melo (restless) - Matthew Lewinski (lewinski) @@ -380,7 +384,6 @@ Symfony is the result of the work of many people who made the code better - Nicolas LEFEVRE (nicoweb) - alquerci - Mateusz Sip (mateusz_sip) - - Andre Rømcke (andrerom) - Francesco Levorato - Dmitrii Poddubnyi (karser) - Vitaliy Zakharov (zakharovvi) @@ -391,6 +394,7 @@ Symfony is the result of the work of many people who made the code better - Tomasz Kowalczyk (thunderer) - Artur Eshenbrener - Andreas Braun + - Arjen van der Meijden - Damien Alexandre (damienalexandre) - Thomas Perez (scullwm) - Felix Labrecque @@ -412,7 +416,6 @@ Symfony is the result of the work of many people who made the code better - Iker Ibarguren (ikerib) - Kirill chEbba Chebunin (chebba) - Greg Thornton (xdissent) - - Quynh Xuan Nguyen (xuanquynh) - Martin Hujer (martinhujer) - Philipp Cordes - Costin Bereveanu (schniper) @@ -425,6 +428,7 @@ Symfony is the result of the work of many people who made the code better - Pavel Volokitin (pvolok) - Smaine Milianni (ismail1432) - Arthur de Moulins (4rthem) + - Matthias Althaus (althaus) - Nicolas Dewez (nicolas_dewez) - Endre Fejes - Tobias Naumann (tna) @@ -461,6 +465,7 @@ Symfony is the result of the work of many people who made the code better - Steffen Roßkamp - Alexandru Furculita (afurculita) - Valentin Jonovs (valentins-jonovs) + - Laurent VOULLEMIER (lvo) - Jeanmonod David (jeanmonod) - Christopher Davis (chrisguitarguy) - Webnet team (webnet) @@ -558,14 +563,15 @@ Symfony is the result of the work of many people who made the code better - Jakub Škvára (jskvara) - Andrew Udvare (audvare) - alexpods - - Arjen van der Meijden - Adam Szaraniec (mimol) - Dariusz Ruminski - Erik Trapman (eriktrapman) + - Rokas Mikalkėnas (rokasm) - De Cock Xavier (xdecock) - Almog Baku (almogbaku) - Scott Arciszewski - Xavier HAUSHERR + - Christopher Hertel (chertel) - Norbert Orzechowicz (norzechowicz) - Denis Charrier (brucewouaigne) - Matthijs van den Bos (matthijs) @@ -591,7 +597,9 @@ Symfony is the result of the work of many people who made the code better - Martin Morávek (keeo) - Steven Surowiec - Kevin Saliou (kbsali) + - Ruud Kamphuis (ruudk) - Shawn Iwinski + - Gawain Lynch (gawain) - NothingWeAre - Ryan - Alexander Deruwe (aderuwe) @@ -620,7 +628,6 @@ Symfony is the result of the work of many people who made the code better - Sebastian Krebs - Piotr Stankowski - Baptiste Leduc (bleduc) - - Laurent VOULLEMIER (lvo) - Jean-Christophe Cuvelier [Artack] - Simon DELICATA - alcaeus @@ -645,6 +652,7 @@ Symfony is the result of the work of many people who made the code better - Desjardins Jérôme (jewome62) - Kévin THERAGE (kevin_therage) - Simeon Kolev (simeon_kolev9) + - Jonas Elfering - Nahuel Cuesta (ncuesta) - Chris Boden (cboden) - Christophe Villeger (seragan) @@ -702,6 +710,7 @@ Symfony is the result of the work of many people who made the code better - Ulumuddin Yunus (joenoez) - Johann Saunier (prophet777) - Sergey (upyx) + - Andreas Erhard - Michael Devery (mickadoo) - Antoine Corcy - Sascha Grossenbacher @@ -745,6 +754,7 @@ Symfony is the result of the work of many people who made the code better - RJ Garcia - Delf Tonder (leberknecht) - Raulnet + - Ondrej Exner - Mark Sonnabaum - Massimiliano Braglia (massimilianobraglia) - Richard Quadling @@ -754,6 +764,7 @@ Symfony is the result of the work of many people who made the code better - Alexander Volochnev (exelenz) - Michael Piecko - yclian + - Alan Poulain - Aleksey Prilipko - Tomas Norkūnas (norkunas) - Andrew Berry @@ -794,7 +805,6 @@ Symfony is the result of the work of many people who made the code better - Andrew Tchircoff (andrewtch) - michaelwilliams - 1emming - - Matthias Althaus - Leevi Graham (leevigraham) - Nykopol (nykopol) - Tri Pham (phamuyentri) @@ -806,7 +816,6 @@ Symfony is the result of the work of many people who made the code better - John Bohn (jbohn) - Marc Morera (mmoreram) - Saif Eddin Gmati (azjezz) - - Stadly - Andrew Hilobok (hilobok) - Noah Heck (myesain) - Christian Soronellas (theunic) @@ -814,7 +823,6 @@ Symfony is the result of the work of many people who made the code better - fedor.f - Yosmany Garcia (yosmanyga) - Wouter de Wild - - Antoine M (amakdessi) - Degory Valentine - izzyp - Benoit Lévêque (benoit_leveque) @@ -835,7 +843,6 @@ Symfony is the result of the work of many people who made the code better - Ben - Vincent Composieux (eko) - Jayson Xu (superjavason) - - Christopher Hertel (chertel) - Hubert Lenoir (hubert_lenoir) - fago - Harm van Tilborg @@ -887,13 +894,11 @@ Symfony is the result of the work of many people who made the code better - Patrick Allaert - Gustavo Falco (gfalco) - Matt Robinson (inanimatt) - - Ruud Kamphuis (ruudk) - Aleksey Podskrebyshev - Calin Mihai Pristavu - David Marín Carreño (davefx) - Fabien LUCAS (flucas2) - Omar Yepez (oyepez003) - - Gawain Lynch (gawain) - mwsaz - Jelle Kapitein - Benoît Bourgeois @@ -917,6 +922,7 @@ Symfony is the result of the work of many people who made the code better - Morgan Auchede (mauchede) - Sascha Dens (saschadens) - Don Pinkster + - Saif Eddin G - Maksim Muruev - Emil Einarsson - Thomas Landauer @@ -937,6 +943,7 @@ Symfony is the result of the work of many people who made the code better - Arno Geurts - Adán Lobato (adanlobato) - Ian Jenkins (jenkoian) + - Marcos Gómez Vilches (markitosgv) - Matthew Davis (mdavis1982) - Maks - Antoine LA @@ -960,7 +967,6 @@ Symfony is the result of the work of many people who made the code better - Benoît Merlet (trompette) - Koen Kuipers - datibbaw - - Rokas Mikalkėnas (rokasm) - Erik Saunier (snickers) - Rootie - Kyle @@ -968,6 +974,7 @@ Symfony is the result of the work of many people who made the code better - sensio - Chris Tanaskoski - Thomas Jarrand + - Antoine Bluchet (soyuka) - Sebastien Morel (plopix) - Patrick Kaufmann - Anton Dyshkant @@ -979,7 +986,9 @@ Symfony is the result of the work of many people who made the code better - d-ph - Renan Taranto (renan-taranto) - Thomas Talbot (ioni) + - Dmitry Simushev - Rikijs Murgs + - Uladzimir Tsykun - Ben Ramsey (ramsey) - Amaury Leroux de Lens (amo__) - Christian Jul Jensen @@ -1004,11 +1013,11 @@ Symfony is the result of the work of many people who made the code better - Sander Marechal - Franz Wilding (killerpoke) - ProgMiner - - Jonas Elfering - Oleg Golovakhin (doc_tr) - Joost van Driel - Icode4Food (icode4food) - Radosław Benkel + - EStyles (insidestyles) - kevin.nadin - jean pasqualini (darkilliant) - Ross Motley (rossmotley) @@ -1035,6 +1044,7 @@ Symfony is the result of the work of many people who made the code better - Ashura - Hryhorii Hrebiniuk - johnstevenson + - Antonio Pauletich (x-coder264) - hamza - dantleech - Bastien DURAND (deamon) @@ -1054,6 +1064,7 @@ Symfony is the result of the work of many people who made the code better - chispita - Wojciech Sznapka - Gavin Staniforth + - Ksaveras Šakys (xawiers) - Ariel J. Birnbaum - Danijel Obradović - Pablo Borowicz @@ -1062,6 +1073,7 @@ Symfony is the result of the work of many people who made the code better - Máximo Cuadros (mcuadros) - Lukas Mencl - tamirvs + - gauss - julien.galenski - Christian Neff - Chris Tiearney @@ -1078,6 +1090,7 @@ Symfony is the result of the work of many people who made the code better - Mert Simsek (mrtsmsk0) - Lin Clark - Jeremy David (jeremy.david) + - Jordi Rejas - Troy McCabe - Ville Mattila - ilyes kooli @@ -1119,6 +1132,7 @@ Symfony is the result of the work of many people who made the code better - hugofonseca (fonsecas72) - Martynas Narbutas - Toon Verwerft (veewee) + - battye - Bailey Parker - Eddie Jaoude - Antanas Arvasevicius @@ -1154,6 +1168,7 @@ Symfony is the result of the work of many people who made the code better - Alexander Cheprasov - Rodrigo Díez Villamuera (rodrigodiez) - James Hudson + - Stephen Clouse - e-ivanov - Einenlum - Jochen Bayer (jocl) @@ -1204,6 +1219,7 @@ Symfony is the result of the work of many people who made the code better - antograssiot - Ilya Vertakov - Brooks Boyd + - johnillo - Roger Webb - Dmitriy Simushev - Pawel Smolinski @@ -1213,6 +1229,7 @@ Symfony is the result of the work of many people who made the code better - Max Voloshin (maxvoloshin) - Nicolas Fabre (nfabre) - Raul Rodriguez (raul782) + - mshavliuk - WybrenKoelmans - Derek Lambert - MightyBranch @@ -1254,6 +1271,7 @@ Symfony is the result of the work of many people who made the code better - Jelte Steijaert (jelte) - Quique Porta (quiqueporta) - stoccc + - Andrea Quintino (dirk39) - Tomasz Szymczyk (karion) - Alex Vasilchenko - sez-open @@ -1272,9 +1290,9 @@ Symfony is the result of the work of many people who made the code better - Lars Ambrosius Wallenborn (larsborn) - Oriol Mangas Abellan (oriolman) - Sebastian Göttschkes (sgoettschkes) + - Toni Peric (tperic) - Tatsuya Tsuruoka - Ross Tuck - - Andreas Erhard - Kévin Gomez (kevin) - Mihai Nica (redecs) - Soufian EZ-ZANTAR (soezz) @@ -1391,6 +1409,7 @@ Symfony is the result of the work of many people who made the code better - Samuel Gordalina (gordalina) - Max Romanovsky (maxromanovsky) - Nicolas Eeckeloo (neeckeloo) + - Andriy Prokopenko (sleepyboy) - Mathieu Morlon - Daniel Tschinder - Arnaud CHASSEUX @@ -1407,6 +1426,7 @@ Symfony is the result of the work of many people who made the code better - Jon Gotlin (jongotlin) - Michael Dowling (mtdowling) - Karlos Presumido (oneko) + - Tony Vermeiren (tony) - Thomas Counsell - BilgeXA - r1pp3rj4ck @@ -1494,6 +1514,7 @@ Symfony is the result of the work of many people who made the code better - Gavin Staniforth - Alessandro Tagliapietra (alex88) - Biji (biji) + - Jérôme Tanghe (deuchnord) - Alex Teterin (errogaht) - Gunnar Lium (gunnarlium) - Tiago Garcia (tiagojsag) @@ -1504,7 +1525,6 @@ Symfony is the result of the work of many people who made the code better - Enrico Schultz - Evert Harmeling - mschop - - Alan Poulain - Martin Eckhardt - natechicago - Sergei Gorjunov @@ -1519,6 +1539,7 @@ Symfony is the result of the work of many people who made the code better - Francisco Facioni (fran6co) - Iwan van Staveren (istaveren) - Povilas S. (povilas) + - Laurent Negre (raulnet) - Evrard Boulou - pborreli - Boris Betzholz @@ -1636,6 +1657,7 @@ Symfony is the result of the work of many people who made the code better - michalmarcinkowski - Warwick - Chris + - Farid Jalilov - Florent Olivaud - JakeFr - Simon Sargeant @@ -1716,6 +1738,7 @@ Symfony is the result of the work of many people who made the code better - Dmitriy Fedorenko - vlakoff - bertillon + - thib92 - Rudolf Ratusiński - Bertalan Attila - AmsTaFF (amstaff) @@ -1805,6 +1828,7 @@ Symfony is the result of the work of many people who made the code better - Gabriel Birke - skafandri - Derek Bonner + - martijn - Alan Chen - insidestyles - Maerlyn @@ -1882,6 +1906,7 @@ Symfony is the result of the work of many people who made the code better - Yorkie Chadwick (yorkie76) - GuillaumeVerdon - Philipp Keck + - Angel Fernando Quiroz Campos - Ondrej Mirtes - akimsko - Youpie @@ -1968,6 +1993,7 @@ Symfony is the result of the work of many people who made the code better - patrick-mcdougle - Dariusz Czech - Jack Wright + - MrNicodemuz - Anonymous User - Paweł Tomulik - Eric J. Duran @@ -1993,6 +2019,7 @@ Symfony is the result of the work of many people who made the code better - Tammy D - Daniel STANCU - Ryan Rud + - mmokhi - Ondrej Slinták - vlechemin - Brian Corrigan @@ -2002,6 +2029,7 @@ Symfony is the result of the work of many people who made the code better - fmarchalemisys - mieszko4 - Steve Preston + - Wojciech Skorodecki - Kevin Frantz - Neophy7e - bokonet @@ -2023,6 +2051,7 @@ Symfony is the result of the work of many people who made the code better - Ondřej Führer - Sema - Elan Ruusamäe + - Jon Dufresne - Thorsten Hallwas - Michael Squires - Egor Gorbachev @@ -2068,7 +2097,6 @@ Symfony is the result of the work of many people who made the code better - phc - Дмитрий Пацура - ilyes kooli - - Matthias Althaus - Michaël VEROUX - Julia - Lin Lu @@ -2129,7 +2157,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) + - Mehdi Achour (machour) - Matthieu Mota (matthieumota) - Matthieu Moquet (mattketmo) - Moritz Borgmann (mborgmann) @@ -2211,6 +2239,7 @@ Symfony is the result of the work of many people who made the code better - Mohamed Karnichi (amiral) - Andrew Carter (andrewcarteruk) - Adam Elsodaney (archfizz) + - Pablo Lozano (arkadis) - Gregório Bonfante Borba (bonfante) - Bogdan Rancichi (devck) - Daniel Kolvik (dkvk) diff --git a/composer.json b/composer.json index b1fde067a7c1c..71c597d122df6 100644 --- a/composer.json +++ b/composer.json @@ -22,13 +22,13 @@ "doctrine/event-manager": "~1.0", "doctrine/persistence": "~1.0", "fig/link-util": "^1.0", - "twig/twig": "^1.40|^2.9", + "twig/twig": "^1.41|^2.10", "psr/cache": "~1.0", "psr/container": "^1.0", "psr/link": "^1.0", "psr/log": "~1.0", "psr/simple-cache": "^1.0", - "symfony/contracts": "^1.0.2", + "symfony/contracts": "^1.1.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "~1.0", "symfony/polyfill-mbstring": "~1.0", @@ -115,9 +115,9 @@ "psr/container-implementation": "1.0", "psr/log-implementation": "1.0", "psr/simple-cache-implementation": "1.0", - "symfony/cache-contracts": "1.0", - "symfony/service-contracts": "1.0", - "symfony/translation-contracts": "1.0" + "symfony/cache-implementation": "1.0", + "symfony/service-implementation": "1.0", + "symfony/translation-implementation": "1.0" }, "autoload": { "psr-4": { diff --git a/link b/link index b70c06dda7770..2b76a466c3248 100755 --- a/link +++ b/link @@ -23,14 +23,12 @@ use Symfony\Component\Filesystem\Filesystem; * @author Kévin Dunglas */ -if (2 !== $argc) { - echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL; - echo "Usage: $argv[0] /path/to/the/project".PHP_EOL; - exit(1); -} +$pathToProject = $argv[1] ?? getcwd(); -if (!is_dir("$argv[1]/vendor/symfony")) { - echo "The directory \"$argv[1]\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL; +if (!is_dir("$pathToProject/vendor/symfony")) { + echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL; + echo "Usage: $argv[0] /path/to/the/project".PHP_EOL.PHP_EOL; + echo "The directory \"$pathToProject\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL; exit(1); } @@ -50,7 +48,7 @@ foreach ($directories as $dir) { } } -foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { +foreach (glob("$pathToProject/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { $package = 'symfony/'.basename($dir); if (is_link($dir)) { echo "\"$package\" is already a symlink, skipping.".PHP_EOL; @@ -68,6 +66,6 @@ foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL; } -foreach (glob("$argv[1]/var/cache/*") as $cacheDir) { +foreach (glob("$pathToProject/var/cache/*") as $cacheDir) { $filesystem->remove($cacheDir); } diff --git a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php index 66b99ecf62065..4496d3ac9a3d9 100644 --- a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php +++ b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php @@ -37,51 +37,49 @@ public function __construct(ContainerInterface $container) } /** - * Dispatches an event to all registered listeners. - * - * @param string $eventName The name of the event to dispatch. The name of the event is - * the name of the method that is invoked on listeners. - * @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners. - * If not supplied, the single empty EventArgs instance is used. - * - * @return bool + * {@inheritdoc} */ public function dispatchEvent($eventName, EventArgs $eventArgs = null) { - if (isset($this->listeners[$eventName])) { - $eventArgs = null === $eventArgs ? EventArgs::getEmptyInstance() : $eventArgs; + if (!isset($this->listeners[$eventName])) { + return; + } - $initialized = isset($this->initialized[$eventName]); + $eventArgs = null === $eventArgs ? EventArgs::getEmptyInstance() : $eventArgs; - foreach ($this->listeners[$eventName] as $hash => $listener) { - if (!$initialized && \is_string($listener)) { - $this->listeners[$eventName][$hash] = $listener = $this->container->get($listener); - } + if (!isset($this->initialized[$eventName])) { + $this->initializeListeners($eventName); + } - $listener->$eventName($eventArgs); - } - $this->initialized[$eventName] = true; + foreach ($this->listeners[$eventName] as $hash => $listener) { + $listener->$eventName($eventArgs); } } /** - * Gets the listeners of a specific event or all listeners. - * - * @param string $event The name of the event - * - * @return array The event listeners for the specified event, or all event listeners + * {@inheritdoc} */ public function getListeners($event = null) { - return $event ? $this->listeners[$event] : $this->listeners; + if (null !== $event) { + if (!isset($this->initialized[$event])) { + $this->initializeListeners($event); + } + + return $this->listeners[$event]; + } + + foreach ($this->listeners as $event => $listeners) { + if (!isset($this->initialized[$event])) { + $this->initializeListeners($event); + } + } + + return $this->listeners; } /** - * Checks whether an event has any registered listeners. - * - * @param string $event - * - * @return bool TRUE if the specified event has any listeners, FALSE otherwise + * {@inheritdoc} */ public function hasListeners($event) { @@ -89,20 +87,11 @@ public function hasListeners($event) } /** - * Adds an event listener that listens on the specified events. - * - * @param string|array $events The event(s) to listen on - * @param object|string $listener The listener object - * - * @throws \RuntimeException + * {@inheritdoc} */ public function addEventListener($events, $listener) { if (\is_string($listener)) { - if ($this->initialized) { - throw new \RuntimeException('Adding lazy-loading listeners after construction is not supported.'); - } - $hash = '_service_'.$listener; } else { // Picks the hash code related to that listener @@ -113,14 +102,15 @@ public function addEventListener($events, $listener) // Overrides listener if a previous one was associated already // Prevents duplicate listeners on same event (same instance only) $this->listeners[$event][$hash] = $listener; + + if (\is_string($listener)) { + unset($this->initialized[$event]); + } } } /** - * Removes an event listener from the specified events. - * - * @param string|array $events - * @param object|string $listener + * {@inheritdoc} */ public function removeEventListener($events, $listener) { @@ -138,4 +128,17 @@ public function removeEventListener($events, $listener) } } } + + /** + * @param string $eventName + */ + private function initializeListeners($eventName) + { + foreach ($this->listeners[$eventName] as $hash => $listener) { + if (\is_string($listener)) { + $this->listeners[$eventName][$hash] = $this->container->get($listener); + } + } + $this->initialized[$eventName] = true; + } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php index 2e97edb1d2e14..b3fb8bc3ac94e 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php @@ -28,8 +28,8 @@ protected function setUp() public function testDispatchEvent() { - $this->container->set('foobar', $listener1 = new MyListener()); - $this->evm->addEventListener('foo', 'foobar'); + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); $this->evm->addEventListener('foo', $listener2 = new MyListener()); $this->evm->dispatchEvent('foo'); @@ -38,19 +38,69 @@ public function testDispatchEvent() $this->assertTrue($listener2->called); } + public function testAddEventListenerAfterDispatchEvent() + { + $this->container->set('lazy1', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy1'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); + + $this->evm->dispatchEvent('foo'); + + $this->container->set('lazy2', $listener3 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy2'); + $this->evm->addEventListener('foo', $listener4 = new MyListener()); + + $this->evm->dispatchEvent('foo'); + + $this->assertTrue($listener1->called); + $this->assertTrue($listener2->called); + $this->assertTrue($listener3->called); + $this->assertTrue($listener4->called); + } + + public function testGetListenersForEvent() + { + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); + + $this->assertSame([$listener1, $listener2], array_values($this->evm->getListeners('foo'))); + } + + public function testGetListeners() + { + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); + + $this->assertSame([$listener1, $listener2], array_values($this->evm->getListeners()['foo'])); + } + public function testRemoveEventListener() { - $this->evm->addEventListener('foo', 'bar'); - $this->evm->addEventListener('foo', $listener = new MyListener()); + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); + + $this->evm->removeEventListener('foo', $listener2); + $this->assertSame([$listener1], array_values($this->evm->getListeners('foo'))); - $listeners = ['foo' => ['_service_bar' => 'bar', spl_object_hash($listener) => $listener]]; - $this->assertSame($listeners, $this->evm->getListeners()); - $this->assertSame($listeners['foo'], $this->evm->getListeners('foo')); + $this->evm->removeEventListener('foo', 'lazy'); + $this->assertSame([], $this->evm->getListeners('foo')); + } + + public function testRemoveEventListenerAfterDispatchEvent() + { + $this->container->set('lazy', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); + $this->evm->addEventListener('foo', $listener2 = new MyListener()); + + $this->evm->dispatchEvent('foo'); - $this->evm->removeEventListener('foo', $listener); - $this->assertSame(['_service_bar' => 'bar'], $this->evm->getListeners('foo')); + $this->evm->removeEventListener('foo', $listener2); + $this->assertSame([$listener1], array_values($this->evm->getListeners('foo'))); - $this->evm->removeEventListener('foo', 'bar'); + $this->evm->removeEventListener('foo', 'lazy'); $this->assertSame([], $this->evm->getListeners('foo')); } } diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php index 984e2e2a1b598..097014c98e6ae 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface; /** * Tests for {@see \Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper}. @@ -182,6 +183,7 @@ public function getProxyCandidates() $definitions = [ [new Definition(__CLASS__), true], [new Definition('stdClass'), true], + [new Definition(DumperInterface::class), true], [new Definition(uniqid('foo', true)), false], [new Definition(), false], ]; diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 6d96cbd221943..a32a19cf0557f 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -399,7 +399,7 @@ {# Support #} {%- block form_rows -%} - {% for child in form if not child.rendered %} + {% for child in form|filter(child => not child.rendered) %} {{- form_row(child) -}} {% endfor %} {%- endblock form_rows -%} diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 9674f21031509..345dc26e47037 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^7.1.3", "symfony/contracts": "^1.0.2", - "twig/twig": "^1.40|^2.9" + "twig/twig": "^1.41|^2.10" }, "require-dev": { "symfony/asset": "~3.4|~4.0", diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index 9debddcad771b..15b054a76052a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -145,6 +145,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $options['show_hidden'] = $input->getOption('show-hidden'); $options['raw_text'] = $input->getOption('raw'); $options['output'] = $io; + $options['is_debug'] = $this->getApplication()->getKernel()->isDebug(); try { $helper->describe($io, $object, $options); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 0739202166196..8fdbacdd9117c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; @@ -333,7 +334,11 @@ protected function describeContainerDefinition(Definition $definition, array $op if ($argument instanceof Reference) { $argumentsInformation[] = sprintf('Service(%s)', (string) $argument); } elseif ($argument instanceof IteratorArgument) { - $argumentsInformation[] = sprintf('Iterator (%d element(s))', \count($argument->getValues())); + if ($argument instanceof TaggedIteratorArgument) { + $argumentsInformation[] = sprintf('Tagged Iterator for "%s"%s', $argument->getTag(), $options['is_debug'] ? '' : sprintf(' (%d element(s))', \count($argument->getValues()))); + } else { + $argumentsInformation[] = sprintf('Iterator (%d element(s))', \count($argument->getValues())); + } } elseif ($argument instanceof ServiceLocatorArgument) { $argumentsInformation[] = sprintf('Service locator (%d element(s))', \count($argument->getValues())); } elseif ($argument instanceof Definition) { diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index cee4b1d2883fa..755566f45bdfa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1671,7 +1671,7 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con } if ($pool['tags']) { - if ($config['pools'][$pool['tags']]['tags'] ?? false) { + if (true !== $pool['tags'] && ($config['pools'][$pool['tags']]['tags'] ?? false)) { $pool['tags'] = '.'.$pool['tags'].'.inner'; } $container->register($name, TagAwareAdapter::class) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml index df4e209f6e775..cbbed8fc9bf1d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml @@ -95,7 +95,7 @@ - + %serializer.mapping.cache.file% diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php index 33b0cb6375845..83792e28da8fd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php @@ -217,6 +217,7 @@ abstract protected function getFormat(); private function assertDescription($expectedDescription, $describedObject, array $options = []) { + $options['is_debug'] = false; $options['raw_output'] = true; $options['raw_text'] = true; $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true); diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json index 4e163c2eedec4..d9db82a45c117 100644 --- a/src/Symfony/Bundle/TwigBundle/composer.json +++ b/src/Symfony/Bundle/TwigBundle/composer.json @@ -22,7 +22,7 @@ "symfony/http-foundation": "~4.1", "symfony/http-kernel": "~4.1", "symfony/polyfill-ctype": "~1.8", - "twig/twig": "~1.40|~2.9" + "twig/twig": "~1.41|~2.10" }, "require-dev": { "symfony/asset": "~3.4|~4.0", diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php index 35cf31fbf99e9..224c7a87a3f53 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php @@ -146,7 +146,7 @@ public function toolbarAction(Request $request, $token) $url = null; try { - $url = $this->generator->generate('_profiler', ['token' => $token]); + $url = $this->generator->generate('_profiler', ['token' => $token], UrlGeneratorInterface::ABSOLUTE_URL); } catch (\Exception $e) { // the profiler is not enabled } @@ -282,7 +282,7 @@ public function searchAction(Request $request) $this->profiler->disable(); - $ip = preg_replace('/[^:\d\.]/', '', $request->query->get('ip')); + $ip = $request->query->get('ip'); $method = $request->query->get('method'); $statusCode = $request->query->get('status_code'); $url = $request->query->get('url'); diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig index 923049aebc43c..03ad94f92429c 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig @@ -259,7 +259,7 @@

Defined as regular env variables

{% set requestserver = [] %} - {% for key, value in collector.requestserver if key not in collector.dotenvvars.keys %} + {% for key, value in collector.requestserver|filter((_, key) => key not in collector.dotenvvars.keys) %} {% set requestserver = requestserver|merge({(key): value}) %} {% endfor %} {{ include('@WebProfiler/Profiler/table.html.twig', { data: requestserver }, with_context = false) }} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_item.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_item.html.twig index 69872418cfb21..d81e877977667 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_item.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_item.html.twig @@ -1,5 +1,5 @@
- {% if link is not defined or link %}{% endif %} + {% if link is not defined or link %}{% endif %}
{{ icon|default('') }}
{% if link|default(false) %}
{% endif %}
{{ text|default('') }}
diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index c43de7eef3dc2..7cba80a6c5c66 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -22,7 +22,7 @@ "symfony/routing": "~3.4|~4.0", "symfony/twig-bundle": "~4.2", "symfony/var-dumper": "~3.4|~4.0", - "twig/twig": "~1.34|~2.4" + "twig/twig": "^1.41|^2.10" }, "require-dev": { "symfony/console": "~3.4|~4.0", diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index 0eceb6e572b39..498c00ca643a4 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -59,6 +59,26 @@ public function testGet() $this->assertFalse($isHit); } + public function testRecursiveGet() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $cache = $this->createCachePool(0, __FUNCTION__); + + $v = $cache->get('k1', function () use (&$counter, $cache) { + $v = $cache->get('k2', function () use (&$counter) { return ++$counter; }); + $v = $cache->get('k2', function () use (&$counter) { return ++$counter; }); + + return $v; + }); + + $this->assertSame(1, $counter); + $this->assertSame(1, $v); + $this->assertSame(1, $cache->get('k2', function () { return 2; })); + } + public function testGetMetadata() { if (isset($this->skippedTests[__FUNCTION__])) { diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php index cee80ac196ec0..3a5904b10710d 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php @@ -23,6 +23,7 @@ class PhpArrayAdapterTest extends AdapterTestCase { protected $skippedTests = [ 'testGet' => 'PhpArrayAdapter is read-only.', + 'testRecursiveGet' => 'PhpArrayAdapter is read-only.', 'testBasicUsage' => 'PhpArrayAdapter is read-only.', 'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.', 'testClear' => 'PhpArrayAdapter is read-only.', diff --git a/src/Symfony/Component/Cache/Traits/ContractsTrait.php b/src/Symfony/Component/Cache/Traits/ContractsTrait.php index bd7be08dd5e8e..6d602dfece664 100644 --- a/src/Symfony/Component/Cache/Traits/ContractsTrait.php +++ b/src/Symfony/Component/Cache/Traits/ContractsTrait.php @@ -31,6 +31,7 @@ trait ContractsTrait } private $callbackWrapper = [LockRegistry::class, 'compute']; + private $computing = []; /** * Wraps the callback passed to ->get() in a callable. @@ -68,26 +69,27 @@ function (CacheItem $item, float $startTime, ?array &$metadata) { CacheItem::class ); - return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata) { + return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) { // don't wrap nor save recursive calls - if (null === $callbackWrapper = $this->callbackWrapper) { + if (isset($this->computing[$key])) { $value = $callback($item, $save); $save = false; return $value; } - $this->callbackWrapper = null; + + $this->computing[$key] = $key; $startTime = microtime(true); try { - $value = $callbackWrapper($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { + $value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { $setMetadata($item, $startTime, $metadata); }); $setMetadata($item, $startTime, $metadata); return $value; } finally { - $this->callbackWrapper = $callbackWrapper; + unset($this->computing[$key]); } }, $beta, $metadata); } diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index 8f9e669a33222..eb1110c0aa946 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -18,7 +18,7 @@ "provide": { "psr/cache-implementation": "1.0", "psr/simple-cache-implementation": "1.0", - "symfony/cache-contracts-implementation": "1.0" + "symfony/cache-implementation": "1.0" }, "require": { "php": "^7.1.3", diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index a7e73becf55f4..3890dd29eddd8 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\ServiceSubscriberInterface as LegacyServiceSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; /** @@ -164,6 +165,13 @@ private function generateSignature(\ReflectionClass $class) yield print_r($class->name::getSubscribedEvents(), true); } + if (interface_exists(MessageSubscriberInterface::class, false) && $class->isSubclassOf(MessageSubscriberInterface::class)) { + yield MessageSubscriberInterface::class; + foreach ($class->name::getHandledMessages() as $key => $value) { + yield $key.print_r($value, true); + } + } + if (interface_exists(LegacyServiceSubscriberInterface::class, false) && $class->isSubclassOf(LegacyServiceSubscriberInterface::class)) { yield LegacyServiceSubscriberInterface::class; yield print_r([$class->name, 'getSubscribedServices'](), true); diff --git a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php index abc461cd7c898..e22933245d252 100644 --- a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Config\Resource\ReflectionClassResource; use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; class ReflectionClassResourceTest extends TestCase { @@ -147,6 +148,24 @@ public function testEventSubscriber() $this->assertTrue($res->isFresh(0)); } + public function testMessageSubscriber() + { + $res = new ReflectionClassResource(new \ReflectionClass(TestMessageSubscriber::class)); + $this->assertTrue($res->isFresh(0)); + + TestMessageSubscriberConfigHolder::$handledMessages = ['SomeMessageClass' => []]; + $this->assertFalse($res->isFresh(0)); + + $res = new ReflectionClassResource(new \ReflectionClass(TestMessageSubscriber::class)); + $this->assertTrue($res->isFresh(0)); + + TestMessageSubscriberConfigHolder::$handledMessages = ['OtherMessageClass' => []]; + $this->assertFalse($res->isFresh(0)); + + $res = new ReflectionClassResource(new \ReflectionClass(TestMessageSubscriber::class)); + $this->assertTrue($res->isFresh(0)); + } + public function testServiceSubscriber() { $res = new ReflectionClassResource(new \ReflectionClass(TestServiceSubscriber::class)); @@ -174,6 +193,20 @@ public static function getSubscribedEvents() } } +class TestMessageSubscriber implements MessageSubscriberInterface +{ + public static function getHandledMessages(): iterable + { + foreach (TestMessageSubscriberConfigHolder::$handledMessages as $key => $subscribedMessage) { + yield $key => $subscribedMessage; + } + } +} +class TestMessageSubscriberConfigHolder +{ + public static $handledMessages = []; +} + class TestServiceSubscriber implements ServiceSubscriberInterface { public static $subscribedServices = []; diff --git a/src/Symfony/Component/Config/composer.json b/src/Symfony/Component/Config/composer.json index 35fbffdb69a41..00a88e81b5c50 100644 --- a/src/Symfony/Component/Config/composer.json +++ b/src/Symfony/Component/Config/composer.json @@ -24,6 +24,7 @@ "symfony/dependency-injection": "~3.4|~4.0", "symfony/event-dispatcher": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", + "symfony/messenger": "~4.1", "symfony/yaml": "~3.4|~4.0" }, "conflict": { diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 17df91f994483..7522cef8f2fe6 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -610,6 +610,15 @@ public function find($name) $this->init(); $aliases = []; + + foreach ($this->commands as $command) { + foreach ($command->getAliases() as $alias) { + if (!$this->has($alias)) { + $this->commands[$alias] = $command; + } + } + } + $allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands); $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name); $commands = preg_grep('{^'.$expr.'}', $allCommands); diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index b8b76833a6f3f..4c8c8e166cfb0 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -200,6 +200,7 @@ protected function writeError(OutputInterface $output, \Exception $error) */ private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete): string { + $fullChoice = ''; $ret = ''; $i = 0; @@ -226,6 +227,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu } elseif ("\177" === $c) { // Backspace Character if (0 === $numMatches && 0 !== $i) { --$i; + $fullChoice = substr($fullChoice, 0, -1); // Move cursor backwards $output->write("\033[1D"); } @@ -262,8 +264,10 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu if ($numMatches > 0 && -1 !== $ofs) { $ret = $matches[$ofs]; // Echo out remaining chars for current match - $output->write(substr($ret, $i)); - $i = \strlen($ret); + $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)))); + $output->write($remainingCharacters); + $fullChoice .= $remainingCharacters; + $i = \strlen($fullChoice); } if ("\n" === $c) { @@ -282,14 +286,21 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu $output->write($c); $ret .= $c; + $fullChoice .= $c; ++$i; + $tempRet = $ret; + + if ($question instanceof ChoiceQuestion && $question->isMultiselect()) { + $tempRet = $this->mostRecentlyEnteredValue($fullChoice); + } + $numMatches = 0; $ofs = 0; foreach ($autocomplete as $value) { // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) - if (0 === strpos($value, $ret)) { + if (0 === strpos($value, $tempRet)) { $matches[$numMatches++] = $value; } } @@ -301,8 +312,9 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu if ($numMatches > 0 && -1 !== $ofs) { // Save cursor position $output->write("\0337"); - // Write highlighted text - $output->write(''.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $i)).''); + // Write highlighted text, complete the partially entered response + $charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))); + $output->write(''.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).''); // Restore cursor position $output->write("\0338"); } @@ -311,7 +323,22 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu // Reset stty so it behaves normally again shell_exec(sprintf('stty %s', $sttyMode)); - return $ret; + return $fullChoice; + } + + private function mostRecentlyEnteredValue($entered) + { + // Determine the most recent value that the user entered + if (false === strpos($entered, ',')) { + return $entered; + } + + $choices = explode(',', $entered); + if (\strlen($lastChoice = trim($choices[\count($choices) - 1])) > 0) { + return $lastChoice; + } + + return $entered; } /** diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index efbe2a81fdbcc..0533bb42e7e79 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -73,8 +73,8 @@ public static function setUpBeforeClass() require_once self::$fixturesPath.'/FooSubnamespaced1Command.php'; require_once self::$fixturesPath.'/FooSubnamespaced2Command.php'; require_once self::$fixturesPath.'/FooWithoutAliasCommand.php'; - require_once self::$fixturesPath.'/TestTiti.php'; - require_once self::$fixturesPath.'/TestToto.php'; + require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering.php'; + require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering2.php'; } protected function normalizeLineBreaks($text) @@ -165,6 +165,28 @@ public function testRegister() $this->assertEquals('foo', $command->getName(), '->register() registers a new command'); } + public function testRegisterAmbiguous() + { + $code = function (InputInterface $input, OutputInterface $output) { + $output->writeln('It works!'); + }; + + $application = new Application(); + $application->setAutoExit(false); + $application + ->register('test-foo') + ->setAliases(['test']) + ->setCode($code); + + $application + ->register('test-bar') + ->setCode($code); + + $tester = new ApplicationTester($application); + $tester->run(['test']); + $this->assertContains('It works!', $tester->getDisplay(true)); + } + public function testAdd() { $application = new Application(); @@ -304,9 +326,9 @@ public function testFindAmbiguousNamespace() public function testFindNonAmbiguous() { $application = new Application(); - $application->add(new \TestTiti()); - $application->add(new \TestToto()); - $this->assertEquals('test-toto', $application->find('test')->getName()); + $application->add(new \TestAmbiguousCommandRegistering()); + $application->add(new \TestAmbiguousCommandRegistering2()); + $this->assertEquals('test-ambiguous', $application->find('test')->getName()); } /** diff --git a/src/Symfony/Component/Console/Tests/Fixtures/TestToto.php b/src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering.php similarity index 65% rename from src/Symfony/Component/Console/Tests/Fixtures/TestToto.php rename to src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering.php index 2e6a8195938bb..bece09fcdde82 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/TestToto.php +++ b/src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering.php @@ -4,19 +4,19 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -class TestToto extends Command +class TestAmbiguousCommandRegistering extends Command { protected function configure() { $this - ->setName('test-toto') - ->setDescription('The test-toto command') + ->setName('test-ambiguous') + ->setDescription('The test-ambiguous command') ->setAliases(['test']) ; } protected function execute(InputInterface $input, OutputInterface $output) { - $output->write('test-toto'); + $output->write('test-ambiguous'); } } diff --git a/src/Symfony/Component/Console/Tests/Fixtures/TestTiti.php b/src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering2.php similarity index 62% rename from src/Symfony/Component/Console/Tests/Fixtures/TestTiti.php rename to src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering2.php index 72e29d2a0a2dc..9dde48624546d 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/TestTiti.php +++ b/src/Symfony/Component/Console/Tests/Fixtures/TestAmbiguousCommandRegistering2.php @@ -4,18 +4,18 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -class TestTiti extends Command +class TestAmbiguousCommandRegistering2 extends Command { protected function configure() { $this - ->setName('test-titi') - ->setDescription('The test:titi command') + ->setName('test-ambiguous2') + ->setDescription('The test-ambiguous2 command') ; } protected function execute(InputInterface $input, OutputInterface $output) { - $output->write('test-titi'); + $output->write('test-ambiguous2'); } } diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index 69d5470b8c20c..2acbad4785212 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -667,6 +667,37 @@ public function testTraversableAutocomplete() $this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); } + public function testTraversableMultiselectAutocomplete() + { + // + // F + // A<3x UP ARROW>,F + // F00o,A,SecurityBundle + // Acme,As<29x BACKSPACE>S + // Ac,As<3x BACKSPACE>d + $inputStream = $this->getInputStream("\nF\t\nA\033[A\033[A\033[A\t,F\t\nF00\177\177o\t,A\033[B\t, SecurityBundle\nAcme\t, As\t\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177S\t\nAc\t,As\t\177\177\177d\t\n"); + + $dialog = new QuestionHelper(); + $helperSet = new HelperSet([new FormatterHelper()]); + $dialog->setHelperSet($helperSet); + + $question = new ChoiceQuestion( + 'Please select a bundle (defaults to AcmeDemoBundle and AsseticBundle)', + ['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle'], + '0,1' + ); + + // This tests that autocomplete works for all multiselect choices entered by the user + $question->setMultiselect(true); + + $this->assertEquals(['AcmeDemoBundle', 'AsseticBundle'], $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); + $this->assertEquals(['FooBundle'], $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); + $this->assertEquals(['AsseticBundle', 'FooBundle'], $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); + $this->assertEquals(['FooBundle', 'AsseticBundle', 'SecurityBundle'], $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); + $this->assertEquals(['SecurityBundle'], $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); + $this->assertEquals(['AcmeDemoBundle', 'AsseticBundle'], $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); + } + protected function getInputStream($input) { $stream = fopen('php://memory', 'r+', false); diff --git a/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php b/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php index 30c5665e6009e..a0e2f770f0015 100644 --- a/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php +++ b/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php @@ -171,7 +171,11 @@ private function convertFileToClass(string $path, string $file, string $prefix): } } - require_once $file; + try { + require_once $file; + } catch (\Throwable $e) { + return null; + } foreach ($candidates as $candidate) { if ($this->classExists($candidate)) { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php index e335307482aec..c670b27b9399a 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php @@ -101,7 +101,11 @@ public static function register(ContainerBuilder $container, array $refMap, $cal ->setPublic(false) ->addTag('container.service_locator'); - if (!$container->has($id = '.service_locator.'.ContainerBuilder::hash($locator))) { + if (null !== $callerId && $container->hasDefinition($callerId)) { + $locator->setBindings($container->getDefinition($callerId)->getBindings()); + } + + if (!$container->hasDefinition($id = '.service_locator.'.ContainerBuilder::hash($locator))) { $container->setDefinition($id, $locator); } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index ba704d5d9ef60..467171eda2442 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -690,7 +690,7 @@ protected function {$methodName}($lazyInitialization) $code .= $this->addServiceInclude($id, $definition); if ($this->getProxyDumper()->isProxyCandidate($definition)) { - $factoryCode = $asFile ? ($definition->isShared() ? "\$this->load('%s.php', false)" : "\$this->factories[%2\$s](false)") : '$this->%s(false)'; + $factoryCode = $asFile ? ($definition->isShared() ? "\$this->load('%s.php', false)" : '$this->factories[%2$s](false)') : '$this->%s(false)'; $code .= $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName, $this->doExport($id))); } @@ -1386,14 +1386,14 @@ private function getServiceConditionals($value): string if (!$this->container->hasDefinition($service)) { return 'false'; } - $conditions[] = sprintf("isset(\$this->%s[%s])", $this->container->getDefinition($service)->isPublic() ? 'services' : 'privates', $this->doExport($service)); + $conditions[] = sprintf('isset($this->%s[%s])', $this->container->getDefinition($service)->isPublic() ? 'services' : 'privates', $this->doExport($service)); } foreach (ContainerBuilder::getServiceConditionals($value) as $service) { if ($this->container->hasDefinition($service) && !$this->container->getDefinition($service)->isPublic()) { continue; } - $conditions[] = sprintf("\$this->has(%s)", $this->doExport($service)); + $conditions[] = sprintf('$this->has(%s)', $this->doExport($service)); } if (!$conditions) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php index d7e5586e0ab06..27ee7db533f6d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; @@ -128,4 +129,19 @@ public function testInheritedKeyOverwritesPreviousServiceWithKey() $this->assertSame(TestDefinition1::class, \get_class($locator('bar'))); } + + public function testBindingsAreCopied() + { + $container = new ContainerBuilder(); + + $container->register('foo') + ->setBindings(['foo' => 'foo']); + + $locator = ServiceLocatorTagPass::register($container, ['foo' => new Reference('foo')], 'foo'); + $locator = $container->getDefinition($locator); + $locator = $container->getDefinition($locator->getFactory()[0]); + + $this->assertSame(['foo'], array_keys($locator->getBindings())); + $this->assertInstanceOf(BoundArgument::class, $locator->getBindings()['foo']); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 358384b4dea34..8fa53c4d1f834 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -262,7 +262,7 @@ public function testAddServiceIdWithUnsupportedCharacters() $class = 'Symfony_DI_PhpDumper_Test_Unsupported_Characters'; $container = new ContainerBuilder(); $container->setParameter("'", 'oh-no'); - $container->register("foo*/oh-no", 'FooClass')->setPublic(true); + $container->register('foo*/oh-no', 'FooClass')->setPublic(true); $container->register('bar$', 'FooClass')->setPublic(true); $container->register('bar$!', 'FooClass')->setPublic(true); $container->compile(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php b/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php index 9c0962880fc92..8d55936712f3c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php @@ -14,7 +14,7 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Contracts\Service\ServiceSubscriberInterface; -use Symfony\Contracts\Tests\Service\ServiceLocatorTest as BaseServiceLocatorTest; +use Symfony\Contracts\Service\Test\ServiceLocatorTest as BaseServiceLocatorTest; class ServiceLocatorTest extends BaseServiceLocatorTest { diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json index 32f52797e4345..0195421c1fd14 100644 --- a/src/Symfony/Component/DependencyInjection/composer.json +++ b/src/Symfony/Component/DependencyInjection/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^7.1.3", "psr/container": "^1.0", - "symfony/contracts": "^1.0" + "symfony/contracts": "^1.1.1" }, "require-dev": { "symfony/yaml": "~3.4|~4.0", @@ -40,7 +40,7 @@ }, "provide": { "psr/container-implementation": "1.0", - "symfony/service-contracts-implementation": "1.0" + "symfony/service-implementation": "1.0" }, "autoload": { "psr-4": { "Symfony\\Component\\DependencyInjection\\": "" }, diff --git a/src/Symfony/Component/Finder/Iterator/SortableIterator.php b/src/Symfony/Component/Finder/Iterator/SortableIterator.php index f95341f3552fa..eda093fa2ce22 100644 --- a/src/Symfony/Component/Finder/Iterator/SortableIterator.php +++ b/src/Symfony/Component/Finder/Iterator/SortableIterator.php @@ -42,7 +42,7 @@ public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = if (self::SORT_BY_NAME === $sort) { $this->sort = function ($a, $b) use ($order) { - return $order * strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname()); + return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); }; } elseif (self::SORT_BY_NAME_NATURAL === $sort) { $this->sort = function ($a, $b) use ($order) { @@ -56,7 +56,7 @@ public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = return $order; } - return $order * strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname()); + return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); }; } elseif (self::SORT_BY_ACCESSED_TIME === $sort) { $this->sort = function ($a, $b) use ($order) { diff --git a/src/Symfony/Component/Form/FormInterface.php b/src/Symfony/Component/Form/FormInterface.php index 5ed0376ed6008..b73927f3bcaaf 100644 --- a/src/Symfony/Component/Form/FormInterface.php +++ b/src/Symfony/Component/Form/FormInterface.php @@ -113,11 +113,11 @@ public function getErrors($deep = false, $flatten = true); * @return $this * * @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\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. + * @throws Exception\TransformationFailedException if the synchronization failed */ public function setData($modelData); diff --git a/src/Symfony/Component/Form/Resources/translations/validators.be.xlf b/src/Symfony/Component/Form/Resources/translations/validators.be.xlf new file mode 100644 index 0000000000000..004ba594b3875 --- /dev/null +++ b/src/Symfony/Component/Form/Resources/translations/validators.be.xlf @@ -0,0 +1,19 @@ + + + + + + This form should not contain extra fields. + Гэта форма не павінна мець дадатковых палей. + + + The uploaded file was too large. Please try to upload a smaller file. + Запампаваны файл быў занадта вялікім. Калі ласка, паспрабуйце запампаваць файл меншага памеру. + + + The CSRF token is invalid. Please try to resubmit the form. + CSRF-токен не сапраўдны. Калі ласка, паспрабуйце яшчэ раз адправіць форму. + + + + diff --git a/src/Symfony/Component/Form/Resources/translations/validators.da.xlf b/src/Symfony/Component/Form/Resources/translations/validators.da.xlf index f52f4e0a30db9..346e7cf5746fd 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.da.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.da.xlf @@ -14,6 +14,122 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF-token er ugyldig. + + This value is not a valid currency. + Denne værdi er ikke en gyldig valuta. + + + This value should be equal to {{ compared_value }}. + Denne værdi skal være lig med {{ compared_value }}. + + + This value should be greater than {{ compared_value }}. + Denne værdi skal være større end {{ compared_value }}. + + + This value should be greater than or equal to {{ compared_value }}. + Denne værdi skal være større end eller lig med {{ compared_value }}. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Denne værdi skal være identisk med {{ compared_value_type }} {{ compared_value }}. + + + This value should be less than {{ compared_value }}. + Denne værdi skal være mindre end {{ compared_value }}. + + + This value should be less than or equal to {{ compared_value }}. + Denne værdi skal være mindre end eller lig med {{ compared_value }}. + + + This value should not be equal to {{ compared_value }}. + Denne værdi bør ikke være lig med {{ compared_value }}. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Denne værdi bør ikke være identisk med {{ compared_value_type }} {{ compared_value }}. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Billedforholdet er for stort ({{ratio}}). Tilladt maksimumsforhold er {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Billedforholdet er for lille ({{ ratio }}). Minimumsforventet forventet er {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Billedet er firkantet ({{ width }} x {{ height }} px). Firkantede billeder er ikke tilladt. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Billedet er landskabsorienteret ({{width}} x {{height}} px). Landskabsorienterede billeder er ikke tilladt + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Billedet er portrætorienteret ({{ width }}x{{ height }}px). Portrætorienterede billeder er ikke tilladt. + + + An empty file is not allowed. + En tom fil er ikke tilladt. + + + The host could not be resolved. + Værten kunne ikke løses. + + + This value does not match the expected {{ charset }} charset. + Denne værdi stemmer ikke overens med den forventede {{ charset }} charset. + + + This is not a valid Business Identifier Code (BIC). + Dette er ikke en gyldig Business Identifier Code (BIC).a + + + This is not a valid UUID. + Dette er ikke en gyldig UUID. + + + This value should be a multiple of {{ compared_value }}. + Denne værdi skal være et flertal af {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Denne Business Identifier Code (BIC) er ikke forbundet med IBAN {{ iban }}. + + + This value should be valid JSON. + Denne værdi skal være gyldig JSON. + + + This collection should contain only unique elements. + Denne samling bør kun indeholde unikke elementer. + + + This value should be positive. + Denne værdi skal være positiv. + + + This value should be either positive or zero. + Denne værdi skal være enten positiv eller nul. + + + This value should be negative. + Denne værdi skal være negativ. + + + This value should be either negative or zero. + Denne værdi skal være enten negativ eller nul. + + + This value is not a valid timezone. + Denne værdi er ikke en gyldig tidszone. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Denne adgangskode er blevet lækket i et databrud, det må ikke bruges. Brug venligst en anden adgangskode. + diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php index dc723dc486869..691efc6e830b3 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php @@ -17,13 +17,19 @@ class IntegerToLocalizedStringTransformerTest extends TestCase { + private $defaultLocale; + protected function setUp() { - parent::setUp(); - + $this->defaultLocale = \Locale::getDefault(); \Locale::setDefault('en'); } + protected function tearDown() + { + \Locale::setDefault($this->defaultLocale); + } + public function transformWithRoundingProvider() { return [ diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php index 1f05af6128ca7..9baad43549e62 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php @@ -17,13 +17,19 @@ class NumberToLocalizedStringTransformerTest extends TestCase { + private $defaultLocale; + protected function setUp() { - parent::setUp(); - + $this->defaultLocale = \Locale::getDefault(); \Locale::setDefault('en'); } + protected function tearDown() + { + \Locale::setDefault($this->defaultLocale); + } + public function provideTransformations() { return [ diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php index c6007a398b861..f726edcda466a 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php @@ -17,13 +17,19 @@ class PercentToLocalizedStringTransformerTest extends TestCase { + private $defaultLocale; + protected function setUp() { - parent::setUp(); - + $this->defaultLocale = \Locale::getDefault(); \Locale::setDefault('en'); } + protected function tearDown() + { + \Locale::setDefault($this->defaultLocale); + } + public function testTransform() { $transformer = new PercentToLocalizedStringTransformer(); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php index 8a627c27e4a91..d16f8e4ce9f2d 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php @@ -20,17 +20,19 @@ class DateTypeTest extends BaseTypeTest const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\DateType'; private $defaultTimezone; + private $defaultLocale; protected function setUp() { parent::setUp(); $this->defaultTimezone = date_default_timezone_get(); + $this->defaultLocale = \Locale::getDefault(); } protected function tearDown() { date_default_timezone_set($this->defaultTimezone); - \Locale::setDefault('en'); + \Locale::setDefault($this->defaultLocale); } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/MoneyTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/MoneyTypeTest.php index 507a6ffe374a4..42b796a4e6461 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/MoneyTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/MoneyTypeTest.php @@ -17,6 +17,8 @@ class MoneyTypeTest extends BaseTypeTest { const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\MoneyType'; + private $defaultLocale; + protected function setUp() { // we test against different locales, so we need the full @@ -24,6 +26,15 @@ protected function setUp() IntlTestHelper::requireFullIntl($this, false); parent::setUp(); + + $this->defaultLocale = \Locale::getDefault(); + } + + protected function tearDown() + { + parent::tearDown(); + + \Locale::setDefault($this->defaultLocale); } public function testPassMoneyPatternToView() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php index c19c82b117697..9cc2893c662dc 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php @@ -17,6 +17,8 @@ class NumberTypeTest extends BaseTypeTest { const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\NumberType'; + private $defaultLocale; + protected function setUp() { parent::setUp(); @@ -24,9 +26,17 @@ protected function setUp() // we test against "de_DE", so we need the full implementation IntlTestHelper::requireFullIntl($this, false); + $this->defaultLocale = \Locale::getDefault(); \Locale::setDefault('de_DE'); } + protected function tearDown() + { + parent::tearDown(); + + \Locale::setDefault($this->defaultLocale); + } + public function testDefaultFormatting() { $form = $this->factory->create(static::TESTED_TYPE); diff --git a/src/Symfony/Component/HttpFoundation/Cookie.php b/src/Symfony/Component/HttpFoundation/Cookie.php index 0ba6037d7c362..e6b8b798f24ac 100644 --- a/src/Symfony/Component/HttpFoundation/Cookie.php +++ b/src/Symfony/Component/HttpFoundation/Cookie.php @@ -29,6 +29,7 @@ class Cookie private $sameSite; private $secureDefault = false; + const SAMESITE_NONE = 'none'; const SAMESITE_LAX = 'lax'; const SAMESITE_STRICT = 'strict'; @@ -126,7 +127,7 @@ public function __construct(string $name, string $value = null, $expire = 0, ?st $sameSite = strtolower($sameSite); } - if (!\in_array($sameSite, [self::SAMESITE_LAX, self::SAMESITE_STRICT, null], true)) { + if (!\in_array($sameSite, [self::SAMESITE_LAX, self::SAMESITE_STRICT, self::SAMESITE_NONE, null], true)) { throw new \InvalidArgumentException('The "sameSite" parameter value is not valid.'); } diff --git a/src/Symfony/Component/HttpFoundation/FileBag.php b/src/Symfony/Component/HttpFoundation/FileBag.php index 14fbc7aa9d6b7..efd83ffeb8abd 100644 --- a/src/Symfony/Component/HttpFoundation/FileBag.php +++ b/src/Symfony/Component/HttpFoundation/FileBag.php @@ -84,7 +84,7 @@ protected function convertFileInformation($file) if (UPLOAD_ERR_NO_FILE == $file['error']) { $file = null; } else { - $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error']); + $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error'], false); } } else { $file = array_map([$this, 'convertFileInformation'], $file); diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 2b4fc0c02e82c..fffe2ab81ec0e 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1907,7 +1907,7 @@ private function setPhpDefaultLocale(string $locale) } } - /* + /** * Returns the prefix as encoded in the string when the string starts with * the given prefix, false otherwise. * diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php index 2bd1d62bdbf12..99e8074214b62 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php +++ b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php @@ -21,7 +21,7 @@ interface FlashBagInterface extends SessionBagInterface { /** - * Adds a flash message for type. + * Adds a flash message for the given type. * * @param string $type * @param mixed $message @@ -29,12 +29,12 @@ interface FlashBagInterface extends SessionBagInterface public function add($type, $message); /** - * Registers a message for a given type. + * Registers one or more messages for a given type. * * @param string $type - * @param string|array $message + * @param string|array $messages */ - public function set($type, $message); + public function set($type, $messages); /** * Gets flash messages for a given type. diff --git a/src/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php b/src/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php index a54f8b518bf0d..8b70a88f63dc8 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php +++ b/src/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php @@ -29,7 +29,7 @@ interface ControllerResolverInterface * As several resolvers can exist for a single application, a resolver must * return false when it is not able to determine the controller. * - * The resolver must only throw an exception when it should be able to load + * The resolver must only throw an exception when it should be able to load a * controller but cannot because of some errors made by the developer. * * @return callable|false A PHP callable representing the Controller, diff --git a/src/Symfony/Component/HttpKernel/EventListener/FragmentListener.php b/src/Symfony/Component/HttpKernel/EventListener/FragmentListener.php index 5a789a3eb9b27..99df70d0f9a4c 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/FragmentListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/FragmentListener.php @@ -24,7 +24,7 @@ * All URL paths starting with /_fragment are handled as * content fragments by this listener. * - * If throws an AccessDeniedHttpException exception if the request + * Throws an AccessDeniedHttpException exception if the request * is not signed or if it is not an internal sub-request. * * @author Fabien Potencier diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index cf8c24fb0f660..fd063881387d8 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -73,11 +73,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.2.8'; - const VERSION_ID = 40208; + const VERSION = '4.2.9'; + const VERSION_ID = 40209; const MAJOR_VERSION = 4; const MINOR_VERSION = 2; - const RELEASE_VERSION = 8; + const RELEASE_VERSION = 9; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '07/2019'; diff --git a/src/Symfony/Component/HttpKernel/Tests/Log/LoggerTest.php b/src/Symfony/Component/HttpKernel/Tests/Log/LoggerTest.php index 7354000b16595..17865203f2c96 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Log/LoggerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Log/LoggerTest.php @@ -34,7 +34,7 @@ class LoggerTest extends TestCase protected function setUp() { - $this->tmpFile = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'log'; + $this->tmpFile = tempnam(sys_get_temp_dir(), 'log'); $this->logger = new Logger(LogLevel::DEBUG, $this->tmpFile); } diff --git a/src/Symfony/Component/Intl/CONTRIBUTING.md b/src/Symfony/Component/Intl/CONTRIBUTING.md deleted file mode 100644 index 971e0af7f5903..0000000000000 --- a/src/Symfony/Component/Intl/CONTRIBUTING.md +++ /dev/null @@ -1,91 +0,0 @@ -Contributing to the Intl component -================================== - -A very good way of contributing to the Intl component is by updating the -included data for the ICU version you have installed on your system. - -Preparation ------------ - -To prepare, you need to install the development dependencies of the component. - - $ cd /path/to/Symfony/Component/Intl - $ composer install - -Determining your ICU version ---------------------------- - -The ICU version installed in your PHP environment can be found by running -icu-version.php: - - $ php Resources/bin/icu-version.php - -Updating the ICU data ---------------------- - -To update the data files, run the update-icu-component.php script: - - $ php Resources/bin/update-icu-component.php - -The script needs the binaries "svn" and "make" to be available on your system. -It will download the latest version of the ICU sources for the ICU version -installed in your PHP environment. The script will then compile the "genrb" -binary and use it to compile the ICU data files to binaries. The binaries are -copied to the Resources/ directory of the Icu component found in the -vendor/symfony/icu/ directory. - -Updating the stub data ----------------------- - -In the previous step you updated the Icu component for the ICU version -installed on your system. If you are using the latest ICU version, you should -also create the stub data files which will be used by people who don't have -the intl extension installed. - -To update the stub files, run the update-stubs.php script: - - $ php Resources/bin/update-stubs.php - -The script will fail if you don't have the latest ICU version. If you want to -upgrade the ICU version, adjust the return value of the -`Intl::getIcuStubVersion()` before you run the script. - -The script creates copies of the binary resource bundles in the Icu component -and stores them in the Resources/ directory of the Intl component. The copies -are made for the locale "en" only and are stored in .php files, so that they -can be read even if the intl extension is not available. - -Creating a pull request ------------------------ - -You need to create up to two pull requests: - -* If you updated the Icu component, you need to push that change and create a - pull request in the `symfony/Icu` repository. Make sure to submit the pull - request to the correct master branch. If you updated the ICU data for version - 4.8, your pull request goes to branch `48-master`, for version 49 to - `49-master` and so on. - -* If you updated the stub files of the Intl component, you need to push that - change and create a pull request in the `symfony/symfony` repository. The - pull request should be based on the `master` branch. - -Combining .res files to a .dat-package --------------------------------------- - -The individual *.res files can be combined into a single .dat-file. -Unfortunately, PHP's `ResourceBundle` class is currently not able to handle -.dat-files. - -Once it is, the following steps have to be followed to build the .dat-file: - -1. Package the resource bundles into a single file - - $ find . -name *.res | sed -e "s/\.\///g" > packagelist.txt - $ pkgdata -p region -T build -d . packagelist.txt - -2. Clean up - - $ rm -rf build packagelist.txt - -3. You can now move region.dat to replace the version bundled with Symfony. diff --git a/src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php index 9c6f1dcbc5194..f25f62d90cb66 100644 --- a/src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php @@ -12,8 +12,9 @@ namespace Symfony\Component\Intl\Data\Generator; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler; -use Symfony\Component\Intl\Data\Bundle\Reader\BundleReaderInterface; +use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReader; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; use Symfony\Component\Intl\Data\Bundle\Reader\IntlBundleReader; use Symfony\Component\Intl\Data\Util\LocaleScanner; @@ -29,7 +30,7 @@ abstract class AbstractDataGenerator private $compiler; private $dirName; - public function __construct(GenrbCompiler $compiler, string $dirName) + public function __construct(BundleCompilerInterface $compiler, string $dirName) { $this->compiler = $compiler; $this->dirName = $dirName; @@ -39,7 +40,7 @@ public function generateData(GeneratorConfig $config) { $filesystem = new Filesystem(); $localeScanner = new LocaleScanner(); - $reader = new IntlBundleReader(); + $reader = new BundleEntryReader(new IntlBundleReader()); $writers = $config->getBundleWriters(); $tempDir = sys_get_temp_dir().'/icu-data-'.$this->dirName; @@ -98,36 +99,32 @@ public function generateData(GeneratorConfig $config) abstract protected function scanLocales(LocaleScanner $scanner, $sourceDir); /** - * @param GenrbCompiler $compiler - * @param string $sourceDir - * @param string $tempDir + * @param string $sourceDir + * @param string $tempDir */ - abstract protected function compileTemporaryBundles(GenrbCompiler $compiler, $sourceDir, $tempDir); + abstract protected function compileTemporaryBundles(BundleCompilerInterface $compiler, $sourceDir, $tempDir); abstract protected function preGenerate(); /** - * @param BundleReaderInterface $reader - * @param string $tempDir - * @param string $displayLocale + * @param string $tempDir + * @param string $displayLocale * * @return array|null */ - abstract protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir, $displayLocale); + abstract protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale); /** - * @param BundleReaderInterface $reader - * @param string $tempDir + * @param string $tempDir * * @return array|null */ - abstract protected function generateDataForRoot(BundleReaderInterface $reader, $tempDir); + abstract protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir); /** - * @param BundleReaderInterface $reader - * @param string $tempDir + * @param string $tempDir * * @return array|null */ - abstract protected function generateDataForMeta(BundleReaderInterface $reader, $tempDir); + abstract protected function generateDataForMeta(BundleEntryReaderInterface $reader, $tempDir); } diff --git a/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php index 1be618d7878d7..fead9927a9136 100644 --- a/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Intl\Data\Generator; -use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler; -use Symfony\Component\Intl\Data\Bundle\Reader\BundleReaderInterface; +use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle; use Symfony\Component\Intl\Data\Util\LocaleScanner; @@ -25,37 +25,20 @@ */ class CurrencyDataGenerator extends AbstractDataGenerator { - const UNKNOWN_CURRENCY_ID = 'XXX'; - const EUROPEAN_COMPOSITE_UNIT_ID = 'XBA'; - const EUROPEAN_MONETARY_UNIT_ID = 'XBB'; - const EUROPEAN_UNIT_OF_ACCOUNT_XBC_ID = 'XBC'; - const EUROPEAN_UNIT_OF_ACCOUNT_XBD_ID = 'XBD'; - const TESTING_CURRENCY_CODE_ID = 'XTS'; - const ADB_UNIT_OF_ACCOUNT_ID = 'XUA'; - const GOLD_ID = 'XAU'; - const SILVER_ID = 'XAG'; - const PLATINUM_ID = 'XPT'; - const PALLADIUM_ID = 'XPD'; - const SUCRE_ID = 'XSU'; - const SPECIAL_DRAWING_RIGHTS_ID = 'XDR'; - - /** - * Monetary units excluded from generation. - */ private static $blacklist = [ - self::UNKNOWN_CURRENCY_ID => true, - self::EUROPEAN_COMPOSITE_UNIT_ID => true, - self::EUROPEAN_MONETARY_UNIT_ID => true, - self::EUROPEAN_UNIT_OF_ACCOUNT_XBC_ID => true, - self::EUROPEAN_UNIT_OF_ACCOUNT_XBD_ID => true, - self::TESTING_CURRENCY_CODE_ID => true, - self::ADB_UNIT_OF_ACCOUNT_ID => true, - self::GOLD_ID => true, - self::SILVER_ID => true, - self::PLATINUM_ID => true, - self::PALLADIUM_ID => true, - self::SUCRE_ID => true, - self::SPECIAL_DRAWING_RIGHTS_ID => true, + 'XBA' => true, // European Composite Unit + 'XBB' => true, // European Monetary Unit + 'XBC' => true, // European Unit of Account (XBC) + 'XBD' => true, // European Unit of Account (XBD) + 'XUA' => true, // ADB Unit of Account + 'XAU' => true, // Gold + 'XAG' => true, // Silver + 'XPT' => true, // Platinum + 'XPD' => true, // Palladium + 'XSU' => true, // Sucre + 'XDR' => true, // Special Drawing Rights + 'XTS' => true, // Testing Currency Code + 'XXX' => true, // Unknown Currency ]; /** @@ -76,7 +59,7 @@ protected function scanLocales(LocaleScanner $scanner, $sourceDir) /** * {@inheritdoc} */ - protected function compileTemporaryBundles(GenrbCompiler $compiler, $sourceDir, $tempDir) + protected function compileTemporaryBundles(BundleCompilerInterface $compiler, $sourceDir, $tempDir) { $compiler->compile($sourceDir.'/curr', $tempDir); $compiler->compile($sourceDir.'/misc/currencyNumericCodes.txt', $tempDir); @@ -93,7 +76,7 @@ protected function preGenerate() /** * {@inheritdoc} */ - protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir, $displayLocale) + protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale) { $localeBundle = $reader->read($tempDir, $displayLocale); @@ -112,7 +95,7 @@ protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir /** * {@inheritdoc} */ - protected function generateDataForRoot(BundleReaderInterface $reader, $tempDir) + protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir) { $rootBundle = $reader->read($tempDir, 'root'); @@ -125,7 +108,7 @@ protected function generateDataForRoot(BundleReaderInterface $reader, $tempDir) /** * {@inheritdoc} */ - protected function generateDataForMeta(BundleReaderInterface $reader, $tempDir) + protected function generateDataForMeta(BundleEntryReaderInterface $reader, $tempDir) { $rootBundle = $reader->read($tempDir, 'root'); $supplementalDataBundle = $reader->read($tempDir, 'supplementalData'); diff --git a/src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php b/src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php new file mode 100644 index 0000000000000..a937e85b5452f --- /dev/null +++ b/src/Symfony/Component/Intl/Data/Generator/FallbackTrait.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Data\Generator; + +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; +use Symfony\Component\Intl\Locale; + +/** + * @author Roland Franssen + * + * @internal + */ +trait FallbackTrait +{ + private $fallbackCache = []; + private $generatingFallback = false; + + /** + * @param string $tempDir + * @param string $displayLocale + * + * @return array|null + * + * @see AbstractDataGenerator::generateDataForLocale() + */ + abstract protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale); + + /** + * @param string $tempDir + * + * @return array|null + * + * @see AbstractDataGenerator::generateDataForRoot() + */ + abstract protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir); + + private function generateFallbackData(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): array + { + if (null === $fallback = Locale::getFallback($displayLocale)) { + return []; + } + + if (isset($this->fallbackCache[$fallback])) { + return $this->fallbackCache[$fallback]; + } + + $prevGeneratingFallback = $this->generatingFallback; + $this->generatingFallback = true; + + try { + $data = 'root' === $fallback ? $this->generateDataForRoot($reader, $tempDir) : $this->generateDataForLocale($reader, $tempDir, $fallback); + } finally { + $this->generatingFallback = $prevGeneratingFallback; + } + + return $this->fallbackCache[$fallback] = $data ?: []; + } +} diff --git a/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php index 222f8316b3778..55815145da4a5 100644 --- a/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Intl\Data\Generator; -use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler; -use Symfony\Component\Intl\Data\Bundle\Reader\BundleReaderInterface; +use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle; use Symfony\Component\Intl\Data\Util\LocaleScanner; use Symfony\Component\Intl\Exception\RuntimeException; @@ -108,7 +108,7 @@ protected function scanLocales(LocaleScanner $scanner, $sourceDir) /** * {@inheritdoc} */ - protected function compileTemporaryBundles(GenrbCompiler $compiler, $sourceDir, $tempDir) + protected function compileTemporaryBundles(BundleCompilerInterface $compiler, $sourceDir, $tempDir) { $compiler->compile($sourceDir.'/lang', $tempDir); $compiler->compile($sourceDir.'/misc/metadata.txt', $tempDir); @@ -125,7 +125,7 @@ protected function preGenerate() /** * {@inheritdoc} */ - protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir, $displayLocale) + protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale) { $localeBundle = $reader->read($tempDir, $displayLocale); @@ -145,14 +145,14 @@ protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir /** * {@inheritdoc} */ - protected function generateDataForRoot(BundleReaderInterface $reader, $tempDir) + protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir) { } /** * {@inheritdoc} */ - protected function generateDataForMeta(BundleReaderInterface $reader, $tempDir) + protected function generateDataForMeta(BundleEntryReaderInterface $reader, $tempDir) { $rootBundle = $reader->read($tempDir, 'root'); $metadataBundle = $reader->read($tempDir, 'metadata'); diff --git a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php index 84940e63ae92e..9d57b070696e3 100644 --- a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php @@ -12,230 +12,176 @@ namespace Symfony\Component\Intl\Data\Generator; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Intl\Data\Provider\LanguageDataProvider; -use Symfony\Component\Intl\Data\Provider\RegionDataProvider; -use Symfony\Component\Intl\Data\Provider\ScriptDataProvider; +use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; use Symfony\Component\Intl\Data\Util\LocaleScanner; use Symfony\Component\Intl\Exception\MissingResourceException; -use Symfony\Component\Intl\Exception\ResourceBundleNotFoundException; -use Symfony\Component\Intl\Locale; /** * The rule for compiling the locale bundle. * * @author Bernhard Schussek + * @author Roland Franssen * * @internal */ -class LocaleDataGenerator +class LocaleDataGenerator extends AbstractDataGenerator { - private $dirName; - private $languageDataProvider; - private $scriptDataProvider; - private $regionDataProvider; + use FallbackTrait; - public function __construct(string $dirName, LanguageDataProvider $languageDataProvider, ScriptDataProvider $scriptDataProvider, RegionDataProvider $regionDataProvider) + private $locales = []; + private $localeAliases = []; + private $localeParents = []; + + /** + * {@inheritdoc} + */ + protected function scanLocales(LocaleScanner $scanner, $sourceDir) { - $this->dirName = $dirName; - $this->languageDataProvider = $languageDataProvider; - $this->scriptDataProvider = $scriptDataProvider; - $this->regionDataProvider = $regionDataProvider; + $this->locales = $scanner->scanLocales($sourceDir.'/locales'); + $this->localeAliases = $scanner->scanAliases($sourceDir.'/locales'); + $this->localeParents = $scanner->scanParents($sourceDir.'/locales'); + + return $this->locales; } - public function generateData(GeneratorConfig $config) + /** + * {@inheritdoc} + */ + protected function compileTemporaryBundles(BundleCompilerInterface $compiler, $sourceDir, $tempDir) { $filesystem = new Filesystem(); - $localeScanner = new LocaleScanner(); + $filesystem->mkdir([ + $tempDir.'/lang', + $tempDir.'/region', + ]); + $compiler->compile($sourceDir.'/lang', $tempDir.'/lang'); + $compiler->compile($sourceDir.'/region', $tempDir.'/region'); + } - $writers = $config->getBundleWriters(); + /** + * {@inheritdoc} + */ + protected function preGenerate() + { + // Write parents locale file for the Translation component + \file_put_contents( + __DIR__.'/../../../Translation/Resources/data/parents.json', + \json_encode($this->localeParents, \JSON_PRETTY_PRINT).\PHP_EOL + ); + } - // Prepare filesystem directories - foreach ($writers as $targetDir => $writer) { - $filesystem->remove($targetDir.'/'.$this->dirName); - $filesystem->mkdir($targetDir.'/'.$this->dirName); + /** + * {@inheritdoc} + */ + protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale) + { + // Don't generate aliases, as they are resolved during runtime + // Unless an alias is needed as fallback for de-duplication purposes + if (isset($this->localeAliases[$displayLocale]) && !$this->generatingFallback) { + return; } - $locales = $localeScanner->scanLocales($config->getSourceDir().'/locales'); - $aliases = $localeScanner->scanAliases($config->getSourceDir().'/locales'); - $parents = $localeScanner->scanParents($config->getSourceDir().'/locales'); - - // Flip to facilitate lookup - $flippedLocales = array_flip($locales); - - // Don't generate names for aliases (names will be generated for the - // locale they are duplicating) - $displayLocales = array_diff_key($flippedLocales, $aliases); - - ksort($displayLocales); - - // Generate a list of (existing) locale fallbacks - $fallbackMapping = $this->generateFallbackMapping($displayLocales, $aliases); - - $localeNames = []; - // Generate locale names for all locales that have translations in // at least the language or the region bundle - foreach ($displayLocales as $displayLocale => $_) { - $localeNames[$displayLocale] = []; - - foreach ($locales as $locale) { - try { - // Generate a locale name in the language of each display locale - // Each locale name has the form: "Language (Script, Region, Variant1, ...) - // Script, Region and Variants are optional. If none of them is - // available, the braces are not printed. - if (null !== ($name = $this->generateLocaleName($locale, $displayLocale))) { - $localeNames[$displayLocale][$locale] = $name; - } - } catch (MissingResourceException $e) { - } catch (ResourceBundleNotFoundException $e) { - } - } - } - - // Process again to de-duplicate locales and their fallback locales - // Only keep the differences - foreach ($displayLocales as $displayLocale => $_) { - $fallback = $displayLocale; - - while (isset($fallbackMapping[$fallback])) { - $fallback = $fallbackMapping[$fallback]; - $localeNames[$displayLocale] = array_diff( - $localeNames[$displayLocale], - $localeNames[$fallback] - ); - } - - // If no names remain to be saved for the current locale, skip it - if (0 === \count($localeNames[$displayLocale])) { + $displayFormat = $reader->readEntry($tempDir.'/lang', $displayLocale, ['localeDisplayPattern']); + $pattern = $displayFormat['pattern'] ?? '{0} ({1})'; + $separator = $displayFormat['separator'] ?? '{0}, {1}'; + $localeNames = []; + foreach ($this->locales as $locale) { + // Ensure a normalized list of pure locales + if (\Locale::getAllVariants($locale)) { continue; } - foreach ($writers as $targetDir => $writer) { - $writer->write($targetDir.'/'.$this->dirName, $displayLocale, [ - 'Names' => $localeNames[$displayLocale], - ]); + try { + // Generate a locale name in the language of each display locale + // Each locale name has the form: "Language (Script, Region, Variant1, ...) + // Script, Region and Variants are optional. If none of them is + // available, the braces are not printed. + $localeNames[$locale] = $this->generateLocaleName($reader, $tempDir, $locale, $displayLocale, $pattern, $separator); + } catch (MissingResourceException $e) { + // Silently ignore incomplete locale names + // In this case one should configure at least one fallback locale that is complete (e.g. English) during + // runtime. Alternatively a translation for the missing resource can be proposed upstream. } } - // Generate aliases, needed to enable proper fallback from alias to its - // target - foreach ($aliases as $alias => $aliasOf) { - foreach ($writers as $targetDir => $writer) { - $writer->write($targetDir.'/'.$this->dirName, $alias, [ - '%%ALIAS' => $aliasOf, - ]); - } - } + $data = [ + 'Names' => $localeNames, + ]; - // Create root file which maps locale codes to locale codes, for fallback - foreach ($writers as $targetDir => $writer) { - $writer->write($targetDir.'/'.$this->dirName, 'meta', [ - 'Locales' => $locales, - 'Aliases' => $aliases, - ]); + // Don't de-duplicate a fallback locale + // Ensures the display locale can be de-duplicated on itself + if ($this->generatingFallback) { + return $data; } - // Write parents locale file for the Translation component - \file_put_contents( - __DIR__.'/../../../Translation/Resources/data/parents.json', - \json_encode($parents, \JSON_PRETTY_PRINT).\PHP_EOL - ); - } - - private function generateLocaleName($locale, $displayLocale) - { - $name = null; - - $lang = \Locale::getPrimaryLanguage($locale); - $script = \Locale::getScript($locale); - $region = \Locale::getRegion($locale); - $variants = \Locale::getAllVariants($locale); - - // Currently the only available variant is POSIX, which we don't want - // to include in the list - if (\count($variants) > 0) { + // Process again to de-duplicate locale and its fallback locales + // Only keep the differences + $fallbackData = $this->generateFallbackData($reader, $tempDir, $displayLocale); + if (isset($fallbackData['Names'])) { + $data['Names'] = array_diff($data['Names'], $fallbackData['Names']); + } + if (!$data['Names']) { return; } - // Some languages are translated together with their region, - // i.e. "en_GB" is translated as "British English" - // we don't include these languages though because they mess up - // the name sorting - // $name = $this->langBundle->getLanguageName($displayLocale, $lang, $region); + return $data; + } - // Some languages are not translated - // Example: "az" (Azerbaijani) has no translation in "af" (Afrikaans) - if (null === ($name = $this->languageDataProvider->getName($lang, $displayLocale))) { - return; - } + /** + * {@inheritdoc} + */ + protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir) + { + } - // "as" (Assamese) has no "Variants" block - //if (!$langBundle->get('Variants')) { - // continue; - //} + /** + * {@inheritdoc} + */ + protected function generateDataForMeta(BundleEntryReaderInterface $reader, $tempDir) + { + return [ + 'Locales' => $this->locales, + 'Aliases' => $this->localeAliases, + ]; + } + /** + * @return string + */ + private function generateLocaleName(BundleEntryReaderInterface $reader, $tempDir, $locale, $displayLocale, $pattern, $separator) + { + // Apply generic notation using square brackets as described per http://cldr.unicode.org/translation/language-names + $name = str_replace(['(', ')'], ['[', ']'], $reader->readEntry($tempDir.'/lang', $displayLocale, ['Languages', \Locale::getPrimaryLanguage($locale)])); $extras = []; // Discover the name of the script part of the locale // i.e. in zh_Hans_MO, "Hans" is the script - if ($script) { - // Some scripts are not translated into every language - if (null === ($scriptName = $this->scriptDataProvider->getName($script, $displayLocale))) { - return; - } - - $extras[] = $scriptName; + if ($script = \Locale::getScript($locale)) { + $extras[] = str_replace(['(', ')'], ['[', ']'], $reader->readEntry($tempDir.'/lang', $displayLocale, ['Scripts', $script])); } // Discover the name of the region part of the locale // i.e. in de_AT, "AT" is the region - if ($region) { - // Some regions are not translated into every language - if (null === ($regionName = $this->regionDataProvider->getName($region, $displayLocale))) { - return; + if ($region = \Locale::getRegion($locale)) { + if (!RegionDataGenerator::isValidCountryCode($region)) { + throw new MissingResourceException('Skipping "'.$locale.'" due an invalid country.'); } - $extras[] = $regionName; + $extras[] = str_replace(['(', ')'], ['[', ']'], $reader->readEntry($tempDir.'/region', $displayLocale, ['Countries', $region])); } - if (\count($extras) > 0) { - // Remove any existing extras - // For example, in German, zh_Hans is "Chinesisch (vereinfacht)". - // The latter is the script part which is already included in the - // extras and will be appended again with the other extras. - if (preg_match('/^(.+)\s+\([^\)]+\)$/', $name, $matches)) { - $name = $matches[1]; + if ($extras) { + $extra = array_shift($extras); + foreach ($extras as $part) { + $extra = str_replace(['{0}', '{1}'], [$extra, $part], $separator); } - $name .= ' ('.implode(', ', $extras).')'; + $name = str_replace(['{0}', '{1}'], [$name, $extra], $pattern); } return $name; } - - private function generateFallbackMapping(array $displayLocales, array $aliases) - { - $mapping = []; - - foreach ($displayLocales as $displayLocale => $_) { - $mapping[$displayLocale] = null; - $fallback = $displayLocale; - - // Recursively search for a fallback locale until one is found - while (null !== ($fallback = Locale::getFallback($fallback))) { - // Currently, no locale has an alias as fallback locale. - // If this starts to be the case, we need to add code here. - \assert(!isset($aliases[$fallback])); - - // Check whether the fallback exists - if (isset($displayLocales[$fallback])) { - $mapping[$displayLocale] = $fallback; - break; - } - } - } - - return $mapping; - } } diff --git a/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php index 0728db80309b8..25deae2fa5f90 100644 --- a/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Intl\Data\Generator; -use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler; -use Symfony\Component\Intl\Data\Bundle\Reader\BundleReaderInterface; +use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle; use Symfony\Component\Intl\Data\Util\LocaleScanner; @@ -27,32 +27,18 @@ */ class RegionDataGenerator extends AbstractDataGenerator { - const UNKNOWN_REGION_ID = 'ZZ'; - const OUTLYING_OCEANIA_REGION_ID = 'QO'; - const EUROPEAN_UNION_ID = 'EU'; - const NETHERLANDS_ANTILLES_ID = 'AN'; - const BOUVET_ISLAND_ID = 'BV'; - const HEARD_MCDONALD_ISLANDS_ID = 'HM'; - const CLIPPERTON_ISLAND_ID = 'CP'; - const EUROZONE_ID = 'EZ'; - const UNITED_NATIONS_ID = 'UN'; - - /** - * Regions excluded from generation. - */ private static $blacklist = [ - self::UNKNOWN_REGION_ID => true, // Look like countries, but are sub-continents - self::OUTLYING_OCEANIA_REGION_ID => true, - self::EUROPEAN_UNION_ID => true, - self::EUROZONE_ID => true, - self::UNITED_NATIONS_ID => true, - // No longer exists - self::NETHERLANDS_ANTILLES_ID => true, + 'QO' => true, // Outlying Oceania + 'EU' => true, // European Union + 'EZ' => true, // Eurozone + 'UN' => true, // United Nations // Uninhabited islands - self::BOUVET_ISLAND_ID => true, - self::HEARD_MCDONALD_ISLANDS_ID => true, - self::CLIPPERTON_ISLAND_ID => true, + 'BV' => true, // Bouvet Island + 'HM' => true, // Heard & McDonald Islands + 'CP' => true, // Clipperton Island + // Misc + 'ZZ' => true, // Unknown Region ]; /** @@ -62,6 +48,20 @@ class RegionDataGenerator extends AbstractDataGenerator */ private $regionCodes = []; + public static function isValidCountryCode($region) + { + if (isset(self::$blacklist[$region])) { + return false; + } + + // WORLD/CONTINENT/SUBCONTINENT/GROUPING + if (ctype_digit($region) || \is_int($region)) { + return false; + } + + return true; + } + /** * {@inheritdoc} */ @@ -73,7 +73,7 @@ protected function scanLocales(LocaleScanner $scanner, $sourceDir) /** * {@inheritdoc} */ - protected function compileTemporaryBundles(GenrbCompiler $compiler, $sourceDir, $tempDir) + protected function compileTemporaryBundles(BundleCompilerInterface $compiler, $sourceDir, $tempDir) { $compiler->compile($sourceDir.'/region', $tempDir); } @@ -89,7 +89,7 @@ protected function preGenerate() /** * {@inheritdoc} */ - protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir, $displayLocale) + protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale) { $localeBundle = $reader->read($tempDir, $displayLocale); @@ -109,14 +109,14 @@ protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir /** * {@inheritdoc} */ - protected function generateDataForRoot(BundleReaderInterface $reader, $tempDir) + protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir) { } /** * {@inheritdoc} */ - protected function generateDataForMeta(BundleReaderInterface $reader, $tempDir) + protected function generateDataForMeta(BundleEntryReaderInterface $reader, $tempDir) { $rootBundle = $reader->read($tempDir, 'root'); @@ -139,12 +139,7 @@ protected function generateRegionNames(ArrayAccessibleResourceBundle $localeBund $regionNames = []; foreach ($unfilteredRegionNames as $region => $regionName) { - if (isset(self::$blacklist[$region])) { - continue; - } - - // WORLD/CONTINENT/SUBCONTINENT/GROUPING - if (ctype_digit($region) || \is_int($region)) { + if (!self::isValidCountryCode($region)) { continue; } diff --git a/src/Symfony/Component/Intl/Data/Generator/ScriptDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/ScriptDataGenerator.php index 7ed0625262f68..50f8dd2c10fb0 100644 --- a/src/Symfony/Component/Intl/Data/Generator/ScriptDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/ScriptDataGenerator.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Intl\Data\Generator; -use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler; -use Symfony\Component\Intl\Data\Bundle\Reader\BundleReaderInterface; +use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; use Symfony\Component\Intl\Data\Util\LocaleScanner; /** @@ -42,7 +42,7 @@ protected function scanLocales(LocaleScanner $scanner, $sourceDir) /** * {@inheritdoc} */ - protected function compileTemporaryBundles(GenrbCompiler $compiler, $sourceDir, $tempDir) + protected function compileTemporaryBundles(BundleCompilerInterface $compiler, $sourceDir, $tempDir) { $compiler->compile($sourceDir.'/lang', $tempDir); } @@ -58,7 +58,7 @@ protected function preGenerate() /** * {@inheritdoc} */ - protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir, $displayLocale) + protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale) { $localeBundle = $reader->read($tempDir, $displayLocale); @@ -78,14 +78,14 @@ protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir /** * {@inheritdoc} */ - protected function generateDataForRoot(BundleReaderInterface $reader, $tempDir) + protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir) { } /** * {@inheritdoc} */ - protected function generateDataForMeta(BundleReaderInterface $reader, $tempDir) + protected function generateDataForMeta(BundleEntryReaderInterface $reader, $tempDir) { $rootBundle = $reader->read($tempDir, 'root'); diff --git a/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php index 61814dfda3058..e7dfc29d1febb 100644 --- a/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php @@ -13,7 +13,6 @@ use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; use Symfony\Component\Intl\Exception\MissingResourceException; -use Symfony\Component\Intl\Locale; /** * Data provider for currency-related data. @@ -53,7 +52,7 @@ public function getCurrencies() public function getSymbol($currency, $displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } return $this->reader->readEntry($this->path, $displayLocale, ['Names', $currency, static::INDEX_SYMBOL]); @@ -62,7 +61,7 @@ public function getSymbol($currency, $displayLocale = null) public function getName($currency, $displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } return $this->reader->readEntry($this->path, $displayLocale, ['Names', $currency, static::INDEX_NAME]); @@ -71,7 +70,7 @@ public function getName($currency, $displayLocale = null) public function getNames($displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } // ==================================================================== diff --git a/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php index 60a364b6447b0..768d91e6b7b30 100644 --- a/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Intl\Data\Provider; use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; -use Symfony\Component\Intl\Locale; /** * Data provider for language-related ICU data. @@ -51,7 +50,7 @@ public function getAliases() public function getName($language, $displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } return $this->reader->readEntry($this->path, $displayLocale, ['Names', $language]); @@ -60,7 +59,7 @@ public function getName($language, $displayLocale = null) public function getNames($displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } $languages = $this->reader->readEntry($this->path, $displayLocale, ['Names']); diff --git a/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php index f42be225bcc5b..af0211207d515 100644 --- a/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Intl\Data\Provider; use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; -use Symfony\Component\Intl\Locale; /** * Data provider for locale-related ICU data. @@ -57,7 +56,7 @@ public function getAliases() public function getName($locale, $displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } return $this->reader->readEntry($this->path, $displayLocale, ['Names', $locale]); @@ -66,7 +65,7 @@ public function getName($locale, $displayLocale = null) public function getNames($displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } $names = $this->reader->readEntry($this->path, $displayLocale, ['Names']); diff --git a/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php index f45cae16a1f18..90bca402ddd13 100644 --- a/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Intl\Data\Provider; use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; -use Symfony\Component\Intl\Locale; /** * Data provider for region-related ICU data. @@ -46,7 +45,7 @@ public function getRegions() public function getName($region, $displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } return $this->reader->readEntry($this->path, $displayLocale, ['Names', $region]); @@ -55,7 +54,7 @@ public function getName($region, $displayLocale = null) public function getNames($displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } $names = $this->reader->readEntry($this->path, $displayLocale, ['Names']); diff --git a/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php index 43651cae591d0..76d841b1daeda 100644 --- a/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Intl\Data\Provider; use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; -use Symfony\Component\Intl\Locale; /** * Data provider for script-related ICU data. @@ -46,7 +45,7 @@ public function getScripts() public function getName($script, $displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } return $this->reader->readEntry($this->path, $displayLocale, ['Names', $script]); @@ -55,7 +54,7 @@ public function getName($script, $displayLocale = null) public function getNames($displayLocale = null) { if (null === $displayLocale) { - $displayLocale = Locale::getDefault(); + $displayLocale = \Locale::getDefault(); } $names = $this->reader->readEntry($this->path, $displayLocale, ['Names']); diff --git a/src/Symfony/Component/Intl/Locale.php b/src/Symfony/Component/Intl/Locale.php index fa2da7e50f695..fdfb09674ec69 100644 --- a/src/Symfony/Component/Intl/Locale.php +++ b/src/Symfony/Component/Intl/Locale.php @@ -70,7 +70,7 @@ public static function getFallback($locale): ?string if (\function_exists('locale_parse')) { $localeSubTags = locale_parse($locale); if (1 === \count($localeSubTags)) { - if (self::$defaultFallback === $localeSubTags['language']) { + if ('root' !== self::$defaultFallback && self::$defaultFallback === $localeSubTags['language']) { return 'root'; } @@ -98,7 +98,7 @@ public static function getFallback($locale): ?string return substr($locale, 0, $pos); } - if (self::$defaultFallback === $locale) { + if ('root' !== self::$defaultFallback && self::$defaultFallback === $locale) { return 'root'; } diff --git a/src/Symfony/Component/Intl/Resources/bin/common.php b/src/Symfony/Component/Intl/Resources/bin/common.php index 6c63062d4f913..addaa9415ee1a 100644 --- a/src/Symfony/Component/Intl/Resources/bin/common.php +++ b/src/Symfony/Component/Intl/Resources/bin/common.php @@ -68,6 +68,12 @@ function get_icu_version_from_genrb($genrb) return $matches[1]; } +error_reporting(E_ALL); + +set_error_handler(function ($type, $msg, $file, $line) { + throw new \ErrorException($msg, 0, $type, $file, $line); +}); + set_exception_handler(function (\Throwable $exception) { echo "\n"; @@ -82,10 +88,7 @@ function get_icu_version_from_genrb($genrb) echo get_class($cause).': '.$cause->getMessage()."\n"; echo "\n"; echo $cause->getFile().':'.$cause->getLine()."\n"; - foreach ($cause->getTrace() as $trace) { - echo $trace['file'].':'.$trace['line']."\n"; - } - echo "\n"; + echo $cause->getTraceAsString()."\n"; $cause = $cause->getPrevious(); $root = false; diff --git a/src/Symfony/Component/Intl/Resources/bin/update-data.php b/src/Symfony/Component/Intl/Resources/bin/update-data.php index d6e25af474569..0ec098363aa6f 100644 --- a/src/Symfony/Component/Intl/Resources/bin/update-data.php +++ b/src/Symfony/Component/Intl/Resources/bin/update-data.php @@ -11,8 +11,6 @@ use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler; -use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReader; -use Symfony\Component\Intl\Data\Bundle\Reader\JsonBundleReader; use Symfony\Component\Intl\Data\Bundle\Writer\JsonBundleWriter; use Symfony\Component\Intl\Data\Generator\CurrencyDataGenerator; use Symfony\Component\Intl\Data\Generator\GeneratorConfig; @@ -20,9 +18,6 @@ use Symfony\Component\Intl\Data\Generator\LocaleDataGenerator; use Symfony\Component\Intl\Data\Generator\RegionDataGenerator; use Symfony\Component\Intl\Data\Generator\ScriptDataGenerator; -use Symfony\Component\Intl\Data\Provider\LanguageDataProvider; -use Symfony\Component\Intl\Data\Provider\RegionDataProvider; -use Symfony\Component\Intl\Data\Provider\ScriptDataProvider; use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Locale; use Symfony\Component\Intl\Util\GitRepository; @@ -170,92 +165,40 @@ $compiler = new GenrbCompiler($genrb, $genrbEnv); $config = new GeneratorConfig($sourceDir.'/data', $icuVersionInDownload); +$jsonDir = dirname(__DIR__).'/data'; -$baseDir = dirname(__DIR__).'/data'; - -//$txtDir = $baseDir.'/txt'; -$jsonDir = $baseDir; -//$phpDir = $baseDir.'/'.Intl::PHP; -//$resDir = $baseDir.'/'.Intl::RB_V2; - -$targetDirs = [$jsonDir/*, $resDir*/]; -$workingDirs = [$jsonDir/*, $txtDir, $resDir*/]; - -//$config->addBundleWriter($txtDir, new TextBundleWriter()); $config->addBundleWriter($jsonDir, new JsonBundleWriter()); echo "Starting resource bundle compilation. This may take a while...\n"; -$filesystem->remove($workingDirs); - -foreach ($workingDirs as $targetDir) { - $filesystem->mkdir([ - $targetDir.'/'.Intl::CURRENCY_DIR, - $targetDir.'/'.Intl::LANGUAGE_DIR, - $targetDir.'/'.Intl::LOCALE_DIR, - $targetDir.'/'.Intl::REGION_DIR, - $targetDir.'/'.Intl::SCRIPT_DIR, - ]); -} - // We don't want to use fallback to English during generation -Locale::setDefaultFallback(null); +Locale::setDefaultFallback('root'); echo "Generating language data...\n"; $generator = new LanguageDataGenerator($compiler, Intl::LANGUAGE_DIR); $generator->generateData($config); -//echo "Compiling...\n"; -// -//$compiler->compile($txtDir.'/'.Intl::LANGUAGE_DIR, $resDir.'/'.Intl::LANGUAGE_DIR); - echo "Generating script data...\n"; $generator = new ScriptDataGenerator($compiler, Intl::SCRIPT_DIR); $generator->generateData($config); -//echo "Compiling...\n"; -// -//$compiler->compile($txtDir.'/'.Intl::SCRIPT_DIR, $resDir.'/'.Intl::SCRIPT_DIR); - echo "Generating region data...\n"; $generator = new RegionDataGenerator($compiler, Intl::REGION_DIR); $generator->generateData($config); -//echo "Compiling...\n"; -// -//$compiler->compile($txtDir.'/'.Intl::REGION_DIR, $resDir.'/'.Intl::REGION_DIR); - echo "Generating currency data...\n"; $generator = new CurrencyDataGenerator($compiler, Intl::CURRENCY_DIR); $generator->generateData($config); -//echo "Compiling...\n"; -// -//$compiler->compile($txtDir.'/'.Intl::CURRENCY_DIR, $resDir.'/'.Intl::CURRENCY_DIR); - echo "Generating locale data...\n"; -$reader = new BundleEntryReader(new JsonBundleReader()); - -$generator = new LocaleDataGenerator( - Intl::LOCALE_DIR, - new LanguageDataProvider($jsonDir.'/'.Intl::LANGUAGE_DIR, $reader), - new ScriptDataProvider($jsonDir.'/'.Intl::SCRIPT_DIR, $reader), - new RegionDataProvider($jsonDir.'/'.Intl::REGION_DIR, $reader) -); - +$generator = new LocaleDataGenerator($compiler, Intl::LOCALE_DIR); $generator->generateData($config); -//echo "Compiling...\n"; -// -//$compiler->compile($txtDir.'/'.Intl::LOCALE_DIR, $resDir.'/'.Intl::LOCALE_DIR); -// -//$filesystem->remove($txtDir); - echo "Resource bundle compilation complete.\n"; $gitInfo = << @@ -631,7 +630,7 @@ public function testGetNames($displayLocale) public function testGetNamesDefaultLocale() { - Locale::setDefault('de_AT'); + \Locale::setDefault('de_AT'); $this->assertSame( $this->dataProvider->getNames('de_AT'), @@ -670,7 +669,7 @@ public function testGetName($displayLocale) public function testGetNameDefaultLocale() { - Locale::setDefault('de_AT'); + \Locale::setDefault('de_AT'); $expected = $this->dataProvider->getNames('de_AT'); $actual = []; diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php index d0ef4d273b45a..562f8386d1c9e 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php @@ -703,7 +703,7 @@ abstract class AbstractDataProviderTest extends TestCase protected function setUp() { - Locale::setDefault('en'); + \Locale::setDefault('en'); Locale::setDefaultFallback('en'); } diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php index 310fe791608f9..84b1fb59fcd54 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php @@ -13,7 +13,6 @@ use Symfony\Component\Intl\Data\Provider\LanguageDataProvider; use Symfony\Component\Intl\Intl; -use Symfony\Component\Intl\Locale; /** * @author Bernhard Schussek @@ -862,7 +861,7 @@ public function testGetNames($displayLocale) public function testGetNamesDefaultLocale() { - Locale::setDefault('de_AT'); + \Locale::setDefault('de_AT'); $this->assertSame( $this->dataProvider->getNames('de_AT'), @@ -898,7 +897,7 @@ public function testGetName($displayLocale) public function testGetNameDefaultLocale() { - Locale::setDefault('de_AT'); + \Locale::setDefault('de_AT'); $names = $this->dataProvider->getNames('de_AT'); diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php index aeca40cdbd6cd..88242a6f9bcb3 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php @@ -13,7 +13,6 @@ use Symfony\Component\Intl\Data\Provider\LocaleDataProvider; use Symfony\Component\Intl\Intl; -use Symfony\Component\Intl\Locale; /** * @author Bernhard Schussek @@ -64,7 +63,7 @@ public function testGetNames($displayLocale) public function testGetNamesDefaultLocale() { - Locale::setDefault('de_AT'); + \Locale::setDefault('de_AT'); $this->assertSame( $this->dataProvider->getNames('de_AT'), @@ -100,7 +99,7 @@ public function testGetName($displayLocale) public function testGetNameDefaultLocale() { - Locale::setDefault('de_AT'); + \Locale::setDefault('de_AT'); $names = $this->dataProvider->getNames('de_AT'); diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php index 1f5febb2b86bf..aeb922f9e3e5f 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php @@ -13,7 +13,6 @@ use Symfony\Component\Intl\Data\Provider\RegionDataProvider; use Symfony\Component\Intl\Intl; -use Symfony\Component\Intl\Locale; /** * @author Bernhard Schussek @@ -316,7 +315,7 @@ public function testGetNames($displayLocale) public function testGetNamesDefaultLocale() { - Locale::setDefault('de_AT'); + \Locale::setDefault('de_AT'); $this->assertSame( $this->dataProvider->getNames('de_AT'), diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php index db4b81ebdb13f..8620fb2060fbc 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php @@ -13,7 +13,6 @@ use Symfony\Component\Intl\Data\Provider\ScriptDataProvider; use Symfony\Component\Intl\Intl; -use Symfony\Component\Intl\Locale; /** * @author Bernhard Schussek @@ -255,7 +254,7 @@ public function testGetNames($displayLocale) public function testGetNamesDefaultLocale() { - Locale::setDefault('de_AT'); + \Locale::setDefault('de_AT'); $this->assertSame( $this->dataProvider->getNames('de_AT'), @@ -291,7 +290,7 @@ public function testGetName($displayLocale) public function testGetNameDefaultLocale() { - Locale::setDefault('de_AT'); + \Locale::setDefault('de_AT'); $names = $this->dataProvider->getNames('de_AT'); diff --git a/src/Symfony/Component/Intl/Tests/LocaleTest.php b/src/Symfony/Component/Intl/Tests/LocaleTest.php index ff908cbcabd00..fd998612a7eae 100644 --- a/src/Symfony/Component/Intl/Tests/LocaleTest.php +++ b/src/Symfony/Component/Intl/Tests/LocaleTest.php @@ -46,4 +46,28 @@ public function testGetFallback($expected, $locale) { $this->assertSame($expected, Locale::getFallback($locale)); } + + public function testNoDefaultFallback() + { + $prev = Locale::getDefaultFallback(); + Locale::setDefaultFallback(null); + + $this->assertSame('nl', Locale::getFallback('nl_NL')); + $this->assertNull(Locale::getFallback('nl')); + $this->assertNull(Locale::getFallback('root')); + + Locale::setDefaultFallback($prev); + } + + public function testDefaultRootFallback() + { + $prev = Locale::getDefaultFallback(); + Locale::setDefaultFallback('root'); + + $this->assertSame('nl', Locale::getFallback('nl_NL')); + $this->assertSame('root', Locale::getFallback('nl')); + $this->assertNull(Locale::getFallback('root')); + + Locale::setDefaultFallback($prev); + } } diff --git a/src/Symfony/Component/Ldap/Exception/ConnectionException.php b/src/Symfony/Component/Ldap/Exception/ConnectionException.php index cded4cf2a389a..7fa8e89f6f4a2 100644 --- a/src/Symfony/Component/Ldap/Exception/ConnectionException.php +++ b/src/Symfony/Component/Ldap/Exception/ConnectionException.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Ldap\Exception; /** - * ConnectionException is throw if binding to ldap can not be established. + * ConnectionException is thrown if binding to ldap can not be established. * * @author Grégoire Pineau */ diff --git a/src/Symfony/Component/Ldap/Exception/DriverNotFoundException.php b/src/Symfony/Component/Ldap/Exception/DriverNotFoundException.php index 40258435bb6a7..382cdf5ca6686 100644 --- a/src/Symfony/Component/Ldap/Exception/DriverNotFoundException.php +++ b/src/Symfony/Component/Ldap/Exception/DriverNotFoundException.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Ldap\Exception; /** - * LdapException is throw if php ldap module is not loaded. + * LdapException is thrown if php ldap module is not loaded. * * @author Charles Sarrazin */ diff --git a/src/Symfony/Component/Ldap/Exception/LdapException.php b/src/Symfony/Component/Ldap/Exception/LdapException.php index 4045f32cf44b5..df8eabfbcba88 100644 --- a/src/Symfony/Component/Ldap/Exception/LdapException.php +++ b/src/Symfony/Component/Ldap/Exception/LdapException.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Ldap\Exception; /** - * LdapException is throw if php ldap module is not loaded. + * LdapException is thrown if php ldap module is not loaded. * * @author Grégoire Pineau */ diff --git a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/EntryManagerTest.php b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/EntryManagerTest.php new file mode 100644 index 0000000000000..0617762ed6f08 --- /dev/null +++ b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/EntryManagerTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Ldap\Tests\Adapter\ExtLdap; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Ldap\Adapter\ExtLdap\Connection; +use Symfony\Component\Ldap\Adapter\ExtLdap\EntryManager; +use Symfony\Component\Ldap\Entry; + +class EntryManagerTest extends TestCase +{ + /** + * @expectedException \Symfony\Component\Ldap\Exception\NotBoundException + * @expectedExceptionMessage Query execution is not possible without binding the connection first. + */ + public function testGetResources() + { + $connection = $this->getMockBuilder(Connection::class)->getMock(); + $connection + ->expects($this->once()) + ->method('isBound')->willReturn(false); + + $entry = new Entry('$$$$$$'); + $entryManager = new EntryManager($connection); + $entryManager->update($entry); + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php index 41e0df22bc501..e61fe5937af78 100644 --- a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php @@ -32,7 +32,7 @@ public function __construct(ReceiverInterface $decoratedReceiver, int $memoryLim $this->memoryLimit = $memoryLimit; $this->logger = $logger; $this->memoryResolver = $memoryResolver ?: function () { - return \memory_get_usage(); + return \memory_get_usage(true); }; } diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index 54d18911498ed..e0417fdf34c0d 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -751,7 +751,7 @@ function (OptionsResolver $resolver) { 0, ]; - yield 'It explicitly ignores a depreciation' => [ + yield 'It explicitly ignores a deprecation' => [ function (OptionsResolver $resolver) { $resolver ->setDefault('baz', function (Options $options) { diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 8b7f539e0fe10..5c53e33559284 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -419,6 +419,7 @@ public function wait(callable $callback = null) } while ($running); while ($this->isRunning()) { + $this->checkTimeout(); usleep(1000); } diff --git a/src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php b/src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php new file mode 100755 index 0000000000000..c37aeb5c8ffd9 --- /dev/null +++ b/src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +use Symfony\Component\Process\Exception\ProcessTimedOutException; +use Symfony\Component\Process\Process; + +require \dirname(__DIR__).'/vendor/autoload.php'; + +list('e' => $php) = getopt('e:') + ['e' => 'php']; + +try { + $process = new Process("exec $php -r \"echo 'ready'; trigger_error('error', E_USER_ERROR);\""); + $process->start(); + $process->setTimeout(0.5); + while (false === strpos($process->getOutput(), 'ready')) { + usleep(1000); + } + $process->signal(SIGSTOP); + $process->wait(); + + return $process->getExitCode(); +} catch (ProcessTimedOutException $t) { + echo $t->getMessage().PHP_EOL; + + return 1; +} diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 187226bd49de0..8ac81bb72fe2f 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1510,6 +1510,25 @@ public function testEnvArgument() $this->assertSame($env, $p->getEnv()); } + public function testWaitStoppedDeadProcess() + { + $process = $this->getProcess(self::$phpBin.' '.__DIR__.'/ErrorProcessInitiator.php -e '.self::$phpBin); + $process->start(); + $process->setTimeout(2); + $process->wait(); + $this->assertFalse($process->isRunning()); + } + + /** + * @param string $commandline + * @param string|null $cwd + * @param array|null $env + * @param string|null $input + * @param int $timeout + * @param array $options + * + * @return Process + */ private function getProcess($commandline, string $cwd = null, array $env = null, $input = null, ?int $timeout = 60): Process { if (\is_string($commandline)) { diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 6bf6e210968e6..2eb3d17ea9c04 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -62,6 +62,7 @@ class PropertyAccessor implements PropertyAccessorInterface */ private $cacheItemPool; + private $propertyPathCache = []; private $readPropertyCache = []; private $writePropertyCache = []; private static $resultProto = [self::VALUE => null]; @@ -795,7 +796,7 @@ private function getPropertyPath($propertyPath): PropertyPath * * @return AdapterInterface * - * @throws RuntimeException When the Cache Component isn't available + * @throws \LogicException When the Cache Component isn't available */ public static function createCache($namespace, $defaultLifetime, $version, LoggerInterface $logger = null) { diff --git a/src/Symfony/Component/PropertyInfo/README.md b/src/Symfony/Component/PropertyInfo/README.md index 5ac21f384e59b..1cf30318deb8b 100644 --- a/src/Symfony/Component/PropertyInfo/README.md +++ b/src/Symfony/Component/PropertyInfo/README.md @@ -7,6 +7,7 @@ of popular sources. Resources --------- + * [Documentation](https://symfony.com/doc/current/components/property_info.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php index ae834bf4ba5c4..65470664e5c2c 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php @@ -248,7 +248,8 @@ public function getResolver() */ protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method) { - $name = strtolower(str_replace('\\', '_', $class->name).'_'.$method->name); + $name = str_replace('\\', '_', $class->name).'_'.$method->name; + $name = \function_exists('mb_strtolower') && preg_match('//u', $name) ? mb_strtolower($name, 'UTF-8') : strtolower($name); if ($this->defaultRouteIndex > 0) { $name .= '_'.$this->defaultRouteIndex; } diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherTrait.php b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherTrait.php index 42cd41a9153c0..18b1018773b1c 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherTrait.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherTrait.php @@ -42,7 +42,7 @@ public function match($pathinfo) throw new MethodNotAllowedException(array_keys($allow)); } if (!$this instanceof RedirectableUrlMatcherInterface) { - throw new ResourceNotFoundException(); + throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo)); } if (!\in_array($this->context->getMethod(), ['HEAD', 'GET'], true)) { // no-op @@ -67,7 +67,7 @@ public function match($pathinfo) } } - throw new ResourceNotFoundException(); + throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo)); } private function doMatch(string $pathinfo, array &$allow = [], array &$allowSchemes = []): array @@ -110,10 +110,8 @@ private function doMatch(string $pathinfo, array &$allow = [], array &$allowSche } $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]); - if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) { - if ($hasRequiredScheme) { - $allow += $requiredMethods; - } + if ($hasRequiredScheme && $requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) { + $allow += $requiredMethods; continue; } @@ -157,15 +155,13 @@ private function doMatch(string $pathinfo, array &$allow = [], array &$allowSche } } - $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]); - if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) { - if ($hasRequiredScheme) { - $allow += $requiredMethods; - } + if ($requiredSchemes && !isset($requiredSchemes[$context->getScheme()])) { + $allowSchemes += $requiredSchemes; continue; } - if (!$hasRequiredScheme) { - $allowSchemes += $requiredSchemes; + + if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) { + $allow += $requiredMethods; continue; } diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php index 7b2662a2a392e..dca1d6366fa02 100644 --- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php +++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php @@ -89,7 +89,7 @@ public function match($pathinfo) return $ret; } - if ('/' === $pathinfo && !$this->allow) { + if ('/' === $pathinfo && !$this->allow && !$this->allowSchemes) { throw new NoConfigurationException(); } @@ -182,24 +182,16 @@ protected function matchCollection($pathinfo, RouteCollection $routes) if ($supportsTrailingSlash && (!$requiredMethods || \in_array('GET', $requiredMethods))) { return $this->allow = $this->allowSchemes = []; } - continue; } - $hasRequiredScheme = !$route->getSchemes() || $route->hasScheme($this->context->getScheme()); - if ($requiredMethods) { - if (!\in_array($method, $requiredMethods)) { - if ($hasRequiredScheme) { - $this->allow = array_merge($this->allow, $requiredMethods); - } - - continue; - } - } - - if (!$hasRequiredScheme) { + if ($route->getSchemes() && !$route->hasScheme($this->context->getScheme())) { $this->allowSchemes = array_merge($this->allowSchemes, $route->getSchemes()); + continue; + } + if ($requiredMethods && !\in_array($method, $requiredMethods)) { + $this->allow = array_merge($this->allow, $requiredMethods); continue; } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/EncodingClass.php b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/EncodingClass.php new file mode 100644 index 0000000000000..dac72e3ddcfca --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/EncodingClass.php @@ -0,0 +1,10 @@ +assertEquals('/nl/suffix', $routes->get('action.nl')->getPath()); } + /** + * @requires function mb_strtolower + */ + public function testDefaultRouteName() + { + $methodRouteData = [ + 'name' => null, + ]; + + $reader = $this->getReader(); + $reader + ->expects($this->once()) + ->method('getMethodAnnotations') + ->will($this->returnValue([new RouteAnnotation($methodRouteData)])) + ; + + $loader = new class($reader) extends AnnotationClassLoader { + protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, $annot) + { + } + }; + $routeCollection = $loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\EncodingClass'); + + $defaultName = array_keys($routeCollection->all())[0]; + + $this->assertSame($defaultName, 'symfony_component_routing_tests_fixtures_annotatedclasses_encodingclass_routeàction'); + } + public function testLoadingRouteWithPrefix() { $routes = $this->loader->load(RouteWithPrefixController::class); diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php index ac25493481ef6..9465ef05df23c 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php @@ -29,7 +29,7 @@ protected function setUp() public function testLoad() { - $this->reader->expects($this->exactly(3))->method('getClassAnnotation'); + $this->reader->expects($this->exactly(4))->method('getClassAnnotation'); $this->reader ->expects($this->any()) @@ -52,6 +52,7 @@ public function testLoadIgnoresHiddenDirectories() 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass', 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass', 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\FooClass', + 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\EncodingClass', ]); $this->reader diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index 8f99f7b8e9988..823441159a87b 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -727,6 +727,7 @@ public function testNestedCollections() /** * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException + * @expectedExceptionMessage No routes found for "/". */ public function testSchemeAndMethodMismatch() { diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf new file mode 100644 index 0000000000000..c3cd7911e55cb --- /dev/null +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf @@ -0,0 +1,67 @@ + + + + + + An authentication exception occurred. + Памылка аўтэнтыфікацыі. + + + Authentication credentials could not be found. + Дадзеныя аўтэнтыфікацыі не знойдзены. + + + Authentication request could not be processed due to a system problem. + Запыт аўтэнтыфікацыі не можа быць апрацаваны ў сувязі з праблемай у сістэме. + + + Invalid credentials. + Несапраўдныя дадзеныя аўтэнтыфікацыі. + + + Cookie has already been used by someone else. + Нехта іншы ўжо выкарыстаў гэтыя кукі (cookie). + + + Not privileged to request the resource. + Адсутнічаюць правы на запыт гэтага рэсурсу. + + + Invalid CSRF token. + Несапраўдны CSRF-токен. + + + No authentication provider found to support the authentication token. + Не знойдзен правайдар аўтэнтыфікацыі, які можа падтрымліваць гэты токен аўтэнтыфікацыі. + + + No session available, it either timed out or cookies are not enabled. + Сесія не даступна, яе час скончыўся, або кукі (cookies) выключаны. + + + No token could be found. + Токен не знойдзен. + + + Username could not be found. + Імя карыстальніка не знойдзена. + + + Account has expired. + Скончыўся тэрмін дзеяння акаўнта. + + + Credentials have expired. + Скончыўся тэрмін дзеяння дадзеных аўтэнтыфікацыі. + + + Account is disabled. + Акаўнт адключан. + + + Account is locked. + Акаўнт заблакіраван. + + + + diff --git a/src/Symfony/Component/Security/Http/Authorization/AccessDeniedHandlerInterface.php b/src/Symfony/Component/Security/Http/Authorization/AccessDeniedHandlerInterface.php index aea901181f601..871c877f57295 100644 --- a/src/Symfony/Component/Security/Http/Authorization/AccessDeniedHandlerInterface.php +++ b/src/Symfony/Component/Security/Http/Authorization/AccessDeniedHandlerInterface.php @@ -26,7 +26,7 @@ interface AccessDeniedHandlerInterface /** * Handles an access denied failure. * - * @return Response may return null + * @return Response|null */ public function handle(Request $request, AccessDeniedException $accessDeniedException); } diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index cae8593c15954..695e5216a5894 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -417,7 +417,13 @@ protected function instantiateObject(array &$data, $class, array &$context, \Ref throw new RuntimeException(sprintf('Cannot create an instance of %s from serialized data because the variadic parameter %s can only accept an array.', $class, $constructorParameter->name)); } - $params = array_merge($params, $data[$paramName]); + $variadicParameters = []; + foreach ($data[$paramName] as $parameterData) { + $variadicParameters[] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $context, $format); + } + + $params = array_merge($params, $variadicParameters); + unset($data[$key]); } } elseif ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key, $data))) { $parameterData = $data[$key]; diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php new file mode 100644 index 0000000000000..9c6fd980a1524 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +class VariadicConstructorTypedArgsDummy +{ + private $foo; + + public function __construct(Dummy ...$foo) + { + $this->foo = $foo; + } + + public function getFoo() + { + return $this->foo; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php index fbf33aa7c6393..d18fe410b2e9f 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php @@ -8,11 +8,15 @@ use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; +use Symfony\Component\Serializer\Normalizer\PropertyNormalizer; +use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Tests\Fixtures\AbstractNormalizerDummy; +use Symfony\Component\Serializer\Tests\Fixtures\Dummy; use Symfony\Component\Serializer\Tests\Fixtures\NullableConstructorArgumentDummy; use Symfony\Component\Serializer\Tests\Fixtures\ProxyDummy; use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorDummy; use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorNormalizer; +use Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorTypedArgsDummy; /** * Provides a dummy Normalizer which extends the AbstractNormalizer. @@ -121,9 +125,6 @@ public function testObjectWithStaticConstructor() $this->assertNull($dummy->foo); } - /** - * @requires PHP 7.1 - */ public function testObjectWithNullableConstructorArgument() { $normalizer = new ObjectNormalizer(); @@ -131,4 +132,18 @@ public function testObjectWithNullableConstructorArgument() $this->assertNull($dummy->getFoo()); } + + public function testObjectWithVariadicConstructorTypedArguments() + { + $normalizer = new PropertyNormalizer(); + $normalizer->setSerializer(new Serializer([$normalizer])); + $data = ['foo' => [['foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz', 'qux' => 'Qux'], ['foo' => 'FOO', 'bar' => 'BAR', 'baz' => 'BAZ', 'qux' => 'QUX']]]; + $dummy = $normalizer->denormalize($data, VariadicConstructorTypedArgsDummy::class); + + $this->assertInstanceOf(VariadicConstructorTypedArgsDummy::class, $dummy); + $this->assertCount(2, $dummy->getFoo()); + foreach ($dummy->getFoo() as $foo) { + $this->assertInstanceOf(Dummy::class, $foo); + } + } } diff --git a/src/Symfony/Component/Translation/DataCollectorTranslator.php b/src/Symfony/Component/Translation/DataCollectorTranslator.php index 68200a7f45c21..0284b77e9bcd6 100644 --- a/src/Symfony/Component/Translation/DataCollectorTranslator.php +++ b/src/Symfony/Component/Translation/DataCollectorTranslator.php @@ -68,10 +68,10 @@ public function transChoice($id, $number, array $parameters = [], $domain = null { if ($this->translator instanceof TranslatorInterface) { $trans = $this->translator->trans($id, ['%count%' => $number] + $parameters, $domain, $locale); + } else { + $trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale); } - $trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale); - $this->collectMessage($locale, $domain, $id, $trans, ['%count%' => $number] + $parameters); return $trans; diff --git a/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php b/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php index be0a548aa1f06..cf618d95a219e 100644 --- a/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Translation\Tests; use Symfony\Component\Translation\IdentityTranslator; -use Symfony\Contracts\Tests\Translation\TranslatorTest; +use Symfony\Contracts\Translation\Test\TranslatorTest; class IdentityTranslatorTest extends TranslatorTest { diff --git a/src/Symfony/Component/Translation/composer.json b/src/Symfony/Component/Translation/composer.json index 809625b5ad2f1..ca9e7f297d271 100644 --- a/src/Symfony/Component/Translation/composer.json +++ b/src/Symfony/Component/Translation/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0.2", + "symfony/contracts": "^1.1.1", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { @@ -37,7 +37,7 @@ "symfony/yaml": "<3.4" }, "provide": { - "symfony/translation-contracts-implementation": "1.0" + "symfony/translation-implementation": "1.0" }, "suggest": { "symfony/config": "", diff --git a/src/Symfony/Component/Validator/DependencyInjection/AddValidatorInitializersPass.php b/src/Symfony/Component/Validator/DependencyInjection/AddValidatorInitializersPass.php index dcc02ca694589..d7bea0fb73d94 100644 --- a/src/Symfony/Component/Validator/DependencyInjection/AddValidatorInitializersPass.php +++ b/src/Symfony/Component/Validator/DependencyInjection/AddValidatorInitializersPass.php @@ -62,7 +62,7 @@ public function process(ContainerBuilder $container) } while (!($class = $translator->getClass()) && $translator instanceof ChildDefinition) { - $translator = $translator->getParent(); + $translator = $container->findDefinition($translator->getParent()); } if (!is_subclass_of($class, LegacyTranslatorInterface::class)) { diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf new file mode 100644 index 0000000000000..ab3845ee20153 --- /dev/null +++ b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf @@ -0,0 +1,367 @@ + + + + + + This value should be false. + Значэнне павінна быць Не. + + + This value should be true. + Значэнне павінна быць Так. + + + This value should be of type {{ type }}. + Тып значэння павінен быць {{ type }}. + + + This value should be blank. + Значэнне павінна быць пустым. + + + The value you selected is not a valid choice. + Абранае вамі значэнне не сапраўднае. + + + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. + Вы павінны выбраць хаця б {{ limit }} варыянт.|Вы павінны выбраць хаця б {{ limit }} варыянтаў. + + + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. + Вы павінны выбраць не больш за {{ limit }} варыянт.|Вы павінны выбраць не больш за {{ limit }} варыянтаў. + + + One or more of the given values is invalid. + Адзін або некалькі пазначаных значэнняў з'яўляецца несапраўдным. + + + This field was not expected. + Гэта поле не чакаецца. + + + This field is missing. + Гэта поле адсутнічае. + + + This value is not a valid date. + Гэта значэнне не з'яўляецца карэктнай датай. + + + This value is not a valid datetime. + Гэта значэнне не з'яўляецца карэктнай датай i часом. + + + This value is not a valid email address. + Гэта значэнне не з'яўляецца карэктным адрасам электроннай пошты. + + + The file could not be found. + Файл не знойдзен. + + + The file is not readable. + Файл не чытаецца. + + + The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. + Файл занадта вялікі ({{ size }} {{ suffix }}). Максімальна дазволены памер {{ limit }} {{ suffix }}. + + + The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. + MIME-тып файлу некарэкты ({{ type }}). Дазволеныя MIME-тыпы файлу {{ types }}. + + + This value should be {{ limit }} or less. + Значэнне павінна быць {{ limit }} або менш. + + + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. + Значэнне занадта доўгае. Яно павінна мець {{ limit }} сімвал або менш.|Значэнне занадта доўгае. Яно павінна мець {{ limit }} сімвалаў або менш. + + + This value should be {{ limit }} or more. + Значэнне павінна быць {{ limit }} або больш. + + + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. + Значэнне занадта кароткае. Яно павінна мець прынамсі {{ limit }} сімвал.|Значэнне занадта кароткае. Яно павінна мець прынамсі {{ limit }} сімвалаў. + + + This value should not be blank. + Значэнне не павінна быць пустым. + + + This value should not be null. + Значэнне не павінна быць null. + + + This value should be null. + Значэнне павінна быць null. + + + This value is not valid. + Значэнне з'яўляецца не сапраўдным. + + + This value is not a valid time. + Значэнне не з'яўляецца сапраўдным часам. + + + This value is not a valid URL. + Значэнне не з'яўляецца сапраўдным URL-адрасам. + + + The two values should be equal. + Абодва значэнні павінны быць аднолькавымі. + + + The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. + Файл занадта вялікі. Максімальна дазволены памер {{ limit }} {{ suffix }}. + + + The file is too large. + Файл занадта вялікі. + + + The file could not be uploaded. + Немагчыма запампаваць файл. + + + This value should be a valid number. + Значэнне павінна быць лікам. + + + This file is not a valid image. + Гэты файл не з'яўляецца сапраўднай выявай. + + + This is not a valid IP address. + Значэнне не з'яўляецца сапраўдным IP-адрасам. + + + This value is not a valid language. + Значэнне не з'яўляецца сапраўдным мовай. + + + This value is not a valid locale. + Значэнне не з'яўляецца сапраўднай лакаллю. + + + This value is not a valid country. + Значэнне не з'яўляецца сапраўднай краінай. + + + This value is already used. + Гэта значэнне ўжо выкарыстоўваецца. + + + The size of the image could not be detected. + Немагчыма вызначыць памер выявы. + + + The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. + Гэта выява занадта вялікая ({{ width }}px). Дазваляецца максімальная шырыня {{ max_width }}px. + + + The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. + Гэта выява занадта маленькая ({{ width }}px). Дазваляецца мінімальная шырыня {{ min_width }}px. + + + The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. + Гэты выява занадта вялікая ({{ width }}px). Дазваляецца максімальная вышыня {{ max_width }}px. + + + The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. + Гэта выява занадта маленькая ({{ width }}px). Дазваляецца мінімальная вышыня {{ min_width }}px. + + + This value should be the user's current password. + Значэнне павінна быць цяперашнім паролем карыстальніка. + + + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. + Значэнне павінна мець {{ limit }} сімвал.|Значэнне павінна мець {{ limit }} сімвалаў. + + + The file was only partially uploaded. + Файл быў запампаваны толькі часткова. + + + No file was uploaded. + Файл не быў запампаваны. + + + No temporary folder was configured in php.ini. + У php.ini не была налажана часовая папка, або часовая папка не існуе. + + + Cannot write temporary file to disk. + Немагчыма запісаць часовы файл на дыск. + + + A PHP extension caused the upload to fail. + Пашырэнне PHP выклікала памылку загрузкі. + + + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. + Калекцыя павінна змяшчаць прынамсі {{ limit }} элемент.|Калекцыя павінна змяшчаць прынамсі {{ limit }} элементаў. + + + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. + Калекцыя павінна змяшчаць {{ limit }} або менш элемент.|Калекцыя павінна змяшчаць {{ limit }} або менш элементаў. + + + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. + Калекцыя павінна змяшчаць роўна {{ limit }} элемент.|Калекцыя павінна змяшчаць роўна {{ limit }} элементаў. + + + Invalid card number. + Несапраўдны нумар карты. + + + Unsupported card type or invalid card number. + Тып карты не падтрымліваецца або несапраўдны нумар карты. + + + This is not a valid International Bank Account Number (IBAN). + Несапраўдны міжнародны нумар банкаўскага рахунку (IBAN). + + + This value is not a valid ISBN-10. + Гэта значэнне не з'яўляецца сапраўдным ISBN-10. + + + This value is not a valid ISBN-13. + Гэта значэнне не з'яўляецца сапраўдным ISBN-13. + + + This value is neither a valid ISBN-10 nor a valid ISBN-13. + Гэта значэнне не з'яўляецца сапраўдным ISBN-10 або ISBN-13. + + + This value is not a valid ISSN. + Гэта значэнне не з'яўляецца сапраўдным ISSN. + + + This value is not a valid currency. + Гэта значэнне не з'яўляецца сапраўднай валютай. + + + This value should be equal to {{ compared_value }}. + Значэнне павінна раўняцца {{ compared_value }}. + + + This value should be greater than {{ compared_value }}. + Значэнне павінна быць больш чым {{ compared_value }}. + + + This value should be greater than or equal to {{ compared_value }}. + Значэнне павінна быць больш чым або раўняцца {{ compared_value }}. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Значэнне павінна быць ідэнтычным {{ compared_value_type }} {{ compared_value }}. + + + This value should be less than {{ compared_value }}. + Значэнне павінна быць менш чым {{ compared_value }}. + + + This value should be less than or equal to {{ compared_value }}. + Значэнне павінна быць менш чым або раўняцца {{ compared_value }}. + + + This value should not be equal to {{ compared_value }}. + Значэнне не павінна раўняцца {{ compared_value }}. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Значэнне не павінна быць ідэнтычным {{ compared_value_type }} {{ compared_value }}. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Суадносіны бакоў выявы з'яўляецца занадта вялікім ({{ ratio }}). Дазваляецца максімальныя суадносіны {{max_ratio}} . + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Суадносіны бакоў выявы з'яўляецца занадта маленькімі ({{ ratio }}). Дазваляецца мінімальныя суадносіны {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Выява квадратная ({{width}}x{{height}}px). Квадратныя выявы не дазволены. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Выява ў альбомнай арыентацыі ({{ width }}x{{ height }}px). Выявы ў альбомнай арыентацыі не дазволены. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Выява ў партрэтнай арыентацыі ({{ width }}x{{ height }}px). Выявы ў партрэтнай арыентацыі не дазволены. + + + An empty file is not allowed. + Пусты файл не дазволены. + + + The host could not be resolved. + Не магчыма знайсці імя хоста. + + + This value does not match the expected {{ charset }} charset. + Гэта значэнне не супадае з чаканай {{ charset }} кадыроўкай. + + + This is not a valid Business Identifier Code (BIC). + Несапраўдны банкаўскі ідэнтыфікацыйны код (BIC). + + + Error + Памылка + + + This is not a valid UUID. + Гэта несапраўдны UUID. + + + This value should be a multiple of {{ compared_value }}. + Значэнне павінна быць кратным {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Банкаўскі ідэнтыфікацыйны код (BIC) не звязан з IBAN {{ iban }}. + + + This value should be valid JSON. + Гэта значэнне павінна быць у фармаце JSON. + + + This collection should contain only unique elements. + Калекцыя павінна змяшчаць толькі ўнікальныя элементы. + + + This value should be positive. + Значэнне павінна быць дадатным. + + + This value should be either positive or zero. + Значэнне павінна быць дадатным ці нуль. + + + This value should be negative. + Значэнне павінна быць адмоўным. + + + This value should be either negative or zero. + Значэнне павінна быць адмоўным ці нуль. + + + This value is not a valid timezone. + Значэнне не з'яўляецца сапраўдным гадзінным поясам. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Гэты пароль быў выкрадзены ў выніку ўзлому дадзеных, таму яго нельга выкарыстоўваць. Калі ласка, выкарыстоўвайце іншы пароль. + + + + diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 9283683fee183..8b7654f537c48 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -433,6 +433,45 @@ public function testApplyWithEventDispatcher() $this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents); } + public function testApplyDoesNotTriggerExtraGuardWithEventDispatcher() + { + $transitions[] = new Transition('a-b', 'a', 'b'); + $transitions[] = new Transition('a-c', 'a', 'c'); + $definition = new Definition(['a', 'b', 'c'], $transitions); + + $subject = new \stdClass(); + $subject->marking = null; + $eventDispatcher = new EventDispatcherMock(); + $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $eventDispatcher, 'workflow_name'); + + $eventNameExpected = [ + 'workflow.guard', + 'workflow.workflow_name.guard', + 'workflow.workflow_name.guard.a-b', + 'workflow.leave', + 'workflow.workflow_name.leave', + 'workflow.workflow_name.leave.a', + 'workflow.transition', + 'workflow.workflow_name.transition', + 'workflow.workflow_name.transition.a-b', + 'workflow.enter', + 'workflow.workflow_name.enter', + 'workflow.workflow_name.enter.b', + 'workflow.entered', + 'workflow.workflow_name.entered', + 'workflow.workflow_name.entered.b', + 'workflow.completed', + 'workflow.workflow_name.completed', + 'workflow.workflow_name.completed.a-b', + 'workflow.announce', + 'workflow.workflow_name.announce', + ]; + + $marking = $workflow->apply($subject, 'a-b'); + + $this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents); + } + public function testEventName() { $definition = $this->createComplexWorkflowDefinition(); diff --git a/src/Symfony/Contracts/README.md b/src/Symfony/Contracts/README.md index 9cb73af23f1dd..6725488e9d006 100644 --- a/src/Symfony/Contracts/README.md +++ b/src/Symfony/Contracts/README.md @@ -16,8 +16,8 @@ Design Principles * they must be backward compatible with existing Symfony components. Packages that implement specific contracts should list them in the "provide" -section of their "composer.json" file, using the `symfony/*-contracts-implementation` -convention (e.g. `"provide": { "symfony/cache-contracts-implementation": "1.0" }`). +section of their "composer.json" file, using the `symfony/*-implementation` +convention (e.g. `"provide": { "symfony/cache-implementation": "1.0" }`). FAQ --- diff --git a/src/Symfony/Contracts/Tests/Service/ServiceLocatorTest.php b/src/Symfony/Contracts/Service/Test/ServiceLocatorTest.php similarity index 98% rename from src/Symfony/Contracts/Tests/Service/ServiceLocatorTest.php rename to src/Symfony/Contracts/Service/Test/ServiceLocatorTest.php index 22487a8992791..69594583f5985 100644 --- a/src/Symfony/Contracts/Tests/Service/ServiceLocatorTest.php +++ b/src/Symfony/Contracts/Service/Test/ServiceLocatorTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Contracts\Tests\Service; +namespace Symfony\Contracts\Service\Test; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; diff --git a/src/Symfony/Contracts/Tests/Translation/TranslatorTest.php b/src/Symfony/Contracts/Translation/Test/TranslatorTest.php similarity index 99% rename from src/Symfony/Contracts/Tests/Translation/TranslatorTest.php rename to src/Symfony/Contracts/Translation/Test/TranslatorTest.php index ac5f9c7aebe18..48466300b5abf 100644 --- a/src/Symfony/Contracts/Tests/Translation/TranslatorTest.php +++ b/src/Symfony/Contracts/Translation/Test/TranslatorTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Contracts\Tests\Translation; +namespace Symfony\Contracts\Translation\Test; use PHPUnit\Framework\TestCase; use Symfony\Contracts\Translation\TranslatorInterface; diff --git a/src/Symfony/Contracts/composer.json b/src/Symfony/Contracts/composer.json index 2f198a0c3b330..9701f4b253592 100644 --- a/src/Symfony/Contracts/composer.json +++ b/src/Symfony/Contracts/composer.json @@ -25,9 +25,9 @@ "suggest": { "psr/cache": "When using the Cache contracts", "psr/container": "When using the Service contracts", - "symfony/cache-contracts-implementation": "", - "symfony/service-contracts-implementation": "", - "symfony/translation-contracts-implementation": "" + "symfony/cache-implementation": "", + "symfony/service-implementation": "", + "symfony/translation-implementation": "" }, "autoload": { "psr-4": { "Symfony\\Contracts\\": "" }, diff --git a/src/Symfony/Contracts/phpunit.xml.dist b/src/Symfony/Contracts/phpunit.xml.dist index e222d9f5a7ecf..fd93d020f23f8 100644 --- a/src/Symfony/Contracts/phpunit.xml.dist +++ b/src/Symfony/Contracts/phpunit.xml.dist @@ -15,6 +15,8 @@ ./Tests/ + ./Service/Test/ + ./Translation/Test/ @@ -23,6 +25,8 @@ ./ ./Tests + ./Service/Test/ + ./Translation/Test/ ./vendor