diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 9c126e2ef2422..c5c9bfecf4d09 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -52,5 +52,4 @@ jobs: - name: Psalm run: | - ./vendor/bin/psalm.phar --no-progress - ./vendor/bin/psalm.phar --output-format=github --no-progress + ./vendor/bin/psalm.phar --no-progress || ./vendor/bin/psalm.phar --output-format=github --no-progress diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 430d67c4c8cda..1eefe6f5583c6 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -15,18 +15,18 @@ jobs: runs-on: Ubuntu-20.04 env: - extensions: amqp,apcu,igbinary,intl,mbstring,memcached,mongodb,redis + extensions: amqp,apcu,igbinary,intl,mbstring,memcached,mongodb,redis-5.3.4 strategy: matrix: include: - php: '7.2' - - php: '8.0' + - php: '8.1' - php: '7.4' mode: high-deps - php: '8.0' mode: low-deps - - php: '8.1' + - php: '8.2' mode: experimental fail-fast: false @@ -36,11 +36,10 @@ jobs: with: fetch-depth: 2 - - name: Configure for PHP 8.1 - if: "${{ matrix.php == '8.1' }}" + - name: Configure for PHP >= 8.2 + if: "${{ matrix.php >= '8.2' }}" run: | - echo "extensions=mbstring" >> $GITHUB_ENV - composer config platform.php 8.0.99 + composer config platform.php 8.1.99 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -136,7 +135,7 @@ jobs: echo "::endgroup::" - name: Patch return types - if: "${{ matrix.php == '8.0' && ! matrix.mode }}" + if: "${{ matrix.php == '8.1' && ! matrix.mode }}" run: | sed -i 's/"\*\*\/Tests\/"//' composer.json composer install -q --optimize-autoloader diff --git a/CHANGELOG-5.3.md b/CHANGELOG-5.3.md index c949725e03b9b..bd3f2385357e7 100644 --- a/CHANGELOG-5.3.md +++ b/CHANGELOG-5.3.md @@ -7,6 +7,38 @@ in 5.3 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/v5.3.0...v5.3.1 +* 5.3.8 (2021-09-28) + + * bug #43206 [Workflow] Add missing audit-trail settings in framework workflow con… (Stephan Wentz) + * bug #42354 [Ldap][Security] Make LdapAuthenticator an EntryPoint (dcp-dev, chalasr) + * bug #43146 [SecurityBundle] Fixed LogicException message of FirewallAwareTrait (fkropfhamer) + * bug #43158 [Cache] Fix invalidating tags on Redis <5 (wouterj) + * bug #43179 [Ldap] Fix `resource` type checks & docblocks on PHP 8.1 (chalasr) + * bug #43174 [Messenger] relax parameter type (xabbuh) + * bug #43137 [FrameworkBundle] Avoid secrets:decrypt-to-local command to fail (noniagriconomie) + * bug #43171 [VarDumper] fix dumping typed references from properties (nicolas-grekas) + * bug #43124 [Messenger] [Redis] Allow authentication with user and password (GaryPEGEOT) + * bug #39350 [FrameworkBundle] Remove translation data_collector BEFORE adding it to profiler (l-vo) + * bug #43115 [DependencyInjection] Fix iterator in ServiceConfigurator (jderusse) + * bug #43073 [Notifier] Update FirebaseTransport.php (dima-gr) + * bug #43031 [Form] Do not trim unassigned unicode characters (simonberger) + * bug #43058 [WebProfilerBundle] Fix displaying certain configs (HypeMC) + * bug #43022 [PhpUnitBridge] Track unsilenced deprecations only for userland (nicolas-grekas) + * bug #42979 [FrameworkBundle] fix session-related BC layer triggering deprecation (nicolas-grekas) + * bug #42672 [PropertyAccess] Fix Regression in PropertyAccessor::isWritable() (haase-fabian) + * bug #42976 [Mime] Allow array as input for RawMessage (derrabus) + * bug #42932 [Messenger] Support rediss in transport bridge (RuslanZavacky) + * bug #42771 [FrameworkBundle] Match 5.3 and 5.1 mailer configuration (wizardz) + * bug #42098 [PropertyInfo] Support for intersection types (derrabus) + * bug #42904 [Cache] Make sure PdoAdapter::prune() always returns a bool (derrabus) + * bug #42896 [HttpClient] Fix handling timeouts when responses are destructed (nicolas-grekas) + * bug #42862 [Framework] Clean "about" command help after Environment section was removed (GromNaN) + * bug #42835 [Cache] Fix implicit float to int cast (derrabus) + * bug #42831 [Mime] Update mime types (fabpot) + * bug #42830 [HttpKernel] Fix empty timeline in profiler (nicodmf) + * bug #42815 [DependencyInjection] Fix circular reference in autowired decorators (shyim) + * bug #42819 Fix tests failing with DBAL 3 (derrabus) + * 5.3.7 (2021-08-30) * bug #42769 [HttpClient] Don't pass float to `usleep()` (derrabus) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5c9b27862671f..f804602f54457 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -12,10 +12,10 @@ The Symfony Connect username in parenthesis allows to get more information - Tobias Schultze (tobion) - Robin Chalas (chalas_r) - Christophe Coevoet (stof) + - Wouter De Jong (wouterj) - Jérémy DERUSSÉ (jderusse) - Maxime Steinhausser (ogizanagi) - Kévin Dunglas (dunglas) - - Wouter De Jong (wouterj) - Grégoire Pineau (lyrixx) - Jordi Boggiano (seldaek) - Victor Berchet (victor) @@ -48,11 +48,11 @@ The Symfony Connect username in parenthesis allows to get more information - Eriksen Costa (eriksencosta) - Ener-Getick (energetick) - Sarah Khalil (saro0h) - - Pierre du Plessis (pierredup) - Kevin Bond (kbond) + - Pierre du Plessis (pierredup) + - Valentin Udaltsov (vudaltsov) - Iltar van der Berg (kjarli) - Jonathan Wage (jwage) - - Valentin Udaltsov (vudaltsov) - Matthias Pigulla (mpdude) - Vasilij Duško (staff) - Diego Saint Esteben (dosten) @@ -91,6 +91,7 @@ The Symfony Connect username in parenthesis allows to get more information - Issei Murasawa (issei_m) - Eric Clemmons (ericclemmons) - Charles Sarrazin (csarrazi) + - Antoine M (amakdessi) - Vasilij Dusko - Douglas Greenshields (shieldo) - Graham Campbell (graham) @@ -99,7 +100,6 @@ The Symfony Connect username in parenthesis allows to get more information - Deni - Henrik Westphal (snc) - Dariusz Górecki (canni) - - Antoine M (amakdessi) - Fran Moreno (franmomu) - Dariusz Ruminski - Jérôme Vasseur (jvasseur) @@ -112,26 +112,27 @@ The Symfony Connect username in parenthesis allows to get more information - Bart van den Burg (burgov) - Jordan Alliot (jalliot) - John Wards (johnwards) + - Alexander Schranz (alexander-schranz) - Baptiste Clavié (talus) - Antoine Hérault (herzult) - Paráda József (paradajozsef) - - Alexander Schranz (alexander-schranz) - Arnaud Le Blanc (arnaud-lb) - Przemysław Bogusz (przemyslaw-bogusz) + - Vincent Langlet (deviling) - Maxime STEINHAUSSER + - Tomas Norkūnas (norkunas) - Michal Piotrowski (eventhorizon) - Tomáš Votruba (tomas_votruba) - Massimiliano Arione (garak) - Mathias Arlaud (mtarld) - Tim Nagel (merk) - - Vincent Langlet (deviling) - Chris Wilkinson (thewilkybarkid) - - Tomas Norkūnas (norkunas) - Peter Kokot (maastermedia) - Lars Strojny (lstrojny) - Brice BERNARD (brikou) - Ahmed TAILOULOUTE (ahmedtai) - Gregor Harlan (gharlan) + - HypeMC (hypemc) - marc.weistroff - lenar - Alexander Schwenn (xelaris) @@ -144,29 +145,29 @@ The Symfony Connect username in parenthesis allows to get more information - Jacob Dreesen (jdreesen) - Malte Schlüter (maltemaltesich) - Joel Wurtz (brouznouf) + - Théo FIDRY (theofidry) - Florian Voutzinos (florianv) - Teoh Han Hui (teohhanhui) - Colin Frei - Javier Spagnoletti (phansys) - Joshua Thijssen - - HypeMC (hypemc) - Daniel Wehner (dawehner) - Tugdual Saunier (tucksaun) - excelwebzone - Gordon Franke (gimler) - Saif Eddin Gmati (azjezz) + - Alexandre Daubois (alexandre-daubois) - Jesse Rushlow (geeshoe) - Fabien Pennequin (fabienpennequin) - - Théo FIDRY (theofidry) - Olivier Dolbeau (odolbeau) - - Alexandre Daubois (alexandre-daubois) + - Smaine Milianni (ismail1432) + - Richard van Laak (rvanlaak) - Eric GELOEN (gelo) - Matthieu Napoli (mnapoli) - Jannik Zschiesche (apfelbox) - Mathieu Santostefano (welcomattic) - Robert Schönthal (digitalkaoz) - Florian Lonqueu-Brochard (florianlb) - - Richard van Laak (rvanlaak) - Tigran Azatyan (tigranazatyan) - YaFou - Gary PEGEOT (gary-p) @@ -183,10 +184,10 @@ The Symfony Connect username in parenthesis allows to get more information - Hidenori Goto (hidenorigoto) - Jan Rosier (rosier) - Alessandro Chitolina (alekitto) + - Ruud Kamphuis (ruudk) - Albert Casademont (acasademont) - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) - - Smaine Milianni (ismail1432) - SpacePossum - Pablo Godel (pgodel) - Andreas Braun @@ -194,7 +195,6 @@ The Symfony Connect username in parenthesis allows to get more information - François-Xavier de Guillebon (de-gui_f) - Oleg Voronkovich - hacfi (hifi) - - Ruud Kamphuis (ruudk) - Rafael Dohms (rdohms) - George Mponos (gmponos) - jwdeitch @@ -215,6 +215,7 @@ The Symfony Connect username in parenthesis allows to get more information - Timo Bakx (timobakx) - Marco Pivetta (ocramius) - Vincent Touzet (vincenttouzet) + - Nate Wiebe (natewiebe13) - Rouven Weßling (realityking) - Jérôme Parmentier (lctrs) - Ben Davies (bendavies) @@ -248,6 +249,7 @@ The Symfony Connect username in parenthesis allows to get more information - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) - Mathieu Lechat (mat_the_cat) + - Jeroen Noten (jeroennoten) - Marek Štípek (maryo) - Daniel Espendiller - Possum @@ -263,7 +265,6 @@ The Symfony Connect username in parenthesis allows to get more information - Hidde Wieringa (hiddewie) - Antonio Pauletich (x-coder264) - Andre Rømcke (andrerom) - - Nate Wiebe (natewiebe13) - Philippe Segatori - Thibaut Cheymol (tcheymol) - Sebastien Morel (plopix) @@ -287,10 +288,10 @@ The Symfony Connect username in parenthesis allows to get more information - François Pluchino (francoispluchino) - Rokas Mikalkėnas (rokasm) - bronze1man - - Jeroen Noten (jeroennoten) - sun (sun) - Larry Garfield (crell) - Edi Modrić (emodric) + - Gocha Ossinkine (ossinkine) - Roman Martinuk (a2a4) - Leo Feyer (leofeyer) - Nikolay Labinskiy (e-moe) @@ -314,8 +315,10 @@ The Symfony Connect username in parenthesis allows to get more information - Dustin Whittle (dustinwhittle) - jeff - John Kary (johnkary) + - zairig imad (zairigimad) - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) + - Maciej Malarz (malarzm) - Michele Orselli (orso) - Sven Paulus (subsven) - Daniel STANCU @@ -330,7 +333,6 @@ The Symfony Connect username in parenthesis allows to get more information - Bohan Yang (brentybh) - Pascal Montoya - Julien Brochet (mewt) - - Gocha Ossinkine (ossinkine) - Tristan Darricau (nicofuma) - Victor Bocharsky (bocharsky_bw) - Bozhidar Hristov (warxcell) @@ -360,12 +362,10 @@ The Symfony Connect username in parenthesis allows to get more information - Manuel Reinhard (sprain) - Harm van Tilborg (hvt) - Danny Berger (dpb587) - - zairig imad (zairigimad) - Antonio J. García Lagar (ajgarlag) - Adam Prager (padam87) - Judicaël RUFFIEUX (axanagor) - Benoît Burnichon (bburnichon) - - Maciej Malarz (malarzm) - Roman Marintšenko (inori) - Xavier Montaña Carreras (xmontana) - Mickaël Andrieu (mickaelandrieu) @@ -400,6 +400,7 @@ The Symfony Connect username in parenthesis allows to get more information - Bob den Otter (bopp) - Thomas Schulz (king2500) - Frank de Jonge (frenkynet) + - Artem Henvald (artemgenvald) - Lescot Edouard (idetox) - Nikita Konstantinov - Wodor Wodorski @@ -422,10 +423,12 @@ The Symfony Connect username in parenthesis allows to get more information - Roumen Damianoff (roumen) - Kim Hemsø Rasmussen (kimhemsoe) - Oleg Andreyev + - Martin Herndl (herndlm) - Pavel Kirpitsov (pavel-kirpichyov) - Pascal Luna (skalpa) - Wouter Van Hecke - Iker Ibarguren (ikerib) + - Bob van de Vijver (bobvandevijver) - Peter Kruithof (pkruithof) - Michael Holm (hollo) - Sylvain Fabre (sylfabre) @@ -437,6 +440,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gonzalo Vilaseca (gonzalovilaseca) - Ben Hakim - Haralan Dobrev (hkdobrev) + - Marco Petersen (ocrampete16) - MatTheCat - Vilius Grigaliūnas - David Badura (davidbadura) @@ -493,7 +497,6 @@ The Symfony Connect username in parenthesis allows to get more information - Oleksandr Barabolia (oleksandrbarabolia) - Christopher Davis (chrisguitarguy) - ivan - - Artem Henvald (artemgenvald) - Greg Anderson - Tri Pham (phamuyentri) - BoShurik @@ -519,15 +522,14 @@ The Symfony Connect username in parenthesis allows to get more information - Inal DJAFAR (inalgnu) - Christian Gärtner (dagardner) - Dmytro Borysovskyi (dmytr0) - - Bob van de Vijver (bobvandevijver) - Tomasz Kowalczyk (thunderer) - Artur Eshenbrener + - Soner Sayakci - Thomas Perez (scullwm) - Felix Labrecque - Yaroslav Kiliba - Terje Bråten - Renan Gonçalves (renan_saddam) - - Marco Petersen (ocrampete16) - Tarmo Leppänen (tarlepp) - Martin Auswöger - Robbert Klarenbeek (robbertkl) @@ -536,6 +538,7 @@ The Symfony Connect username in parenthesis allows to get more information - JhonnyL - hossein zolfi (ocean) - Clément Gautier (clementgautier) + - Koen Reiniers (koenre) - Dāvis Zālītis (k0d3r1s) - Sanpi - Eduardo Gulias (egulias) @@ -617,6 +620,7 @@ The Symfony Connect username in parenthesis allows to get more information - Valentin Jonovs (valentins-jonovs) - Bastien DURAND (deamon) - Jeanmonod David (jeanmonod) + - Christin Gruber (christingruber) - Andrey Sevastianov - Webnet team (webnet) - Urinbayev Shakhobiddin (shokhaa) @@ -666,6 +670,7 @@ The Symfony Connect username in parenthesis allows to get more information - Andrew M-Y (andr) - Krasimir Bosilkov (kbosilkov) - Marcin Michalski (marcinmichalski) + - Yoann RENARD (yrenard) - Vitaliy Tverdokhlib (vitaliytv) - Ariel Ferrandini (aferrandini) - Niklas Keller @@ -676,7 +681,6 @@ The Symfony Connect username in parenthesis allows to get more information - Tim Goudriaan (codedmonkey) - Jonas Flodén (flojon) - AnneKir - - Soner Sayakci - Tobias Weichart - Miro Michalicka - Marcin Sikoń (marphi) @@ -692,7 +696,6 @@ The Symfony Connect username in parenthesis allows to get more information - Christian Wahler - Giso Stallenberg (gisostallenberg) - Gintautas Miselis - - Koen Reiniers (koenre) - Rob Bast - Roberto Espinoza (respinoza) - Pierre Rineau @@ -725,10 +728,13 @@ The Symfony Connect username in parenthesis allows to get more information - Jan van Thoor (janvt) - Gladhon - Joshua Nye + - Martin Kirilov (wucdbm) - Nathan Dench (ndenc2) + - Thibault Richard (t-richard) - Sebastian Bergmann - Miroslav Sustek - Pablo Díez (pablodip) + - SiD (plbsid) - Michel Roca (mroca) - Piotr Kugla (piku235) - Kevin McBride @@ -777,8 +783,10 @@ The Symfony Connect username in parenthesis allows to get more information - Norbert Orzechowicz (norzechowicz) - Denis Charrier (brucewouaigne) - Matthijs van den Bos (matthijs) + - Simon Podlipsky (simpod) - DemigodCode - Jaik Dean (jaikdean) + - Pavel Popov (metaer) - Lenard Palko - arai - Nils Adermann (naderman) @@ -824,6 +832,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jeremy Benoist - Lenar Lõhmus - Daniël Brekelmans (dbrekelmans) + - Simon Heimberg (simon_heimberg) - Benjamin Laugueux (yzalis) - Zach Badgett (zachbadgett) - Aurélien Fredouelle @@ -860,7 +869,6 @@ The Symfony Connect username in parenthesis allows to get more information - Jules Matsounga (hyoa) - Quentin Dequippe (qdequippe) - khoptynskyi - - Christin Gruber (christingruber) - Jean-Christophe Cuvelier [Artack] - julien57 - Julien Montel (julienmgel) @@ -914,6 +922,7 @@ The Symfony Connect username in parenthesis allows to get more information - Nahuel Cuesta (ncuesta) - Chris Boden (cboden) - Christophe Villeger (seragan) + - Hendrik Luup - Julien Fredon - Jacek Wilczyński (jacekwilczynski) - Xavier Leune (xleune) @@ -954,7 +963,6 @@ The Symfony Connect username in parenthesis allows to get more information - Mardari Dorel (dorumd) - Daisuke Ohata - Vincent Simonin - - Yoann RENARD (yrenard) - Alex Bogomazov (alebo) - maxime.steinhausser - Claus Due (namelesscoder) @@ -987,7 +995,6 @@ The Symfony Connect username in parenthesis allows to get more information - rtek - Benjamin Dos Santos - Jérémy Jarrié (gagnar) - - Martin Herndl (herndlm) - Tomas Javaisis - Ivan Grigoriev - Johann Saunier (prophet777) @@ -1058,7 +1065,6 @@ The Symfony Connect username in parenthesis allows to get more information - mohammadreza honarkhah - develop - flip111 - - Thibault Richard (t-richard) - VJ - RJ Garcia - Adam Wójs (awojs) @@ -1081,7 +1087,6 @@ The Symfony Connect username in parenthesis allows to get more information - Andrea Sprega (asprega) - Alexander Volochnev (exelenz) - Viktor Bajraktar (njutn95) - - SiD (plbsid) - Mbechezi Nawo - Michael Piecko - Toni Peric (tperic) @@ -1144,7 +1149,6 @@ The Symfony Connect username in parenthesis allows to get more information - michaelwilliams - Romain - Matěj Humpál - - Martin Kirilov - Pierre Grimaud (pgrimaud) - Alexandre Parent - 1emming @@ -1182,6 +1186,7 @@ The Symfony Connect username in parenthesis allows to get more information - Krzysiek Łabuś - Juraj Surman - Camille Dejoye + - Fabien S (bafs) - 1ma (jautenim) - Douglas Hammond (wizhippo) - Xavier Lacot (xavier) @@ -1204,7 +1209,6 @@ The Symfony Connect username in parenthesis allows to get more information - roromix - Dmitry Pigin (dotty) - Vincent Composieux (eko) - - Simon Podlipsky (simpod) - Jayson Xu (superjavason) - Hubert Lenoir (hubert_lenoir) - fago @@ -1248,6 +1252,7 @@ The Symfony Connect username in parenthesis allows to get more information - Aleksandar Jakovljevic (ajakov) - Laurent Bassin (lbassin) - Hamza Makraz (makraz) + - Tomasz Ignatiuk - andrey1s - Abhoryo - Fabian Vogler (fabian) @@ -1269,11 +1274,13 @@ The Symfony Connect username in parenthesis allows to get more information - Tony Malzhacker - Pchol - Mathieu MARCHOIS + - W0rma - Cyril Quintin (cyqui) - Cyrille Bourgois (cyrilleb) - Gerard van Helden (drm) - Johnny Peck (johnnypeck) - Marcos Rezende (rezehnde) + - Roman Anasal - Ivan Menshykov - David Romaní - Patrick Allaert @@ -1344,7 +1351,6 @@ The Symfony Connect username in parenthesis allows to get more information - Harry Walter (haswalt) - Johnson Page (jwpage) - Ruben Gonzalez (rubenruateltek) - - Simon Heimberg (simon_heimberg) - Michael Roterman (wtfzdotnet) - Arno Geurts - Adán Lobato (adanlobato) @@ -1412,6 +1418,7 @@ The Symfony Connect username in parenthesis allows to get more information - Antoine Bluchet (soyuka) - Patrick Kaufmann - Anton Dyshkant + - Paul Oms - Reece Fowell (reecefowell) - stefan.r - Guillaume Gammelin @@ -1558,6 +1565,7 @@ The Symfony Connect username in parenthesis allows to get more information - Maximilian Berghoff (electricmaxxx) - nacho - Piotr Antosik (antek88) + - Volker Killesreiter (ol0lll) - Vedran Mihočinec (v-m-i) - Sergey Novikov (s12v) - creiner @@ -1677,6 +1685,7 @@ The Symfony Connect username in parenthesis allows to get more information - rchoquet - gitlost - Taras Girnyk + - Dmitry Derepko - Jan Vernarsky - Amine Yakoubi - Eduardo García Sanz (coma) @@ -1686,7 +1695,9 @@ The Symfony Connect username in parenthesis allows to get more information - James Gilliland - fduch (fduch) - Juan Miguel Besada Vidal (soutlink) + - dlorek - Stuart Fyfe + - Carl Casbolt (carlcasbolt) - David de Boer (ddeboer) - Eno Mullaraj (emullaraj) - Nathan PAGE (nathix) @@ -1695,6 +1706,7 @@ The Symfony Connect username in parenthesis allows to get more information - arnaud (arnooo999) - Gilles Doge (gido) - Oscar Esteve (oesteve) + - Peter Potrowl - abulford - Philipp Kretzschmar - antograssiot @@ -1762,10 +1774,12 @@ The Symfony Connect username in parenthesis allows to get more information - Christian Rishøj - Patrick Berenschot - SuRiKmAn + - rtek - Jelte Steijaert (jelte) - David Négrier (moufmouf) - Quique Porta (quiqueporta) - Artem Oliynyk (artemoliynyk) + - Ben Roberts (benr77) - Andrea Quintino (dirk39) - Tomasz Szymczyk (karion) - Alex Vasilchenko @@ -1896,7 +1910,6 @@ The Symfony Connect username in parenthesis allows to get more information - Luis Galeas - Bogdan Scordaliu - Martin Pärtel - - Fabien S (bafs) - Daniel Rotter (danrot) - Frédéric Bouchery (fbouchery) - kylekatarnls (kylekatarnls) @@ -1921,6 +1934,7 @@ The Symfony Connect username in parenthesis allows to get more information - Guillaume BRETOU (guiguiboy) - Nikita Popov (nikic) - Carsten Nielsen (phreaknerd) + - Michael Olšavský - Jay Severson - Benny Born - Emirald Mateli @@ -2049,6 +2063,7 @@ The Symfony Connect username in parenthesis allows to get more information - Antonio Peric-Mazar (antonioperic) - César Suárez (csuarez) - Bjorn Twachtmann (dotbjorn) + - Wahyu Kristianto (kristories) - Tobias Genberg (lorceroth) - Nicolas Badey (nico-b) - Shane Preece (shane) @@ -2112,6 +2127,7 @@ The Symfony Connect username in parenthesis allows to get more information - Joni Halme - Matt Farmer - catch + - aetxebeste - siganushka - Alexandre Segura - Josef Cech @@ -2192,6 +2208,7 @@ The Symfony Connect username in parenthesis allows to get more information - David Stone - jjanvier - Julius Beckmann + - Ruben Jansen - shreypuranik - loru88 - Thibaut Salanon @@ -2261,6 +2278,7 @@ The Symfony Connect username in parenthesis allows to get more information - Alessio Baglio (ioalessio) - Johannes Müller (johmue) - Jordi Llonch (jordillonch) + - Jordi Sala Morales (jsala) - Mouad ZIANI (mouadziani) - Nicholas Ruunu (nicholasruunu) - Jeroen van den Nieuwenhuisen (nieuwenhuisen) @@ -2275,8 +2293,8 @@ The Symfony Connect username in parenthesis allows to get more information - alex - Nicole Cordes - Nicolas PHILIPPE - - Roman Anasal - Roman Orlov + - Simon Ackermann - VolCh - Alexey Popkov - Gijs Kunze @@ -2437,6 +2455,7 @@ The Symfony Connect username in parenthesis allows to get more information - Filipe Guerra - Jean Ragouin - Gerben Wijnja + - Emre YILMAZ - Rowan Manning - Per Modin - David Windell @@ -2521,6 +2540,7 @@ The Symfony Connect username in parenthesis allows to get more information - Bart Reunes (metalarend) - Muriel (metalmumu) - Michael Pohlers (mick_the_big) + - Misha Klomp (mishaklomp) - mlpo (mlpo) - Marek Šimeček (mssimi) - Dmitriy Tkachenko (neka) @@ -2598,6 +2618,7 @@ The Symfony Connect username in parenthesis allows to get more information - temperatur - misterx - Cas + - Vincent Godé - Dusan Kasan - Michael Steininger - Nardberjean @@ -2628,6 +2649,7 @@ The Symfony Connect username in parenthesis allows to get more information - Michel Bardelmeijer - Tomas Kmieliauskas - Ikko Ashimine + - Brad Jones - Billie Thompson - lol768 - jamogon @@ -2681,6 +2703,7 @@ The Symfony Connect username in parenthesis allows to get more information - James Michael DuPont - Kasperki - Tammy D + - Rodolfo Ruiz - Enrico - Ryan Rud - Ondrej Slinták @@ -2701,6 +2724,7 @@ The Symfony Connect username in parenthesis allows to get more information - Markus Staab - Pierre-Louis LAUNAY - djama + - Benjamin Rosenberger - Vladyslav Startsev - Michael Gwynne - Eduardo Conceição @@ -2717,6 +2741,7 @@ The Symfony Connect username in parenthesis allows to get more information - nsbx - Shude - Richard Hodgson + - Sven Fabricius - Ondřej Führer - Sema - Thorsten Hallwas @@ -2760,6 +2785,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sam Anthony - Christian Stocker - Oussama Elgoumri + - Steve Marvell - Dawid Nowak - Lesnykh Ilia - sabruss @@ -2823,6 +2849,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gerry Vandermaesen (gerryvdm) - Ghazy Ben Ahmed (ghazy) - Arash Tabriziyan (ghost098) + - Greg Szczotka (greg606) - ibasaw (ibasaw) - Vladislav Krupenkin (ideea) - Ilija Tovilo (ilijatovilo) diff --git a/README.md b/README.md index 52860457b2336..02417bc9835d2 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,8 @@ If you discover a security vulnerability within Symfony, please follow our About Us -------- -Symfony development is sponsored by [SensioLabs][21], led by the -[Symfony Core Team][22] and supported by [Symfony contributors][19]. +Symfony development is led by the [Symfony Core Team][22] +and supported by [Symfony contributors][19]. [1]: https://symfony.com [2]: https://symfony.com/projects @@ -80,7 +80,6 @@ Symfony development is sponsored by [SensioLabs][21], led by the [18]: https://symfony.com/doc/current/contributing/documentation/index.html [19]: https://symfony.com/contributors [20]: https://symfony.com/security -[21]: https://sensiolabs.com [22]: https://symfony.com/doc/current/contributing/code/core_team.html [23]: https://github.com/symfony/symfony-demo [24]: https://symfony.com/coc diff --git a/psalm.xml b/psalm.xml index 3f12f1331c272..015c0ed18b21b 100644 --- a/psalm.xml +++ b/psalm.xml @@ -17,4 +17,15 @@ + + + + + + + + + + + diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 1f7f6afe4cc0f..6c0c0b9bc721d 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -166,7 +166,7 @@ public function getTypes(string $class, string $property, array $context = []) case Type::BUILTIN_TYPE_ARRAY: switch ($typeOfField) { case Types::ARRAY: - case Types::JSON_ARRAY: + case 'json_array': return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)]; case Types::SIMPLE_ARRAY: @@ -280,7 +280,7 @@ private function getPhpType(string $doctrineType): ?string case Types::ARRAY: case Types::SIMPLE_ARRAY: - case Types::JSON_ARRAY: + case 'json_array': return Type::BUILTIN_TYPE_ARRAY; } diff --git a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php index 01dce37978c94..5b6b37525426a 100644 --- a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php +++ b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php @@ -13,6 +13,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver\Result as DriverResult; +use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Result; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Types\Types; @@ -57,7 +58,7 @@ public function loadTokenBySeries(string $series) // the alias for lastUsed works around case insensitivity in PostgreSQL $sql = 'SELECT class, username, value, lastUsed AS last_used FROM rememberme_token WHERE series=:series'; $paramValues = ['series' => $series]; - $paramTypes = ['series' => \PDO::PARAM_STR]; + $paramTypes = ['series' => ParameterType::STRING]; $stmt = $this->conn->executeQuery($sql, $paramValues, $paramTypes); $row = $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchAssociative() : $stmt->fetch(\PDO::FETCH_ASSOC); @@ -75,7 +76,7 @@ public function deleteTokenBySeries(string $series) { $sql = 'DELETE FROM rememberme_token WHERE series=:series'; $paramValues = ['series' => $series]; - $paramTypes = ['series' => \PDO::PARAM_STR]; + $paramTypes = ['series' => ParameterType::STRING]; if (method_exists($this->conn, 'executeStatement')) { $this->conn->executeStatement($sql, $paramValues, $paramTypes); } else { @@ -95,9 +96,9 @@ public function updateToken(string $series, string $tokenValue, \DateTime $lastU 'series' => $series, ]; $paramTypes = [ - 'value' => \PDO::PARAM_STR, + 'value' => ParameterType::STRING, 'lastUsed' => Types::DATETIME_MUTABLE, - 'series' => \PDO::PARAM_STR, + 'series' => ParameterType::STRING, ]; if (method_exists($this->conn, 'executeStatement')) { $updated = $this->conn->executeStatement($sql, $paramValues, $paramTypes); @@ -124,10 +125,10 @@ public function createNewToken(PersistentTokenInterface $token) 'lastUsed' => $token->getLastUsed(), ]; $paramTypes = [ - 'class' => \PDO::PARAM_STR, - 'username' => \PDO::PARAM_STR, - 'series' => \PDO::PARAM_STR, - 'value' => \PDO::PARAM_STR, + 'class' => ParameterType::STRING, + 'username' => ParameterType::STRING, + 'series' => ParameterType::STRING, + 'value' => ParameterType::STRING, 'lastUsed' => Types::DATETIME_MUTABLE, ]; if (method_exists($this->conn, 'executeStatement')) { diff --git a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php index 9c31d6d7e76b4..35fc48ff1536f 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php @@ -11,9 +11,9 @@ namespace Symfony\Bridge\Doctrine\Tests\DataCollector; +use Doctrine\DBAL\Connection; use Doctrine\DBAL\Logging\DebugStack; -use Doctrine\DBAL\Platforms\MySqlPlatform; -use Doctrine\DBAL\Version; +use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\Persistence\ManagerRegistry; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector; @@ -22,6 +22,9 @@ use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Dumper\CliDumper; +// Doctrine DBAL 2 compatibility +class_exists(\Doctrine\DBAL\Platforms\MySqlPlatform::class); + class DoctrineDataCollectorTest extends TestCase { public function testCollectConnections() @@ -93,6 +96,8 @@ public function testCollectQueries($param, $types, $expected, $explainable, bool $dumper->setColors(false); $collectedParam->dump($dumper); $this->assertStringMatchesFormat($expected, print_r(stream_get_contents($out, -1, 0), true)); + } elseif (\is_string($expected)) { + $this->assertStringMatchesFormat($expected, $collectedParam); } else { $this->assertEquals($expected, $collectedParam); } @@ -150,7 +155,7 @@ public function testReset() /** * @dataProvider paramProvider */ - public function testSerialization($param, $types, $expected, $explainable, bool $runnable = true) + public function testSerialization($param, array $types, $expected, $explainable, bool $runnable = true) { $queries = [ ['sql' => 'SELECT * FROM table1 WHERE field1 = ?1', 'params' => [$param], 'types' => $types, 'executionMS' => 1], @@ -167,6 +172,8 @@ public function testSerialization($param, $types, $expected, $explainable, bool $dumper->setColors(false); $collectedParam->dump($dumper); $this->assertStringMatchesFormat($expected, print_r(stream_get_contents($out, -1, 0), true)); + } elseif (\is_string($expected)) { + $this->assertStringMatchesFormat($expected, $collectedParam); } else { $this->assertEquals($expected, $collectedParam); } @@ -175,9 +182,9 @@ public function testSerialization($param, $types, $expected, $explainable, bool $this->assertSame($runnable, $collectedQueries['default'][0]['runnable']); } - public function paramProvider() + public function paramProvider(): array { - $tests = [ + return [ ['some value', [], 'some value', true], [1, [], 1, true], [true, [], true, true], @@ -207,30 +214,25 @@ public function paramProvider() , false, ], - ]; - - if (version_compare(Version::VERSION, '2.6', '>=')) { - $tests[] = ['this is not a date', ['date'], "⚠ Could not convert PHP value 'this is not a date' of type 'string' to type 'date'. Expected one of the following types: null, DateTime", false, false]; - $tests[] = [ + ['this is not a date', ['date'], "⚠ Could not convert PHP value 'this is not a date'%S to type %Sdate%S. Expected one of the following types: null, DateTime", false, false], + [ new \stdClass(), ['date'], <<getMockBuilder(\Doctrine\DBAL\Connection::class) + $connection = $this->getMockBuilder(Connection::class) ->disableOriginalConstructor() ->getMock(); $connection->expects($this->any()) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php index 63cba7387c4a1..90cf50684d5d9 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php @@ -296,9 +296,9 @@ public function testLoadChoicesForValuesDoesNotLoadIfEmptyValues() /** * @group legacy */ - public function legacyTestLoadChoicesForValuesLoadsOnlyChoicesIfValueUseIdReader() + public function testLegacyLoadChoicesForValuesLoadsOnlyChoicesIfValueUseIdReader() { - $this->expectDeprecation('Not defining explicitly the IdReader as value callback when query can be optimized has been deprecated in 5.1. Don\'t pass the IdReader to "Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader" or define the choice_value instead.'); + $this->expectDeprecation('Since symfony/doctrine-bridge 5.1: Not defining explicitly the IdReader as value callback when query can be optimized is deprecated. Don\'t pass the IdReader to "Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader" or define the "choice_value" option instead.'); $loader = new DoctrineChoiceLoader( $this->om, $this->class, diff --git a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php index f99a48527c442..be63ef923dfbc 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php @@ -103,9 +103,12 @@ public function testInvalidEntityManagerThrowsException() public function testMiddlewareNoPingInNonWorkerContext() { - $this->connection->expects($this->never()) - ->method('ping') - ->willReturn(false); + // This method has been removed in DBAL 3.0 + if (method_exists(Connection::class, 'ping')) { + $this->connection->expects($this->never()) + ->method('ping') + ->willReturn(false); + } $this->connection->expects($this->never()) ->method('close') diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 152ed0ea75da2..49957bd989e7b 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -52,6 +52,7 @@ }, "conflict": { "doctrine/dbal": "<2.10", + "doctrine/orm": "<2.7.3", "phpunit/phpunit": "<5.4.3", "symfony/dependency-injection": "<4.4", "symfony/form": "<5.1", diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index 32461976f04b8..c2a524c44f699 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -142,7 +142,7 @@ public function handleError($type, $msg, $file, $line, $context = []) $msg = $deprecation->getMessage(); - if (error_reporting() & $type) { + if (\E_DEPRECATED !== $type && (error_reporting() & $type)) { $group = 'unsilenced'; } elseif ($deprecation->isLegacy()) { $group = 'legacy'; diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php index 3e359a04cbc42..05e7c3c6767b4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php @@ -44,9 +44,6 @@ protected function configure() The PHP section displays important configuration that could affect your application. The values might be different between web and CLI. - -The Environment section displays the current environment variables managed by Symfony Dotenv. It will not -be shown if no variables were found. The values might be different between web and CLI. EOT ) ; diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php index bf737308c5450..0e07d88fa3eb7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php @@ -91,9 +91,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($secrets as $k => $v) { if (null === $v) { - $io->error($this->vault->getLastMessage()); - - return 1; + $io->error($this->vault->getLastMessage() ?? sprintf('Secret "%s" has been skipped as there was an error reading it.', $k)); + continue; } $this->localVault->seal($k, $v); diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 7f439bb572f87..c35dc91a52c58 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -122,6 +122,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new RegisterControllerArgumentLocatorsPass()); $container->addCompilerPass(new RemoveEmptyControllerArgumentLocatorsPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new RoutingResolverPass()); + $container->addCompilerPass(new DataCollectorTranslatorPass()); $container->addCompilerPass(new ProfilerPass()); // must be registered before removing private services as some might be listeners/subscribers // but as late as possible to get resolved parameters @@ -141,7 +142,6 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new FragmentRendererPass()); $this->addCompilerPassIfExists($container, SerializerPass::class); $this->addCompilerPassIfExists($container, PropertyInfoPass::class); - $container->addCompilerPass(new DataCollectorTranslatorPass()); $container->addCompilerPass(new ControllerArgumentValueResolverPass()); $container->addCompilerPass(new CachePoolPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 32); $container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING); diff --git a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php index 8ded6a2ee4320..7d4475a7e21ca 100644 --- a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php +++ b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php @@ -128,11 +128,14 @@ public function loginUser(object $user, string $firewallContext = 'main'): self $container = $this->getContainer(); $container->get('security.untracked_token_storage')->setToken($token); - if (!$container->has('session') && !$container->has('session_factory')) { + if ($container->has('session.factory')) { + $session = $container->get('session.factory')->createSession(); + } elseif ($container->has('session')) { + $session = $container->get('session'); + } else { return $this; } - $session = $container->get($container->has('session') ? 'session' : 'session_factory'); $session->set('_security_'.$firewallContext, serialize($token)); $session->save(); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php index 350a6b27d7dc6..b15b29270afd4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php @@ -73,5 +73,9 @@ ->tag('kernel.event_subscriber') ->tag('kernel.reset', ['method' => 'reset']) ->deprecate('symfony/framework-bundle', '5.2', 'The "%service_id%" service is deprecated, use "mailer.message_logger_listener" instead.') + + ->set('mailer.message_logger_listener', MessageLoggerListener::class) + ->tag('kernel.event_subscriber') + ->tag('kernel.reset', ['method' => 'reset']) ; }; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php index 5bc56faad5a05..3fb6ce0a42d49 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php @@ -24,9 +24,5 @@ 'template' => '@WebProfiler/Collector/mailer.html.twig', 'id' => 'mailer', ]) - - ->set('mailer.message_logger_listener', MessageLoggerListener::class) - ->tag('kernel.event_subscriber') - ->tag('kernel.reset', ['method' => 'reset']) ; }; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index edcaca3a90018..bc46570744d16 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -310,6 +310,7 @@ + @@ -339,6 +340,19 @@ + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml index 290ab50e7d8da..79361af57a61f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml @@ -8,6 +8,7 @@ + draft Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest @@ -42,6 +43,7 @@ + start Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php index 70d9178f8ab19..d79d0b7a1df53 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php @@ -29,7 +29,7 @@ private function getForFirewall(): object { $serviceIdentifier = str_replace('FirewallAware', '', static::class); if (null === $request = $this->requestStack->getCurrentRequest()) { - throw new \LogicException('Cannot determine the correct '.$serviceIdentifier.' to use: there is no active Request and so, the firewall cannot be determined. Try using a specific '.$serviceIdentifier().' service.'); + throw new \LogicException('Cannot determine the correct '.$serviceIdentifier.' to use: there is no active Request and so, the firewall cannot be determined. Try using a specific '.$serviceIdentifier.' service.'); } $firewall = $this->firewallMap->getFirewallConfig($request); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Security/UserAuthenticatorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Security/UserAuthenticatorTest.php new file mode 100644 index 0000000000000..ecb9cd8e7e33d --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Security/UserAuthenticatorTest.php @@ -0,0 +1,34 @@ +expectException(\LogicException::class); + $this->expectExceptionMessage('Cannot determine the correct Symfony\Bundle\SecurityBundle\Security\UserAuthenticator to use: there is no active Request and so, the firewall cannot be determined. Try using a specific Symfony\Bundle\SecurityBundle\Security\UserAuthenticator service.'); + + $userAuthenticator->authenticateUser($user, $authenticator, $request); + } +} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig index 7792ea6730a0f..6dfd27bcbc67a 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig @@ -116,14 +116,14 @@ Symfony version - {% if 'n/a' != collector.env %} + {% if 'n/a' is not same as(collector.env) %}
{{ collector.env }} Environment
{% endif %} - {% if 'n/a' != collector.debug %} + {% if 'n/a' is not same as(collector.debug) %}
{{ collector.debug ? 'enabled' : 'disabled' }} Debug diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index 0cfd10ae86be8..efba9eb54a799 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -116,7 +116,7 @@ public static function createSystemCache(string $namespace, int $defaultLifetime return $opcache; } - $apcu = new ApcuAdapter($namespace, (int) $defaultLifetime / 5, $version); + $apcu = new ApcuAdapter($namespace, intdiv($defaultLifetime, 5), $version); if (null !== $logger) { $apcu->setLogger($logger); } diff --git a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php index 568490c2fce76..b54841f0c0fbc 100644 --- a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php @@ -17,7 +17,9 @@ use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Exception\TableNotFoundException; +use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Statement; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Marshaller\DefaultMarshaller; use Symfony\Component\Cache\Marshaller\MarshallerInterface; @@ -191,19 +193,29 @@ public function prune() $deleteSql .= " AND $this->idCol LIKE :namespace"; } + $connection = $this->getConnection(); + $useDbalConstants = $connection instanceof Connection; + try { - $delete = $this->getConnection()->prepare($deleteSql); + $delete = $connection->prepare($deleteSql); } catch (TableNotFoundException $e) { return true; } catch (\PDOException $e) { return true; } - $delete->bindValue(':time', time(), \PDO::PARAM_INT); + $delete->bindValue(':time', time(), $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); if ('' !== $this->namespace) { - $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), \PDO::PARAM_STR); + $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), $useDbalConstants ? ParameterType::STRING : \PDO::PARAM_STR); } try { + // Doctrine DBAL ^2.13 || >= 3.1 + if ($delete instanceof Statement && method_exists($delete, 'executeStatement')) { + $delete->executeStatement(); + + return true; + } + return $delete->execute(); } catch (TableNotFoundException $e) { return true; @@ -217,13 +229,16 @@ public function prune() */ protected function doFetch(array $ids) { + $connection = $this->getConnection(); + $useDbalConstants = $connection instanceof Connection; + $now = time(); $expired = []; $sql = str_pad('', (\count($ids) << 1) - 1, '?,'); $sql = "SELECT $this->idCol, CASE WHEN $this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ? THEN $this->dataCol ELSE NULL END FROM $this->table WHERE $this->idCol IN ($sql)"; - $stmt = $this->getConnection()->prepare($sql); - $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT); + $stmt = $connection->prepare($sql); + $stmt->bindValue($i = 1, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); foreach ($ids as $id) { $stmt->bindValue(++$i, $id); } @@ -247,8 +262,8 @@ protected function doFetch(array $ids) if ($expired) { $sql = str_pad('', (\count($expired) << 1) - 1, '?,'); $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ? AND $this->idCol IN ($sql)"; - $stmt = $this->getConnection()->prepare($sql); - $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT); + $stmt = $connection->prepare($sql); + $stmt->bindValue($i = 1, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); foreach ($expired as $id) { $stmt->bindValue(++$i, $id); } @@ -261,11 +276,14 @@ protected function doFetch(array $ids) */ protected function doHave(string $id) { + $connection = $this->getConnection(); + $useDbalConstants = $connection instanceof Connection; + $sql = "SELECT 1 FROM $this->table WHERE $this->idCol = :id AND ($this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > :time)"; - $stmt = $this->getConnection()->prepare($sql); + $stmt = $connection->prepare($sql); $stmt->bindValue(':id', $id); - $stmt->bindValue(':time', time(), \PDO::PARAM_INT); + $stmt->bindValue(':time', time(), $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); $result = $stmt->execute(); return (bool) (\is_object($result) ? $result->fetchOne() : $stmt->fetchColumn()); @@ -328,6 +346,8 @@ protected function doSave(array $values, int $lifetime) } $conn = $this->getConnection(); + $useDbalConstants = $conn instanceof Connection; + $driver = $this->driver; $insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"; @@ -379,25 +399,25 @@ protected function doSave(array $values, int $lifetime) if ('sqlsrv' === $driver || 'oci' === $driver) { $stmt->bindParam(1, $id); $stmt->bindParam(2, $id); - $stmt->bindParam(3, $data, \PDO::PARAM_LOB); - $stmt->bindValue(4, $lifetime, \PDO::PARAM_INT); - $stmt->bindValue(5, $now, \PDO::PARAM_INT); - $stmt->bindParam(6, $data, \PDO::PARAM_LOB); - $stmt->bindValue(7, $lifetime, \PDO::PARAM_INT); - $stmt->bindValue(8, $now, \PDO::PARAM_INT); + $stmt->bindParam(3, $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB); + $stmt->bindValue(4, $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $stmt->bindValue(5, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $stmt->bindParam(6, $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB); + $stmt->bindValue(7, $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $stmt->bindValue(8, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); } else { $stmt->bindParam(':id', $id); - $stmt->bindParam(':data', $data, \PDO::PARAM_LOB); - $stmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT); - $stmt->bindValue(':time', $now, \PDO::PARAM_INT); + $stmt->bindParam(':data', $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB); + $stmt->bindValue(':lifetime', $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $stmt->bindValue(':time', $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); } if (null === $driver) { $insertStmt = $conn->prepare($insertSql); $insertStmt->bindParam(':id', $id); - $insertStmt->bindParam(':data', $data, \PDO::PARAM_LOB); - $insertStmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT); - $insertStmt->bindValue(':time', $now, \PDO::PARAM_INT); + $insertStmt->bindParam(':data', $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB); + $insertStmt->bindValue(':lifetime', $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $insertStmt->bindValue(':time', $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); } foreach ($values as $id => $data) { diff --git a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php index 304d173737193..58456e6835061 100644 --- a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php @@ -15,6 +15,7 @@ use Predis\Connection\Aggregate\PredisCluster; use Predis\Connection\Aggregate\ReplicationInterface; use Predis\Response\Status; +use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\LogicException; use Symfony\Component\Cache\Marshaller\DeflateMarshaller; @@ -163,6 +164,12 @@ protected function doDeleteYieldTags(array $ids): iterable }); foreach ($results as $id => $result) { + if ($result instanceof \RedisException) { + CacheItem::log($this->logger, 'Failed to delete key "{key}": '.$result->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $result]); + + continue; + } + try { yield $id => !\is_string($result) || '' === $result ? [] : $this->marshaller->unmarshall($result); } catch (\Exception $e) { @@ -201,6 +208,8 @@ protected function doInvalidate(array $tagIds): bool // gargage collect that set from the client side. $lua = <<<'EOLUA' + redis.replicate_commands() + local cursor = '0' local id = KEYS[1] repeat @@ -238,6 +247,8 @@ protected function doInvalidate(array $tagIds): bool }); $lua = <<<'EOLUA' + redis.replicate_commands() + local id = KEYS[1] local cursor = table.remove(ARGV) redis.call('SREM', '{'..id..'}'..id, unpack(ARGV)) @@ -245,7 +256,17 @@ protected function doInvalidate(array $tagIds): bool return redis.call('SSCAN', '{'..id..'}'..id, cursor, 'COUNT', 5000) EOLUA; - foreach ($results as $id => [$cursor, $ids]) { + $success = true; + foreach ($results as $id => $values) { + if ($values instanceof \RedisException) { + CacheItem::log($this->logger, 'Failed to invalidate key "{key}": '.$values->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $values]); + $success = false; + + continue; + } + + [$cursor, $ids] = $values; + while ($ids || '0' !== $cursor) { $this->doDelete($ids); @@ -268,7 +289,7 @@ protected function doInvalidate(array $tagIds): bool } } - return true; + return $success; } private function getRedisEvictionPolicy(): string diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index bf0c89bb1d935..b67fb5cd0cc79 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -227,7 +227,7 @@ public function testPrune() $doSet('qux', 'qux-val', new \DateInterval('PT20S')); sleep(30); - $cache->prune(); + $this->assertTrue($cache->prune()); $this->assertTrue($this->isPruned($cache, 'foo')); $this->assertTrue($this->isPruned($cache, 'bar')); $this->assertTrue($this->isPruned($cache, 'baz')); @@ -238,27 +238,27 @@ public function testPrune() $doSet('baz', 'baz-val', new \DateInterval('PT40S')); $doSet('qux', 'qux-val', new \DateInterval('PT80S')); - $cache->prune(); + $this->assertTrue($cache->prune()); $this->assertFalse($this->isPruned($cache, 'foo')); $this->assertFalse($this->isPruned($cache, 'bar')); $this->assertFalse($this->isPruned($cache, 'baz')); $this->assertFalse($this->isPruned($cache, 'qux')); sleep(30); - $cache->prune(); + $this->assertTrue($cache->prune()); $this->assertFalse($this->isPruned($cache, 'foo')); $this->assertTrue($this->isPruned($cache, 'bar')); $this->assertFalse($this->isPruned($cache, 'baz')); $this->assertFalse($this->isPruned($cache, 'qux')); sleep(30); - $cache->prune(); + $this->assertTrue($cache->prune()); $this->assertFalse($this->isPruned($cache, 'foo')); $this->assertTrue($this->isPruned($cache, 'baz')); $this->assertFalse($this->isPruned($cache, 'qux')); sleep(30); - $cache->prune(); + $this->assertTrue($cache->prune()); $this->assertFalse($this->isPruned($cache, 'foo')); $this->assertTrue($this->isPruned($cache, 'qux')); } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index b77568be593e6..ddfc5fd382143 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -153,8 +153,10 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot, $this->decoratedClass = null; $this->getPreviousValue = null; - if ($isRoot && ($definition = $this->container->getDefinition($this->currentId)) && null !== ($this->decoratedId = $definition->innerServiceId) && $this->container->has($this->decoratedId)) { - $this->decoratedClass = $this->container->findDefinition($this->decoratedId)->getClass(); + if ($isRoot && ($definition = $this->container->getDefinition($this->currentId)) && ($decoratedDefinition = $definition->getDecoratedService()) && null !== ($innerId = $decoratedDefinition[0]) && $this->container->has($innerId)) { + // If the class references to itself and is decorated, provide the inner service id and class to not get a circular reference + $this->decoratedClass = $this->container->findDefinition($innerId)->getClass(); + $this->decoratedId = $decoratedDefinition[1] ?? $this->currentId.'.inner'; } foreach ($this->methodCalls as $i => $call) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php index f4f61ab46a8b2..96d6fd75a7764 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php @@ -32,8 +32,8 @@ public function __destruct() { // default tags should be added last foreach ($this->defaultTags as $name => $attributes) { - foreach ($attributes as $attributes) { - $this->definition->addTag($name, $attributes); + foreach ($attributes as $attribute) { + $this->definition->addTag($name, $attribute); } } $this->defaultTags = []; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index b61dc64fe8234..33e9adecfb4ea 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -985,8 +985,8 @@ public function testAutowireDecorator() ->setAutowired(true) ; - (new DecoratorServicePass())->process($container); (new AutowirePass())->process($container); + (new DecoratorServicePass())->process($container); $definition = $container->getDefinition(Decorator::class); $this->assertSame(Decorator::class.'.inner', (string) $definition->getArgument(1)); @@ -1008,8 +1008,8 @@ public function testAutowireDecoratorChain() ->setAutowired(true) ; - (new DecoratorServicePass())->process($container); (new AutowirePass())->process($container); + (new DecoratorServicePass())->process($container); $definition = $container->getDefinition(DecoratedDecorator::class); $this->assertSame(DecoratedDecorator::class.'.inner', (string) $definition->getArgument(0)); @@ -1026,8 +1026,8 @@ public function testAutowireDecoratorRenamedId() ->setAutowired(true) ; - (new DecoratorServicePass())->process($container); (new AutowirePass())->process($container); + (new DecoratorServicePass())->process($container); $definition = $container->getDefinition(Decorator::class); $this->assertSame('renamed', (string) $definition->getArgument(1)); @@ -1044,12 +1044,11 @@ public function testDoNotAutowireDecoratorWhenSeveralArgumentOfTheType() ->setAutowired(true) ; - (new DecoratorServicePass())->process($container); try { (new AutowirePass())->process($container); $this->fail('AutowirePass should have thrown an exception'); } catch (AutowiringFailedException $e) { - $this->assertSame('Cannot autowire service "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator": argument "$decorated1" of method "__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DecoratorInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator", "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator.inner".', (string) $e->getMessage()); + $this->assertSame('Cannot autowire service "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator": argument "$decorated1" of method "__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DecoratorInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "Symfony\Component\DependencyInjection\Tests\Compiler\Decorated", "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator".', (string) $e->getMessage()); } } @@ -1106,4 +1105,23 @@ public function testArgumentWithTarget() $this->assertSame(BarInterface::class.' $imageStorage', (string) $container->getDefinition('with_target')->getArgument(0)); } + + public function testDecorationWithServiceAndAliasedInterface() + { + $container = new ContainerBuilder(); + + $container->register(DecoratorImpl::class, DecoratorImpl::class) + ->setAutowired(true) + ->setPublic(true); + $container->setAlias(DecoratorInterface::class, DecoratorImpl::class)->setPublic(true); + $container->register(DecoratedDecorator::class, DecoratedDecorator::class) + ->setAutowired(true) + ->setPublic(true) + ->setDecoratedService(DecoratorImpl::class); + + $container->compile(); + + static::assertInstanceOf(DecoratedDecorator::class, $container->get(DecoratorInterface::class)); + static::assertInstanceOf(DecoratedDecorator::class, $container->get(DecoratorImpl::class)); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php index 3714936b4df2b..5bf9465a7a2dd 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php @@ -382,6 +382,10 @@ interface DecoratorInterface { } +class DecoratorImpl implements DecoratorInterface +{ +} + class Decorated implements DecoratorInterface { public function __construct($quz = null, \NonExistent $nonExistent = null, DecoratorInterface $decorated = null, array $foo = []) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.my.xlf b/src/Symfony/Component/Form/Resources/translations/validators.my.xlf new file mode 100644 index 0000000000000..b0180c551172f --- /dev/null +++ b/src/Symfony/Component/Form/Resources/translations/validators.my.xlf @@ -0,0 +1,139 @@ + + + + + + This form should not contain extra fields. + ဤ ဖောင်သည် field အပိုများ မပါ၀င်သင့်ပါ။ + + + The uploaded file was too large. Please try to upload a smaller file. + Upload တင်သောဖိုင်သည်အလွန်ကြီးလွန်းသည်။ ကျေးဇူးပြု၍ သေးငယ်သည့်ဖိုင်ကိုတင်ရန်ကြိုးစားပါ။ + + + The CSRF token is invalid. Please try to resubmit the form. + သင့်လျှော်သော် CSRF တိုကင် မဟုတ်ပါ။ ကျေးဇူးပြု၍ဖောင်ကိုပြန်တင်ပါ။ + + + This value is not a valid HTML5 color. + ဤတန်ဖိုးသည် သင့်လျှော်သော် HTML5 အရောင်မဟုတ်ပါ။ + + + Please enter a valid birthdate. + ကျေးဇူးပြု၍ မှန်ကန်သောမွေးနေ့ကိုထည့်ပါ။ + + + The selected choice is invalid. + သင့် ရွေးချယ်မှုသည်မမှန်ကန်ပါ။ + + + The collection is invalid. + ဤ collection သည်သင့်လျှော်သော် collection မဟုတ်ပါ။ + + + Please select a valid color. + ကျေးဇူးပြု၍ မှန်ကန်သောအရောင်ကိုရွေးပါ။ + + + Please select a valid country. + ကျေးဇူးပြု၍ မှန်ကန်သောနိုင်ငံကိုရွေးပါ။ + + + Please select a valid currency. + ကျေးဇူးပြု၍ မှန်ကန်သောငွေကြေးကိုရွေးပါ။ + + + Please choose a valid date interval. + ကျေးဇူးပြု၍ မှန်ကန်သောနေ ရက်စွဲကိုရွေးပါ။ + + + Please enter a valid date and time. + ကျေးဇူးပြု၍ မှန်ကန်သောနေ ရက်စွဲနှင့်အချိန် ကိုထည့်ပါ။ + + + Please enter a valid date. + ကျေးဇူးပြု၍ မှန်ကန်သောနေ ရက်စွဲကိုထည့်ပါ။ + + + Please select a valid file. + ကျေးဇူးပြု၍ မှန်ကန်သောနေ ဖိုင်ကိုရွေးချယ်ပါ။ + + + The hidden field is invalid. + မသင့် လျှော်သော် hidden field ဖြစ်နေသည်။ + + + Please enter an integer. + ကျေးဇူးပြု၍ Integer တန်ဖိုးသာထည့်ပါ။ + + + Please select a valid language. + ကျေးဇူးပြု၍ မှန်ကန်သော ဘာသာစကားကိုရွေးချယ်ပါ။ + + + Please select a valid locale. + ကျေးဇူးပြု၍ မှန်ကန်သော locale ကိုရွေးချယ်ပါ။ + + + Please enter a valid money amount. + ကျေးဇူးပြု၍ မှန်ကန်သော ပိုက်ဆံပမာဏ ကိုထည့်ပါ။ + + + Please enter a number. + ကျေးဇူးပြု၍ မှန်ကန်သော နံပါတ် ကိုရွေးချယ်ပါ။ + + + The password is invalid. + မှန်ကန်သောစကား၀ှက်မဟုတ်ပါ။ + + + Please enter a percentage value. + ကျေးဇူးပြု၍ ရာခိုင်နှုန်းတန်ဖိုးထည့်ပါ။ + + + The values do not match. + တန်ဖိုးများကိုက်ညီမှုမရှိပါ။ + + + Please enter a valid time. + ကျေးဇူးပြု၍ မှန်ကန်သောအချိန်ကိုထည့်ပါ။ + + + Please select a valid timezone. + ကျေးဇူးပြု၍ မှန်ကန်သောအချိန်ဇုန်ကိုရွေးပါ။ + + + Please enter a valid URL. + ကျေးဇူးပြု၍ သင့်လျှော်သော် URL ကိုရွေးပါ။ + + + Please enter a valid search term. + ကျေးဇူးပြု၍ သင့် လျှော်သော်ရှာဖွေမှု term များထည့်ပါ။ + + + Please provide a valid phone number. + ကျေးဇူးပြု၍ သင့် လျှော်သော်ရှာဖွေမှု ဖုန်းနံပါတ်ထည့်ပါ။ + + + The checkbox has an invalid value. + Checkbox တန်ဖိုးသည် မှန်ကန်မှုမရှိပါ။ + + + Please enter a valid email address. + ကျေးဇူးပြု၍ မှန်ကန်သော် email လိပ်စာထည့်ပါ။ + + + Please select a valid option. + ကျေးဇူးပြု၍ မှန်ကန်သော် ရွေးချယ်မှု ကိုရွေးပါ။ + + + Please select a valid range. + ကျေးဇူးပြု၍ မှန်ကန်သော အပိုင်းအခြား ကိုရွေးပါ။ + + + Please enter a valid week. + ကျေးဇူးပြု၍ မှန်ကန်သောရက်သတ္တပတ်ကိုထည့်ပါ။ + + + + diff --git a/src/Symfony/Component/Form/Tests/Util/StringUtilTest.php b/src/Symfony/Component/Form/Tests/Util/StringUtilTest.php index 1d162250d1568..3058a2e25d84d 100644 --- a/src/Symfony/Component/Form/Tests/Util/StringUtilTest.php +++ b/src/Symfony/Component/Form/Tests/Util/StringUtilTest.php @@ -16,11 +16,20 @@ class StringUtilTest extends TestCase { - public function testTrim() + public function trimProvider() { - $data = ' Foo! '; + return [ + [' Foo! ', 'Foo!'], + ["\u{1F92E}", "\u{1F92E}"], // unassigned character in PCRE versions of assertEquals('Foo!', StringUtil::trim($data)); + /** + * @dataProvider trimProvider + */ + public function testTrim($data, $expectedData) + { + $this->assertSame($expectedData, StringUtil::trim($data)); } /** diff --git a/src/Symfony/Component/Form/Util/StringUtil.php b/src/Symfony/Component/Form/Util/StringUtil.php index 851baf0c19ecb..a33b506b157da 100644 --- a/src/Symfony/Component/Form/Util/StringUtil.php +++ b/src/Symfony/Component/Form/Util/StringUtil.php @@ -31,7 +31,7 @@ private function __construct() */ public static function trim(string $string) { - if (null !== $result = @preg_replace('/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $string)) { + if (null !== $result = @preg_replace('/^[\pZ\p{Cc}\p{Cf}]+|[\pZ\p{Cc}\p{Cf}]+$/u', '', $string)) { return $result; } diff --git a/src/Symfony/Component/HttpClient/Internal/ClientState.php b/src/Symfony/Component/HttpClient/Internal/ClientState.php index c316e7b078920..52fe3c8c054c7 100644 --- a/src/Symfony/Component/HttpClient/Internal/ClientState.php +++ b/src/Symfony/Component/HttpClient/Internal/ClientState.php @@ -22,4 +22,5 @@ class ClientState { public $handlesActivity = []; public $openHandles = []; + public $lastTimeout; } diff --git a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php index 1e64959df8e0b..06518f1a2cb3a 100644 --- a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php +++ b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php @@ -57,13 +57,13 @@ public function __construct(HttpClientInterface $client, string $method, string } $this->response = $client->request($method, $url, ['buffer' => false] + $options); $this->passthru = $passthru; - $this->initializer = static function (self $response) { + $this->initializer = static function (self $response, float $timeout = null) { if (null === $response->shouldBuffer) { return false; } while (true) { - foreach (self::stream([$response]) as $chunk) { + foreach (self::stream([$response], $timeout) as $chunk) { if ($chunk->isTimeout() && $response->passthru) { foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, new TransportException($chunk->getError()))) as $chunk) { if ($chunk->isFirst()) { @@ -179,6 +179,7 @@ public function __destruct() if ($this->initializer && null === $this->getInfo('error')) { try { + self::initialize($this, -0.0); $this->getHeaders(true); } catch (HttpExceptionInterface $httpException) { // no-op diff --git a/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php b/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php index f3c8e149f77f7..1dd8c1f071e04 100644 --- a/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php @@ -145,15 +145,15 @@ public function __wakeup() */ abstract protected function close(): void; - private static function initialize(self $response): void + private static function initialize(self $response, float $timeout = null): void { if (null !== $response->getInfo('error')) { throw new TransportException($response->getInfo('error')); } try { - if (($response->initializer)($response)) { - foreach (self::stream([$response]) as $chunk) { + if (($response->initializer)($response, $timeout)) { + foreach (self::stream([$response], $timeout) as $chunk) { if ($chunk->isFirst()) { break; } diff --git a/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php b/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php index 8c490bcd5b826..105b375d35615 100644 --- a/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php @@ -138,7 +138,7 @@ private function doDestruct() $this->shouldBuffer = true; if ($this->initializer && null === $this->info['error']) { - self::initialize($this); + self::initialize($this, -0.0); $this->checkStatusCode(); } } @@ -159,6 +159,12 @@ public static function stream(iterable $responses, float $timeout = null): \Gene $lastActivity = microtime(true); $elapsedTimeout = 0; + if ($fromLastTimeout = 0.0 === $timeout && '-0' === (string) $timeout) { + $timeout = null; + } elseif ($fromLastTimeout = 0 > $timeout) { + $timeout = -$timeout; + } + while (true) { $hasActivity = false; $timeoutMax = 0; @@ -172,15 +178,21 @@ public static function stream(iterable $responses, float $timeout = null): \Gene foreach ($responses as $j => $response) { $timeoutMax = $timeout ?? max($timeoutMax, $response->timeout); $timeoutMin = min($timeoutMin, $response->timeout, 1); + + if ($fromLastTimeout && null !== $multi->lastTimeout) { + $elapsedTimeout = microtime(true) - $multi->lastTimeout; + } + $chunk = false; if (isset($multi->handlesActivity[$j])) { - // no-op + $multi->lastTimeout = null; } elseif (!isset($multi->openHandles[$j])) { unset($responses[$j]); continue; } elseif ($elapsedTimeout >= $timeoutMax) { $multi->handlesActivity[$j] = [new ErrorChunk($response->offset, sprintf('Idle timeout reached for "%s".', $response->getInfo('url')))]; + $multi->lastTimeout ?? $multi->lastTimeout = $lastActivity; } else { continue; } diff --git a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php index 0c91fb65d1b4c..0dfca6d4a2f97 100644 --- a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpClient\AsyncDecoratorTrait; use Symfony\Component\HttpClient\DecoratorTrait; +use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpClient\Response\AsyncContext; use Symfony\Component\HttpClient\Response\AsyncResponse; use Symfony\Contracts\HttpClient\ChunkInterface; @@ -29,6 +30,10 @@ protected function getHttpClient(string $testCase, \Closure $chunkFilter = null, $this->markTestSkipped("AsyncDecoratorTrait doesn't cache handles"); } + if ('testTimeoutOnDestruct' === $testCase) { + return HttpClient::create(); + } + $chunkFilter = $chunkFilter ?? static function (ChunkInterface $chunk, AsyncContext $context) { yield $chunk; }; return new class($decoratedClient ?? parent::getHttpClient($testCase), $chunkFilter) implements HttpClientInterface { @@ -49,6 +54,15 @@ public function request(string $method, string $url, array $options = []): Respo }; } + public function testTimeoutOnDestruct() + { + if (HttpClient::create() instanceof NativeHttpClient) { + $this->markTestSkipped('NativeHttpClient doesn\'t support opening concurrent requests.'); + } + + HttpClientTestCase::testTimeoutOnDestruct(); + } + public function testRetry404() { $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) { diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php index 7ad91fd6bf8b1..87a460741e334 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php @@ -32,6 +32,15 @@ abstract class HttpClientTestCase extends BaseHttpClientTestCase { private static $vulcainStarted = false; + public function testTimeoutOnDestruct() + { + if (!method_exists(parent::class, 'testTimeoutOnDestruct')) { + $this->markTestSkipped('BaseHttpClientTestCase doesn\'t have testTimeoutOnDestruct().'); + } + + parent::testTimeoutOnDestruct(); + } + public function testAcceptHeader() { $client = $this->getHttpClient(__FUNCTION__); diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php index fcb871b1bc360..6ddb663ac2273 100644 --- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -236,6 +236,10 @@ protected function getHttpClient(string $testCase): HttpClientInterface $this->markTestSkipped('Real transport required'); break; + case 'testTimeoutOnDestruct': + $this->markTestSkipped('Real transport required'); + break; + case 'testDestruct': $this->markTestSkipped("MockHttpClient doesn't timeout on destruct"); break; diff --git a/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php index 819124f1745b4..8080a90d20682 100644 --- a/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php @@ -26,6 +26,11 @@ public function testInformationalResponseStream() $this->markTestSkipped('NativeHttpClient doesn\'t support informational status codes.'); } + public function testTimeoutOnDestruct() + { + $this->markTestSkipped('NativeHttpClient doesn\'t support opening concurrent requests.'); + } + public function testHttp2PushVulcain() { $this->markTestSkipped('NativeHttpClient doesn\'t support HTTP/2.'); diff --git a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php index 4e95603fb81c4..169366d076b79 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php @@ -45,7 +45,7 @@ public function collect(Request $request, Response $response, \Throwable $except } $this->data = [ - 'token' => $response->headers->get('X-Debug-Token'), + 'token' => $request->attributes->get('_stopwatch_token'), 'start_time' => $startTime * 1000, 'events' => [], 'stopwatch_installed' => class_exists(Stopwatch::class, false), diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 21e7e8543254b..027eef0baacf9 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -75,11 +75,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '5.3.7'; - public const VERSION_ID = 50307; + public const VERSION = '5.3.8'; + public const VERSION_ID = 50308; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 3; - public const RELEASE_VERSION = 7; + public const RELEASE_VERSION = 8; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '01/2022'; diff --git a/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php b/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php index 0c6f1543acfdd..26b323f81051a 100644 --- a/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php @@ -32,9 +32,11 @@ public function testClearPool() $pool = $this->createMock(CacheItemPoolInterface::class); $pool ->expects($this->once()) - ->method('clear'); + ->method('clear') + ->willReturn(true) + ; - (new Psr6CacheClearer(['pool' => $pool]))->clearPool('pool'); + $this->assertTrue((new Psr6CacheClearer(['pool' => $pool]))->clearPool('pool')); } public function testClearPoolThrowsExceptionOnUnreferencedPool() diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php index 22ace783a3134..7dbc439d70b62 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php @@ -249,7 +249,8 @@ public function testNoExceptionOnNonExistentTypeHintOptionalArg() $pass->process($container); $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertSame(['foo::barAction', 'foo::fooAction'], array_keys($locator)); + + $this->assertEqualsCanonicalizing(['foo::barAction', 'foo::fooAction'], array_keys($locator)); } public function testArgumentWithNoTypeHintIsOk() @@ -396,7 +397,7 @@ public function testAlias() $pass->process($container); $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertSame([RegisterTestController::class.'::fooAction', 'foo::fooAction'], array_keys($locator)); + $this->assertEqualsCanonicalizing([RegisterTestController::class.'::fooAction', 'foo::fooAction'], array_keys($locator)); } /** diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php index b5e55bdea9e97..b9dd84d592fa6 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php @@ -57,7 +57,7 @@ public function testProcess() 'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing method "setTestCase" of service "c2" from controller candidates: the method is called at instantiation, thus cannot be an action.', ]; - $this->assertSame($expectedLog, $container->getCompiler()->getLog()); + $this->assertEqualsCanonicalizing($expectedLog, $container->getCompiler()->getLog()); } public function testInvoke() diff --git a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php index 6bd52c5ba7054..6c1dc2f7c685e 100644 --- a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php @@ -58,6 +58,9 @@ public function testConstructorDefaultTimeZone() ); } + /** + * @group legacy + */ public function testConstructorWithoutDateType() { $formatter = $this->getDateFormatter('en', null, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN); @@ -65,6 +68,9 @@ public function testConstructorWithoutDateType() $this->assertSame('EEEE, MMMM d, y \'at\' h:mm a', $formatter->getPattern()); } + /** + * @group legacy + */ public function testConstructorWithoutTimeType() { $formatter = $this->getDateFormatter('en', IntlDateFormatter::SHORT, null, 'UTC', IntlDateFormatter::GREGORIAN); diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php index 4fd0bd68877f9..3de499e9d1f03 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Ldap\Adapter\ExtLdap; +use LDAP\Connection as LDAPConnection; use Symfony\Component\Ldap\Adapter\AbstractConnection; use Symfony\Component\Ldap\Exception\AlreadyExistsException; use Symfony\Component\Ldap\Exception\ConnectionException; @@ -32,7 +33,7 @@ class Connection extends AbstractConnection /** @var bool */ private $bound = false; - /** @var resource */ + /** @var resource|LDAPConnection */ private $connection; /** @@ -89,9 +90,7 @@ public function bind(string $dn = null, string $password = null) } /** - * Returns a link resource. - * - * @return resource + * @return resource|LDAPConnection * * @internal */ @@ -165,7 +164,7 @@ private function connect() private function disconnect() { - if ($this->connection && \is_resource($this->connection)) { + if ($this->connection) { ldap_unbind($this->connection); } diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php index 519357ad4c6a5..15b36e9477188 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Ldap\Adapter\ExtLdap; +use LDAP\Connection as LDAPConnection; +use LDAP\Result; use Symfony\Component\Ldap\Adapter\AbstractQuery; use Symfony\Component\Ldap\Exception\LdapException; use Symfony\Component\Ldap\Exception\NotBoundException; @@ -27,7 +29,7 @@ class Query extends AbstractQuery /** @var Connection */ protected $connection; - /** @var resource[] */ + /** @var resource[]|Result[] */ private $results; /** @var array */ @@ -156,7 +158,7 @@ public function execute() * Returns an LDAP search resource. If this query resulted in multiple searches, only the first * page will be returned. * - * @return resource + * @return resource|Result * * @internal */ @@ -172,7 +174,7 @@ public function getResource(int $idx = 0) /** * Returns all LDAP search resources. * - * @return resource[] + * @return resource[]|Result[] * * @internal */ @@ -215,7 +217,7 @@ private function resetPagination() /** * Sets LDAP pagination controls. * - * @param resource $con + * @param resource|LDAPConnection $con */ private function controlPagedResult($con, int $pageSize, bool $critical, string $cookie): bool { @@ -239,8 +241,8 @@ private function controlPagedResult($con, int $pageSize, bool $critical, string /** * Retrieve LDAP pagination cookie. * - * @param resource $con - * @param resource $result + * @param resource|LDAPConnection $con + * @param resource|Result $result */ private function controlPagedResultResponse($con, $result, string $cookie = ''): string { @@ -257,9 +259,9 @@ private function controlPagedResultResponse($con, $result, string $cookie = ''): /** * Calls actual LDAP search function with the prepared options and parameters. * - * @param resource $con + * @param resource|LDAPConnection $con * - * @return resource + * @return resource|Result */ private function callSearchFunction($con, string $func, int $sizeLimit) { diff --git a/src/Symfony/Component/Ldap/Security/LdapAuthenticator.php b/src/Symfony/Component/Ldap/Security/LdapAuthenticator.php index 30928f62278cd..2bc3f5925b389 100644 --- a/src/Symfony/Component/Ldap/Security/LdapAuthenticator.php +++ b/src/Symfony/Component/Ldap/Security/LdapAuthenticator.php @@ -16,7 +16,10 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; +use Symfony\Component\Security\Http\Authenticator\InteractiveAuthenticatorInterface; use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; +use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; +use Symfony\Component\Security\Http\EntryPoint\Exception\NotAnEntryPointException; /** * This class decorates internal authenticators to add the LDAP integration. @@ -29,7 +32,7 @@ * * @final */ -class LdapAuthenticator implements AuthenticatorInterface +class LdapAuthenticator implements AuthenticationEntryPointInterface, InteractiveAuthenticatorInterface { private $authenticator; private $ldapServiceId; @@ -75,4 +78,22 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio { return $this->authenticator->onAuthenticationFailure($request, $exception); } + + public function start(Request $request, AuthenticationException $authException = null): Response + { + if (!$this->authenticator instanceof AuthenticationEntryPointInterface) { + throw new NotAnEntryPointException(sprintf('Decorated authenticator "%s" does not implement interface "%s".', get_debug_type($this->authenticator), AuthenticationEntryPointInterface::class)); + } + + return $this->authenticator->start($request, $authException); + } + + public function isInteractive(): bool + { + if ($this->authenticator instanceof InteractiveAuthenticatorInterface) { + return $this->authenticator->isInteractive(); + } + + return false; + } } diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php index 13be9a333289e..3176c923f10f3 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php @@ -140,7 +140,11 @@ private function getDBALConnectionMock() $schemaConfig->method('getMaxIdentifierLength')->willReturn(63); $schemaConfig->method('getDefaultTableOptions')->willReturn([]); $schemaManager->method('createSchemaConfig')->willReturn($schemaConfig); - $driverConnection->method('getSchemaManager')->willReturn($schemaManager); + if (method_exists(DBALConnection::class, 'createSchemaManager')) { + $driverConnection->method('createSchemaManager')->willReturn($schemaManager); + } else { + $driverConnection->method('getSchemaManager')->willReturn($schemaManager); + } return $driverConnection; } @@ -430,7 +434,11 @@ public function testSetupIndices(string $platformClass, array $expectedIndices) $expectedTable->addIndex($indexColumns); } $schemaManager->method('createSchema')->willReturn($schema); - $driverConnection->method('getSchemaManager')->willReturn($schemaManager); + if (method_exists(DBALConnection::class, 'createSchemaManager')) { + $driverConnection->method('createSchemaManager')->willReturn($schemaManager); + } else { + $driverConnection->method('getSchemaManager')->willReturn($schemaManager); + } $platformMock = $this->createMock($platformClass); $platformMock diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php index e99bf76f7733b..2c3556fbd3d30 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php @@ -14,6 +14,7 @@ use Doctrine\DBAL\Driver\Result as DriverResult; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Result; +use Doctrine\DBAL\Schema\AbstractSchemaManager; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Bridge\Doctrine\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Bridge\Doctrine\Transport\Connection; @@ -175,7 +176,7 @@ public function testItRetrieveTheMessageThatIsOlderThanRedeliverTimeout() public function testTheTransportIsSetupOnGet() { - $this->assertFalse($this->driverConnection->getSchemaManager()->tablesExist('messenger_messages')); + $this->assertFalse($this->createSchemaManager()->tablesExist('messenger_messages')); $this->assertNull($this->connection->get()); $this->connection->send('the body', ['my' => 'header']); @@ -187,4 +188,11 @@ private function formatDateTime(\DateTime $dateTime) { return $dateTime->format($this->driverConnection->getDatabasePlatform()->getDateTimeFormatString()); } + + private function createSchemaManager(): AbstractSchemaManager + { + return method_exists($this->driverConnection, 'createSchemaManager') + ? $this->driverConnection->createSchemaManager() + : $this->driverConnection->getSchemaManager(); + } } diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php index 43974a53e1f06..b09b289c6b403 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php @@ -20,6 +20,7 @@ use Doctrine\DBAL\Platforms\MySqlPlatform; use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Result; +use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\Schema\Comparator; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer; @@ -386,7 +387,7 @@ protected function executeStatement(string $sql, array $parameters = [], array $ private function getSchema(): Schema { - $schema = new Schema([], [], $this->driverConnection->getSchemaManager()->createSchemaConfig()); + $schema = new Schema([], [], $this->createSchemaManager()->createSchemaConfig()); $this->addTableToSchema($schema); return $schema; @@ -437,7 +438,7 @@ private function updateSchema(): void } $comparator = new Comparator(); - $schemaDiff = $comparator->compare($this->driverConnection->getSchemaManager()->createSchema(), $this->getSchema()); + $schemaDiff = $comparator->compare($this->createSchemaManager()->createSchema(), $this->getSchema()); foreach ($schemaDiff->toSaveSql($this->driverConnection->getDatabasePlatform()) as $sql) { if (method_exists($this->driverConnection, 'executeStatement')) { @@ -447,6 +448,13 @@ private function updateSchema(): void } } } + + private function createSchemaManager(): AbstractSchemaManager + { + return method_exists($this->driverConnection, 'createSchemaManager') + ? $this->driverConnection->createSchemaManager() + : $this->driverConnection->getSchemaManager(); + } } if (!class_exists(\Symfony\Component\Messenger\Transport\Doctrine\Connection::class, false)) { diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php index 9223d5a833135..1754c83da008c 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php @@ -78,7 +78,7 @@ public function testFromDsnWithTls() $redis->expects($this->once()) ->method('connect') ->with('tls://127.0.0.1', 6379) - ->willReturn(null); + ->willReturn(true); Connection::fromDsn('redis://127.0.0.1?tls=1', [], $redis); } @@ -92,7 +92,7 @@ public function testFromDsnWithTlsOption() $redis->expects($this->once()) ->method('connect') ->with('tls://127.0.0.1', 6379) - ->willReturn(null); + ->willReturn(true); Connection::fromDsn('redis://127.0.0.1', ['tls' => true], $redis); } @@ -103,7 +103,7 @@ public function testFromDsnWithRedissScheme() $redis->expects($this->once()) ->method('connect') ->with('tls://127.0.0.1', 6379) - ->willReturn(null); + ->willReturn(true); Connection::fromDsn('rediss://127.0.0.1', [], $redis); } @@ -163,15 +163,26 @@ public function testKeepGettingPendingMessages() $this->assertNotNull($connection->get()); } - public function testAuth() + /** + * @param string|array $expected + * + * @dataProvider provideAuthDsn + */ + public function testAuth($expected, string $dsn) { $redis = $this->createMock(\Redis::class); $redis->expects($this->exactly(1))->method('auth') - ->with('password') + ->with($expected) ->willReturn(true); - Connection::fromDsn('redis://password@localhost/queue', [], $redis); + Connection::fromDsn($dsn, [], $redis); + } + + public function provideAuthDsn(): \Generator + { + yield 'Password only' => ['password', 'redis://password@localhost/queue']; + yield 'User and password' => [['user', 'password'], 'redis://user:password@localhost/queue']; } public function testAuthFromOptions() @@ -315,7 +326,7 @@ public function testMaxEntries() $redis->expects($this->exactly(1))->method('xadd') ->with('queue', '*', ['message' => '{"body":"1","headers":[]}'], 20000, true) - ->willReturn(1); + ->willReturn('1'); $connection = Connection::fromDsn('redis://localhost/queue?stream_max_entries=20000', [], $redis); // 1 = always $connection->add('1', []); @@ -355,7 +366,7 @@ public function testLastErrorGetsCleared() { $redis = $this->createMock(\Redis::class); - $redis->expects($this->once())->method('xadd')->willReturn(0); + $redis->expects($this->once())->method('xadd')->willReturn('0'); $redis->expects($this->once())->method('xack')->willReturn(0); $redis->method('getLastError')->willReturnOnConsecutiveCalls('xadd error', 'xack error'); diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportFactoryTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportFactoryTest.php index 728fe67c78bc3..754e5ae07d6c7 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportFactoryTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportFactoryTest.php @@ -27,6 +27,7 @@ public function testSupportsOnlyRedisTransports() $factory = new RedisTransportFactory(); $this->assertTrue($factory->supports('redis://localhost', [])); + $this->assertTrue($factory->supports('rediss://localhost', [])); $this->assertFalse($factory->supports('sqs://localhost', [])); $this->assertFalse($factory->supports('invalid-dsn', [])); } diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php index 4515660c93784..7ffd04caa97f5 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php @@ -111,7 +111,10 @@ public function __construct(array $configuration, array $connectionCredentials = $this->claimInterval = $configuration['claim_interval'] ?? self::DEFAULT_OPTIONS['claim_interval']; } - private static function initializeRedis(\Redis $redis, string $host, int $port, ?string $auth, int $serializer, int $dbIndex): \Redis + /** + * @param string|string[]|null $auth + */ + private static function initializeRedis(\Redis $redis, string $host, int $port, $auth, int $serializer, int $dbIndex): \Redis { $redis->connect($host, $port); $redis->setOption(\Redis::OPT_SERIALIZER, $serializer); @@ -127,7 +130,10 @@ private static function initializeRedis(\Redis $redis, string $host, int $port, return $redis; } - private static function initializeRedisCluster(?\RedisCluster $redis, array $hosts, ?string $auth, int $serializer): \RedisCluster + /** + * @param string|string[]|null $auth + */ + private static function initializeRedisCluster(?\RedisCluster $redis, array $hosts, $auth, int $serializer): \RedisCluster { if (null === $redis) { $redis = new \RedisCluster(null, $hosts, 0.0, 0.0, false, $auth); @@ -233,7 +239,8 @@ public static function fromDsn(string $dsn, array $redisOptions = [], $redis = n $connectionCredentials = [ 'host' => $parsedUrl['host'] ?? '127.0.0.1', 'port' => $parsedUrl['port'] ?? 6379, - 'auth' => $redisOptions['auth'] ?? $parsedUrl['pass'] ?? $parsedUrl['user'] ?? null, + // See: https://github.com/phpredis/phpredis/#auth + 'auth' => $redisOptions['auth'] ?? (isset($parsedUrl['pass']) && isset($parsedUrl['user']) ? [$parsedUrl['user'], $parsedUrl['pass']] : $parsedUrl['pass'] ?? $parsedUrl['user'] ?? null), ]; $pathParts = explode('/', rtrim($parsedUrl['path'] ?? '', '/')); diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/RedisTransportFactory.php b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/RedisTransportFactory.php index 55deeb09e7fa8..88cead8a934f4 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/RedisTransportFactory.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/RedisTransportFactory.php @@ -30,7 +30,7 @@ public function createTransport(string $dsn, array $options, SerializerInterface public function supports(string $dsn, array $options): bool { - return 0 === strpos($dsn, 'redis://'); + return 0 === strpos($dsn, 'redis://') || 0 === strpos($dsn, 'rediss://'); } } diff --git a/src/Symfony/Component/Mime/RawMessage.php b/src/Symfony/Component/Mime/RawMessage.php index 66788d8ad526d..d2a311daebecf 100644 --- a/src/Symfony/Component/Mime/RawMessage.php +++ b/src/Symfony/Component/Mime/RawMessage.php @@ -33,8 +33,11 @@ public function toString(): string if (\is_string($this->message)) { return $this->message; } + if ($this->message instanceof \Traversable) { + $this->message = iterator_to_array($this->message, false); + } - return $this->message = implode('', iterator_to_array($this->message, false)); + return $this->message = implode('', $this->message); } public function toIterable(): iterable diff --git a/src/Symfony/Component/Mime/Tests/RawMessageTest.php b/src/Symfony/Component/Mime/Tests/RawMessageTest.php index 26e7605baba2d..41503451bb1da 100644 --- a/src/Symfony/Component/Mime/Tests/RawMessageTest.php +++ b/src/Symfony/Component/Mime/Tests/RawMessageTest.php @@ -16,16 +16,12 @@ class RawMessageTest extends TestCase { - public function testToString() + /** + * @dataProvider provideMessages + */ + public function testToString($messageParameter) { - $message = new RawMessage('string'); - $this->assertEquals('string', $message->toString()); - $this->assertEquals('string', implode('', iterator_to_array($message->toIterable()))); - // calling methods more than once work - $this->assertEquals('string', $message->toString()); - $this->assertEquals('string', implode('', iterator_to_array($message->toIterable()))); - - $message = new RawMessage(new \ArrayObject(['some', ' ', 'string'])); + $message = new RawMessage($messageParameter); $this->assertEquals('some string', $message->toString()); $this->assertEquals('some string', implode('', iterator_to_array($message->toIterable()))); // calling methods more than once work @@ -33,6 +29,15 @@ public function testToString() $this->assertEquals('some string', implode('', iterator_to_array($message->toIterable()))); } + public function provideMessages(): array + { + return [ + 'string' => ['some string'], + 'traversable' => [new \ArrayObject(['some', ' ', 'string'])], + 'array' => [['some', ' ', 'string']], + ]; + } + public function testSerialization() { $message = new RawMessage('string'); diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php index 2ad0848bf2049..526ad5eb6ac85 100644 --- a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php @@ -96,7 +96,7 @@ protected function doSend(MessageInterface $message): SentMessage $success = $response->toArray(false); $sentMessage = new SentMessage($message, (string) $this); - $sentMessage->setMessageId($success['results'][0]['message_id']); + $sentMessage->setMessageId($success['results'][0]['message_id'] ?? ''); return $sentMessage; } diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php index 77372cd5102c6..bc7c492fd684c 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Notifier\Bridge\GoogleChat; -use Symfony\Component\Notifier\Bridge\GoogleChat\Component\Card; use Symfony\Component\Notifier\Message\ChatMessage; use Symfony\Component\Notifier\Message\MessageOptionsInterface; use Symfony\Component\Notifier\Notification\Notification; diff --git a/src/Symfony/Component/PasswordHasher/README.md b/src/Symfony/Component/PasswordHasher/README.md index 0bddd95d61e80..0878746fca38c 100644 --- a/src/Symfony/Component/PasswordHasher/README.md +++ b/src/Symfony/Component/PasswordHasher/README.md @@ -33,7 +33,7 @@ $passwordHasher->verify($hash, 'plain'); // returns true (valid) Resources --------- - * [Documentation](https://symfony.com/doc/current/password-hasher.html) + * [Documentation](https://symfony.com/doc/current/security.html#c-hashing-passwords) * [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/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 5ece2c17e87bb..583bd886911fe 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -313,10 +313,8 @@ public function isWritable($objectOrArray, $propertyPath) if (!$zval[self::VALUE] instanceof \ArrayAccess && !\is_array($zval[self::VALUE])) { return false; } - } else { - if (!$this->isPropertyWritable($zval[self::VALUE], $propertyPath->getElement($i))) { - return false; - } + } elseif (!\is_object($zval[self::VALUE]) || !$this->isPropertyWritable($zval[self::VALUE], $propertyPath->getElement($i))) { + return false; } if (\is_object($zval[self::VALUE])) { @@ -663,10 +661,6 @@ private function getWriteInfo(string $class, string $property, $value): Property */ private function isPropertyWritable(object $object, string $property): bool { - if (!\is_object($object)) { - return false; - } - $mutatorForArray = $this->getWriteInfo(\get_class($object), $property, []); if (PropertyWriteInfo::TYPE_NONE !== $mutatorForArray->getType() || ($object instanceof \stdClass && property_exists($object, $property))) { diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php index 71e71a7838600..98d6eb57d5936 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php @@ -38,6 +38,14 @@ public function getValidPropertyPaths() ]; } + public function getInvalidPropertyPaths() + { + return [ + [$this->getContainer(['firstName' => 'Bernhard']), 'firstName', 'Bernhard'], + [$this->getContainer(['person' => $this->getContainer(['firstName' => 'Bernhard'])]), 'person.firstName', 'Bernhard'], + ]; + } + /** * @dataProvider getValidPropertyPaths */ @@ -83,4 +91,12 @@ public function testIsWritable($collection, $path) { $this->assertTrue($this->propertyAccessor->isWritable($collection, $path)); } + + /** + * @dataProvider getInvalidPropertyPaths + */ + public function testIsNotWritable($collection, $path) + { + $this->assertFalse($this->propertyAccessor->isWritable($collection, $path)); + } } diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 041502d18fe34..971e47c1ab256 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -552,8 +552,8 @@ private function extractFromReflectionType(\ReflectionType $reflectionType, \Ref $types = []; $nullable = $reflectionType->allowsNull(); - foreach ($reflectionType instanceof \ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType] as $type) { - $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type; + foreach (($reflectionType instanceof \ReflectionUnionType || $reflectionType instanceof \ReflectionIntersectionType) ? $reflectionType->getTypes() : [$reflectionType] as $type) { + $phpTypeOrClass = $type->getName(); if ('null' === $phpTypeOrClass || 'mixed' === $phpTypeOrClass || 'never' === $phpTypeOrClass) { continue; } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 253b9032ba2cb..8ad3315834a8d 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -280,11 +280,20 @@ public function php80TypesProvider() } /** + * @dataProvider php81TypesProvider * @requires PHP 8.1 */ - public function testExtractPhp81Type() + public function testExtractPhp81Type($property, array $type = null) { - $this->assertNull($this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php81Dummy', 'nothing', [])); + $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php81Dummy', $property, [])); + } + + public function php81TypesProvider() + { + return [ + ['nothing', null], + ['collection', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Traversable'), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Countable')]], + ]; } /** diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php index b4e896a434524..1300c3e695f1f 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php @@ -8,4 +8,8 @@ public function getNothing(): never { throw new \Exception('Oops'); } + + public function getCollection(): \Traversable&\Countable + { + } } diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf index 5a8d0c7d84880..212ca70c922e3 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf @@ -70,6 +70,14 @@ Invalid or expired login link. Enllaç d'inici de sessió no vàlid o caducat. + + Too many failed login attempts, please try again in %minutes% minute. + Massa intents d'inici de sessió fallits, torneu-ho a provar en %minutes% minut. + + + Too many failed login attempts, please try again in %minutes% minutes. + Massa intents d'inici de sessió fallits, torneu-ho a provar en %minutes% minuts. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.my.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.my.xlf new file mode 100644 index 0000000000000..df593f0e0b82b --- /dev/null +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.my.xlf @@ -0,0 +1,83 @@ + + + + + + An authentication exception occurred. + အသုံးပြုခွင့် ခြွင်းချက်တစ်ခုဖြစ်သွားသည်။ + + + Authentication credentials could not be found. + အသုံးပြုခွင့် အထောက်အထားများ ရှာမတွေ့ပါ။ + + + Authentication request could not be processed due to a system problem. + System ပြဿနာအခက်အခဲရှိ နေပါသဖြင့် အသုံးပြုခွင့်တောင်းဆိုချက်ကို ဆောင်ရွက်၍မရ နိုင်ပါ။ + + + Invalid credentials. + သင့်လျှော်သော် အထောက်အထားမဟုတ်ပါ။ + + + Cookie has already been used by someone else. + Cookie ကို တစ်စုံတစ်ယောက်မှ အသုံးပြုပြီးဖြစ်သည်။ + + + Not privileged to request the resource. + အရင်းအမြစ်ကိုတောင်းဆိုရန်အခွင့်ထူးမရပါ။ + + + Invalid CSRF token. + သင့်လျှော်သော် CSRF token မဟုတ်ပါ။ + + + No authentication provider found to support the authentication token. + အထောက်အထားစိစစ်ခြင်းသင်္ကေတကိုပံ့ပိုးရန် မည်သည့်အထောက်အထားစိစစ်ရေး ၀န်ဆောင်မှုမှမတွေ့ပါ။ + + + No session available, it either timed out or cookies are not enabled. + Session မအားလပ်ပါ။ Session အချိန်ကုန်သွားခြင်း (သို့မဟုတ်) cookies များကိုဖွင့်ထားခြင်းမရှိပါ။ + + + No token could be found. + Toke ရှာမတွေ့ပါ။ + + + Username could not be found. + အသုံးပြုသူအမည် ရှာဖွေတွေ့ရှိချင်းမရှိပါ။ + + + Account has expired. + အကောင့် သက်တမ်းကုန်လွန်သွားပါပြီ။ + + + Credentials have expired. + အထောက်အထားသက်တန်း ကုန်လွန်သွားပါပြီ။ + + + Account is disabled. + အကောင့်ပိတ်ထားပါသည်။ + + + Account is locked. + အကောင့် လောခ်ကျသွားပါပြီ။ + + + Too many failed login attempts, please try again later. + Login ၀င်ရန်ကြိုးစားမှုများလွန်းပါသည်၊ ကျေးဇူးပြု၍ နောက်မှထပ်ကြိုးစားပါ။ + + + Invalid or expired login link. + မသင့်လျှော်သော် (သို့မဟုတ်) သက်တန်းကုန်သော login link ဖြစ်ပါသည်။ + + + Too many failed login attempts, please try again in %minutes% minute. + Too many failed login attempts, please try again in %minutes% minute. + + + Too many failed login attempts, please try again in %minutes% minutes. + Login ၀င်ရန်ကြိုးစားမှုများလွန်းပါသည်၊ ကျေးဇူးပြု၍ နောက် %minutes% မှထပ်မံကြိုးစားပါ။ + + + + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.sk.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.sk.xlf index 3caa51ab01306..8e06befafdf33 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.sk.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.sk.xlf @@ -70,6 +70,14 @@ Invalid or expired login link. Neplatný alebo expirovaný odkaz na prihlásenie. + + Too many failed login attempts, please try again in %minutes% minute. + Príliš veľa neúspešných pokusov o prihlásenie. Skúste to znova o %minutes% minútu. + + + Too many failed login attempts, please try again in %minutes% minutes. + Príliš veľa neúspešných pokusov o prihlásenie. Skúste to znova o %minutes% minút. + diff --git a/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/UserBadge.php b/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/UserBadge.php index dd24d488dfb52..8357158cc48b0 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/UserBadge.php +++ b/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/UserBadge.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Http\Authenticator\Passport\Badge; +use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\AuthenticationServiceException; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Http\EventListener\UserProviderListener; diff --git a/src/Symfony/Component/Security/Http/EntryPoint/Exception/NotAnEntryPointException.php b/src/Symfony/Component/Security/Http/EntryPoint/Exception/NotAnEntryPointException.php new file mode 100644 index 0000000000000..e421dcf0cd67b --- /dev/null +++ b/src/Symfony/Component/Security/Http/EntryPoint/Exception/NotAnEntryPointException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\EntryPoint\Exception; + +/** + * Thrown by generic decorators when a decorated authenticator does not implement + * {@see AuthenticationEntryPointInterface}. + * + * @author Robin Chalas + */ +class NotAnEntryPointException extends \RuntimeException +{ +} diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index 73f4f4553d8c0..32a1b60d60452 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -31,6 +31,7 @@ use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; +use Symfony\Component\Security\Http\EntryPoint\Exception\NotAnEntryPointException; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Http\Util\TargetPathTrait; @@ -195,11 +196,7 @@ private function handleLogoutException(ExceptionEvent $event, LogoutException $e private function startAuthentication(Request $request, AuthenticationException $authException): Response { if (null === $this->authenticationEntryPoint) { - if (null !== $this->logger) { - $this->logger->notice(sprintf('No Authentication entry point configured, returning a %s HTTP response. Configure "entry_point" on the firewall "%s" if you want to modify the response.', Response::HTTP_UNAUTHORIZED, $this->firewallName)); - } - - throw new HttpException(Response::HTTP_UNAUTHORIZED, $authException->getMessage(), $authException, [], $authException->getCode()); + $this->throwUnauthorizedException($authException); } if (null !== $this->logger) { @@ -219,7 +216,11 @@ private function startAuthentication(Request $request, AuthenticationException $ } } - $response = $this->authenticationEntryPoint->start($request, $authException); + try { + $response = $this->authenticationEntryPoint->start($request, $authException); + } catch (NotAnEntryPointException $e) { + $this->throwUnauthorizedException($authException); + } if (!$response instanceof Response) { $given = get_debug_type($response); @@ -237,4 +238,13 @@ protected function setTargetPath(Request $request) $this->saveTargetPath($request->getSession(), $this->firewallName, $request->getUri()); } } + + private function throwUnauthorizedException(AuthenticationException $authException) + { + if (null !== $this->logger) { + $this->logger->notice(sprintf('No Authentication entry point configured, returning a %s HTTP response. Configure "entry_point" on the firewall "%s" if you want to modify the response.', Response::HTTP_UNAUTHORIZED, $this->firewallName)); + } + + throw new HttpException(Response::HTTP_UNAUTHORIZED, $authException->getMessage(), $authException, [], $authException->getCode()); + } } diff --git a/src/Symfony/Component/Semaphore/SemaphoreInterface.php b/src/Symfony/Component/Semaphore/SemaphoreInterface.php index 6897498145bec..363b31f4c5cb1 100644 --- a/src/Symfony/Component/Semaphore/SemaphoreInterface.php +++ b/src/Symfony/Component/Semaphore/SemaphoreInterface.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Semaphore; use Symfony\Component\Semaphore\Exception\SemaphoreAcquiringException; +use Symfony\Component\Semaphore\Exception\SemaphoreExpiredException; use Symfony\Component\Semaphore\Exception\SemaphoreReleasingException; /** diff --git a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php index bb866ec9bcc36..13f99c1d241e7 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php @@ -95,13 +95,13 @@ public function supportsNormalization($data, string $format = null) */ public function denormalize($data, string $type, string $format = null, array $context = []) { - if (!preg_match('/^data:([a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}\/[a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}(;[a-z0-9\-]+\=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9\!\$\&\\\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i', $data)) { + if (null === $data || !preg_match('/^data:([a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}\/[a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}(;[a-z0-9\-]+\=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9\!\$\&\\\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i', $data)) { throw new NotNormalizableValueException('The provided "data:" URI is not valid.'); } try { switch ($type) { - case 'Symfony\Component\HttpFoundation\File\File': + case File::class: if (!class_exists(File::class)) { throw new InvalidArgumentException(sprintf('Cannot denormalize to a "%s" without the HttpFoundation component installed. Try running "composer require symfony/http-foundation".', File::class)); } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/DataUriNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/DataUriNormalizerTest.php index 24c5672bea43f..02bd050bd395b 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/DataUriNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/DataUriNormalizerTest.php @@ -139,6 +139,7 @@ public function invalidUriProvider() ['data:text/html;charset,%3Ch1%3EHello!%3C%2Fh1%3E'], ['data:base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC'], [''], + [null], ['http://wikipedia.org'], ['base64'], ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC'], diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf index f53eb0e61ad82..4a73556e504d7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Aquest valor no és un número d'identificació de valors internacionals (ISIN) vàlid. + + This value should be a valid expression. + Aquest valor hauria de ser una expressió vàlida. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf new file mode 100644 index 0000000000000..7f45aaed64f36 --- /dev/null +++ b/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf @@ -0,0 +1,395 @@ + + + + + + This value should be false. + ဤတန်ဖိုးသည် false ဖြစ်ရမည်။ + + + This value should be true. + ဤတန်ဖိုးသည် 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 }} ခုရွေးချယ်ရမည်။ + + + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. + သင်သည်အများဆုံး {{ 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. + ဤတန်ဖိုးသည် မှန်ကန်သော် ရက်စွဲ/အချိန် မဟုတ်ပါ။ + + + 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 }} (သို့မဟုတ်) {{ 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)။ ခွင့်ပြုထားသည့်အနည်းဆုံးအလျားသည် {{max_width}}px ဖြစ်သည်။ + + + The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. + ပုံ၏အနံသည် ကြီးလွန်းသည် ({{ height }}px)။ ခွင့်ပြုထားသည့်အများဆုံးအနံသည် {{max_height}}px ဖြစ်သည်။ + + + The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. + ပုံ၏အနံသည် သေးလွန်းသည် ({{ height }}px)။ ခွင့်ပြုထားသည့်အနည်းဆုံးအနံသည် {{min_height}}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}} အတိအကျရှိသင့်သည်။ + + + The file was only partially uploaded. + ဤဖိုင်သည်တစ်စိတ်တစ်ပိုင်းသာ upload တင်ခဲ့သည်။ + + + No file was uploaded. + မည်သည့် ဖိုင်မျှ upload မလုပ်ခဲ့ပါ။ + + + No temporary folder was configured in php.ini. + php.ini တွင်ယာယီဖိုင်တွဲကိုပြင်ဆင်ထားခြင်းမရှိပါ၊ + + + Cannot write temporary file to disk. + ယာရီဖိုင်ကို disk မရေးနိုင်ပါ။ + + + A PHP extension caused the upload to fail. + PHP extension တစ်ခုကြောင့် upload တင်၍မရနိုင်ပါ။ + + + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. + ဤ collection တွင် {{limit}} element (သို့မဟုတ်) ထို့ထက်မပိုသင့်ပါ။ + + + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. + ဤ collection တွင် {{limit}} element (သို့မဟုတ်) ၎င်းထက်နည်းသင့်သည်။ + + + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. + ဤစုစည်းမှုတွင် {{limit}} element အတိအကျပါသင့်သည်။ + + + Invalid card number. + ကဒ်နံပါတ်မမှန်ပါ။ + + + Unsupported card type or invalid card number. + ကဒ်အမျိုးအစားမမှန်ပါ (သို့မဟုတ်) ကဒ်နံပါတ်မမှန်ပါ။ + + + This is not a valid International Bank Account Number (IBAN). + ဤတန်ဖိုးသည် တရား၀င်နိုင်ငံတကာဘဏ်အကောင့်နံပါတ် (International Bank Account Number, 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 }} ထက်ကြီးသင့်သည် (သို့မဟုတ်) ဤတန်ဖိုးသည် {{ 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. + host ဖြေရှင်း၍မနိုင်ပါ။ + + + This value does not match the expected {{ charset }} charset. + ဤတန်ဖိုးသည် မျှော်မှန်းထားသော {{ charset }} စားလုံးနှင့် ကိုက်ညီမှုမရှိပါ။ + + + This is not a valid Business Identifier Code (BIC). + ၎င်းသည်မှန်ကန်သော Business Identifier Code (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 }}. + ဤ Business Identifier Code (BIC) သည် IBAN {{ iban }} နှင့်ဆက်စပ်မှုမရှိပါ။ + + + This value should be valid JSON. + ဤတန်ဖိုးသည် သင့်လျှော်သော် JSON တန်ဖိုးဖြစ်သင့်သည်။ + + + This collection should contain only unique elements. + ဤ collection ကိုယ်ပိုင် 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. + ဤစကားဝှက် သည် ဒေတာပေါက်ကြားမှုတစ်ခုဖြစ်ခဲ့သည်။ ဤစကား၀ှက်ကိုအသုံးမပြုရပါ။ ကျေးဇူးပြု၍ အခြားစကားဝှက်ကိုသုံးပါ။ + + + This value should be between {{ min }} and {{ max }}. + ဤတန်ဖိုးသည် {{ min }} နှင့် {{ max }} ကြားရှိသင့်သည်။ + + + This value is not a valid hostname. + ဤတန်ဖိုးသည် သင့်လျှော်သော် hostname မဟုတ်ပါ။ + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + ဤ collection တွင်ပါပါ၀င်သော elements အရေအတွက်သည် {{ compared_value }} ၏ စတူဖြစ်သင့်သည်။ + + + This value should satisfy at least one of the following constraints: + ဤတန်ဖိုးသည် အောက်ပါကန့်သတ်ချက်များအနက်မှအနည်းဆုံးတစ်ခု ဖြည့်ဆည်းပေးသင့်သည်။ + + + Each element of this collection should satisfy its own set of constraints. + ဤ collection ၏ element တစ်ခုစီသည်၎င်း၏ကိုယ်ပိုင်ကန့်သတ်ချက်များကိုဖြည့်ဆည်းသင့်သည်။ + + + This value is not a valid International Securities Identification Number (ISIN). + ဤတန်ဖိုးသည် သင့်လျှော်သော် အပြည်ပြည်ဆိုင်ရာငွေချေးသက်သေခံနံပါတ် ,International Securities Identification Number (ISIN) မဟုတ်ပါ။ + + + This value should be a valid expression. + ဤတန်ဖိုးသည်မှန်ကန်သောစကားရပ်ဖြစ်သင့်သည်။ + + + + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index 2f7660ea08e17..64a5c80fb6d24 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Această valoare nu este un număr internațional de identificare (ISIN) valabil. + + This value should be a valid expression. + Această valoare ar trebui să fie o expresie validă. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf index a0c55ea6db146..ad61814197df9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - V php.ini nie je nastavená cesta k adresáru pre dočasné súbory. + V php.ini nie je nastavená cesta k addressáru pre dočasné súbory. Cannot write temporary file to disk. @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Táto hodnota nie je platné medzinárodné označenie cenného papiera (ISIN). + + This value should be a valid expression. + Táto hodnota by mala byť platným výrazom. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf index 31453ff15736d..847bf3c26888b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). ค่า​รหัสหลักทรัพย์สากล (ISIN) ไม่ถูกต้อง + + This value should be a valid expression. + ค่านี้ควรเป็นนิพจน์ที่ถูกต้อง + diff --git a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php index 90d5ac9bcb8da..ad92ac341e273 100644 --- a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php @@ -66,29 +66,39 @@ protected function doClone($var) // $v is the original value or a stub object in case of hard references if (\PHP_VERSION_ID >= 70400) { - $zvalIsRef = null !== \ReflectionReference::fromArrayElement($vals, $k); + $zvalRef = ($r = \ReflectionReference::fromArrayElement($vals, $k)) ? $r->getId() : null; } else { $refs[$k] = $cookie; - $zvalIsRef = $vals[$k] === $cookie; + $zvalRef = $vals[$k] === $cookie; } - if ($zvalIsRef) { + if ($zvalRef) { $vals[$k] = &$stub; // Break hard references to make $queue completely unset($stub); // independent from the original structure - if ($v instanceof Stub && isset($hardRefs[spl_object_id($v)])) { - $vals[$k] = $refs[$k] = $v; + if (\PHP_VERSION_ID >= 70400 ? null !== $vals[$k] = $hardRefs[$zvalRef] ?? null : $v instanceof Stub && isset($hardRefs[spl_object_id($v)])) { + if (\PHP_VERSION_ID >= 70400) { + $v = $vals[$k]; + } else { + $refs[$k] = $vals[$k] = $v; + } if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) { ++$v->value->refCount; } ++$v->refCount; continue; } - $refs[$k] = $vals[$k] = new Stub(); - $refs[$k]->value = $v; - $h = spl_object_id($refs[$k]); - $hardRefs[$h] = &$refs[$k]; - $values[$h] = $v; + $vals[$k] = new Stub(); + $vals[$k]->value = $v; $vals[$k]->handle = ++$refsCounter; + + if (\PHP_VERSION_ID >= 70400) { + $hardRefs[$zvalRef] = $vals[$k]; + } else { + $refs[$k] = $vals[$k]; + $h = spl_object_id($refs[$k]); + $hardRefs[$h] = &$refs[$k]; + $values[$h] = $v; + } } // Create $stub when the original value $v can not be used directly // If $v is a nested structure, put that structure in array $a @@ -147,12 +157,17 @@ protected function doClone($var) unset($v[$gid]); $a = []; foreach ($v as $gk => &$gv) { - if ($v === $gv) { + if ($v === $gv && (\PHP_VERSION_ID < 70400 || !isset($hardRefs[\ReflectionReference::fromArrayElement($v, $gk)->getId()]))) { unset($v); $v = new Stub(); $v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0]; $v->handle = -1; - $gv = &$hardRefs[spl_object_id($v)]; + if (\PHP_VERSION_ID >= 70400) { + $gv = &$a[$gk]; + $hardRefs[\ReflectionReference::fromArrayElement($a, $gk)->getId()] = &$gv; + } else { + $gv = &$hardRefs[spl_object_id($v)]; + } $gv = $v; } @@ -251,10 +266,12 @@ protected function doClone($var) } } - if ($zvalIsRef) { - $refs[$k]->value = $stub; - } else { + if (!$zvalRef) { $vals[$k] = $stub; + } elseif (\PHP_VERSION_ID >= 70400) { + $hardRefs[$zvalRef]->value = $stub; + } else { + $refs[$k]->value = $stub; } } diff --git a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php index d9f55eb46c844..1aa8e93bb0115 100644 --- a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php @@ -499,12 +499,55 @@ public function testPhp74() [p1] => 123 [p2] => Symfony\Component\VarDumper\Cloner\Stub Object ( - [type] => 4 - [class] => stdClass - [value] => + [type] => 1 + [class] => + [value] => Symfony\Component\VarDumper\Cloner\Stub Object + ( + [type] => 4 + [class] => stdClass + [value] => + [cut] => 0 + [handle] => %i + [refCount] => 1 + [position] => 0 + [attr] => Array + ( + ) + + ) + [cut] => 0 - [handle] => %i - [refCount] => 0 + [handle] => 1 + [refCount] => 1 + [position] => 0 + [attr] => Array + ( + ) + + ) + + [p3] => Symfony\Component\VarDumper\Cloner\Stub Object + ( + [type] => 1 + [class] => + [value] => Symfony\Component\VarDumper\Cloner\Stub Object + ( + [type] => 4 + [class] => stdClass + [value] => + [cut] => 0 + [handle] => %i + [refCount] => 1 + [position] => 0 + [attr] => Array + ( + ) + + ) + + [cut] => 0 + [handle] => 1 + [refCount] => 1 [position] => 0 [attr] => Array ( diff --git a/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php b/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php index 724fbeb7bdb6e..8bd4c496a1715 100644 --- a/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php +++ b/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php @@ -6,9 +6,11 @@ class Php74 { public $p1 = 123; public \stdClass $p2; + public \stdClass $p3; public function __construct() { $this->p2 = new \stdClass(); + $this->p3 = &$this->p2; } } diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/FooSerializable.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/FooSerializable.php new file mode 100644 index 0000000000000..63d9fd230c790 --- /dev/null +++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/FooSerializable.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Tests\Fixtures; + +class FooSerializable implements \Serializable +{ + private $foo; + + public function __construct(string $foo) + { + $this->foo = $foo; + } + + public function getFoo(): string + { + return $this->foo; + } + + public function serialize(): string + { + return serialize([$this->getFoo()]); + } + + public function unserialize($str) + { + [$this->foo] = unserialize($str); + } +} diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/MySerializable.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/MySerializable.php new file mode 100644 index 0000000000000..8d649a22a944d --- /dev/null +++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/MySerializable.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Tests\Fixtures; + +class MySerializable implements \Serializable +{ + public function serialize(): string + { + return '123'; + } + + public function unserialize($data): void + { + // no-op + } +} diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/foo-serializable.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/foo-serializable.php index fd4e2671010b3..c6285fd1fbebe 100644 --- a/src/Symfony/Component/VarExporter/Tests/Fixtures/foo-serializable.php +++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/foo-serializable.php @@ -2,7 +2,7 @@ return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( $o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ - 'C:51:"Symfony\\Component\\VarExporter\\Tests\\FooSerializable":20:{a:1:{i:0;s:3:"bar";}}', + 'C:60:"Symfony\\Component\\VarExporter\\Tests\\Fixtures\\FooSerializable":20:{a:1:{i:0;s:3:"bar";}}', ]), null, [], diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/serializable.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/serializable.php index fcf32278b0685..9e7b52803d924 100644 --- a/src/Symfony/Component/VarExporter/Tests/Fixtures/serializable.php +++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/serializable.php @@ -2,7 +2,7 @@ return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( $o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ - 'C:50:"Symfony\\Component\\VarExporter\\Tests\\MySerializable":3:{123}', + 'C:59:"Symfony\\Component\\VarExporter\\Tests\\Fixtures\\MySerializable":3:{123}', ]), null, [], diff --git a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php index cd10c7af37a8a..c10a87761ce8c 100644 --- a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php +++ b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php @@ -16,7 +16,9 @@ use Symfony\Component\VarExporter\Exception\ClassNotFoundException; use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; use Symfony\Component\VarExporter\Internal\Registry; +use Symfony\Component\VarExporter\Tests\Fixtures\FooSerializable; use Symfony\Component\VarExporter\Tests\Fixtures\FooUnitEnum; +use Symfony\Component\VarExporter\Tests\Fixtures\MySerializable; use Symfony\Component\VarExporter\VarExporter; class VarExporterTest extends TestCase @@ -137,9 +139,28 @@ public function provideExport() yield ['array-iterator', new \ArrayIterator([123], 1)]; yield ['array-object-custom', new MyArrayObject([234])]; - $value = new MySerializable(); + $errorHandler = set_error_handler(static function (int $errno, string $errstr) use (&$errorHandler) { + if (\E_DEPRECATED === $errno && str_contains($errstr, 'implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead')) { + // We're testing if the component handles deprecated Serializable implementations well. + // This kind of implementation triggers a deprecation warning since PHP 8.1 that we explicitly want to + // ignore here. We probably need to reevaluate this piece of code for PHP 9. + return true; + } + + return $errorHandler ? $errorHandler(...\func_get_args()) : false; + }); - yield ['serializable', [$value, $value]]; + try { + $mySerializable = new MySerializable(); + $fooSerializable = new FooSerializable('bar'); + } finally { + restore_error_handler(); + } + + yield ['serializable', [$mySerializable, $mySerializable]]; + yield ['foo-serializable', $fooSerializable]; + + unset($mySerializable, $fooSerializable, $errorHandler); $value = new MyWakeup(); $value->sub = new MyWakeup(); @@ -211,8 +232,6 @@ public function provideExport() yield ['abstract-parent', new ConcreteClass()]; - yield ['foo-serializable', new FooSerializable('bar')]; - yield ['private-constructor', PrivateConstructor::create('bar')]; yield ['php74-serializable', new Php74Serializable()]; @@ -223,19 +242,6 @@ public function provideExport() } } -class MySerializable implements \Serializable -{ - public function serialize(): string - { - return '123'; - } - - public function unserialize($data) - { - // no-op - } -} - class MyWakeup { public $sub; @@ -384,31 +390,6 @@ public function __construct() } } -class FooSerializable implements \Serializable -{ - private $foo; - - public function __construct(string $foo) - { - $this->foo = $foo; - } - - public function getFoo(): string - { - return $this->foo; - } - - public function serialize(): string - { - return serialize([$this->getFoo()]); - } - - public function unserialize($str) - { - [$this->foo] = unserialize($str); - } -} - class Php74Serializable implements \Serializable { public function __serialize(): array diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 38b845438dd30..da21de4f5c114 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -835,6 +835,38 @@ public function testTimeoutWithActiveConcurrentStream() } } + public function testTimeoutOnDestruct() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $start = microtime(true); + $responses = []; + + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + + try { + while ($response = array_shift($responses)) { + try { + unset($response); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + } + } + + $duration = microtime(true) - $start; + + $this->assertLessThan(1.0, $duration); + } finally { + $p1->stop(); + $p2->stop(); + } + } + public function testDestruct() { $client = $this->getHttpClient(__FUNCTION__);