diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index be833bfec1a14..00a24cbcfc13c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | 7.1 for features / 5.4, 6.3, 6.4, or 7.0 for bug fixes +| Branch? | 7.1 for features / 5.4, 6.4, or 7.0 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no diff --git a/.github/sync-translations.php b/.github/sync-translations.php index eb3f8e840ab4a..13f05d1459c86 100644 --- a/.github/sync-translations.php +++ b/.github/sync-translations.php @@ -12,7 +12,7 @@ require __DIR__.'/../vendor/autoload.php'; -function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, string $domain) +function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, string $domain, ?\DOMElement $header = null) { $dom = new \DOMDocument('1.0', 'utf-8'); $dom->formatOutput = true; @@ -27,6 +27,10 @@ function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, string $d $xliffFile->setAttribute('datatype', 'plaintext'); $xliffFile->setAttribute('original', 'file.ext'); + if (null !== $header) { + mergeDom($dom, $xliffFile, $header); + } + $xliffBody = $xliffFile->appendChild($dom->createElement('body')); foreach ($messages->all($domain) as $source => $target) { $translation = $dom->createElement('trans-unit'); @@ -62,6 +66,24 @@ function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, string $d return preg_replace('/^ +/m', '$0$0', $dom->saveXML()); } +function mergeDom(\DOMDocument $dom, \DOMNode $tree, \DOMNode $input) +{ + $new = $dom->createElement($input->tagName); + foreach ($input->attributes as $key => $value) { + $new->setAttribute($key, $value); + } + $tree->appendChild($new); + foreach ($input->childNodes as $child) { + if ($child instanceof \DOMText) { + $new->appendChild($dom->createTextNode(str_replace(' ', ' ', $child->textContent))); + } elseif ($child instanceof \DOMNode) { + mergeDom($dom, $new, $child); + } else { + // We just need to update our script to handle this node types + throw new \LogicException('Unsupported node type: '.get_class($child)); + } + } +} foreach (['Security/Core' => 'security', 'Form' => 'validators', 'Validator' => 'validators'] as $component => $domain) { $dir = __DIR__.'/../src/Symfony/Component/'.$component.'/Resources/translations'; @@ -95,6 +117,13 @@ function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, string $d $localeCatalogue->setMetadata($source, $metadata, $domain); } - file_put_contents($file, dumpXliff1('en', $localeCatalogue, $domain)); + $inputDom = new \DOMDocument(); + $inputDom->loadXML(file_get_contents($file->getRealPath())); + $header = null; + if (1 === $inputDom->getElementsByTagName('header')->count()) { + $header = $inputDom->getElementsByTagName('header')->item(0); + } + + file_put_contents($file, dumpXliff1('en', $localeCatalogue, $domain, $header)); } } diff --git a/CHANGELOG-5.4.md b/CHANGELOG-5.4.md index c6fa311ebc53c..43c657cae08c7 100644 --- a/CHANGELOG-5.4.md +++ b/CHANGELOG-5.4.md @@ -7,6 +7,35 @@ in 5.4 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.4.0...v5.4.1 +* 5.4.36 (2024-02-27) + + * bug #54045 [Config][Messenger][Security] Don't turn deprecations into exceptions when unserializing (nicolas-grekas) + * bug #54035 [DependencyInjection] Fix computing error messages involving service locators (nicolas-grekas) + * bug #53959 [Serializer] Fix unknown types normalization type when know type (Myks92) + * bug #53960 [Messenger] the 'use_notify' option is on the factory, not on the postgres connection (dbu) + * bug #54031 [ErrorHandler] Fix parsing messages that contain anonymous classes on PHP >= 8.3.3 (nicolas-grekas) + * bug #53967 [ErrorHandler] return the unchanged text if preg_replace_callback() fails (xabbuh) + * bug #54001 [Console] Fix display of Table on Windows OS (VincentLanglet) + * bug #53989 [FrameworkBundle] Fix config builder with extensions extended in `build()` (HypeMC) + * bug #54004 [WebProfilerBundle] disable turbo in web profiler toolbar to avoid link prefetching (davidgorges) + * bug #53975 [Cache] explicitly cast boolean SSL stream options (xabbuh) + * bug #53913 [TwigBridge] Fix compat with Twig v3.9 (nicolas-grekas) + * bug #53944 [Messenger] Gracefully fallback to empty queue config (Wirone) + * bug #53934 [Mailer] Fix signed emails breaking the profiler (HypeMC) + * bug #53924 [FrameworkBundle] Check if the _route attribute exists on the request (xvilo) + * bug #53910 [Messenger] Fix SQS visibility_timeout type (valtzu) + * bug #53889 [HttpClient] Make retry strategy work again (Nyholm) + * bug #53755 [Validator] Fix fields without constraints in `Collection` (xabbuh, HypeMC) + * bug #53821 [Process] Fix Inconsistent Exit Status in proc_get_status for PHP Versions Below 8.3 (Luc45) + * bug #53792 [FrameworkBundle] Fix eager-loading of env vars in ConfigBuilderCacheWarmer (nicolas-grekas) + * bug #53785 [FrameworkBundle] Prevent silenced warning by checking if /proc/mount exists (shyim) + * bug #53730 [Messenger] [Beanstalkd] fix tube stats when it's empty (eminjk) + * bug #53754 [DoctrineBridge] forward-compatibility with field mappings in Doctrine ORM 4 (xabbuh) + * bug #53707 [Console] Fix color support for TTY output (theofidry) + * bug #53712 [Mailer] Fix usage of stream_set_timeout in case of microseconds (aleksejs1) + * bug #53715 [String] Fix plural of word ending by pus (Fan2Shrek) + * bug #53711 [Console] Allow false as a $shortcut in InputOption (jayminsilicon) + * 5.4.35 (2024-01-30) * bug #52913 [Routing] Fixed priority getting lost when setting localized prefix (pritasil) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 8ae25e554297b..c4a195380c0a3 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -6,8 +6,8 @@ Symfony is the result of the work of many people who made the code better. The Symfony Connect username in parenthesis allows to get more information - Fabien Potencier (fabpot) - Nicolas Grekas (nicolas-grekas) - - Alexander M. Turek (derrabus) - Christian Flothmann (xabbuh) + - Alexander M. Turek (derrabus) - Bernhard Schussek (bschussek) - Robin Chalas (chalas_r) - Tobias Schultze (tobion) @@ -23,8 +23,8 @@ The Symfony Connect username in parenthesis allows to get more information - Ryan Weaver (weaverryan) - Javier Eguiluz (javier.eguiluz) - Jérémy DERUSSÉ (jderusse) - - Jules Pietri (heah) - Roland Franssen + - Jules Pietri (heah) - Johannes S (johannes) - Oskar Stark (oskarstark) - Kris Wallsmith (kriswallsmith) @@ -35,10 +35,10 @@ The Symfony Connect username in parenthesis allows to get more information - Samuel ROZE (sroze) - Jérôme Tamarelle (gromnan) - Pascal Borreli (pborreli) - - Romain Neutron - Antoine Lamirault (alamirault) - - Joseph Bielawski (stloyd) + - Romain Neutron - HypeMC (hypemc) + - Joseph Bielawski (stloyd) - Drak (drak) - Abdellatif Ait boudad (aitboudad) - Kevin Bond (kbond) @@ -51,15 +51,16 @@ The Symfony Connect username in parenthesis allows to get more information - Igor Wiedler - Jan Schädlich (jschaedl) - Mathieu Lechat (mat_the_cat) - - Jonathan Wage (jwage) - Matthias Pigulla (mpdude) - Gabriel Ostrolucký (gadelat) + - Jonathan Wage (jwage) - Valentin Udaltsov (vudaltsov) - Alexandre Salomé (alexandresalome) - Grégoire Paris (greg0ire) - William DURAND - ornicar - Dany Maillard (maidmaid) + - Vincent Langlet (deviling) - Eriksen Costa - Diego Saint Esteben (dosten) - stealth35 ‏ (stealth35) @@ -70,7 +71,6 @@ The Symfony Connect username in parenthesis allows to get more information - Pierre du Plessis (pierredup) - David Maicher (dmaicher) - Bulat Shakirzyanov (avalanche123) - - Vincent Langlet (deviling) - Iltar van der Berg - Miha Vrhovnik (mvrhov) - Gary PEGEOT (gary-p) @@ -84,45 +84,45 @@ The Symfony Connect username in parenthesis allows to get more information - Laurent VOULLEMIER (lvo) - Konstantin Kudryashov (everzet) - Tomasz Kowalczyk (thunderer) + - Simon André (simonandre) - Guilhem N (guilhemn) - Bilal Amarni (bamarni) - Eriksen Costa + - Mathias Arlaud (mtarld) - Florin Patan (florinpatan) - Vladimir Reznichenko (kalessil) - Peter Rehm (rpet) - Henrik Bjørnskov (henrikbjorn) - - Mathias Arlaud (mtarld) - Dariusz Ruminski + - David Buchmann (dbu) - Andrej Hudec (pulzarraider) - Jáchym Toušek (enumag) - - Simon André (simonandre) - - David Buchmann (dbu) - Christian Raue - Eric Clemmons (ericclemmons) - Denis (yethee) + - Ruud Kamphuis (ruudk) - Michel Weimerskirch (mweimerskirch) - Issei Murasawa (issei_m) - Douglas Greenshields (shieldo) - Frank A. Fiebig (fafiebig) - Baldini - - Ruud Kamphuis (ruudk) - Alex Pott - Fran Moreno (franmomu) - Arnout Boks (aboks) - Charles Sarrazin (csarrazi) + - Tomas Norkūnas (norkunas) - Henrik Westphal (snc) - Dariusz Górecki (canni) - Ener-Getick - Graham Campbell (graham) - - Tomas Norkūnas (norkunas) + - Antoine Makdessi (amakdessi) + - Hubert Lenoir (hubert_lenoir) - Tugdual Saunier (tucksaun) - Lee McDermott - Brandon Turner - Massimiliano Arione (garak) - Luis Cordova (cordoval) - - Antoine Makdessi (amakdessi) - Konstantin Myakshin (koc) - - Hubert Lenoir (hubert_lenoir) - Daniel Holmes (dholmes) - Julien Falque (julienfalque) - Toni Uebernickel (havvg) @@ -131,20 +131,20 @@ The Symfony Connect username in parenthesis allows to get more information - Jordan Alliot (jalliot) - John Wards (johnwards) - Phil E. Taylor (philetaylor) + - Théo FIDRY - Antoine Hérault (herzult) - Konstantin.Myakshin - Yanick Witschi (toflar) - - Théo FIDRY + - Jeroen Spee (jeroens) - Arnaud Le Blanc (arnaud-lb) - Joel Wurtz (brouznouf) - Sebastiaan Stok (sstok) - Maxime STEINHAUSSER + - Rokas Mikalkėnas (rokasm) - gnito-org - - Jeroen Spee (jeroens) - Tim Nagel (merk) - Chris Wilkinson (thewilkybarkid) - Jérôme Vasseur (jvasseur) - - Rokas Mikalkėnas (rokasm) - Peter Kokot (peterkokot) - Brice BERNARD (brikou) - Tac Tacelosky (tacman1123) @@ -155,13 +155,13 @@ The Symfony Connect username in parenthesis allows to get more information - Vladimir Tsykun (vtsykun) - Jacob Dreesen (jdreesen) - Włodzimierz Gajda (gajdaw) + - Javier Spagnoletti (phansys) - Martin Auswöger - Adrien Brault (adrienbrault) - Florian Voutzinos (florianv) - Teoh Han Hui (teohhanhui) - Przemysław Bogusz (przemyslaw-bogusz) - Colin Frei - - Javier Spagnoletti (phansys) - excelwebzone - Paráda József (paradajozsef) - Baptiste Clavié (talus) @@ -170,6 +170,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gordon Franke (gimler) - Malte Schlüter (maltemaltesich) - jeremyFreeAgent (jeremyfreeagent) + - Nicolas Philippe (nikophil) - Joshua Thijssen - Vasilij Dusko - Daniel Wehner (dawehner) @@ -177,9 +178,9 @@ The Symfony Connect username in parenthesis allows to get more information - Robert Schönthal (digitalkaoz) - Smaine Milianni (ismail1432) - François-Xavier de Guillebon (de-gui_f) + - Maximilian Beckers (maxbeckers) - noniagriconomie - Eric GELOEN (gelo) - - Nicolas Philippe (nikophil) - Gabriel Caruso - Stefano Sala (stefano.sala) - Ion Bazan (ionbazan) @@ -204,21 +205,21 @@ The Symfony Connect username in parenthesis allows to get more information - SpacePossum - Richard van Laak (rvanlaak) - Andreas Schempp (aschempp) - - Maximilian Beckers (maxbeckers) - Andreas Braun - Hugo Alliaume (kocal) + - Valtteri R (valtzu) - Pablo Godel (pgodel) - Florent Mata (fmata) - Alessandro Chitolina (alekitto) - Dāvis Zālītis (k0d3r1s) - Rafael Dohms (rdohms) + - Roman Martinuk (a2a4) - jwdeitch - David Prévot (taffit) - Jérôme Parmentier (lctrs) - Ahmed TAILOULOUTE (ahmedtai) - Simon Berger - Jérémy Derussé - - Valtteri R (valtzu) - Matthieu Napoli (mnapoli) - Tomas Votruba (tomas_votruba) - Arman Hosseini (arman) @@ -228,7 +229,6 @@ The Symfony Connect username in parenthesis allows to get more information - Vyacheslav Pavlov - Albert Casademont (acasademont) - George Mponos (gmponos) - - Roman Martinuk (a2a4) - Richard Shank (iampersistent) - Thomas Landauer (thomas-landauer) - Romain Monteil (ker0x) @@ -265,6 +265,7 @@ The Symfony Connect username in parenthesis allows to get more information - zairig imad (zairigimad) - Colin O'Dell (colinodell) - Sébastien Alfaiate (seb33300) + - Daniel Burger - James Halsall (jaitsu) - Christian Scheb - Guillaume (guill) @@ -274,6 +275,7 @@ The Symfony Connect username in parenthesis allows to get more information - Anthony GRASSIOT (antograssiot) - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) + - Jan Rosier (rosier) - Andreas Möller (localheinz) - Marek Štípek (maryo) - Daniel Espendiller @@ -295,8 +297,8 @@ The Symfony Connect username in parenthesis allows to get more information - Timo Bakx (timobakx) - soyuka - Ruben Gonzalez (rubenrua) + - Bob van de Vijver (bobvandevijver) - Benjamin Dulau (dbenjamin) - - Daniel Burger - Markus Fasselt (digilist) - Denis Brumann (dbrumann) - mcfedr (mcfedr) @@ -304,7 +306,6 @@ The Symfony Connect username in parenthesis allows to get more information - Mathieu Lemoine (lemoinem) - Christian Schmidt - Andreas Hucks (meandmymonkey) - - Jan Rosier (rosier) - Noel Guilbert (noel) - Stadly - Stepan Anchugov (kix) @@ -335,7 +336,6 @@ The Symfony Connect username in parenthesis allows to get more information - Dustin Whittle (dustinwhittle) - Timothée Barray (tyx) - jeff - - Bob van de Vijver (bobvandevijver) - John Kary (johnkary) - Võ Xuân Tiến (tienvx) - fd6130 (fdtvui) @@ -346,6 +346,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sven Paulus (subsven) - Maxime Veber (nek-) - Bastien Jaillot (bastnic) + - Soner Sayakci - Valentine Boineau (valentineboineau) - Rui Marinho (ruimarinho) - Patrick Landolt (scube) @@ -362,11 +363,13 @@ The Symfony Connect username in parenthesis allows to get more information - henrikbjorn - Marcel Beerta (mazen) - Mantis Development + - Marko Kaznovac (kaznovac) - Hidde Wieringa (hiddewie) - Florent Morselli (spomky_) - dFayet - Rob Frawley 2nd (robfrawley) - Renan (renanbr) + - Karoly Gossler (connorhu) - Nikita Konstantinov (unkind) - Dariusz - Francois Zaninotto @@ -382,12 +385,13 @@ The Symfony Connect username in parenthesis allows to get more information - Benoît Burnichon (bburnichon) - maxime.steinhausser - Oleg Andreyev (oleg.andreyev) + - Priyadi Iman Nurcahyo (priyadi) - Roman Ring (inori) - Xavier Montaña Carreras (xmontana) - Peter Kruithof (pkruithof) + - Alex Hofbauer (alexhofbauer) - Romaric Drigon (romaricdrigon) - Sylvain Fabre (sylfabre) - - Soner Sayakci - Xavier Perez - Arjen Brouwer (arjenjb) - Artem Lopata @@ -421,7 +425,6 @@ The Symfony Connect username in parenthesis allows to get more information - Bob den Otter (bopp) - Thomas Schulz (king2500) - Kyle - - Marko Kaznovac (kaznovac) - Dariusz Rumiński - Philippe SEGATORI (tigitz) - Frank de Jonge @@ -429,7 +432,6 @@ The Symfony Connect username in parenthesis allows to get more information - Dane Powell - Sebastien Morel (plopix) - Christopher Davis (chrisguitarguy) - - Karoly Gossler (connorhu) - Loïc Frémont (loic425) - Matthieu Auger (matthieuauger) - Sergey Belyshkin (sbelyshkin) @@ -544,7 +546,6 @@ The Symfony Connect username in parenthesis allows to get more information - Pavel Kirpitsov (pavel-kirpichyov) - Robert Meijers - Artur Eshenbrener - - Priyadi Iman Nurcahyo (priyadi) - Harm van Tilborg (hvt) - Thomas Perez (scullwm) - Cédric Anne @@ -584,6 +585,7 @@ The Symfony Connect username in parenthesis allows to get more information - Kirill chEbba Chebunin - Pol Dellaiera (drupol) - Alex (aik099) + - javaDeveloperKid - Fabien Villepinte - SiD (plbsid) - Greg Thornton (xdissent) @@ -596,6 +598,7 @@ The Symfony Connect username in parenthesis allows to get more information - Marek Kalnik (marekkalnik) - Vyacheslav Salakhutdinov (megazoll) - Maksym Slesarenko (maksym_slesarenko) + - Marc Biorklund (mbiork) - Hassan Amouhzi - Tamas Szijarto - Michele Locati @@ -645,6 +648,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ben Roberts (benr77) - Valentin Jonovs - geoffrey + - Benoit Galati (benoitgalati) - Benjamin (yzalis) - Jeanmonod David (jeanmonod) - Webnet team (webnet) @@ -670,6 +674,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sergey Melesh (sergex) - Greg Anderson - lancergr + - Benjamin Zaslavsky (tiriel) - Tri Pham (phamuyentri) - Angelov Dejan (angelov) - Ivan Nikolaev (destillat) @@ -687,7 +692,6 @@ The Symfony Connect username in parenthesis allows to get more information - vagrant - Matthias Krauser (mkrauser) - Benjamin Cremer (bcremer) - - Alex Hofbauer (alexhofbauer) - Maarten de Boer (mdeboer) - Asier Illarramendi (doup) - AKeeman (akeeman) @@ -756,7 +760,6 @@ The Symfony Connect username in parenthesis allows to get more information - Jérémy M (th3mouk) - Trent Steel (trsteel88) - boombatower - - javaDeveloperKid - Alireza Mirsepassi (alirezamirsepassi) - Jérôme Macias (jeromemacias) - Andrey Astakhov (aast) @@ -782,6 +785,7 @@ The Symfony Connect username in parenthesis allows to get more information - nikos.sotiropoulos - BENOIT POLASZEK (bpolaszek) - Eduardo Oliveira (entering) + - kor3k kor3k (kor3k) - Oleksii Zhurbytskyi - Bilge - Anatoly Pashin (b1rdex) @@ -892,6 +896,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jan Ole Behrens (deegital) - wicliff wolda (wickedone) - Mantas Var (mvar) + - Ramunas Pabreza (doobas) - Yuriy Vilks (igrizzli) - Terje Bråten - Sebastian Krebs @@ -900,11 +905,11 @@ The Symfony Connect username in parenthesis allows to get more information - Julien Maulny - Gennadi Janzen - Quentin Dequippe (qdequippe) - - Benoit Galati (benoitgalati) - Paul Oms - James Hemery - wuchen90 - Wouter van der Loop (toppy-hennie) + - Ninos - julien57 - Mátyás Somfai (smatyas) - Bastien DURAND (deamon) @@ -932,6 +937,7 @@ The Symfony Connect username in parenthesis allows to get more information - Christin Gruber (christingruber) - Sebastian Blum - Daniel González (daniel.gonzalez) + - Jonathan H. Wage - Julien Turby - Ricky Su (ricky) - scyzoryck @@ -992,7 +998,6 @@ The Symfony Connect username in parenthesis allows to get more information - Rodrigo Aguilera - Vladimir Varlamov (iamvar) - Aurimas Niekis (gcds) - - Benjamin Zaslavsky (tiriel) - Vincent Chalamon - Matthieu Calie (matth--) - Benjamin Schoch (bschoch) @@ -1029,13 +1034,16 @@ The Symfony Connect username in parenthesis allows to get more information - Quentin de Longraye (quentinus95) - Chris Heng (gigablah) - Mickaël Buliard (mbuliard) + - Cornel Cruceru (amne) - Richard Bradley - Ulumuddin Cahyadi Yunus (joenoez) - rtek + - Mickaël Isaert (misaert) - Adrien Jourdier (eclairia) - Florian Pfitzer (marmelatze) - Ivan Grigoriev (greedyivan) - Johann Saunier (prophet777) + - Stiven Llupa (sllupa) - Kevin SCHNEKENBURGER - Fabien Salles (blacked) - Andreas Erhard (andaris) @@ -1113,6 +1121,7 @@ The Symfony Connect username in parenthesis allows to get more information - Aleksandr Volochnev (exelenz) - Robin van der Vleuten (robinvdvleuten) - Grinbergs Reinis (shima5) + - Kieran Brahney - Klaus Silveira (klaussilveira) - Michael Piecko (michael.piecko) - Toni Peric (tperic) @@ -1132,9 +1141,11 @@ The Symfony Connect username in parenthesis allows to get more information - zenas1210 - Gert de Pagter - Julien DIDIER (juliendidier) + - Ворожцов Максим (myks92) - Dalibor Karlović - Randy Geraads - Andreas Leathley (iquito) + - Vladimir Luchaninov (luchaninov) - Sebastian Grodzicki (sgrodzicki) - Mohamed Gamal - Eric COURTIAL @@ -1229,6 +1240,7 @@ The Symfony Connect username in parenthesis allows to get more information - Glodzienski - Natsuki Ikeguchi - Krzysztof Łabuś (crozin) + - Pierre Ambroise (dotordu) - Xavier Lacot (xavier) - Jon Dufresne - possum @@ -1265,7 +1277,6 @@ The Symfony Connect username in parenthesis allows to get more information - Carlos Buenosvinos (carlosbuenosvinos) - Christian Gripp (core23) - Jake (jakesoft) - - kor3k kor3k (kor3k) - Rustam Bakeev (nommyde) - Vincent CHALAMON - Ivan Kurnosov @@ -1304,6 +1315,7 @@ The Symfony Connect username in parenthesis allows to get more information - Tomasz Ignatiuk - andrey1s - Abhoryo + - louismariegaborit - Fabian Vogler (fabian) - Korvin Szanto - Stéphan Kochen @@ -1314,7 +1326,6 @@ The Symfony Connect username in parenthesis allows to get more information - Maksim Kotlyar (makasim) - Neil Ferreira - Julie Hourcade (juliehde) - - Marc Biorklund (mbiork) - Dmitry Parnas (parnas) - Loïc Beurlet - Ana Raro @@ -1411,6 +1422,7 @@ The Symfony Connect username in parenthesis allows to get more information - Markus S. (staabm) - Marc Laporte - Michał Jusięga + - Kay Wei - Dominik Ulrich - den - Gábor Tóth @@ -1447,7 +1459,6 @@ The Symfony Connect username in parenthesis allows to get more information - Patrick Kaufmann - Mickael Perraud - Anton Dyshkant - - Ramunas Pabreza - Rafael Villa Verde - Zoran Makrevski (zmakrevski) - Yann LUCAS (drixs6o9) @@ -1478,6 +1489,7 @@ The Symfony Connect username in parenthesis allows to get more information - The Whole Life to Learn - Pierre Tondereau - Joel Lusavuvu (enigma97) + - Valentin Barbu (jimie) - Alex Vo (votanlean) - Mikkel Paulson - ergiegonzaga @@ -1493,6 +1505,7 @@ The Symfony Connect username in parenthesis allows to get more information - Malte Schlüter - Jules Matsounga (hyoa) - Yewhen Khoptynskyi (khoptynskyi) + - Nicolas Attard (nicolasattard) - Jérôme Nadaud (jnadaud) - Frank Naegler - Sam Malone @@ -1503,7 +1516,6 @@ The Symfony Connect username in parenthesis allows to get more information - xaav - Jean-Christophe Cuvelier [Artack] - Mahmoud Mostafa (mahmoud) - - Ninos - Alexandre Tranchant (alexandre_t) - Anthony Moutte - Ahmed Abdou @@ -1574,6 +1586,7 @@ The Symfony Connect username in parenthesis allows to get more information - Giuseppe Campanelli - Valentin - pizzaminded + - Nicolas Valverde - Konstantin S. M. Möllers (ksmmoellers) - Ken Stanley - ivan @@ -1763,6 +1776,7 @@ The Symfony Connect username in parenthesis allows to get more information - Joan Cruz - inspiran - Alex Demchenko + - Richard van Velzen - Cristobal Dabed - Daniel Mecke (daniel_mecke) - Matteo Giachino (matteosister) @@ -1775,10 +1789,10 @@ The Symfony Connect username in parenthesis allows to get more information - Maximilian Zumbansen - Maximilian Ruta (deltachaos) - Jon Green (jontjs) - - Mickaël Isaert (misaert) - Jakub Sacha - Julius Kiekbusch - Kamil Musial + - Lucas Bustamante - Olaf Klischat - orlovv - Claude Dioudonnat @@ -1786,12 +1800,14 @@ The Symfony Connect username in parenthesis allows to get more information - Peter Smeets (darkspartan) - Julien Bianchi (jubianchi) - Michael Dawart (mdawart) + - Sem Schidler (xvilo) - Robert Meijers - Tijs Verkoyen - James Sansbury - Marcin Chwedziak - hjkl - Dan Wilga + - Thijs Reijgersberg - Jan Böhmer - Florian Heller - Oleksii Svitiashchuk @@ -1800,6 +1816,7 @@ The Symfony Connect username in parenthesis allows to get more information - Tristan Bessoussa (sf_tristanb) - Rodrigo Díez Villamuera (rodrigodiez) - Brad Treloar + - pritasil - Stephen Clouse - e-ivanov - Nathanaël Martel (nathanaelmartel) @@ -1851,7 +1868,6 @@ The Symfony Connect username in parenthesis allows to get more information - Matthias Neid - Yannick - Kuzia - - Vladimir Luchaninov (luchaninov) - spdionis - maxime.perrimond - rchoquet @@ -1917,6 +1933,7 @@ The Symfony Connect username in parenthesis allows to get more information - Raul Rodriguez (raul782) - Piet Steinhart - mousezheng + - Radoslaw Kowalewski - mshavliuk - Rémy LESCALLIER - MightyBranch @@ -1933,6 +1950,7 @@ The Symfony Connect username in parenthesis allows to get more information - Krzysztof Przybyszewski (kprzybyszewski) - Vladimir Mantulo (mantulo) - Boullé William (williamboulle) + - Jesper Noordsij - Frederic Godfrin - Paul Matthews - aim8604 @@ -1943,7 +1961,6 @@ The Symfony Connect username in parenthesis allows to get more information - Juan Traverso - David Legatt (dlegatt) - Alain Flaus (halundra) - - Ворожцов Максим (myks92) - Arthur Woimbée - tsufeki - Théo DELCEY @@ -1974,6 +1991,7 @@ The Symfony Connect username in parenthesis allows to get more information - heccjj - Alexandre Melard - Rafał Toboła + - Dominik Schwind (dominikschwind) - Stefano A. (stefano93) - PierreRebeilleau - AlbinoDrought @@ -2298,7 +2316,6 @@ The Symfony Connect username in parenthesis allows to get more information - Rick Prent - skalpa - Kai - - Jonathan H. Wage - Bartłomiej Zając - Pieter Jordaan - Tournoud (damientournoud) @@ -2350,6 +2367,7 @@ The Symfony Connect username in parenthesis allows to get more information - SnakePin - Matthew Covey - Tristan Kretzer + - Adriaan Zonnenberg - Charly Terrier (charlypoppins) - Dcp (decap94) - Emre Akinci (emre) @@ -2414,6 +2432,7 @@ The Symfony Connect username in parenthesis allows to get more information - izenin - Mephistofeles - Oleh Korneliuk + - Emmanuelpcg - Evgeny Ruban - Hoffmann András - LubenZA @@ -2423,6 +2442,7 @@ The Symfony Connect username in parenthesis allows to get more information - Flavian Sierk - Rik van der Heijden - knezmilos13 + - Thomas Beaujean - alireza - Michael Bessolov - Zdeněk Drahoš @@ -2463,6 +2483,7 @@ The Symfony Connect username in parenthesis allows to get more information - Malte Wunsch (maltewunsch) - Marie Minasyan (marie.minassyan) - Simo Heinonen (simoheinonen) + - Pavel Stejskal (spajxo) - Szymon Kamiński (szk) - Tiago Garcia (tiagojsag) - Artiom @@ -2517,6 +2538,7 @@ The Symfony Connect username in parenthesis allows to get more information - Eric Caron - Arnau González - GurvanVgx + - Jiri Falis - 2manypeople - Wing - Thomas Bibb @@ -2525,6 +2547,7 @@ The Symfony Connect username in parenthesis allows to get more information - Matt Farmer - catch - aetxebeste + - Roberto Guido - roromix - Vitali Tsyrkin - Juga Paazmaya @@ -2535,8 +2558,8 @@ The Symfony Connect username in parenthesis allows to get more information - AntoineDly - Konstantinos Alexiou - Andrii Boiko - - louismariegaborit - Dilek Erkut + - mikocevar - Harold Iedema - WaiSkats - Morimoto Ryosuke @@ -2580,6 +2603,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sebastian Drewer-Gutland (sdg) - Sander van der Vlugt (stranding) - Maxim Tugaev (tugmaks) + - casdal - Florian Bogey - Waqas Ahmed - Bert Hekman @@ -2614,7 +2638,9 @@ The Symfony Connect username in parenthesis allows to get more information - Flinsch - Maciej Schmidt - botbotbot + - Cosmin Sandu - tatankat + - Cláudio Cesar - Timon van der Vorm - nuncanada - Thierry Marianne @@ -2626,7 +2652,9 @@ The Symfony Connect username in parenthesis allows to get more information - Adam Katz - Almog Baku (almogbaku) - Arrakis (arrakis) + - Danil Khaliullin (bifidokk) - Benjamin Schultz (bschultz) + - Christian Grasso (chris54721) - Vladimir Khramtsov (chrome) - Gerd Christian Kunze (derdu) - Stephanie Trumtel (einahp) @@ -2752,6 +2780,7 @@ The Symfony Connect username in parenthesis allows to get more information - Steeve Titeca (stiteca) - Thomas Citharel (tcit) - Artem Lopata (bumz) + - Soha Jin - alex - evgkord - Roman Orlov @@ -2805,6 +2834,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ivo - Ismo Vuorinen - Markus Staab + - Ryan Hendrickson - Valentin - Sören Bernstein - michael.kubovic @@ -2863,7 +2893,6 @@ The Symfony Connect username in parenthesis allows to get more information - Trevor N. Suarez (rican7) - Sergii Dolgushev (serhey) - Clément Bertillon (skigun) - - Stiven Llupa (sllupa) - Rein Baarsma (solidwebcode) - tante kinast (tante) - Stephen Lewis (tehanomalousone) @@ -2880,11 +2909,13 @@ The Symfony Connect username in parenthesis allows to get more information - Tim van Densen - Andrzej - Alexander Zogheb + - tomasz-kusy - Rémi Blaise - Nicolas Séverin - Houssem - Joel Marcey - zolikonta + - Daniel Bartoníček - David Christmann - root - pf @@ -3004,9 +3035,11 @@ The Symfony Connect username in parenthesis allows to get more information - florian-michael-mast - tourze - Vlad Dumitrache + - wetternest - Erik van Wingerden - Valouleloup - Pathpat + - Jaymin G - robmro27 - Vallel Blanco - Alexis MARQUIS @@ -3134,6 +3167,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gabriel Moreira - Alexey Popkov - ChS + - toxxxa - michal - Jannik Zschiesche - Alexis MARQUIS @@ -3208,7 +3242,6 @@ The Symfony Connect username in parenthesis allows to get more information - Steffen Keuper - Kai Eichinger - Antonio Angelino - - Kay Wei - Jens Schulze - Tema Yud - Matt Fields @@ -3242,6 +3275,7 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel Bannert - Karim Miladi - Michael Genereux + - Greg Korba - patrick-mcdougle - Tyler Stroud - Dariusz Czech @@ -3415,6 +3449,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sergio Santoro - tirnanog06 - Andrejs Leonovs + - llupa - Alfonso Fernández García - phc - Дмитрий Пацура @@ -3441,9 +3476,9 @@ The Symfony Connect username in parenthesis allows to get more information - Bernard van der Esch (adeptofvoltron) - Adrian Günter (adrianguenter) - Andreas Forsblom (aforsblo) + - Aleksejs Kovalovs (aleksejs1) - Alex Olmos (alexolmos) - Cedric BERTOLINI (alsciende) - - Cornel Cruceru (amne) - Robin Kanters (anddarerobin) - Antoine (antoinela_adveris) - Juan Ases García (ases) @@ -3467,6 +3502,7 @@ The Symfony Connect username in parenthesis allows to get more information - Kamil Piwowarski (cyklista) - Damon Jones (damon__jones) - David Courtey (david-crty) + - David Gorges (davidgorges) - Alexandre Fiocre (demos77) - Łukasz Giza (destroyer) - Daniel Londero (dlondero) @@ -3578,6 +3614,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ryan Linnit - Konrad - Kovacs Nicolas + - eminjk - craigmarvelley - Stano Turza - Antoine Leblanc @@ -3606,6 +3643,7 @@ The Symfony Connect username in parenthesis allows to get more information - DSeemiller - Jan Emrich - Anne-Julia Seitz + - mindaugasvcs - Mark Topper - Romain - Xavier REN diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 6386318ef97d9..33721ea667c7a 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -13,6 +13,7 @@ use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\JoinColumnMapping; use Doctrine\ORM\Mapping\MappingException as LegacyMappingException; use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\Mapping\MappingException; @@ -119,13 +120,13 @@ public function guessRequired(string $class, string $property) if ($classMetadata->isAssociationWithSingleJoinColumn($property)) { $mapping = $classMetadata->getAssociationMapping($property); - if (!isset($mapping['joinColumns'][0]['nullable'])) { + if (null === self::getMappingValue($mapping['joinColumns'][0], 'nullable')) { // The "nullable" option defaults to true, in that case the // field should not be required. return new ValueGuess(false, Guess::HIGH_CONFIDENCE); } - return new ValueGuess(!$mapping['joinColumns'][0]['nullable'], Guess::HIGH_CONFIDENCE); + return new ValueGuess(!self::getMappingValue($mapping['joinColumns'][0], 'nullable'), Guess::HIGH_CONFIDENCE); } return null; @@ -198,4 +199,18 @@ private static function getRealClass(string $class): string return substr($class, $pos + Proxy::MARKER_LENGTH + 2); } + + /** + * @param array|JoinColumnMapping $mapping + * + * @return mixed + */ + private static function getMappingValue($mapping, string $key) + { + if ($mapping instanceof JoinColumnMapping) { + return $mapping->$key; + } + + return $mapping[$key] ?? null; + } } diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index f33a62cb6257c..daff866d1e5fd 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -16,6 +16,9 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\AssociationMapping; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\EmbeddedClassMapping; +use Doctrine\ORM\Mapping\FieldMapping; +use Doctrine\ORM\Mapping\JoinColumnMapping; use Doctrine\ORM\Mapping\MappingException as OrmMappingException; use Doctrine\Persistence\Mapping\MappingException; use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; @@ -88,20 +91,20 @@ public function getTypes(string $class, string $property, array $context = []) if ($metadata instanceof ClassMetadata) { $associationMapping = $metadata->getAssociationMapping($property); - if (isset($associationMapping['indexBy'])) { - $subMetadata = $this->entityManager->getClassMetadata($associationMapping['targetEntity']); + if (self::getMappingValue($associationMapping, 'indexBy')) { + $subMetadata = $this->entityManager->getClassMetadata(self::getMappingValue($associationMapping, 'targetEntity')); // Check if indexBy value is a property - $fieldName = $associationMapping['indexBy']; + $fieldName = self::getMappingValue($associationMapping, 'indexBy'); if (null === ($typeOfField = $subMetadata->getTypeOfField($fieldName))) { - $fieldName = $subMetadata->getFieldForColumn($associationMapping['indexBy']); + $fieldName = $subMetadata->getFieldForColumn(self::getMappingValue($associationMapping, 'indexBy')); // Not a property, maybe a column name? if (null === ($typeOfField = $subMetadata->getTypeOfField($fieldName))) { // Maybe the column name is the association join column? $associationMapping = $subMetadata->getAssociationMapping($fieldName); $indexProperty = $subMetadata->getSingleAssociationReferencedJoinColumnName($fieldName); - $subMetadata = $this->entityManager->getClassMetadata($associationMapping['targetEntity']); + $subMetadata = $this->entityManager->getClassMetadata(self::getMappingValue($associationMapping, 'targetEntity')); // Not a property, maybe a column name? if (null === ($typeOfField = $subMetadata->getTypeOfField($indexProperty))) { @@ -128,7 +131,7 @@ public function getTypes(string $class, string $property, array $context = []) } if ($metadata instanceof ClassMetadata && isset($metadata->embeddedClasses[$property])) { - return [new Type(Type::BUILTIN_TYPE_OBJECT, false, $metadata->embeddedClasses[$property]['class'])]; + return [new Type(Type::BUILTIN_TYPE_OBJECT, false, self::getMappingValue($metadata->embeddedClasses[$property], 'class'))]; } if ($metadata->hasField($property)) { @@ -140,7 +143,7 @@ public function getTypes(string $class, string $property, array $context = []) $nullable = $metadata instanceof ClassMetadata && $metadata->isNullable($property); $enumType = null; - if (null !== $enumClass = $metadata->getFieldMapping($property)['enumType'] ?? null) { + if (null !== $enumClass = self::getMappingValue($metadata->getFieldMapping($property), 'enumType') ?? null) { $enumType = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $enumClass); } @@ -236,17 +239,17 @@ private function getMetadata(string $class): ?ClassMetadata */ private function isAssociationNullable($associationMapping): bool { - if (isset($associationMapping['id']) && $associationMapping['id']) { + if (self::getMappingValue($associationMapping, 'id')) { return false; } - if (!isset($associationMapping['joinColumns'])) { + if (!self::getMappingValue($associationMapping, 'joinColumns')) { return true; } - $joinColumns = $associationMapping['joinColumns']; + $joinColumns = self::getMappingValue($associationMapping, 'joinColumns'); foreach ($joinColumns as $joinColumn) { - if (isset($joinColumn['nullable']) && !$joinColumn['nullable']) { + if (false === self::getMappingValue($joinColumn, 'nullable')) { return false; } } @@ -302,4 +305,18 @@ private function getPhpType(string $doctrineType): ?string return null; } + + /** + * @param array|AssociationMapping|EmbeddedClassMapping|FieldMapping|JoinColumnMapping $mapping + * + * @return mixed + */ + private static function getMappingValue($mapping, string $key) + { + if ($mapping instanceof AssociationMapping || $mapping instanceof EmbeddedClassMapping || $mapping instanceof FieldMapping || $mapping instanceof JoinColumnMapping) { + return $mapping->$key; + } + + return $mapping[$key] ?? null; + } } diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php index 601ef0f2b5fa6..b168fc7d98711 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php +++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php @@ -13,6 +13,7 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata as OrmClassMetadata; +use Doctrine\ORM\Mapping\FieldMapping; use Doctrine\ORM\Mapping\MappingException as OrmMappingException; use Doctrine\Persistence\Mapping\MappingException; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; @@ -75,7 +76,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool foreach ($doctrineMetadata->fieldMappings as $mapping) { $enabledForProperty = $enabledForClass; $lengthConstraint = null; - foreach ($metadata->getPropertyMetadata($mapping['fieldName']) as $propertyMetadata) { + foreach ($metadata->getPropertyMetadata(self::getFieldMappingValue($mapping, 'fieldName')) as $propertyMetadata) { // Enabling or disabling auto-mapping explicitly always takes precedence if (AutoMappingStrategy::DISABLED === $propertyMetadata->getAutoMappingStrategy()) { continue 2; @@ -95,26 +96,26 @@ public function loadClassMetadata(ClassMetadata $metadata): bool continue; } - if (true === ($mapping['unique'] ?? false) && !isset($existingUniqueFields[$mapping['fieldName']])) { - $metadata->addConstraint(new UniqueEntity(['fields' => $mapping['fieldName']])); + if (true === (self::getFieldMappingValue($mapping, 'unique') ?? false) && !isset($existingUniqueFields[self::getFieldMappingValue($mapping, 'fieldName')])) { + $metadata->addConstraint(new UniqueEntity(['fields' => self::getFieldMappingValue($mapping, 'fieldName')])); $loaded = true; } - if (null === ($mapping['length'] ?? null) || null !== ($mapping['enumType'] ?? null) || !\in_array($mapping['type'], ['string', 'text'], true)) { + if (null === (self::getFieldMappingValue($mapping, 'length') ?? null) || null !== (self::getFieldMappingValue($mapping, 'enumType') ?? null) || !\in_array(self::getFieldMappingValue($mapping, 'type'), ['string', 'text'], true)) { continue; } if (null === $lengthConstraint) { - if (isset($mapping['originalClass']) && !str_contains($mapping['declaredField'], '.')) { - $metadata->addPropertyConstraint($mapping['declaredField'], new Valid()); + if (self::getFieldMappingValue($mapping, 'originalClass') && !str_contains(self::getFieldMappingValue($mapping, 'declaredField'), '.')) { + $metadata->addPropertyConstraint(self::getFieldMappingValue($mapping, 'declaredField'), new Valid()); $loaded = true; - } elseif (property_exists($className, $mapping['fieldName']) && (!$doctrineMetadata->isMappedSuperclass || $metadata->getReflectionClass()->getProperty($mapping['fieldName'])->isPrivate())) { - $metadata->addPropertyConstraint($mapping['fieldName'], new Length(['max' => $mapping['length']])); + } elseif (property_exists($className, self::getFieldMappingValue($mapping, 'fieldName')) && (!$doctrineMetadata->isMappedSuperclass || $metadata->getReflectionClass()->getProperty(self::getFieldMappingValue($mapping, 'fieldName'))->isPrivate())) { + $metadata->addPropertyConstraint(self::getFieldMappingValue($mapping, 'fieldName'), new Length(['max' => self::getFieldMappingValue($mapping, 'length')])); $loaded = true; } } elseif (null === $lengthConstraint->max) { // If a Length constraint exists and no max length has been explicitly defined, set it - $lengthConstraint->max = $mapping['length']; + $lengthConstraint->max = self::getFieldMappingValue($mapping, 'length'); } } @@ -138,4 +139,18 @@ private function getExistingUniqueFields(ClassMetadata $metadata): array return $fields; } + + /** + * @param array|FieldMapping $mapping + * + * @return mixed + */ + private static function getFieldMappingValue($mapping, string $key) + { + if ($mapping instanceof FieldMapping) { + return $mapping->$key; + } + + return $mapping[$key] ?? null; + } } diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index 4f93acd01cdb2..adddfe6f76995 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -403,27 +403,55 @@ private static function hasColorSupport() return false; } - if ('Hyper' === getenv('TERM_PROGRAM')) { + if (!self::isTty()) { + return false; + } + + if ('\\' === \DIRECTORY_SEPARATOR && \function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(\STDOUT)) { return true; } - if (\DIRECTORY_SEPARATOR === '\\') { - return (\function_exists('sapi_windows_vt100_support') - && sapi_windows_vt100_support(\STDOUT)) - || false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || 'xterm' === getenv('TERM'); + if ('Hyper' === getenv('TERM_PROGRAM') + || false !== getenv('COLORTERM') + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + ) { + return true; } + if ('dumb' === $term = (string) getenv('TERM')) { + return false; + } + + // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 + return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); + } + + /** + * Checks if the stream is a TTY, i.e; whether the output stream is connected to a terminal. + * + * Reference: Composer\Util\Platform::isTty + * https://github.com/composer/composer + */ + private static function isTty(): bool + { + // Detect msysgit/mingw and assume this is a tty because detection + // does not work correctly, see https://github.com/composer/composer/issues/9690 + if (\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { + return true; + } + + // Modern cross-platform function, includes the fstat fallback so if it is present we trust it if (\function_exists('stream_isatty')) { return @stream_isatty(\STDOUT); } - if (\function_exists('posix_isatty')) { - return @posix_isatty(\STDOUT); + // Only trusting this if it is positive, otherwise prefer fstat fallback. + if (\function_exists('posix_isatty') && @posix_isatty(\STDOUT)) { + return true; } - $stat = fstat(\STDOUT); + $stat = @fstat(\STDOUT); // Check if formatted mode is S_IFCHR return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; diff --git a/src/Symfony/Bridge/Twig/Node/DumpNode.php b/src/Symfony/Bridge/Twig/Node/DumpNode.php index 3cd92674bd020..4b710f82cb42e 100644 --- a/src/Symfony/Bridge/Twig/Node/DumpNode.php +++ b/src/Symfony/Bridge/Twig/Node/DumpNode.php @@ -11,12 +11,14 @@ namespace Symfony\Bridge\Twig\Node; +use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\Node; /** * @author Julien Galenski */ +#[YieldReady] final class DumpNode extends Node { private $varPrefix; diff --git a/src/Symfony/Bridge/Twig/Node/FormThemeNode.php b/src/Symfony/Bridge/Twig/Node/FormThemeNode.php index 2d4659ae7bb61..e38557ceacbce 100644 --- a/src/Symfony/Bridge/Twig/Node/FormThemeNode.php +++ b/src/Symfony/Bridge/Twig/Node/FormThemeNode.php @@ -12,12 +12,14 @@ namespace Symfony\Bridge\Twig\Node; use Symfony\Component\Form\FormRenderer; +use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\Node; /** * @author Fabien Potencier */ +#[YieldReady] final class FormThemeNode extends Node { public function __construct(Node $form, Node $resources, int $lineno, ?string $tag = null, bool $only = false) diff --git a/src/Symfony/Bridge/Twig/Node/StopwatchNode.php b/src/Symfony/Bridge/Twig/Node/StopwatchNode.php index 796ee4dab8d16..9a69d4eff39fc 100644 --- a/src/Symfony/Bridge/Twig/Node/StopwatchNode.php +++ b/src/Symfony/Bridge/Twig/Node/StopwatchNode.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Twig\Node; +use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\Expression\AssignNameExpression; use Twig\Node\Node; @@ -20,6 +21,7 @@ * * @author Wouter J */ +#[YieldReady] final class StopwatchNode extends Node { public function __construct(Node $name, Node $body, AssignNameExpression $var, int $lineno = 0, ?string $tag = null) diff --git a/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php b/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php index 5a96d7420122f..d24d7f75f236b 100644 --- a/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php +++ b/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Twig\Node; +use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\Expression\AbstractExpression; use Twig\Node\Node; @@ -18,6 +19,7 @@ /** * @author Fabien Potencier */ +#[YieldReady] final class TransDefaultDomainNode extends Node { public function __construct(AbstractExpression $expr, int $lineno = 0, ?string $tag = null) diff --git a/src/Symfony/Bridge/Twig/Node/TransNode.php b/src/Symfony/Bridge/Twig/Node/TransNode.php index 881104c8cc3fd..0224d46ae0e50 100644 --- a/src/Symfony/Bridge/Twig/Node/TransNode.php +++ b/src/Symfony/Bridge/Twig/Node/TransNode.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Twig\Node; +use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\Expression\AbstractExpression; use Twig\Node\Expression\ArrayExpression; @@ -22,6 +23,7 @@ /** * @author Fabien Potencier */ +#[YieldReady] final class TransNode extends Node { public function __construct(Node $body, ?Node $domain = null, ?AbstractExpression $count = null, ?AbstractExpression $vars = null, ?AbstractExpression $locale = null, int $lineno = 0, ?string $tag = null) @@ -53,9 +55,10 @@ public function compile(Compiler $compiler): void $vars = null; } [$msg, $defaults] = $this->compileString($this->getNode('body'), $defaults, (bool) $vars); + $display = class_exists(YieldReady::class) ? 'yield' : 'echo'; $compiler - ->write('echo $this->env->getExtension(\'Symfony\Bridge\Twig\Extension\TranslationExtension\')->trans(') + ->write($display.' $this->env->getExtension(\'Symfony\Bridge\Twig\Extension\TranslationExtension\')->trans(') ->subcompile($msg) ; diff --git a/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php b/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php index c6d3064676937..1ac37b9c64a16 100644 --- a/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Twig\Node\TransNode; +use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Environment; use Twig\Loader\LoaderInterface; @@ -35,7 +36,8 @@ public function testCompileStrict() $this->assertEquals( sprintf( - 'echo $this->env->getExtension(\'Symfony\Bridge\Twig\Extension\TranslationExtension\')->trans("trans %%var%%", array_merge(["%%var%%" => %s], %s), "messages");', + '%s $this->env->getExtension(\'Symfony\Bridge\Twig\Extension\TranslationExtension\')->trans("trans %%var%%", array_merge(["%%var%%" => %s], %s), "messages");', + class_exists(YieldReady::class) ? 'yield' : 'echo', $this->getVariableGetterWithoutStrictCheck('var'), $this->getVariableGetterWithStrictCheck('foo') ), diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php index aabb0061e48b9..18472263ccd23 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php @@ -15,10 +15,14 @@ use Symfony\Component\Config\Builder\ConfigBuilderGenerator; use Symfony\Component\Config\Builder\ConfigBuilderGeneratorInterface; use Symfony\Component\Config\Definition\ConfigurationInterface; +use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; +use Symfony\Component\DependencyInjection\ParameterBag\ContainerBag; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; +use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\KernelInterface; /** @@ -46,12 +50,27 @@ public function warmUp(string $cacheDir) { $generator = new ConfigBuilderGenerator($this->kernel->getBuildDir()); - foreach ($this->kernel->getBundles() as $bundle) { - $extension = $bundle->getContainerExtension(); - if (null === $extension) { - continue; + if ($this->kernel instanceof Kernel) { + /** @var ContainerBuilder $container */ + $container = \Closure::bind(function (Kernel $kernel) { + $containerBuilder = $kernel->getContainerBuilder(); + $kernel->prepareContainer($containerBuilder); + + return $containerBuilder; + }, null, $this->kernel)($this->kernel); + + $extensions = $container->getExtensions(); + } else { + $extensions = []; + foreach ($this->kernel->getBundles() as $bundle) { + $extension = $bundle->getContainerExtension(); + if (null !== $extension) { + $extensions[] = $extension; + } } + } + foreach ($extensions as $extension) { try { $this->dumpExtension($extension, $generator); } catch (\Exception $e) { @@ -71,7 +90,8 @@ private function dumpExtension(ExtensionInterface $extension, ConfigBuilderGener if ($extension instanceof ConfigurationInterface) { $configuration = $extension; } elseif ($extension instanceof ConfigurationExtensionInterface) { - $configuration = $extension->getConfiguration([], new ContainerBuilder($this->kernel->getContainer()->getParameterBag())); + $container = $this->kernel->getContainer(); + $configuration = $extension->getConfiguration([], new ContainerBuilder($container instanceof Container ? new ContainerBag($container) : new ParameterBag())); } if (!$configuration) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php index 4be5c2c98a0a5..20df3f69ed78a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -49,9 +49,6 @@ public function __construct(CacheClearerInterface $cacheClearer, ?Filesystem $fi $this->filesystem = $filesystem ?? new Filesystem(); } - /** - * {@inheritdoc} - */ protected function configure() { $this @@ -71,9 +68,6 @@ protected function configure() ; } - /** - * {@inheritdoc} - */ protected function execute(InputInterface $input, OutputInterface $output): int { $fs = $this->filesystem; @@ -208,7 +202,7 @@ private function isNfs(string $dir): bool if (null === $mounts) { $mounts = []; - if ('/' === \DIRECTORY_SEPARATOR && $files = @file('/proc/mounts')) { + if ('/' === \DIRECTORY_SEPARATOR && is_readable('/proc/mounts') && $files = @file('/proc/mounts')) { foreach ($files as $mount) { $mount = \array_slice(explode(' ', $mount), 1, -3); if (!\in_array(array_pop($mount), ['vboxsf', 'nfs'])) { diff --git a/src/Symfony/Bundle/FrameworkBundle/DataCollector/RouterDataCollector.php b/src/Symfony/Bundle/FrameworkBundle/DataCollector/RouterDataCollector.php index c5d0673deadc3..c2edc86378d64 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DataCollector/RouterDataCollector.php +++ b/src/Symfony/Bundle/FrameworkBundle/DataCollector/RouterDataCollector.php @@ -28,7 +28,7 @@ public function guessRoute(Request $request, $controller) $controller = $controller[0]; } - if ($controller instanceof RedirectController) { + if ($controller instanceof RedirectController && $request->attributes->has('_route')) { return $request->attributes->get('_route'); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php index c64e5d3b4cdd3..85975c62170e0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php @@ -14,9 +14,21 @@ use Symfony\Bundle\FrameworkBundle\CacheWarmer\ConfigBuilderCacheWarmer; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; +use Symfony\Component\Config\Definition\Builder\NodeDefinition; +use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Extension\Extension; +use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Bundle\Bundle; +use Symfony\Component\HttpKernel\Bundle\BundleInterface; use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\HttpKernel\KernelInterface; class ConfigBuilderCacheWarmerTest extends TestCase { @@ -38,21 +50,102 @@ protected function tearDown(): void public function testBuildDirIsUsedAsConfigBuilderOutputDir() { - $kernel = new class($this->varDir) extends Kernel { + $kernel = new TestKernel($this->varDir); + $kernel->boot(); + + $warmer = new ConfigBuilderCacheWarmer($kernel); + $warmer->warmUp($kernel->getCacheDir()); + + self::assertDirectoryExists($kernel->getBuildDir().'/Symfony'); + self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony'); + } + + public function testWithCustomKernelImplementation() + { + $kernel = new class($this->varDir) implements KernelInterface { private $varDir; public function __construct(string $varDir) { - parent::__construct('test', false); - $this->varDir = $varDir; } + public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response + { + return new Response(); + } + public function registerBundles(): iterable { yield new FrameworkBundle(); } + public function registerContainerConfiguration(LoaderInterface $loader): void + { + } + + public function boot(): void + { + } + + public function shutdown(): void + { + } + + public function getBundles(): array + { + $bundles = []; + foreach ($this->registerBundles() as $bundle) { + $bundles[$bundle->getName()] = $bundle; + } + + return $bundles; + } + + public function getBundle(string $name): BundleInterface + { + foreach ($this->getBundles() as $bundleName => $bundle) { + if ($bundleName === $name) { + return $bundle; + } + } + + throw new \InvalidArgumentException(); + } + + public function locateResource(string $name): string + { + return __DIR__; + } + + public function getEnvironment(): string + { + return 'test'; + } + + public function isDebug(): bool + { + return false; + } + + public function getProjectDir(): string + { + return __DIR__; + } + + public function getContainer(): ContainerInterface + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.debug', $this->isDebug()); + + return $container; + } + + public function getStartTime(): float + { + return -\INF; + } + public function getBuildDir(): string { return $this->varDir.'/build'; @@ -63,8 +156,14 @@ public function getCacheDir(): string return $this->varDir.'/cache'; } - public function registerContainerConfiguration(LoaderInterface $loader) + public function getLogDir(): string { + return $this->varDir.'/cache'; + } + + public function getCharset(): string + { + return 'UTF-8'; } }; $kernel->boot(); @@ -72,7 +171,241 @@ public function registerContainerConfiguration(LoaderInterface $loader) $warmer = new ConfigBuilderCacheWarmer($kernel); $warmer->warmUp($kernel->getCacheDir()); - self::assertDirectoryExists($kernel->getBuildDir().'/Symfony'); - self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php'); + } + + public function testExtensionAddedInKernel() + { + $kernel = new class($this->varDir) extends TestKernel { + protected function build(ContainerBuilder $container): void + { + $container->registerExtension(new class() extends Extension implements ConfigurationInterface { + public function load(array $configs, ContainerBuilder $container): void + { + } + + public function getConfigTreeBuilder(): TreeBuilder + { + $treeBuilder = new TreeBuilder('app'); + $rootNode = $treeBuilder->getRootNode(); + + $rootNode + ->children() + ->scalarNode('provider')->end() + ->end() + ; + + return $treeBuilder; + } + + public function getAlias(): string + { + return 'app'; + } + }); + } + }; + $kernel->boot(); + + $warmer = new ConfigBuilderCacheWarmer($kernel); + $warmer->warmUp($kernel->getCacheDir()); + + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/AppConfig.php'); + } + + public function testKernelAsExtension() + { + $kernel = new class($this->varDir) extends TestKernel implements ExtensionInterface, ConfigurationInterface { + public function load(array $configs, ContainerBuilder $container): void + { + } + + public function getXsdValidationBasePath() + { + return false; + } + + public function getNamespace(): string + { + return 'http://www.example.com/schema/acme'; + } + + public function getAlias(): string + { + return 'kernel'; + } + + public function getConfigTreeBuilder(): TreeBuilder + { + $treeBuilder = new TreeBuilder('kernel'); + $rootNode = $treeBuilder->getRootNode(); + + $rootNode + ->children() + ->scalarNode('provider')->end() + ->end() + ; + + return $treeBuilder; + } + }; + $kernel->boot(); + + $warmer = new ConfigBuilderCacheWarmer($kernel); + $warmer->warmUp($kernel->getCacheDir()); + + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/KernelConfig.php'); + } + + public function testExtensionsExtendedInBuildMethods() + { + $kernel = new class($this->varDir) extends TestKernel { + protected function build(ContainerBuilder $container): void + { + /** @var TestSecurityExtension $extension */ + $extension = $container->getExtension('test_security'); + $extension->addAuthenticatorFactory(new class() implements TestAuthenticatorFactoryInterface { + public function getKey(): string + { + return 'token'; + } + + public function addConfiguration(NodeDefinition $node): void + { + } + }); + } + + public function registerBundles(): iterable + { + yield from parent::registerBundles(); + + yield new class() extends Bundle { + public function getContainerExtension(): ExtensionInterface + { + return new TestSecurityExtension(); + } + }; + + yield new class() extends Bundle { + public function build(ContainerBuilder $container): void + { + /** @var TestSecurityExtension $extension */ + $extension = $container->getExtension('test_security'); + $extension->addAuthenticatorFactory(new class() implements TestAuthenticatorFactoryInterface { + public function getKey(): string + { + return 'form-login'; + } + + public function addConfiguration(NodeDefinition $node): void + { + $node + ->children() + ->scalarNode('provider')->end() + ->end() + ; + } + }); + } + }; + } + }; + $kernel->boot(); + + $warmer = new ConfigBuilderCacheWarmer($kernel); + $warmer->warmUp($kernel->getCacheDir()); + + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/SecurityConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/Security/FirewallConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/Security/FirewallConfig/FormLoginConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/Security/FirewallConfig/TokenConfig.php'); + } +} + +class TestKernel extends Kernel +{ + private $varDir; + + public function __construct(string $varDir) + { + parent::__construct('test', false); + + $this->varDir = $varDir; + } + + public function registerBundles(): iterable + { + yield new FrameworkBundle(); + } + + public function getBuildDir(): string + { + return $this->varDir.'/build'; + } + + public function getCacheDir(): string + { + return $this->varDir.'/cache'; + } + + public function registerContainerConfiguration(LoaderInterface $loader): void + { + } +} + +interface TestAuthenticatorFactoryInterface +{ + public function getKey(): string; + + public function addConfiguration(NodeDefinition $builder): void; +} + +class TestSecurityExtension extends Extension implements ConfigurationInterface +{ + /** @var TestAuthenticatorFactoryInterface[] */ + private $factories; + + public function load(array $configs, ContainerBuilder $container): void + { + } + + public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface + { + return $this; + } + + public function addAuthenticatorFactory(TestAuthenticatorFactoryInterface $factory): void + { + $this->factories[] = $factory; + } + + public function getConfigTreeBuilder(): TreeBuilder + { + $treeBuilder = new TreeBuilder('security'); + $rootNode = $treeBuilder->getRootNode(); + + $firewallNodeBuilder = $rootNode + ->fixXmlConfig('firewall') + ->children() + ->arrayNode('firewalls') + ->isRequired() + ->requiresAtLeastOneElement() + ->useAttributeAsKey('name') + ->prototype('array') + ->children() + ; + + foreach ($this->factories as $factory) { + $name = str_replace('-', '_', $factory->getKey()); + $factoryNode = $firewallNodeBuilder->arrayNode($name); + + $factory->addConfiguration($factoryNode); + } + + return $treeBuilder; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DataCollector/RouterDataCollectorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DataCollector/RouterDataCollectorTest.php new file mode 100644 index 0000000000000..5681bd04ae48f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DataCollector/RouterDataCollectorTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\DataCollector; + +use Symfony\Bundle\FrameworkBundle\Controller\RedirectController; +use Symfony\Bundle\FrameworkBundle\DataCollector\RouterDataCollector; +use Symfony\Bundle\FrameworkBundle\Tests\TestCase; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\ControllerEvent; +use Symfony\Component\HttpKernel\KernelInterface; + +class RouterDataCollectorTest extends TestCase +{ + public function testRouteRedirectControllerNoRouteAtrribute() + { + $collector = new RouterDataCollector(); + + $request = Request::create('http://test.com/foo?bar=baz'); + $response = new RedirectResponse('http://test.com/redirect'); + + $event = $this->createControllerEvent($request); + + $collector->onKernelController($event); + $collector->collect($request, $response); + + $this->assertTrue($collector->getRedirect()); + $this->assertEquals('http://test.com/redirect', $collector->getTargetUrl()); + $this->assertEquals('n/a', $collector->getTargetRoute()); + } + + public function testRouteRedirectControllerWithRouteAttribute() + { + $collector = new RouterDataCollector(); + + $request = Request::create('http://test.com/foo?bar=baz'); + $request->attributes->set('_route', 'current-route'); + + $response = new RedirectResponse('http://test.com/redirect'); + + $event = $this->createControllerEvent($request); + + $collector->onKernelController($event); + $collector->collect($request, $response); + + $this->assertTrue($collector->getRedirect()); + $this->assertEquals('http://test.com/redirect', $collector->getTargetUrl()); + $this->assertEquals('current-route', $collector->getTargetRoute()); + } + + protected function createControllerEvent(Request $request): ControllerEvent + { + $kernel = $this->createMock(KernelInterface::class); + + return new ControllerEvent($kernel, new RedirectController(), $request, null); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 8479f1d888f78..c1f08b1837366 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -66,7 +66,7 @@ "symfony/property-info": "^4.4|^5.0|^6.0", "symfony/web-link": "^4.4|^5.0|^6.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "twig/twig": "^2.10|^3.0" + "twig/twig": "^2.10|^3.0.4" }, "conflict": { "doctrine/annotations": "<1.13.1", diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/mailer.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/mailer.html.twig index f7ea5a1f42ace..3897ea77eca32 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/mailer.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/mailer.html.twig @@ -121,14 +121,35 @@

Headers

Subject -

{{ message.getSubject() ?? '(empty)' }}

+ {% if message.subject is defined %} + {# Email instance #} +

{{ message.getSubject() ?? '(empty)' }}

+ {% elseif message.headers.has('subject') %} +

{{ message.headers.get('subject').bodyAsString()|default('(empty)') }}

+ {% else %} +

(empty)

+ {% endif %}
From -
{{ message.getFrom()|map(addr => addr.toString())|join(', ')|default('(empty)') }}
+ {% if message.from is defined %} + {# Email instance #} +
{{ message.getFrom()|map(addr => addr.toString())|join(', ')|default('(empty)') }}
+ {% elseif message.headers.has('from') %} +
{{ message.headers.get('from').bodyAsString()|default('(empty)') }}
+ {% else %} +
(empty)
+ {% endif %} To -
{{ message.getTo()|map(addr => addr.toString())|join(', ')|default('(empty)') }}
+ {% if message.to is defined %} + {# Email instance #} +
{{ message.getTo()|map(addr => addr.toString())|join(', ')|default('(empty)') }}
+ {% elseif message.headers.has('to') %} +
{{ message.headers.get('to').bodyAsString()|default('(empty)') }}
+ {% else %} +
(empty)
+ {% endif %}
Headers @@ -191,6 +212,13 @@
{% endfor %} + {% else %} +
+

Content

+
+
{{ message.body().toString() }}
+
+
{% endif %}

Parts Hierarchy

diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig index 8d06534d6e073..70b5f136814ad 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig @@ -6,7 +6,7 @@
-
+
{% for name, template in templates %} {% if block('toolbar', template) is defined %} {% with { diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index a2a92aefd50df..8fcd7bac5a303 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -250,6 +250,22 @@ public static function createConnection(string $dsn, array $options = []) $extra = [ 'stream' => $params['ssl'] ?? null, ]; + $booleanStreamOptions = [ + 'allow_self_signed', + 'capture_peer_cert', + 'capture_peer_cert_chain', + 'disable_compression', + 'SNI_enabled', + 'verify_peer', + 'verify_peer_name', + ]; + + foreach ($extra['stream'] ?? [] as $streamOption => $value) { + if (\in_array($streamOption, $booleanStreamOptions, true) && \is_string($value)) { + $extra['stream'][$streamOption] = filter_var($value, \FILTER_VALIDATE_BOOL); + } + } + if (isset($params['auth'])) { $extra['auth'] = $params['auth']; } diff --git a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php index dfc46e97fbfa6..faa6ea19b1138 100644 --- a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php +++ b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php @@ -156,7 +156,7 @@ private function safelyUnserialize(string $file) $signalingException = new \UnexpectedValueException(); $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback'); $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) { - if (__FILE__ === $file) { + if (__FILE__ === $file && !\in_array($type, [\E_DEPRECATED, \E_USER_DEPRECATED], true)) { throw $signalingException; } diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index e236be92a3913..7b9de922914dc 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -503,19 +503,7 @@ private function isInteractiveInput($inputStream): bool return self::$stdinIsInteractive; } - if (\function_exists('stream_isatty')) { - return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r')); - } - - if (\function_exists('posix_isatty')) { - return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r')); - } - - if (!\function_exists('shell_exec')) { - return self::$stdinIsInteractive = true; - } - - return self::$stdinIsInteractive = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); + return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r')); } /** diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 408a76d67dd61..698f9693bfad1 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -621,9 +621,10 @@ private function buildTableRows(array $rows): TableRows if (!strstr($cell ?? '', "\n")) { continue; } - $escaped = implode("\n", array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode("\n", $cell))); + $eol = str_contains($cell ?? '', "\r\n") ? "\r\n" : "\n"; + $escaped = implode($eol, array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode($eol, $cell))); $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; - $lines = explode("\n", str_replace("\n", "\n", $cell)); + $lines = explode($eol, str_replace($eol, ''.$eol, $cell)); foreach ($lines as $lineKey => $line) { if ($colspan > 1) { $line = new TableCell($line, ['colspan' => $colspan]); @@ -685,8 +686,9 @@ private function fillNextRows(array $rows, int $line): array $nbLines = $cell->getRowspan() - 1; $lines = [$cell]; if (strstr($cell, "\n")) { - $lines = explode("\n", str_replace("\n", "\n", $cell)); - $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines; + $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n"; + $lines = explode($eol, str_replace($eol, ''.$eol.'', $cell)); + $nbLines = \count($lines) > $nbLines ? substr_count($cell, $eol) : $nbLines; $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); unset($lines[0]); diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php index 1d8dbca310212..99807f59e6bac 100644 --- a/src/Symfony/Component/Console/Input/InputOption.php +++ b/src/Symfony/Component/Console/Input/InputOption.php @@ -69,7 +69,7 @@ public function __construct(string $name, $shortcut = null, ?int $mode = null, s throw new InvalidArgumentException('An option name cannot be empty.'); } - if ('' === $shortcut || [] === $shortcut) { + if ('' === $shortcut || [] === $shortcut || false === $shortcut) { $shortcut = null; } diff --git a/src/Symfony/Component/Console/Output/StreamOutput.php b/src/Symfony/Component/Console/Output/StreamOutput.php index 0ef15cf318b46..5f5ffce329b93 100644 --- a/src/Symfony/Component/Console/Output/StreamOutput.php +++ b/src/Symfony/Component/Console/Output/StreamOutput.php @@ -95,50 +95,29 @@ protected function hasColorSupport() return false; } - if (!$this->isTty()) { + // Detect msysgit/mingw and assume this is a tty because detection + // does not work correctly, see https://github.com/composer/composer/issues/9690 + if (!@stream_isatty($this->stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { return false; } - if (\DIRECTORY_SEPARATOR === '\\' - && \function_exists('sapi_windows_vt100_support') - && @sapi_windows_vt100_support($this->stream) - ) { + if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($this->stream)) { return true; } - return 'Hyper' === getenv('TERM_PROGRAM') + if ('Hyper' === getenv('TERM_PROGRAM') + || false !== getenv('COLORTERM') || false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') - || str_starts_with((string) getenv('TERM'), 'xterm'); - } - - /** - * Checks if the stream is a TTY, i.e; whether the output stream is connected to a terminal. - * - * Reference: Composer\Util\Platform::isTty - * https://github.com/composer/composer - */ - private function isTty(): bool - { - // Detect msysgit/mingw and assume this is a tty because detection - // does not work correctly, see https://github.com/composer/composer/issues/9690 - if (\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { + ) { return true; } - // Modern cross-platform function, includes the fstat fallback so if it is present we trust it - if (\function_exists('stream_isatty')) { - return stream_isatty($this->stream); - } - - // Only trusting this if it is positive, otherwise prefer fstat fallback. - if (\function_exists('posix_isatty') && posix_isatty($this->stream)) { - return true; + if ('dumb' === $term = (string) getenv('TERM')) { + return false; } - $stat = @fstat($this->stream); - - // Check if formatted mode is S_IFCHR - return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; + // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 + return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); } } diff --git a/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php b/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php index 55a840ac7c7a8..83b295fccfcf4 100644 --- a/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php +++ b/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php @@ -69,6 +69,8 @@ public function testShortcut() $this->assertEquals('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in an array'); $option = new InputOption('foo', '0|z'); $this->assertEquals('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in a string-list'); + $option = new InputOption('foo', false); + $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null when given a false as value'); } public function testModes() diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php index fd3173831d2e6..f4d01d8bceef9 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php @@ -25,9 +25,6 @@ class CheckExceptionOnInvalidReferenceBehaviorPass extends AbstractRecursivePass { private $serviceLocatorContextIds = []; - /** - * {@inheritdoc} - */ public function process(ContainerBuilder $container) { $this->serviceLocatorContextIds = []; @@ -58,15 +55,7 @@ protected function processValue($value, bool $isRoot = false) if (isset($this->serviceLocatorContextIds[$currentId])) { $currentId = $this->serviceLocatorContextIds[$currentId]; $locator = $this->container->getDefinition($this->currentId)->getFactory()[0]; - - foreach ($locator->getArgument(0) as $k => $v) { - if ($v->getValues()[0] === $value) { - if ($k !== $id) { - $currentId = $k.'" in the container provided to "'.$currentId; - } - throw new ServiceNotFoundException($id, $currentId, null, $this->getAlternatives($id)); - } - } + $this->throwServiceNotFoundException($value, $currentId, $locator->getArgument(0)); } if ('.' === $currentId[0] && $graph->hasNode($currentId)) { @@ -80,14 +69,21 @@ protected function processValue($value, bool $isRoot = false) $currentId = $sourceId; break; } + + if (isset($this->serviceLocatorContextIds[$sourceId])) { + $currentId = $this->serviceLocatorContextIds[$sourceId]; + $locator = $this->container->getDefinition($this->currentId); + $this->throwServiceNotFoundException($value, $currentId, $locator->getArgument(0)); + } } } - throw new ServiceNotFoundException($id, $currentId, null, $this->getAlternatives($id)); + $this->throwServiceNotFoundException($value, $currentId, $value); } - private function getAlternatives(string $id): array + private function throwServiceNotFoundException(Reference $ref, string $sourceId, $value): void { + $id = (string) $ref; $alternatives = []; foreach ($this->container->getServiceIds() as $knownId) { if ('' === $knownId || '.' === $knownId[0]) { @@ -100,6 +96,31 @@ private function getAlternatives(string $id): array } } - return $alternatives; + $pass = new class() extends AbstractRecursivePass { + public $ref; + public $sourceId; + public $alternatives; + + /** + * @return mixed + */ + public function processValue($value, bool $isRoot = false) + { + if ($this->ref !== $value) { + return parent::processValue($value, $isRoot); + } + $sourceId = $this->sourceId; + if (null !== $this->currentId && $this->currentId !== (string) $value) { + $sourceId = $this->currentId.'" in the container provided to "'.$sourceId; + } + + throw new ServiceNotFoundException((string) $value, $sourceId, null, $this->alternatives); + } + }; + $pass->ref = $ref; + $pass->sourceId = $sourceId; + $pass->alternatives = $alternatives; + + $pass->processValue($value, true); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php index b2bd5023d8f6a..f98d06560d089 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php @@ -82,7 +82,11 @@ public function testProcessDefinitionWithBindings() $this->addToAssertionCount(1); } - public function testWithErroredServiceLocator() + /** + * @testWith [true] + * [false] + */ + public function testWithErroredServiceLocator(bool $inline) { $this->expectException(ServiceNotFoundException::class); $this->expectExceptionMessage('The service "foo" in the container provided to "bar" has a dependency on a non-existent service "baz".'); @@ -91,11 +95,17 @@ public function testWithErroredServiceLocator() ServiceLocatorTagPass::register($container, ['foo' => new Reference('baz')], 'bar'); (new AnalyzeServiceReferencesPass())->process($container); - (new InlineServiceDefinitionsPass())->process($container); + if ($inline) { + (new InlineServiceDefinitionsPass())->process($container); + } $this->process($container); } - public function testWithErroredHiddenService() + /** + * @testWith [true] + * [false] + */ + public function testWithErroredHiddenService(bool $inline) { $this->expectException(ServiceNotFoundException::class); $this->expectExceptionMessage('The service "bar" has a dependency on a non-existent service "foo".'); @@ -104,7 +114,9 @@ public function testWithErroredHiddenService() ServiceLocatorTagPass::register($container, ['foo' => new Reference('foo')], 'bar'); (new AnalyzeServiceReferencesPass())->process($container); - (new InlineServiceDefinitionsPass())->process($container); + if ($inline) { + (new InlineServiceDefinitionsPass())->process($container); + } $this->process($container); } diff --git a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php index d5e81052ce6f3..5db2f30a1c7b4 100644 --- a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php +++ b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php @@ -1097,7 +1097,7 @@ private function fixReturnStatements(\ReflectionMethod $method, string $returnTy $braces = 0; for (; $i < $end; ++$i) { if (!$inClosure) { - $inClosure = str_contains($code[$i], 'function ('); + $inClosure = false !== strpos($code[$i], 'function ('); } if ($inClosure) { diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php index d7b90439a5a5c..28b93c2b158b7 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php @@ -457,7 +457,7 @@ public function handleError(int $type, string $message, string $file, int $line) return true; } } else { - if (false !== strpos($message, '@anonymous')) { + if (PHP_VERSION_ID < 80303 && false !== strpos($message, '@anonymous')) { $backtrace = debug_backtrace(false, 5); for ($i = 1; isset($backtrace[$i]); ++$i) { @@ -465,8 +465,7 @@ public function handleError(int $type, string $message, string $file, int $line) && ('trigger_error' === $backtrace[$i]['function'] || 'user_error' === $backtrace[$i]['function']) ) { if ($backtrace[$i]['args'][0] !== $message) { - $message = $this->parseAnonymousClass($backtrace[$i]['args'][0]); - $logMessage = $this->levels[$type].': '.$message; + $message = $backtrace[$i]['args'][0]; } break; @@ -474,6 +473,11 @@ public function handleError(int $type, string $message, string $file, int $line) } } + if (false !== strpos($message, "@anonymous\0")) { + $message = $this->parseAnonymousClass($message); + $logMessage = $this->levels[$type].': '.$message; + } + $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line); if ($throw || $this->tracedErrors & $type) { diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php index 80b65ad8b3501..5b264fa5a7e90 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php +++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php @@ -329,7 +329,7 @@ private function formatFileFromText(string $text) { return preg_replace_callback('/in ("|")?(.+?)\1(?: +(?:on|at))? +line (\d+)/s', function ($match) { return 'in '.$this->formatFile($match[2], $match[3]); - }, $text); + }, $text) ?? $text; } private function formatLogMessage(string $message, array $context) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.sq.xlf b/src/Symfony/Component/Form/Resources/translations/validators.sq.xlf index 2c730bcfefc69..0feb137f85538 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.sq.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.sq.xlf @@ -1,18 +1,27 @@ +
+ + Për fjalët e huaja, të cilat nuk kanë përkthim të drejtpërdrejtë, ju lutemi të ndiqni rregullat e mëposhtme: + a) në rast se emri është akronim i përdorur gjerësisht si i përveçëm, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Gjinia gjykohet sipas rastit. Shembull: JSON-i (mashkullore) + b) në rast se emri është akronim i papërdorur gjerësisht si i përveçëm, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Gjinia është femërore. Shembull: URL-ja (femërore) + c) në rast se emri duhet lakuar për shkak të rasës në fjali, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Shembull: host-i, prej host-it + d) në rast se emri nuk duhet lakuar për shkak të trajtës në fjali, atëherë, emri rrethohet me thonjëzat “”. Shembull: “locale” + +
This form should not contain extra fields. - Kjo formë nuk duhet të përmbajë fusha shtesë. + Ky formular nuk duhet të përmbajë fusha shtesë. The uploaded file was too large. Please try to upload a smaller file. - Skedari i ngarkuar ishte shumë i madh. Ju lutemi provoni të ngarkoni një skedar më të vogël. + Skeda e ngarkuar ishte shumë e madhe. Ju lutemi provoni të ngarkoni një skedë më të vogël. The CSRF token is invalid. Please try to resubmit the form. - Vlera CSRF është e pavlefshme. Ju lutemi provoni të ridërgoni formën. + Vlera CSRF është e pavlefshme. Ju lutemi provoni të ridërgoni formularin. This value is not a valid HTML5 color. @@ -24,7 +33,7 @@ The selected choice is invalid. - Opsioni i zgjedhur është i pavlefshëm. + Alternativa e zgjedhur është e pavlefshme. The collection is invalid. @@ -40,11 +49,11 @@ Please select a valid currency. - Ju lutemi zgjidhni një monedhë të vlefshme. + Ju lutemi zgjidhni një valutë të vlefshme. Please choose a valid date interval. - Ju lutemi zgjidhni një interval të vlefshëm të datës. + Ju lutemi zgjidhni një interval të vlefshëm. Please enter a valid date and time. @@ -56,7 +65,7 @@ Please select a valid file. - Ju lutemi zgjidhni një skedar të vlefshëm. + Ju lutemi zgjidhni një skedë të vlefshme. The hidden field is invalid. @@ -68,11 +77,11 @@ Please select a valid language. - Ju lutem zgjidhni një gjuhë të vlefshme. + Ju lutemi zgjidhni një gjuhë të vlefshme. Please select a valid locale. - Ju lutemi zgjidhni një lokale të vlefshme. + Ju lutemi zgjidhni një “locale” të vlefshme. Please enter a valid money amount. @@ -96,7 +105,7 @@ Please enter a valid time. - Ju lutemi shkruani një kohë të vlefshme. + Ju lutemi shkruani një orë të vlefshme. Please select a valid timezone. @@ -120,15 +129,15 @@ Please enter a valid email address. - Ju lutemi shkruani një adresë të vlefshme emaili. + Ju lutemi shkruani një adresë të vlefshme email-i. Please select a valid option. - Ju lutemi zgjidhni një opsion të vlefshëm. + Ju lutemi zgjidhni një alternativë të vlefshme. Please select a valid range. - Ju lutemi zgjidhni një diapazon të vlefshëm. + Ju lutemi zgjidhni një seri të vlefshme. Please enter a valid week. diff --git a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php index ae0d004f7651b..890e2e96743c8 100644 --- a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php +++ b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php @@ -65,7 +65,8 @@ public function __construct(HttpClientInterface $client, string $method, string while (true) { foreach (self::stream([$response], $timeout) as $chunk) { if ($chunk->isTimeout() && $response->passthru) { - foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, $chunk->getError())) as $chunk) { + // Timeouts thrown during initialization are transport errors + foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, new TransportException($chunk->getError()))) as $chunk) { if ($chunk->isFirst()) { return false; } diff --git a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php index 0e4befafcf4fb..9edf41318555e 100644 --- a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php @@ -13,13 +13,14 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpClient\Exception\ServerException; -use Symfony\Component\HttpClient\Exception\TimeoutException; +use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\NativeHttpClient; use Symfony\Component\HttpClient\Response\AsyncContext; use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\HttpClient\Retry\GenericRetryStrategy; +use Symfony\Component\HttpClient\Retry\RetryStrategyInterface; use Symfony\Component\HttpClient\RetryableHttpClient; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\Test\TestHttpServer; @@ -247,32 +248,36 @@ public function testRetryOnErrorAssertContent() self::assertSame('Test out content', $response->getContent(), 'Content should be buffered'); } - /** - * @testWith ["GET"] - * ["POST"] - * ["PUT"] - * ["PATCH"] - * ["DELETE"] - */ - public function testRetryOnHeaderTimeout(string $method) + public function testRetryOnTimeout() { $client = HttpClient::create(); - if ($client instanceof NativeHttpClient) { - $this->markTestSkipped('NativeHttpClient cannot timeout before receiving headers'); - } - TestHttpServer::start(); - $client = new RetryableHttpClient($client); - $response = $client->request($method, 'http://localhost:8057/timeout-header', ['timeout' => 0.1]); + $strategy = new class() implements RetryStrategyInterface { + public $isCalled = false; + + public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool + { + $this->isCalled = true; + + return false; + } + + public function getDelay(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): int + { + return 0; + } + }; + $client = new RetryableHttpClient($client, $strategy); + $response = $client->request('GET', 'http://localhost:8057/timeout-header', ['timeout' => 0.1]); try { $response->getStatusCode(); - $this->fail(TimeoutException::class.' expected'); - } catch (TimeoutException $e) { + $this->fail(TransportException::class.' expected'); + } catch (TransportException $e) { } - $this->assertSame('Idle timeout reached for "http://localhost:8057/timeout-header".', $response->getInfo('error')); + $this->assertTrue($strategy->isCalled, 'The HTTP retry strategy should be called'); } } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 13734f1b36e10..556682e22b7a3 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,11 +78,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.35'; - public const VERSION_ID = 50435; + public const VERSION = '5.4.36'; + public const VERSION_ID = 50436; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 35; + public const RELEASE_VERSION = 36; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php index 368fbd28c3375..e2db2487578fc 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php @@ -160,7 +160,7 @@ public function initialize(): void } stream_set_blocking($this->stream, true); - stream_set_timeout($this->stream, $timeout); + stream_set_timeout($this->stream, (int) $timeout, (int) (($timeout - (int) $timeout) * 1000000)); $this->in = &$this->stream; $this->out = &$this->stream; } diff --git a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/Connection.php index dba0514a19b71..49fd1c638f3c6 100644 --- a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/Connection.php @@ -129,7 +129,7 @@ public static function fromDsn(string $dsn, array $options = [], ?HttpClientInte 'buffer_size' => (int) $options['buffer_size'], 'wait_time' => (int) $options['wait_time'], 'poll_timeout' => $options['poll_timeout'], - 'visibility_timeout' => $options['visibility_timeout'], + 'visibility_timeout' => null !== $options['visibility_timeout'] ? (int) $options['visibility_timeout'] : null, 'auto_setup' => filter_var($options['auto_setup'], \FILTER_VALIDATE_BOOLEAN), 'queue_name' => (string) $options['queue_name'], ]; diff --git a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php index b0c9fe46f59c3..3ea7784d862fd 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php @@ -535,7 +535,7 @@ static function () { public function queue(string $queueName): \AMQPQueue { if (!isset($this->amqpQueues[$queueName])) { - $queueConfig = $this->queuesOptions[$queueName]; + $queueConfig = $this->queuesOptions[$queueName] ?? []; $amqpQueue = $this->amqpFactory->createQueue($this->channel()); $amqpQueue->setName($queueName); diff --git a/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Transport/Connection.php index 7ce26eec29f87..df1f7ab56901f 100644 --- a/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Transport/Connection.php @@ -182,6 +182,7 @@ public function reject(string $id): void public function getMessageCount(): int { try { + $this->client->useTube($this->tube); $tubeStats = $this->client->statsTube($this->tube); } catch (Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineTransportFactory.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineTransportFactory.php index 4ddb85882970c..4011decd85be2 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineTransportFactory.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineTransportFactory.php @@ -35,6 +35,9 @@ public function __construct($registry) $this->registry = $registry; } + /** + * @param array $options You can set 'use_notify' to false to not use LISTEN/NOTIFY with postgresql + */ public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface { $useNotify = ($options['use_notify'] ?? true); diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php index 4d0c3f422971d..545856d762339 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php @@ -16,6 +16,8 @@ /** * Uses PostgreSQL LISTEN/NOTIFY to push messages to workers. * + * If you do not want to use the LISTEN mechanism, set the `use_notify` option to `false` when calling DoctrineTransportFactory::createTransport. + * * @internal * * @author Kévin Dunglas @@ -23,12 +25,10 @@ final class PostgreSqlConnection extends Connection { /** - * * use_notify: Set to false to disable the use of LISTEN/NOTIFY. Default: true * * check_delayed_interval: The interval to check for delayed messages, in milliseconds. Set to 0 to disable checks. Default: 60000 (1 minute) * * get_notify_timeout: The length of time to wait for a response when calling PDO::pgsqlGetNotify, in milliseconds. Default: 0. */ protected const DEFAULT_OPTIONS = parent::DEFAULT_OPTIONS + [ - 'use_notify' => true, 'check_delayed_interval' => 60000, 'get_notify_timeout' => 0, ]; diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php index 3617dcab53d71..d24576a9e9743 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php @@ -326,7 +326,7 @@ public function testGetAfterReject() $failing = $connection->get(); $connection->reject($failing['id']); - $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget', ['delete_after_ack' => true]); + $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget', ['delete_after_ack' => true], $redis); $this->assertNotNull($connection->get()); } finally { $redis->unlink('messenger-rejectthenget'); diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php index 17db02965b822..0af44fd32e068 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php @@ -58,7 +58,7 @@ private function safelyUnserialize(string $contents) $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback'); $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler) { - if (__FILE__ === $file) { + if (__FILE__ === $file && !\in_array($type, [\E_DEPRECATED, \E_USER_DEPRECATED], true)) { throw new \ErrorException($msg, 0, $type, $file, $line); } diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/README.md b/src/Symfony/Component/Notifier/Bridge/Smsapi/README.md index 8d5d0b8318f3d..faea65b8221f4 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsapi/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/README.md @@ -1,7 +1,8 @@ SMSAPI Notifier =============== -Provides [Smsapi](https://ssl.smsapi.pl) integration for Symfony Notifier. +Provides [Smsapi](https://smsapi.pl) integration for Symfony Notifier. +This bridge can also be used with https://smsapi.com. DSN example ----------- @@ -10,11 +11,16 @@ DSN example SMSAPI_DSN=smsapi://TOKEN@default?from=FROM ``` +// for https://smsapi.com set the correct endpoint: +``` +SMSAPI_DSN=smsapi://TOKEN@api.smsapi.com?from=FROM +``` + where: - `TOKEN` is your API Token (OAuth) - `FROM` is the sender name -See your account info at https://ssl.smsapi.pl/ +See your account info at https://smsapi.pl or https://smsapi.com Resources --------- diff --git a/src/Symfony/Component/PasswordHasher/Command/UserPasswordHashCommand.php b/src/Symfony/Component/PasswordHasher/Command/UserPasswordHashCommand.php index 1d0e1d09fa71e..70499f4f21e35 100644 --- a/src/Symfony/Component/PasswordHasher/Command/UserPasswordHashCommand.php +++ b/src/Symfony/Component/PasswordHasher/Command/UserPasswordHashCommand.php @@ -70,7 +70,7 @@ protected function configure() Suppose that you have the following security configuration in your application: -# app/config/security.yml +# config/packages/security.yml security: password_hashers: Symfony\Component\Security\Core\User\InMemoryUser: plaintext diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 2b6ed9efa9e27..a4b0a784cf26e 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -80,6 +80,7 @@ class Process implements \IteratorAggregate private $processPipes; private $latestSignal; + private $cachedExitCode; private static $sigchild; @@ -1345,6 +1346,19 @@ protected function updateStatus(bool $blocking) $this->processInformation = proc_get_status($this->process); $running = $this->processInformation['running']; + // In PHP < 8.3, "proc_get_status" only returns the correct exit status on the first call. + // Subsequent calls return -1 as the process is discarded. This workaround caches the first + // retrieved exit status for consistent results in later calls, mimicking PHP 8.3 behavior. + if (\PHP_VERSION_ID < 80300) { + if (!isset($this->cachedExitCode) && !$running && -1 !== $this->processInformation['exitcode']) { + $this->cachedExitCode = $this->processInformation['exitcode']; + } + + if (isset($this->cachedExitCode) && !$running && -1 === $this->processInformation['exitcode']) { + $this->processInformation['exitcode'] = $this->cachedExitCode; + } + } + $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running); if ($this->fallbackStatus && $this->isSigchildEnabled()) { diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index daf842e1f9889..a2e370de664e4 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1541,6 +1541,60 @@ public function testEnvCaseInsensitiveOnWindows() } } + public function testMultipleCallsToProcGetStatus() + { + $process = $this->getProcess('echo foo'); + $process->start(static function () use ($process) { + return $process->isRunning(); + }); + while ($process->isRunning()) { + usleep(1000); + } + $this->assertSame(0, $process->getExitCode()); + } + + public function testFailingProcessWithMultipleCallsToProcGetStatus() + { + $process = $this->getProcess('exit 123'); + $process->start(static function () use ($process) { + return $process->isRunning(); + }); + while ($process->isRunning()) { + usleep(1000); + } + $this->assertSame(123, $process->getExitCode()); + } + + /** + * @group slow + */ + public function testLongRunningProcessWithMultipleCallsToProcGetStatus() + { + $process = $this->getProcess('sleep 1 && echo "done" && php -r "exit(0);"'); + $process->start(static function () use ($process) { + return $process->isRunning(); + }); + while ($process->isRunning()) { + usleep(1000); + } + $this->assertSame(0, $process->getExitCode()); + } + + /** + * @group slow + */ + public function testLongRunningProcessWithMultipleCallsToProcGetStatusError() + { + $process = $this->getProcess('sleep 1 && echo "failure" && php -r "exit(123);"'); + $process->start(static function () use ($process) { + return $process->isRunning(); + }); + while ($process->isRunning()) { + usleep(1000); + } + $this->assertSame(123, $process->getExitCode()); + } + /** * @group transient-on-windows */ @@ -1556,7 +1610,6 @@ public function testNotTerminableInputPipe() /** * @param string|array $commandline - * @param mixed $input */ private function getProcess($commandline, ?string $cwd = null, ?array $env = null, $input = null, ?int $timeout = 60): Process { diff --git a/src/Symfony/Component/Security/Http/Authenticator/InteractiveAuthenticatorInterface.php b/src/Symfony/Component/Security/Http/Authenticator/InteractiveAuthenticatorInterface.php index 71b6ade28d085..d7a6b516476a1 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/InteractiveAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Http/Authenticator/InteractiveAuthenticatorInterface.php @@ -16,8 +16,8 @@ * be used by interactive authenticators. * * Interactive login requires explicit user action (e.g. a login - * form or HTTP basic authentication). Implementing this interface - * will dispatch the InteractiveLoginEvent upon successful login. + * form). Implementing this interface will dispatch the InteractiveLoginEvent + * upon successful login. * * @author Wouter de Jong */ diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 9b3c129bbf657..06f2c3907b2f6 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -301,7 +301,7 @@ private function safelyUnserialize(string $serializedToken) $token = null; $prevUnserializeHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler) { - if (__FILE__ === $file) { + if (__FILE__ === $file && !\in_array($type, [\E_DEPRECATED, \E_USER_DEPRECATED], true)) { throw new \ErrorException($msg, 0x37313BC, $type, $file, $line); } diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 8643aa98ce624..2192f8ac23c97 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -410,10 +410,16 @@ protected function instantiateObject(array &$data, string $class, array &$contex continue; } + $constructorParameterType = 'unknown'; + $reflectionType = $constructorParameter->getType(); + if ($reflectionType instanceof \ReflectionNamedType) { + $constructorParameterType = $reflectionType->getName(); + } + $exception = NotNormalizableValueException::createForUnexpectedDataType( sprintf('Failed to create object because the class misses the "%s" property.', $constructorParameter->name), $data, - ['unknown'], + [$constructorParameterType], $context['deserialization_path'], true ); diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 921d3fd010ef8..1fa299682dd3f 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -1308,7 +1308,7 @@ public function testCollectDenormalizationErrorsWithConstructor(?ClassMetadataFa [ 'currentType' => 'array', 'expectedTypes' => [ - 'unknown', + 'string', ], 'path' => 'string', 'useMessageForUser' => true, @@ -1317,7 +1317,7 @@ public function testCollectDenormalizationErrorsWithConstructor(?ClassMetadataFa [ 'currentType' => 'array', 'expectedTypes' => [ - 'unknown', + 'int', ], 'path' => 'int', 'useMessageForUser' => true, @@ -1548,7 +1548,7 @@ public function testPartialDenormalizationWithMissingConstructorTypes() [ 'currentType' => 'array', 'expectedTypes' => [ - 'unknown', + 'string', ], 'path' => 'two', 'useMessageForUser' => true, diff --git a/src/Symfony/Component/String/Inflector/EnglishInflector.php b/src/Symfony/Component/String/Inflector/EnglishInflector.php index 30b18a3814faf..60eace3c9b283 100644 --- a/src/Symfony/Component/String/Inflector/EnglishInflector.php +++ b/src/Symfony/Component/String/Inflector/EnglishInflector.php @@ -291,6 +291,12 @@ final class EnglishInflector implements InflectorInterface // circuses (circus) ['suc', 3, true, true, 'cuses'], + // hippocampi (hippocampus) + ['supmacoppih', 11, false, false, 'hippocampi'], + + // campuses (campus) + ['sup', 3, true, true, 'puses'], + // status (status) ['sutats', 6, true, true, ['status', 'statuses']], diff --git a/src/Symfony/Component/String/Tests/Inflector/EnglishInflectorTest.php b/src/Symfony/Component/String/Tests/Inflector/EnglishInflectorTest.php index 378592282e883..51849fd42540a 100644 --- a/src/Symfony/Component/String/Tests/Inflector/EnglishInflectorTest.php +++ b/src/Symfony/Component/String/Tests/Inflector/EnglishInflectorTest.php @@ -298,6 +298,8 @@ public static function pluralizeProvider() ['waltz', 'waltzes'], ['wife', 'wives'], ['icon', 'icons'], + ['hippocampus', 'hippocampi'], + ['campus', 'campuses'], // test casing: if the first letter was uppercase, it should remain so ['Man', 'Men'], diff --git a/src/Symfony/Component/Validator/Constraints/Collection.php b/src/Symfony/Component/Validator/Constraints/Collection.php index 316033508a62e..d7a1a8f69ade5 100644 --- a/src/Symfony/Component/Validator/Constraints/Collection.php +++ b/src/Symfony/Component/Validator/Constraints/Collection.php @@ -42,7 +42,7 @@ class Collection extends Composite */ public function __construct($fields = null, ?array $groups = null, $payload = null, ?bool $allowExtraFields = null, ?bool $allowMissingFields = null, ?string $extraFieldsMessage = null, ?string $missingFieldsMessage = null) { - if (\is_array($fields) && ([] === $fields || ($firstField = reset($fields)) instanceof Constraint || ($firstField[0] ?? null) instanceof Constraint)) { + if (self::isFieldsOption($fields)) { $fields = ['fields' => $fields]; } @@ -87,4 +87,31 @@ protected function getCompositeOption() { return 'fields'; } + + private static function isFieldsOption($options): bool + { + if (!\is_array($options)) { + return false; + } + + foreach ($options as $optionOrField) { + if ($optionOrField instanceof Constraint) { + return true; + } + + if (null === $optionOrField) { + continue; + } + + if (!\is_array($optionOrField)) { + return false; + } + + if ($optionOrField && !($optionOrField[0] ?? null) instanceof Constraint) { + return false; + } + } + + return true; + } } diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf index fcae07cec0e79..9ca83564ebadc 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Tato hodnota není platnou IP adresou. + Tato hodnota není platnou IP adresou. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - V php.ini nebyla nastavena cesta k dočasnému adresáři, nebo nastavený adresář neexistuje. + V php.ini nebyla nastavena cesta k dočasnému adresáři, nebo nastavený adresář neexistuje. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Tato hodnota není platným Mezinárodním bankovním číslem účtu (IBAN). + Tato hodnota není platným Mezinárodním bankovním číslem účtu (IBAN). This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Tato hodnota není platným Kódem obchodního identifikátoru (BIC). + Tato hodnota není platným Kódem obchodního identifikátoru (BIC). Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Tato hodnota není platným UUID. + Tato hodnota není platným UUID. This value should be a multiple of {{ compared_value }}. @@ -436,7 +436,7 @@ This value is not a valid MAC address. - Tato hodnota není platnou MAC adresou. + Tato hodnota není platnou MAC adresou.
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 4c1fa82e2f471..abe75d5304ae3 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Este valor no es una dirección IP válida. + Este valor no es una dirección IP válida. This value is not a valid language. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Este valor no es un Número de Cuenta Bancaria Internacional (IBAN) válido. + Este valor no es un Número de Cuenta Bancaria Internacional (IBAN) válido. This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Este valor no es un Código de Identificación de Negocios (BIC) válido. + Este valor no es un Código de Identificación de Negocios (BIC) válido. Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Este valor no es un UUID válido. + Este valor no es un UUID válido. This value should be a multiple of {{ compared_value }}. @@ -436,7 +436,7 @@ This value is not a valid MAC address. - Este valor no es una dirección MAC válida. + Este valor no es una dirección MAC válida. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf index 853d7a09954ef..0af593467f591 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - See väärtus ei ole kehtiv IP-aadress. + See väärtus ei ole kehtiv IP-aadress. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - php.ini-s ei olnud seadistatud ajutist kausta, või seadistatud kaust ei eksisteeri. + Ajutine kaust php.ini-s ei olnud seadistatud või seadistatud kaust ei eksisteeri. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - See väärtus ei ole kehtiv Rahvusvaheline Pangakonto Number (IBAN). + See väärtus ei ole kehtiv Rahvusvaheline Kontonumber (IBAN). This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - See väärtus ei ole kehtiv Äriühingu Tuvastuskood (BIC). + See väärtus ei ole kehtiv BIC-kood. Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - See väärtus ei ole kehtiv UUID. + See väärtus ei ole kehtiv UUID. This value should be a multiple of {{ compared_value }}. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index 9186d8b3bae84..eed237ce27e40 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - Privremena mapa nije konfigurirana u php.ini, ili konfigurirana mapa ne postoji. + Privremena mapa nije konfigurirana u php.ini-u, ili konfigurirana mapa ne postoji. Cannot write temporary file to disk. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf index 56591ac0fa729..df39afd709671 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Ez az érték nem érvényes IP-cím. + Ez az érték nem érvényes IP-cím. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - Nem lett ideiglenes mappa beállítva a php.ini-ben, vagy a beállított mappa nem létezik. + Nem lett ideiglenes mappa beállítva a php.ini-ben, vagy a beállított mappa nem létezik. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Ez az érték nem érvényes Nemzetközi Bankszámlaszám (IBAN). + Ez az érték nem érvényes Nemzetközi Bankszámlaszám (IBAN). This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Ez az érték nem érvényes Üzleti Azonosító Kód (BIC). + Ez az érték nem érvényes Üzleti Azonosító Kód (BIC). Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Ez az érték nem érvényes UUID. + Ez az érték nem érvényes UUID. This value should be a multiple of {{ compared_value }}. @@ -436,7 +436,7 @@ This value is not a valid MAC address. - Ez az érték nem érvényes MAC-cím. + Ez az érték nem érvényes MAC-cím. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index 8fe556696d7cc..bd7b25882d82c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Questo valore non è un indirizzo IP valido. + Questo valore non è un indirizzo IP valido. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - Nessuna cartella temporanea è stata configurata in php.ini, o la cartella configurata non esiste. + Non è stata configurata una cartella temporanea in php.ini, o la cartella configurata non esiste. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Questo valore non è un Numero di Conto Bancario Internazionale (IBAN) valido. + Questo valore non è un IBAN valido. This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Questo valore non è un Codice Identificativo di Business (BIC) valido. + Questo valore non è un codice identificativo bancario (BIC) valido. Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Questo valore non è un UUID valido. + Questo valore non è un UUID valido. This value should be a multiple of {{ compared_value }}. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index b8c00c26cc61f..81d57cab48eec 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -432,7 +432,7 @@ The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. - De gedetecteerde karaktercodering is ongeldig ({{ detected }}). Toegestane coderingen zijn {{ encodings }}. + De gedetecteerde karaktercodering is ongeldig ({{ detected }}). Toegestane coderingen zijn {{ encodings }}. This value is not a valid MAC address. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index b380f686eeaa0..5861a6d1434c6 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Este valor não é um endereço IP válido. + Este valor não é um endereço IP válido. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - Nenhuma pasta temporária foi configurada no php.ini, ou a pasta configurada não existe. + Nenhuma pasta temporária foi configurada no php.ini, ou a pasta configurada não existe. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Este valor não é um Número de Conta Bancária Internacional (IBAN) válido. + Este valor não é um Número de Conta Bancária Internacional (IBAN) válido. This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Este valor não é um Código de Identificação de Negócio (BIC) válido. + Este valor não é um Código de Identificação de Negócio (BIC) válido. Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Este valor não é um UUID válido. + Este valor não é um UUID válido. This value should be a multiple of {{ compared_value }}. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index 5c4a4cd308cfb..426f6319cee20 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Această valoare nu este o adresă IP validă. + Această valoare nu este o adresă de IP validă. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - Nu a fost configurat niciun folder temporar în php.ini, sau folderul configurat nu există. + Nu a fost configurat niciun folder temporar în php.ini, sau folderul configurat nu există. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Această valoare nu este un Număr de Cont Bancar Internațional (IBAN) valid. + Această valoare nu este un Număr de Cont Bancar Internațional (IBAN) valid. This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Această valoare nu este un Cod de Identificare a Afacerilor (BIC) valid. + Această valoare nu este un Cod de Identificare a Afacerilor (BIC) valid. Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Această valoare nu este un UUID valid. + Această valoare nu este un UUID valid. This value should be a multiple of {{ compared_value }}. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index 2e96883727892..22900d5c266b5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Это значение не является действительным IP-адресом. + Это значение не является действительным IP-адресом. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - В php.ini не была настроена временная папка, или настроенная папка не существует. + В php.ini не была настроена временная папка, или настроенная папка не существует. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Это значение не является действительным Международным банковским счетом (IBAN). + Это значение не является действительным Международным банковским счетом (IBAN). This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Это значение не является действительным Бизнес-идентификатором (BIC). + Это значение не является действительным Бизнес-идентификатором (BIC). Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Это значение не является действительным UUID. + Это значение не является действительным UUID. This value should be a multiple of {{ compared_value }}. @@ -436,7 +436,7 @@ This value is not a valid MAC address. - Это значение не является действительным MAC-адресом. + Это значение не является действительным MAC-адресом. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf index 252a51969a78d..596a66166cf4d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Ta vrednost ni veljaven IP naslov. + Ta vrednost ni veljaven IP naslov. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - V php.ini ni bila nastavljena začasna mapa, ali nastavljena mapa ne obstaja. + V php.ini ni bila nastavljena začasna mapa, ali pa nastavljena mapa ne obstaja. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Ta vrednost ni veljavna Mednarodna številka bančnega računa (IBAN). + Ta vrednost ni veljavna mednarodna številka bančnega računa (IBAN). This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Ta vrednost ni veljavna Poslovna identifikacijska koda (BIC). + Ta vrednost ni veljavna poslovna identifikacijska koda (BIC). Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Ta vrednost ni veljaven UUID. + Ta vrednost ni veljaven UUID. This value should be a multiple of {{ compared_value }}. @@ -436,7 +436,7 @@ This value is not a valid MAC address. - Ta vrednost ni veljaven MAC naslov. + Ta vrednost ni veljaven MAC naslov. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf index d04b4af8561d8..3ac3603144ca2 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf @@ -1,6 +1,15 @@ +
+ + Për fjalët e huaja, të cilat nuk kanë përkthim të drejtpërdrejtë, ju lutemi të ndiqni rregullat e mëposhtme: + a) në rast se emri është akronim i përdorur gjerësisht si i përveçëm, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Gjinia gjykohet sipas rastit. Shembull: JSON (mashkullore) + b) në rast se emri është akronim i papërdorur gjerësisht si i përveçëm, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Gjinia është femërore. Shembull: URL (femërore) + c) në rast se emri duhet lakuar për shkak të rasës në fjali, atëherë, emri lakohet pa thonjëza dhe mbaresa shkruhet me vizë ndarëse. Shembull: host-i, prej host-it + d) në rast se emri nuk duhet lakuar për shkak të trajtës në fjali, atëherë, emri rrethote me thonjëzat “”. Shembull: “locale” + +
This value should be false. @@ -24,11 +33,11 @@ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Duhet të zgjedhni së paku {{ limit }} alternativë.|Duhet të zgjedhni së paku {{ limit }} alternativa. + Duhet të zgjidhni së paku {{ limit }} alternativë.|Duhet të zgjidhni së paku {{ limit }} alternativa. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Duhet të zgjedhni më së shumti {{ limit }} alternativë.|Duhet të zgjedhni më së shumti {{ limit }} alternativa. + Duhet të zgjidhni së shumti {{ limit }} alternativë.|Duhet të zgjidhni së shumti {{ limit }} alternativa. One or more of the given values is invalid. @@ -48,7 +57,7 @@ This value is not a valid datetime. - Kjo vlerë nuk është datë-kohë e vlefshme. + Kjo vlerë nuk është datë dhe orë e vlefshme. This value is not a valid email address. @@ -56,19 +65,19 @@ The file could not be found. - File nuk mund të gjindej. + Skeda nuk u gjet. The file is not readable. - File nuk është i lexueshëm. + Skeda nuk është e lexueshme. The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. - File është shumë i madh ({{ size }} {{ suffix }}). Madhësia maksimale e lejuar është {{ limit }} {{ suffix }}. + Skeda është shumë e madhe ({{ size }} {{ suffix }}). Madhësia maksimale e lejuar është {{ limit }} {{ suffix }}. The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - Lloji mime i file-it është i pavlefshëm ({{ type }}). Llojet mime të lejuara janë {{ types }}. + Lloji “mime” i skedës është i pavlefshëm ({{ type }}). Llojet “mime” të lejuara janë {{ types }}. This value should be {{ limit }} or less. @@ -76,7 +85,7 @@ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Kjo vlerë është shumë e gjatë. Duhet të përmbaj {{ limit }} karakter ose më pak.|Kjo vlerë është shumë e gjatë. Duhet të përmbaj {{ limit }} karaktere ose më pak. + Kjo vlerë është shumë e gjatë. Duhet të përmbajë {{ limit }} karakter ose më pak.|Kjo vlerë është shumë e gjatë. Duhet të përmbajë {{ limit }} karaktere ose më pak. This value should be {{ limit }} or more. @@ -84,7 +93,7 @@ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Kjo vlerë është shumë e shkurtër. Duhet të përmbaj {{ limit }} karakter ose më shumë.|Kjo vlerë është shumë e shkurtër. Duhet të përmbaj {{ limit }} karaktere ose më shumë. + Kjo vlerë është shumë e shkurtër. Duhet të përmbajë {{ limit }} karakter ose më shumë.|Kjo vlerë është shumë e shkurtër. Duhet të përmbajë {{ limit }} karaktere ose më shumë. This value should not be blank. @@ -92,11 +101,11 @@ This value should not be null. - Kjo vlerë nuk duhet të jetë null. + Kjo vlerë nuk duhet të jetë “null”. This value should be null. - Kjo vlerë duhet të jetë null. + Kjo vlerë duhet të jetë “null”. This value is not valid. @@ -104,7 +113,7 @@ This value is not a valid time. - Kjo vlerë nuk është kohë e vlefshme. + Kjo vlerë nuk është një orë e vlefshme. This value is not a valid URL. @@ -116,39 +125,39 @@ The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. - Ky file është shumë i madh. Madhësia maksimale e lejuar është {{ limit }} {{ suffix }}. + Kjo skedë është shumë e madhe. Madhësia maksimale e lejuar është {{ limit }} {{ suffix }}. The file is too large. - Ky file është shumë i madh. + Kjo skedë është shumë e madhe. The file could not be uploaded. - Ky file nuk mund të ngarkohet. + Kjo skedë nuk mund të ngarkohet. This value should be a valid number. - Kjo vlerë duhet të jetë numër i vlefshëm. + Kjo vlerë duhet të jetë një numër i vlefshëm. This file is not a valid image. - Ky file nuk është imazh i vlefshëm. + Kjo skedë nuk është një imazh i vlefshëm. This value is not a valid IP address. - Kjo vlerë nuk është një adresë IP e vlefshme. + Kjo vlerë nuk është një adresë IP e vlefshme. This value is not a valid language. - Kjo vlerë nuk është gjuhë e vlefshme. + Kjo vlerë nuk është një gjuhë e vlefshme. This value is not a valid locale. - Kjo vlerë nuk është nje locale i vlefshëm. + Kjo vlerë nuk është nje “locale” e vlefshme. This value is not a valid country. - Kjo vlerë nuk është shtet i vlefshëm. + Kjo vlerë nuk është një shtet i vlefshëm. This value is already used. @@ -176,7 +185,7 @@ This value should be the user's current password. - Kjo vlerë duhet të jetë fjalëkalimi aktual i përdoruesit. + Kjo vlerë duhet të jetë fjalëkalimi i tanishëm i përdoruesit. This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. @@ -184,23 +193,23 @@ The file was only partially uploaded. - Ky file është ngarkuar pjesërisht. + Kjo skedë është ngarkuar pjesërisht. No file was uploaded. - Nuk është ngarkuar ndonjë file. + Nuk është ngarkuar ndonjë skedë. No temporary folder was configured in php.ini, or the configured folder does not exist. - Asnjë dosje e përkohshme nuk është konfiguruar në php.ini, ose dosja e konfiguruar nuk ekziston. + Nuk është konfiguruar asnjë skedar i përkohshëm në php.ini, ose skedari i konfiguruar nuk ekziston. Cannot write temporary file to disk. - Nuk mund të shkruhet file i përkohshëm në disk. + Nuk mund të shkruhet skeda e përkohshme në disk. A PHP extension caused the upload to fail. - Një ekstension i PHP-së shkaktoi dështimin e ngarkimit. + Një shtojcë PHP shkaktoi dështimin e ngarkimit. This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. @@ -224,7 +233,7 @@ This value is not a valid International Bank Account Number (IBAN). - Kjo vlerë nuk është një Numër i Llogarisë Bankare Ndërkombëtare (IBAN) i vlefshëm. + Kjo vlerë nuk është një Numër Llogarie Bankare Ndërkombëtare (IBAN) i vlefshëm. This value is not a valid ISBN-10. @@ -244,7 +253,7 @@ This value is not a valid currency. - Kjo vlerë nuk është një monedhë e vlefshme. + Kjo vlerë nuk është një valutë e vlefshme. This value should be equal to {{ compared_value }}. @@ -300,7 +309,7 @@ An empty file is not allowed. - Një file i zbrazët nuk lejohet. + Një skedë e zbrazët nuk lejohet. The host could not be resolved. @@ -312,7 +321,7 @@ This value is not a valid Business Identifier Code (BIC). - Kjo vlerë nuk është një Kod Identifikues i Biznesit (BIC) i vlefshëm. + Kjo vlerë nuk është një Kod Identifikues Biznesi (BIC) i vlefshëm. Error @@ -320,7 +329,7 @@ This value is not a valid UUID. - Kjo vlerë nuk është një UUID i vlefshëm. + Kjo vlerë nuk është një UUID e vlefshme. This value should be a multiple of {{ compared_value }}. @@ -328,7 +337,7 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. - Ky Kod Identifikues i Biznesit (BIC) nuk është i lidhur me IBAN {{ iban }}. + Ky Kod Identifikues Biznesi (BIC) nuk është i lidhur me IBAN {{ iban }}. This value should be valid JSON. @@ -368,7 +377,7 @@ This value is not a valid hostname. - Kjo vlerë nuk është një emër i vlefshëm hosti. + Kjo vlerë nuk është një emër i vlefshëm host-i. The number of elements in this collection should be a multiple of {{ compared_value }}. @@ -404,7 +413,7 @@ The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. - Emri i skedarit është shumë i gjatë. Duhet të ketë maksimumi {{ filename_max_length }} karakter ose më pak.|Emri i skedarit është shumë i gjatë. Duhet të ketë maksimumi {{ filename_max_length }} karaktere ose më pak. + Emri i skedës është shumë i gjatë. Duhet të ketë maksimumi {{ filename_max_length }} karakter ose më pak.|Emri i skedës është shumë i gjatë. Duhet të ketë maksimumi {{ filename_max_length }} karaktere ose më pak. The password strength is too low. Please use a stronger password. @@ -420,7 +429,7 @@ Mixing numbers from different scripts is not allowed. - Përzierja e numrave nga skriptet e ndryshme nuk lejohet. + Përzierja e numrave nga shkrimet e ndryshme nuk lejohet. Using hidden overlay characters is not allowed. @@ -432,7 +441,7 @@ The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. - Kodimi i karakterit të identifikuar është i pavlefshëm ({{ detected }}). Kodimet e lejuara janë {{ encodings }}. + Kodimi i karakterit të identifikuar është i pavlefshëm ({{ detected }}). Kodimet e lejuara janë {{ encodings }}. This value is not a valid MAC address. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf index 2ec539cc5b5ee..ec106fa78ebb7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Detta värde är inte en giltig IP-adress. + Värdet är inte en giltig IP-adress. This value is not a valid language. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini, or the configured folder does not exist. - Ingen tillfällig mapp konfigurerades i php.ini, eller den konfigurerade mappen finns inte. + Ingen tillfällig mapp konfigurerades i php.ini, eller den konfigurerade mappen finns inte. Cannot write temporary file to disk. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Detta värde är inte ett giltigt Internationellt Bankkontonummer (IBAN). + Värdet är inte ett giltigt internationellt bankkontonummer (IBAN). This value is not a valid ISBN-10. @@ -308,11 +308,11 @@ This value does not match the expected {{ charset }} charset. - Detta värde har inte den förväntade teckenkodningen {{ charset }}. + Värdet har inte den förväntade teckenkodningen {{ charset }}. This value is not a valid Business Identifier Code (BIC). - Detta värde är inte en giltig Företagsidentifieringskod (BIC). + Värdet är inte en giltig BIC-kod. Error @@ -320,11 +320,11 @@ This value is not a valid UUID. - Detta värde är inte en giltig UUID. + Värdet är inte en giltig UUID. This value should be a multiple of {{ compared_value }}. - Detta värde ska vara en multipel av {{ compared_value }}. + Värdet ska vara en multipel av {{ compared_value }}. This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. @@ -332,7 +332,7 @@ This value should be valid JSON. - Detta värde ska vara giltig JSON. + Värdet ska vara giltig JSON. This collection should contain only unique elements. @@ -340,23 +340,23 @@ This value should be positive. - Detta värde bör vara positivt. + Värdet ska vara positivt. This value should be either positive or zero. - Detta värde bör vara antingen positivt eller noll. + Värdet ska vara antingen positivt eller noll. This value should be negative. - Detta värde bör vara negativt. + Värdet ska vara negativt. This value should be either negative or zero. - Detta värde bör vara antingen negativt eller noll. + Värdet ska vara antingen negativt eller noll. This value is not a valid timezone. - Detta värde är inte en giltig tidszon. + Värdet är inte en giltig tidszon. This password has been leaked in a data breach, it must not be used. Please use another password. @@ -364,7 +364,7 @@ This value should be between {{ min }} and {{ max }}. - Detta värde bör ligga mellan {{ min }} och {{ max }}. + Värdet bör ligga mellan {{ min }} och {{ max }}. This value is not a valid hostname. @@ -376,7 +376,7 @@ This value should satisfy at least one of the following constraints: - Det här värdet skall uppfylla minst ett av följande krav: + Värdet ska uppfylla minst ett av följande krav: Each element of this collection should satisfy its own set of constraints. @@ -384,19 +384,19 @@ This value is not a valid International Securities Identification Number (ISIN). - Det här värdet är inte ett giltigt "International Securities Identification Number" (ISIN). + Värdet är inte ett giltigt "International Securities Identification Number" (ISIN). This value should be a valid expression. - Det här värdet bör vara ett giltigt uttryck. + Värdet ska vara ett giltigt uttryck. This value is not a valid CSS color. - Det här värdet är inte en giltig CSS-färg. + Värdet är inte en giltig CSS-färg. This value is not a valid CIDR notation. - Det här värdet är inte en giltig CIDR-notation. + Värdet är inte en giltig CIDR-notation. The value of the netmask should be between {{ min }} and {{ max }}. @@ -412,7 +412,7 @@ This value contains characters that are not allowed by the current restriction-level. - Detta värde innehåller tecken som inte är tillåtna. + Värdet innehåller tecken som inte är tillåtna. Using invisible characters is not allowed. @@ -436,7 +436,7 @@ This value is not a valid MAC address. - Detta värde är inte en giltig MAC-adress. + Värdet är inte en giltig MAC-adress.
diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php index 2b9acb8d43fa4..19cffc693158f 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php @@ -170,6 +170,50 @@ public function testEmptyFieldsInOptions() 'extraFieldsMessage' => 'foo bar baz', ]); + $this->assertSame([], $constraint->fields); + $this->assertTrue($constraint->allowExtraFields); + $this->assertSame('foo bar baz', $constraint->extraFieldsMessage); + } + + /** + * @testWith [[]] + * [null] + */ + public function testEmptyConstraintListForField(?array $fieldConstraint) + { + $constraint = new Collection( + [ + 'foo' => $fieldConstraint, + ], + null, + null, + true, + null, + 'foo bar baz' + ); + + $this->assertArrayHasKey('foo', $constraint->fields); + $this->assertInstanceOf(Required::class, $constraint->fields['foo']); + $this->assertTrue($constraint->allowExtraFields); + $this->assertSame('foo bar baz', $constraint->extraFieldsMessage); + } + + /** + * @testWith [[]] + * [null] + */ + public function testEmptyConstraintListForFieldInOptions(?array $fieldConstraint) + { + $constraint = new Collection([ + 'fields' => [ + 'foo' => $fieldConstraint, + ], + 'allowExtraFields' => true, + 'extraFieldsMessage' => 'foo bar baz', + ]); + + $this->assertArrayHasKey('foo', $constraint->fields); + $this->assertInstanceOf(Required::class, $constraint->fields['foo']); $this->assertTrue($constraint->allowExtraFields); $this->assertSame('foo bar baz', $constraint->extraFieldsMessage); } diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index abb29a952cb8a..3e86e4ab49faa 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -610,19 +610,30 @@ private function hasColorSupport($stream): bool return false; } - if ('Hyper' === getenv('TERM_PROGRAM')) { + // Detect msysgit/mingw and assume this is a tty because detection + // does not work correctly, see https://github.com/composer/composer/issues/9690 + if (!@stream_isatty($stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { + return false; + } + + if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($stream)) { + return true; + } + + if ('Hyper' === getenv('TERM_PROGRAM') + || false !== getenv('COLORTERM') + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + ) { return true; } - if (\DIRECTORY_SEPARATOR === '\\') { - return (\function_exists('sapi_windows_vt100_support') - && @sapi_windows_vt100_support($stream)) - || false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || 'xterm' === getenv('TERM'); + if ('dumb' === $term = (string) getenv('TERM')) { + return false; } - return stream_isatty($stream); + // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 + return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); } /** diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php index 1c7dcc07ff4e9..dba799c55cfe3 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php @@ -370,9 +370,7 @@ public function testThrowingCaster() › twig source › } - %s%eTemplate.php:%d { …} - %s%eTemplate.php:%d { …} - %s%eTemplate.php:%d { …} + %A%eTemplate.php:%d { …} %s%eTests%eDumper%eCliDumperTest.php:%d { …} %A } } @@ -572,7 +570,7 @@ public function testCollapse() ], [ 'bar' => 123, - ] + ], ]); $dumper = new CliDumper();