From 6128dd0b75a864cea57f99a78dc2e372da7c43c2 Mon Sep 17 00:00:00 2001 From: JohJohan Date: Thu, 21 May 2020 10:16:02 +0200 Subject: [PATCH 001/120] ticket_36879 - Fix mandrill raw http request setting from email/name --- .../Mailchimp/Tests/Transport/MandrillHttpTransportTest.php | 3 ++- .../Bridge/Mailchimp/Transport/MandrillHttpTransport.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php index cfdc30bb78e63..22d0a8c75f65e 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php @@ -57,8 +57,9 @@ public function testSend() $body = json_decode($options['body'], true); $message = $body['raw_message']; $this->assertSame('KEY', $body['key']); + $this->assertSame('Fabien', $body['from_name']); + $this->assertSame('fabpot@symfony.com', $body['from_email']); $this->assertSame('saif.gmati@symfony.com', $body['to'][0]); - $this->assertSame('Fabien ', $body['from_email']); $this->assertStringContainsString('Subject: Hello!', $message); $this->assertStringContainsString('To: Saif Eddin ', $message); diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php index 82cdcff73f6f4..33ac42f903d30 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php @@ -49,7 +49,8 @@ protected function doSendHttp(SentMessage $message): ResponseInterface 'to' => array_map(function (Address $recipient): string { return $recipient->getAddress(); }, $envelope->getRecipients()), - 'from_email' => $envelope->getSender()->toString(), + 'from_email' => $envelope->getSender()->getAddress(), + 'from_name' => $envelope->getSender()->getName(), 'raw_message' => $message->toString(), ], ]); From ab5ac9a02dd6e6526dfc569f646a2ca08d16fe10 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 12 Jun 2020 12:56:53 +0200 Subject: [PATCH 002/120] updated CHANGELOG for 3.4.42 --- CHANGELOG-3.4.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG-3.4.md b/CHANGELOG-3.4.md index dfd39c33e34d0..a2da20414f835 100644 --- a/CHANGELOG-3.4.md +++ b/CHANGELOG-3.4.md @@ -7,6 +7,16 @@ in 3.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/v3.4.0...v3.4.1 +* 3.4.42 (2020-06-12) + + * bug #37103 [Form] switch the context when validating nested forms (xabbuh) + * bug #37182 [HttpKernel] Fix regression where Store does not return response body correctly (mpdude) + * bug #36913 [FrameworkBundle] fix type annotation on ControllerTrait::addFlash() (ThomasLandauer) + * bug #37169 [Cache] fix forward compatibility with Doctrine DBAL 3 (xabbuh) + * bug #37085 [Form] properly cascade validation to child forms (xabbuh) + * bug #37095 [PhpUnitBridge] Fix undefined index when output of "composer show" cannot be parsed (nicolas-grekas) + * bug #37092 [PhpUnitBridge] fix undefined var on version 3.4 (nicolas-grekas) + * 3.4.41 (2020-05-31) * bug #36894 [Validator] never directly validate Existence (Required/Optional) constraints (xabbuh) From 4a02bde238fa0d4b18512452ace4a12315886326 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 12 Jun 2020 12:57:05 +0200 Subject: [PATCH 003/120] update CONTRIBUTORS for 3.4.42 --- CONTRIBUTORS.md | 53 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index baf025cfe0487..cd95879aaaa07 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -65,18 +65,18 @@ Symfony is the result of the work of many people who made the code better - Kevin Bond (kbond) - Saša Stamenković (umpirsky) - Peter Rehm (rpet) + - Gábor Egyed (1ed) - Gabriel Ostrolucký (gadelat) - Henrik Bjørnskov (henrikbjorn) - - Gábor Egyed (1ed) - Miha Vrhovnik - David Maicher (dmaicher) + - Titouan Galopin (tgalopin) - Diego Saint Esteben (dii3g0) - Jan Schädlich (jschaedl) - - Titouan Galopin (tgalopin) - Konstantin Kudryashov (everzet) + - Vladimir Reznichenko (kalessil) - Bilal Amarni (bamarni) - Mathieu Piot (mpiot) - - Vladimir Reznichenko (kalessil) - Florin Patan (florinpatan) - Jáchym Toušek (enumag) - Andrej Hudec (pulzarraider) @@ -91,12 +91,12 @@ Symfony is the result of the work of many people who made the code better - Henrik Westphal (snc) - Dariusz Górecki (canni) - David Buchmann (dbu) + - Jérôme Tamarelle (gromnan) - Graham Campbell (graham) - Dariusz Ruminski - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) - - Jérôme Tamarelle (gromnan) - Daniel Holmes (dholmes) - Toni Uebernickel (havvg) - Fran Moreno (franmomu) @@ -106,11 +106,11 @@ Symfony is the result of the work of many people who made the code better - Antoine Hérault (herzult) - Paráda József (paradajozsef) - Arnaud Le Blanc (arnaud-lb) + - Sebastiaan Stok (sstok) - Maxime STEINHAUSSER - Baptiste Clavié (talus) - Michal Piotrowski (eventhorizon) - Tim Nagel (merk) - - Sebastiaan Stok (sstok) - Chris Wilkinson (thewilkybarkid) - Brice BERNARD (brikou) - marc.weistroff @@ -170,6 +170,7 @@ Symfony is the result of the work of many people who made the code better - Philipp Wahala (hifi) - Rafael Dohms (rdohms) - jwdeitch + - Ahmed TAILOULOUTE (ahmedtai) - Mikael Pajunen - Arman Hosseini (arman) - Niels Keurentjes (curry684) @@ -177,7 +178,6 @@ Symfony is the result of the work of many people who made the code better - Richard van Laak (rvanlaak) - Richard Shank (iampersistent) - Thomas Rabaix (rande) - - Ahmed TAILOULOUTE (ahmedtai) - Vincent Touzet (vincenttouzet) - jeremyFreeAgent (jeremyfreeagent) - Rouven Weßling (realityking) @@ -198,6 +198,7 @@ Symfony is the result of the work of many people who made the code better - GDIBass - Samuel NELA (snela) - Saif (╯°□°)╯ (azjezz) + - Gary PEGEOT (gary-p) - James Halsall (jaitsu) - Matthieu Napoli (mnapoli) - Florent Mata (fmata) @@ -220,7 +221,6 @@ Symfony is the result of the work of many people who made the code better - DQNEO - Andre Rømcke (andrerom) - mcfedr (mcfedr) - - Gary PEGEOT (gary-p) - Ruben Gonzalez (rubenrua) - Benjamin Dulau (dbenjamin) - Jan Rosier (rosier) @@ -244,6 +244,7 @@ Symfony is the result of the work of many people who made the code better - Matthieu Bontemps (mbontemps) - apetitpa - Pierre Minnieur (pminnieur) + - David Prévot - fivestar - Dominique Bongiraud - Jeremy Livingston (jeremylivingston) @@ -277,7 +278,6 @@ Symfony is the result of the work of many people who made the code better - Ruud Kamphuis (ruudk) - Pavel Batanov (scaytrase) - Mantis Development - - David Prévot - Loïc Faugeron - Hidde Wieringa (hiddewie) - dFayet @@ -371,6 +371,7 @@ Symfony is the result of the work of many people who made the code better - Chris Smith (cs278) - Thomas Bisignani (toma) - Florian Klein (docteurklein) + - Benjamin Leveque (benji07) - Manuel Kiessling (manuelkiessling) - Atsuhiro KUBO (iteman) - rudy onfroy (ronfroy) @@ -407,6 +408,7 @@ Symfony is the result of the work of many people who made the code better - Dariusz Rumiński - Berny Cantos (xphere81) - Thierry Thuon (lepiaf) + - Guilhem N (guilhemn) - Ricard Clau (ricardclau) - Mark Challoner (markchalloner) - Philippe Segatori @@ -432,6 +434,7 @@ Symfony is the result of the work of many people who made the code better - Tomasz Kowalczyk (thunderer) - Artur Eshenbrener - Timo Bakx (timobakx) + - Harm van Tilborg (hvt) - Thomas Perez (scullwm) - Felix Labrecque - Yaroslav Kiliba @@ -471,7 +474,6 @@ Symfony is the result of the work of many people who made the code better - Michele Locati - Pavel Volokitin (pvolok) - Valentine Boineau (valentineboineau) - - Benjamin Leveque (benji07) - Arthur de Moulins (4rthem) - Matthias Althaus (althaus) - Nicolas Dewez (nicolas_dewez) @@ -516,10 +518,11 @@ Symfony is the result of the work of many people who made the code better - Steffen Roßkamp - Alexandru Furculita (afurculita) - Valentin Jonovs (valentins-jonovs) - - Guilhem N (guilhemn) + - Sebastien Morel (plopix) - Jeanmonod David (jeanmonod) - Christopher Davis (chrisguitarguy) - Webnet team (webnet) + - Joe Bennett (kralos) - Farhad Safarov - Jan Schumann - Niklas Fiekas @@ -556,6 +559,7 @@ Symfony is the result of the work of many people who made the code better - Ariel Ferrandini (aferrandini) - Dirk Pahl (dirkaholic) - cedric lombardot (cedriclombardot) + - Arkadius Stefanski (arkadius) - Tim Goudriaan (codedmonkey) - Jonas Flodén (flojon) - Tobias Weichart @@ -621,6 +625,7 @@ Symfony is the result of the work of many people who made the code better - Maks Slesarenko - Filip Procházka (fprochazka) - mmoreram + - Jeroen Thora (bolle) - Markus Lanthaler (lanthaler) - Remi Collet - Vicent Soria Durá (vicentgodella) @@ -688,6 +693,7 @@ Symfony is the result of the work of many people who made the code better - Pavel Campr (pcampr) - Andrii Dembitskyi - Johnny Robeson (johnny) + - Thomas Landauer (thomas-landauer) - Guilliam Xavier - Disquedur - Michiel Boeckaert (milio) @@ -701,13 +707,11 @@ Symfony is the result of the work of many people who made the code better - Piotr Stankowski - Baptiste Leduc (bleduc) - Julien Maulny - - Sebastien Morel (plopix) - Jean-Christophe Cuvelier [Artack] - Julien Montel (julienmgel) - Simon DELICATA - Artem Henvald (artemgenvald) - Dmitry Simushev - - Joe Bennett (kralos) - alcaeus - Thomas Talbot (ioni) - Fred Cox @@ -722,10 +726,12 @@ Symfony is the result of the work of many people who made the code better - Marvin Butkereit - Renan - Ricky Su (ricky) + - Marcin Szepczynski (czepol) - Kyle Evans (kevans91) - Charles-Henri Bruyand - Max Rath (drak3) - Stéphane Escandell (sescandell) + - Baptiste Leduc (korbeil) - Konstantin S. M. Möllers (ksmmoellers) - James Johnston - Noémi Salaün (noemi-salaun) @@ -776,7 +782,6 @@ Symfony is the result of the work of many people who made the code better - maxime.steinhausser - adev - Stefan Warman - - Arkadius Stefanski (arkadius) - Tristan Maindron (tmaindron) - Behnoush Norouzali (behnoush) - Wesley Lancel @@ -949,12 +954,10 @@ Symfony is the result of the work of many people who made the code better - Jayson Xu (superjavason) - Hubert Lenoir (hubert_lenoir) - fago - - Harm van Tilborg - Jan Prieser - GDIBass - Antoine Lamirault - Adrien Lucas (adrienlucas) - - Jeroen Thora (bolle) - Zhuravlev Alexander (scif) - Stefano Degenkamp (steef) - James Michael DuPont @@ -1038,7 +1041,6 @@ Symfony is the result of the work of many people who made the code better - Don Pinkster - Maksim Muruev - Emil Einarsson - - Thomas Landauer - 243083df - Thibault Duplessis - Rimas Kudelis @@ -1060,6 +1062,7 @@ Symfony is the result of the work of many people who made the code better - Hugo Alliaume (kocal) - Marcos Gómez Vilches (markitosgv) - Matthew Davis (mdavis1982) + - Paulo Ribeiro (paulo) - Markus S. (staabm) - Benjamin Morel - Maks @@ -1118,7 +1121,6 @@ Symfony is the result of the work of many people who made the code better - xaav - Mahmoud Mostafa (mahmoud) - Antonio Jose Cerezo (ajcerezo) - - Baptiste Leduc (korbeil) - Ahmed Abdou - Daniel Iwaniec - Thomas Ferney @@ -1157,6 +1159,8 @@ Symfony is the result of the work of many people who made the code better - zairig imad (zairigimad) - Anton Babenko (antonbabenko) - Irmantas Šiupšinskas (irmantas) + - Benoit Mallo + - Lescot Edouard (idetox) - Danilo Silva - Giuseppe Campanelli - Arnaud PETITPAS (apetitpa) @@ -1226,11 +1230,13 @@ Symfony is the result of the work of many people who made the code better - gr1ev0us - mlazovla - Alejandro Diaz Torres + - quentin neyrat (qneyrat) - Max Beutel - Jan Vernieuwe (vernija) - Antanas Arvasevicius - Pierre Dudoret - Thomas + - j.schmitt - Maximilian Berghoff (electricmaxxx) - nacho - Piotr Antosik (antek88) @@ -1326,7 +1332,9 @@ Symfony is the result of the work of many people who made the code better - Carlos Ortega Huetos - rpg600 - Péter Buri (burci) + - John VanDeWeghe - kaiwa + - Claude Khedhiri (ck-developer) - Charles Sanquer (csanquer) - Albert Ganiev (helios-ag) - Neil Katin @@ -1363,6 +1371,7 @@ Symfony is the result of the work of many people who made the code better - arnaud (arnooo999) - Gilles Doge (gido) - Oscar Esteve (oesteve) + - Sobhan Sharifi (50bhan) - abulford - Philipp Kretzschmar - antograssiot @@ -1412,6 +1421,7 @@ Symfony is the result of the work of many people who made the code better - Marc Torres - Mark Spink - Alberto Aldegheri + - Sagrario Meneses - Dmitri Petmanson - heccjj - Alexandre Melard @@ -1731,7 +1741,9 @@ Symfony is the result of the work of many people who made the code better - Przemysław Piechota (kibao) - Leonid Terentyev (li0n) - Martynas Sudintas (martiis) + - Douglas Hammond (wizhippo) - ryunosuke + - Bruno BOUTAREL - victoria - Francisco Facioni (fran6co) - Stanislav Gamayunov (happyproff) @@ -1864,6 +1876,7 @@ Symfony is the result of the work of many people who made the code better - Pavel.Batanov - avi123 - Pavel Prischepa + - Sami Mussbach - alsar - downace - Aarón Nieves Fernández @@ -1891,6 +1904,7 @@ Symfony is the result of the work of many people who made the code better - Brian Graham (incognito) - Kevin Vergauwen (innocenzo) - Alessio Baglio (ioalessio) + - Jeroen Noten (jeroennoten) - Johannes Müller (johmue) - Jordi Llonch (jordillonch) - Nicholas Ruunu (nicholasruunu) @@ -1911,6 +1925,7 @@ Symfony is the result of the work of many people who made the code better - Alexey Popkov - Gijs Kunze - Artyom Protaskin + - Steven Dubois - Nathanael d. Noblet - helmer - ged15 @@ -1983,6 +1998,7 @@ Symfony is the result of the work of many people who made the code better - Andrew Marcinkevičius (ifdattic) - Ioana Hazsda (ioana-hazsda) - Jan Marek (janmarek) + - Dmitriy Mamontov (mamontovdmitriy) - Mark de Haan (markdehaan) - Dan Patrick (mdpatrick) - naitsirch (naitsirch) @@ -2343,6 +2359,7 @@ Symfony is the result of the work of many people who made the code better - Ben Miller - Peter Gribanov - Matteo Galli + - Loenix - kwiateusz - jspee - Ilya Bulakh @@ -2466,7 +2483,6 @@ Symfony is the result of the work of many people who made the code better - Marco Petersen (ocrampete16) - ollie harridge (ollietb) - Paul Andrieux (paulandrieux) - - Paulo Ribeiro (paulo) - Paweł Szczepanek (pauluz) - Philippe Degeeter (pdegeeter) - Christian López Espínola (penyaskito) @@ -2521,6 +2537,7 @@ Symfony is the result of the work of many people who made the code better - MaPePeR - Andreas Streichardt - Alexandre Segura + - Marco Pfeiffer - Vivien - Pascal Hofmann - david-binda From 4d48338b6c1643c78fa2eb52c298b1914fd99476 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 12 Jun 2020 12:57:07 +0200 Subject: [PATCH 004/120] updated VERSION for 3.4.42 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index a0eb026f60fa9..1f0e29b97cef5 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.42-DEV'; + const VERSION = '3.4.42'; const VERSION_ID = 30442; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; const RELEASE_VERSION = 42; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From b30f4c1537147cc592374b6ef635a337fe476be5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 12 Jun 2020 13:14:22 +0200 Subject: [PATCH 005/120] bumped Symfony version to 3.4.43 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 1f0e29b97cef5..7fad1ee281311 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.42'; - const VERSION_ID = 30442; + const VERSION = '3.4.43-DEV'; + const VERSION_ID = 30443; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; - const RELEASE_VERSION = 42; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 43; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From 055dd28bb8bdac2fc40b9d903cc69625a82dc969 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 12 Jun 2020 13:19:16 +0200 Subject: [PATCH 006/120] bumped Symfony version to 4.4.11 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 25e8202cdb997..6b08101e216c8 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - const VERSION = '4.4.10'; - const VERSION_ID = 40410; + const VERSION = '4.4.11-DEV'; + const VERSION_ID = 40411; const MAJOR_VERSION = 4; const MINOR_VERSION = 4; - const RELEASE_VERSION = 10; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 11; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2022'; const END_OF_LIFE = '11/2023'; From 992205a759a339e81615b19d759c5bab89c387ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sat, 13 Jun 2020 16:49:13 +0200 Subject: [PATCH 007/120] Fix precendence in 4.4 --- .../Tests/Transport/Doctrine/ConnectionTest.php | 10 +++++----- .../Messenger/Transport/Doctrine/Connection.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php index b4348d4958a48..c0204cdf4b270 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php @@ -209,7 +209,7 @@ public function buildConfigurationProvider(): iterable 'expectedAutoSetup' => false, ]; - yield 'options from options array wins over options from dsn' => [ + yield 'options from dsn array wins over options from options' => [ 'dsn' => 'doctrine://default?table_name=name_from_dsn&redeliver_timeout=1200&queue_name=normal&auto_setup=true', 'options' => [ 'table_name' => 'name_from_options', @@ -218,10 +218,10 @@ public function buildConfigurationProvider(): iterable 'auto_setup' => false, ], 'expectedConnection' => 'default', - 'expectedTableName' => 'name_from_options', - 'expectedRedeliverTimeout' => 1800, - 'expectedQueue' => 'important', - 'expectedAutoSetup' => false, + 'expectedTableName' => 'name_from_dsn', + 'expectedRedeliverTimeout' => 1200, + 'expectedQueue' => 'normal', + 'expectedAutoSetup' => true, ]; yield 'options from dsn with falsey boolean' => [ diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index 19141bd8d94c3..de6d144e45089 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -85,7 +85,7 @@ public static function buildConfiguration(string $dsn, array $options = []): arr } $configuration = ['connection' => $components['host']]; - $configuration += $options + $query + self::DEFAULT_OPTIONS; + $configuration += $query + $options + self::DEFAULT_OPTIONS; $configuration['auto_setup'] = filter_var($configuration['auto_setup'], FILTER_VALIDATE_BOOLEAN); From fcc0e2c143caba8cf5ff0dda363af7e60d1be92f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 13 Jun 2020 17:55:52 +0200 Subject: [PATCH 008/120] [FrameworkBundle] preserve dots in query-string when redirecting --- .../Controller/RedirectController.php | 3 +- .../Controller/RedirectControllerTest.php | 43 ++++++++----------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php index 244e8a0f355a3..05e39a27a0a6a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php @@ -128,8 +128,7 @@ public function urlRedirectAction(Request $request, $path, $permanent = false, $ $scheme = $request->getScheme(); } - $qs = $request->getQueryString(); - if ($qs) { + if ($qs = $request->server->get('QUERY_STRING') ?: $request->getQueryString()) { if (false === strpos($path, '?')) { $qs = '?'.$qs; } else { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php index 4bd0212e6953d..78d41a2f2bc7e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php @@ -220,9 +220,9 @@ public function pathQueryParamsProvider() return [ ['http://www.example.com/base/redirect-path', '/redirect-path', ''], ['http://www.example.com/base/redirect-path?foo=bar', '/redirect-path?foo=bar', ''], - ['http://www.example.com/base/redirect-path?foo=bar', '/redirect-path', 'foo=bar'], - ['http://www.example.com/base/redirect-path?foo=bar&abc=example', '/redirect-path?foo=bar', 'abc=example'], - ['http://www.example.com/base/redirect-path?foo=bar&abc=example&baz=def', '/redirect-path?foo=bar', 'abc=example&baz=def'], + ['http://www.example.com/base/redirect-path?f.o=bar', '/redirect-path', 'f.o=bar'], + ['http://www.example.com/base/redirect-path?f.o=bar&a.c=example', '/redirect-path?f.o=bar', 'a.c=example'], + ['http://www.example.com/base/redirect-path?f.o=bar&a.c=example&b.z=def', '/redirect-path?f.o=bar', 'a.c=example&b.z=def'], ]; } @@ -246,29 +246,20 @@ public function testPathQueryParams($expectedUrl, $path, $queryString) private function createRequestObject($scheme, $host, $port, $baseUrl, $queryString = '') { - $request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock(); - $request - ->expects($this->any()) - ->method('getScheme') - ->willReturn($scheme); - $request - ->expects($this->any()) - ->method('getHost') - ->willReturn($host); - $request - ->expects($this->any()) - ->method('getPort') - ->willReturn($port); - $request - ->expects($this->any()) - ->method('getBaseUrl') - ->willReturn($baseUrl); - $request - ->expects($this->any()) - ->method('getQueryString') - ->willReturn($queryString); - - return $request; + if ('' !== $queryString) { + parse_str($queryString, $query); + } else { + $query = []; + } + + return new Request($query, [], [], [], [], [ + 'HTTPS' => 'https' === $scheme, + 'HTTP_HOST' => $host.($port ? ':'.$port : ''), + 'SERVER_PORT' => $port, + 'SCRIPT_FILENAME' => $baseUrl, + 'REQUEST_URI' => $baseUrl, + 'QUERY_STRING' => $queryString, + ]); } private function createRedirectController($httpPort = null, $httpsPort = null) From b746dd900cf50a545064e51f5178be8e0b2aab4c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 14 Jun 2020 14:27:25 +0200 Subject: [PATCH 009/120] [DI] tighten detection of local dirs to prevent false positives --- .../Component/DependencyInjection/Dumper/PhpDumper.php | 7 ++++--- .../DependencyInjection/Tests/Dumper/PhpDumperTest.php | 2 +- .../DependencyInjection/Tests/Fixtures/php/services12.php | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 3bfa0c318891e..c66c3bcf7c2cc 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -191,7 +191,7 @@ public function dump(array $options = []) $regex = preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#').$regex; } while (0 < --$i); - $this->targetDirRegex = '#'.preg_quote($dir[0], '#').$regex.'#'; + $this->targetDirRegex = '#(^|file://|[:;, \|\r\n])'.preg_quote($dir[0], '#').$regex.'#'; } } @@ -1993,11 +1993,12 @@ private function isHotPath(Definition $definition) private function export($value) { if (null !== $this->targetDirRegex && \is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) { - $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : ''; $suffix = $matches[0][1] + \strlen($matches[0][0]); + $matches[0][1] += \strlen($matches[1][0]); + $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : ''; $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : ''; $dirname = $this->asFiles ? '$this->containerDir' : '__DIR__'; - $offset = 1 + $this->targetDirMaxMatches - \count($matches); + $offset = 2 + $this->targetDirMaxMatches - \count($matches); if ($this->asFiles || 0 < $offset) { $dirname = sprintf('$this->targetDirs[%d]', $offset); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index b2cbb3caf6283..946d09c74852f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -98,7 +98,7 @@ public function testDumpRelativeDir() $container = new ContainerBuilder(); $container->setDefinition('test', $definition); - $container->setParameter('foo', 'wiz'.\dirname(__DIR__)); + $container->setParameter('foo', 'file://'.\dirname(__DIR__)); $container->setParameter('bar', __DIR__); $container->setParameter('baz', '%bar%/PhpDumperTest.php'); $container->setParameter('buz', \dirname(\dirname(__DIR__))); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services12.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services12.php index 0e8f581e8ab7a..eb21559686fb1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services12.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services12.php @@ -67,7 +67,7 @@ public function isFrozen() */ protected function getTestService() { - return $this->services['test'] = new \stdClass(('wiz'.$this->targetDirs[1]), [('wiz'.$this->targetDirs[1]) => ($this->targetDirs[2].'/')]); + return $this->services['test'] = new \stdClass(('file://'.$this->targetDirs[1]), [('file://'.$this->targetDirs[1]) => ($this->targetDirs[2].'/')]); } public function getParameter($name) @@ -131,7 +131,7 @@ public function getParameterBag() private function getDynamicParameter($name) { switch ($name) { - case 'foo': $value = ('wiz'.$this->targetDirs[1]); break; + case 'foo': $value = ('file://'.$this->targetDirs[1]); break; case 'buz': $value = $this->targetDirs[2]; break; default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); } From 8fe7be42121df4a8360c87b4df27659910f73082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Mon, 8 Jun 2020 21:53:13 +0200 Subject: [PATCH 010/120] Reset question validator attempts only for actual stdin --- .../Console/Helper/QuestionHelper.php | 8 ++-- .../Tests/Helper/QuestionHelperTest.php | 39 +++++++++++++------ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 134f6231e52fe..f9d74ebe594f1 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -509,14 +509,16 @@ private function getShell() private function isTty(): bool { - $inputStream = !$this->inputStream && \defined('STDIN') ? STDIN : $this->inputStream; + if (!\defined('STDIN')) { + return true; + } if (\function_exists('stream_isatty')) { - return stream_isatty($inputStream); + return stream_isatty(fopen('php://input', 'r')); } if (\function_exists('posix_isatty')) { - return posix_isatty($inputStream); + return posix_isatty(fopen('php://input', 'r')); } return true; diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index ddb0c90e19974..b9eb2f66d4f6b 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Console\Tests\Helper; +use Symfony\Component\Console\Application; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\FormatterHelper; @@ -21,6 +22,7 @@ use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Terminal; +use Symfony\Component\Console\Tester\ApplicationTester; /** * @group tty @@ -727,21 +729,36 @@ public function testAskThrowsExceptionOnMissingInputWithValidator() $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), $question); } - public function testAskThrowsExceptionFromValidatorEarlyWhenTtyIsMissing() + public function testQuestionValidatorRepeatsThePrompt() { - $this->expectException('Exception'); - $this->expectExceptionMessage('Bar, not Foo'); + $tries = 0; + $application = new Application(); + $application->setAutoExit(false); + $application->register('question') + ->setCode(function ($input, $output) use (&$tries) { + $question = new Question('This is a promptable question'); + $question->setValidator(function ($value) use (&$tries) { + ++$tries; + if (!$value) { + throw new \Exception(); + } - $output = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')->getMock(); - $output->expects($this->once())->method('writeln'); + return $value; + }); + + (new QuestionHelper())->ask($input, $output, $question); - (new QuestionHelper())->ask( - $this->createStreamableInputInterfaceMock($this->getInputStream('Foo'), true), - $output, - (new Question('Q?'))->setHidden(true)->setValidator(function ($input) { - throw new \Exception("Bar, not $input"); + return 0; }) - ); + ; + + $tester = new ApplicationTester($application); + $tester->setInputs(['', 'not-empty']); + + $statusCode = $tester->run(['command' => 'question'], ['interactive' => true]); + + $this->assertSame(2, $tries); + $this->assertSame($statusCode, 0); } public function testEmptyChoices() From b1f8e5a80a87765e42337cc809ca23c457934bbf Mon Sep 17 00:00:00 2001 From: DerManoMann Date: Wed, 27 May 2020 11:27:33 +1200 Subject: [PATCH 011/120] Make PhpDocExtractor compatible with phpDocumentor v5 Version 5 of phpDocumentor introduced some changes to the `getTagsByName()` method that break the `PhpDocExtractor`. More specific, it now returns an instance of `InvalidTag` instead of `null` when parsing an invalid tag. --- composer.json | 2 +- .../Extractor/PhpDocExtractor.php | 11 ++-- .../Tests/Extractor/PhpDocExtractorTest.php | 34 ++++++++++++- .../Tests/Fixtures/InvalidDummy.php | 50 +++++++++++++++++++ .../Component/PropertyInfo/composer.json | 2 +- 5 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/InvalidDummy.php diff --git a/composer.json b/composer.json index 5ad1c5cc83229..84692253ea65a 100644 --- a/composer.json +++ b/composer.json @@ -121,7 +121,7 @@ "egulias/email-validator": "~1.2,>=1.2.8|~2.0", "symfony/phpunit-bridge": "^5.0.8", "symfony/security-acl": "~2.8|~3.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "twig/cssinliner-extra": "^2.12", "twig/inky-extra": "^2.12", "twig/markdown-extra": "^2.12" diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index 0ae762bc0b6f0..cbabce9eb6c27 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -12,6 +12,7 @@ namespace Symfony\Component\PropertyInfo\Extractor; use phpDocumentor\Reflection\DocBlock; +use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag; use phpDocumentor\Reflection\DocBlockFactory; use phpDocumentor\Reflection\DocBlockFactoryInterface; use phpDocumentor\Reflection\Types\Context; @@ -88,10 +89,12 @@ public function getShortDescription($class, $property, array $context = []): ?st } foreach ($docBlock->getTagsByName('var') as $var) { - $varDescription = $var->getDescription()->render(); + if ($var && !$var instanceof InvalidTag) { + $varDescription = $var->getDescription()->render(); - if (!empty($varDescription)) { - return $varDescription; + if (!empty($varDescription)) { + return $varDescription; + } } } @@ -142,7 +145,7 @@ public function getTypes($class, $property, array $context = []): ?array $types = []; /** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */ foreach ($docBlock->getTagsByName($tag) as $tag) { - if ($tag && null !== $tag->getType()) { + if ($tag && !$tag instanceof InvalidTag && null !== $tag->getType()) { $types = array_merge($types, $this->phpDocTypeHelper->getTypes($tag->getType())); } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php index 0d3c32206786e..d352fa12b61f0 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php @@ -11,6 +11,8 @@ namespace Symfony\Component\PropertyInfo\Tests\Extractor; +use phpDocumentor\Reflection\DocBlock\StandardTagFactory; +use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag; use phpDocumentor\Reflection\Types\Collection; use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; @@ -46,6 +48,26 @@ public function testParamTagTypeIsOmitted() $this->assertNull($this->extractor->getTypes(OmittedParamTagTypeDocBlock::class, 'omittedType')); } + public function invalidTypesProvider() + { + return [ + 'pub' => ['pub', null, null], + 'stat' => ['stat', null, null], + 'foo' => ['foo', $this->isPhpDocumentorV5() ? 'Foo.' : null, null], + 'bar' => ['bar', $this->isPhpDocumentorV5() ? 'Bar.' : null, null], + ]; + } + + /** + * @dataProvider invalidTypesProvider + */ + public function testInvalid($property, $shortDescription, $longDescription) + { + $this->assertNull($this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property)); + $this->assertSame($shortDescription, $this->extractor->getShortDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property)); + $this->assertSame($longDescription, $this->extractor->getLongDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\InvalidDummy', $property)); + } + /** * @dataProvider typesWithNoPrefixesProvider */ @@ -94,7 +116,7 @@ public function typesProvider() ['donotexist', null, null, null], ['staticGetter', null, null, null], ['staticSetter', null, null, null], - ['emptyVar', null, null, null], + ['emptyVar', null, $this->isPhpDocumentorV5() ? 'This should not be removed.' : null, null], ]; } @@ -250,6 +272,16 @@ public function testDocBlockFallback($property, $types) { $this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DockBlockFallback', $property)); } + + protected function isPhpDocumentorV5() + { + if (class_exists(InvalidTag::class)) { + return true; + } + + return (new \ReflectionMethod(StandardTagFactory::class, 'create')) + ->hasReturnType(); + } } class EmptyDocBlock diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/InvalidDummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/InvalidDummy.php new file mode 100644 index 0000000000000..0a4cc81f36be8 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/InvalidDummy.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests\Fixtures; + +/** + * @author Martin Rademacher + */ +class InvalidDummy +{ + /** + * @var + */ + public $pub; + + /** + * @return + */ + public static function getStat() + { + return 'stat'; + } + + /** + * Foo. + * + * @param + */ + public function setFoo($foo) + { + } + + /** + * Bar. + * + * @return + */ + public function getBar() + { + return 'bar'; + } +} diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index fa24113005ea6..f9f97e84a8633 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -30,7 +30,7 @@ "symfony/serializer": "^3.4|^4.0|^5.0", "symfony/cache": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "doctrine/annotations": "~1.7" }, "conflict": { From 7af34697715018bc7c6510289907e003d129e19c Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Tue, 24 Mar 2020 21:48:50 +0100 Subject: [PATCH 012/120] [VarDumper] Fix CliDumper coloration When using AbstractDumper::DUMP_LIGHT_ARRAY --- .../Component/VarDumper/Dumper/CliDumper.php | 3 +- .../VarDumper/Tests/Dumper/CliDumperTest.php | 52 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index 946df78257bae..881241ab3e878 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -268,7 +268,8 @@ public function enterHash(Cursor $cursor, $type, $class, $hasChild) } elseif (Cursor::HASH_RESOURCE === $type) { $prefix = $this->style('note', $class.' resource').($hasChild ? ' {' : ' '); } else { - $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class).' [' : '['; + $unstyledPrefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? 'array:'.$class : ''; + $prefix = $this->style('note', $unstyledPrefix).($unstyledPrefix ? ' [' : '['); } if ($cursor->softRefCount || 0 < $cursor->softRefHandle) { diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php index 7656e09259264..e7efaae95cec3 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\AbstractDumper; use Symfony\Component\VarDumper\Dumper\CliDumper; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; use Twig\Environment; @@ -572,6 +573,57 @@ public function testIncompleteClass() ); } + public function provideDumpArrayWithColor() + { + yield [ + ['foo' => 'bar'], + 0, +<< "\e[1;38;5;113mbar\e[0;38;5;208m"\e[m +\e[0;38;5;208m]\e[m + +EOTXT + ]; + + yield [[], AbstractDumper::DUMP_LIGHT_ARRAY, "\e[0;38;5;208m\e[38;5;38m\e[0;38;5;208m[]\e[m\n"]; + + yield [ + ['foo' => 'bar'], + AbstractDumper::DUMP_LIGHT_ARRAY, + << "\e[1;38;5;113mbar\e[0;38;5;208m"\e[m +\e[0;38;5;208m]\e[m + +EOTXT + ]; + + yield [[], 0, "\e[0;38;5;208m\e[38;5;38m\e[0;38;5;208m[]\e[m\n"]; + } + + /** + * @dataProvider provideDumpArrayWithColor + */ + public function testDumpArrayWithColor($value, $flags, $expectedOut) + { + if ('\\' === \DIRECTORY_SEPARATOR) { + $this->markTestSkipped('Windows console does not support coloration'); + } + + $out = ''; + $dumper = new CliDumper(function ($line, $depth) use (&$out) { + if ($depth >= 0) { + $out .= str_repeat(' ', $depth).$line."\n"; + } + }, null, $flags); + $dumper->setColors(true); + $cloner = new VarCloner(); + $dumper->dump($cloner->cloneVar($value)); + + $this->assertSame($expectedOut, $out); + } + private function getSpecialVars() { foreach (array_keys($GLOBALS) as $var) { From 867642e337284766d566fc2ef5750a7a62cda96b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 15 Jun 2020 14:27:36 +0200 Subject: [PATCH 013/120] [Console] Reset question validator attempts only for actual stdin (bis) --- .../Component/Console/Helper/QuestionHelper.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index f9d74ebe594f1..1b60786c96944 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -104,7 +104,7 @@ private function doAsk(OutputInterface $output, Question $question) { $this->writePrompt($output, $question); - $inputStream = $this->inputStream ?: STDIN; + $inputStream = $this->inputStream ?: fopen('php://stdin', 'r'); $autocomplete = $question->getAutocompleterCallback(); if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { @@ -474,7 +474,7 @@ private function validateAttempts(callable $interviewer, OutputInterface $output } catch (\Exception $error) { } - $attempts = $attempts ?? -(int) $this->isTty(); + $attempts = $attempts ?? -(int) $this->askForever(); } throw $error; @@ -507,18 +507,20 @@ private function getShell() return self::$shell; } - private function isTty(): bool + private function askForever(): bool { - if (!\defined('STDIN')) { + $inputStream = $this->inputStream ?: fopen('php://stdin', 'r'); + + if ('php://stdin' !== (stream_get_meta_data($inputStream)['url'] ?? null)) { return true; } if (\function_exists('stream_isatty')) { - return stream_isatty(fopen('php://input', 'r')); + return stream_isatty($inputStream); } if (\function_exists('posix_isatty')) { - return posix_isatty(fopen('php://input', 'r')); + return posix_isatty($inputStream); } return true; From 9497972500413b05db33d6c0a5a85b0c107240c4 Mon Sep 17 00:00:00 2001 From: Mikko Pesari Date: Wed, 17 Jun 2020 11:19:44 +0300 Subject: [PATCH 014/120] [HttpClient] Convert CurlHttpClient::handlePush() to instance method Fix #37252 --- .../Component/HttpClient/CurlHttpClient.php | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 2fcba7902ebef..0fda8c604c3dd 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -13,7 +13,6 @@ use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; -use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\Exception\InvalidArgumentException; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Internal\CurlClientState; @@ -71,7 +70,7 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions); } - $this->multi = $multi = new CurlClientState(); + $this->multi = new CurlClientState(); self::$curlVersion = self::$curlVersion ?? curl_version(); // Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order @@ -95,10 +94,8 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections return; } - $logger = &$this->logger; - - curl_multi_setopt($this->multi->handle, CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes, &$logger) { - return self::handlePush($parent, $pushed, $requestHeaders, $multi, $maxPendingPushes, $logger); + curl_multi_setopt($this->multi->handle, CURLMOPT_PUSHFUNCTION, function ($parent, $pushed, array $requestHeaders) use ($maxPendingPushes) { + return $this->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes); }); } @@ -361,7 +358,7 @@ public function __destruct() $this->reset(); } - private static function handlePush($parent, $pushed, array $requestHeaders, CurlClientState $multi, int $maxPendingPushes, ?LoggerInterface $logger): int + private function handlePush($parent, $pushed, array $requestHeaders, int $maxPendingPushes): int { $headers = []; $origin = curl_getinfo($parent, CURLINFO_EFFECTIVE_URL); @@ -373,7 +370,7 @@ private static function handlePush($parent, $pushed, array $requestHeaders, Curl } if (!isset($headers[':method']) || !isset($headers[':scheme']) || !isset($headers[':authority']) || !isset($headers[':path'])) { - $logger && $logger->debug(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); return CURL_PUSH_DENY; } @@ -384,21 +381,21 @@ private static function handlePush($parent, $pushed, array $requestHeaders, Curl // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host, // ignoring domains mentioned as alt-name in the certificate for now (same as curl). if (0 !== strpos($origin, $url.'/')) { - $logger && $logger->debug(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); return CURL_PUSH_DENY; } - if ($maxPendingPushes <= \count($multi->pushedResponses)) { - $fifoUrl = key($multi->pushedResponses); - unset($multi->pushedResponses[$fifoUrl]); - $logger && $logger->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); + if ($maxPendingPushes <= \count($this->multi->pushedResponses)) { + $fifoUrl = key($this->multi->pushedResponses); + unset($this->multi->pushedResponses[$fifoUrl]); + $this->logger && $this->logger->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); } $url .= $headers[':path'][0]; - $logger && $logger->debug(sprintf('Queueing pushed response: "%s"', $url)); + $this->logger && $this->logger->debug(sprintf('Queueing pushed response: "%s"', $url)); - $multi->pushedResponses[$url] = new PushedResponse(new CurlResponse($multi, $pushed), $headers, $multi->openHandles[(int) $parent][1] ?? [], $pushed); + $this->multi->pushedResponses[$url] = new PushedResponse(new CurlResponse($this->multi, $pushed), $headers, $this->multi->openHandles[(int) $parent][1] ?? [], $pushed); return CURL_PUSH_OK; } From 8c4b49613ac32c238a794f987dc474ded1df4809 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Jun 2020 17:42:01 +0200 Subject: [PATCH 015/120] [Cache] fix compat with DBAL v3 --- .../Component/Cache/Traits/PdoTrait.php | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Cache/Traits/PdoTrait.php b/src/Symfony/Component/Cache/Traits/PdoTrait.php index 1aa87cd3f1a11..d453904d44a81 100644 --- a/src/Symfony/Component/Cache/Traits/PdoTrait.php +++ b/src/Symfony/Component/Cache/Traits/PdoTrait.php @@ -366,25 +366,31 @@ private function getConnection() if ($this->conn instanceof \PDO) { $this->driver = $this->conn->getAttribute(\PDO::ATTR_DRIVER_NAME); } else { - switch ($this->driver = $this->conn->getDriver()->getName()) { - case 'mysqli': - case 'pdo_mysql': - case 'drizzle_pdo_mysql': + $driver = $this->conn->getDriver(); + + switch (true) { + case $driver instanceof \Doctrine\DBAL\Driver\AbstractMySQLDriver: + case $driver instanceof \Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver: + case $driver instanceof \Doctrine\DBAL\Driver\Mysqli\Driver: + case $driver instanceof \Doctrine\DBAL\Driver\PDOMySql\Driver: $this->driver = 'mysql'; break; - case 'pdo_sqlite': + case $driver instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver: $this->driver = 'sqlite'; break; - case 'pdo_pgsql': + case $driver instanceof \Doctrine\DBAL\Driver\PDOPgSql\Driver: $this->driver = 'pgsql'; break; - case 'oci8': - case 'pdo_oracle': + case $driver instanceof \Doctrine\DBAL\Driver\OCI8\Driver: + case $driver instanceof \Doctrine\DBAL\Driver\PDOOracle\Driver: $this->driver = 'oci'; break; - case 'pdo_sqlsrv': + case $driver instanceof \Doctrine\DBAL\Driver\SQLSrv\Driver: $this->driver = 'sqlsrv'; break; + default: + $this->driver = \get_class($driver); + break; } } } From c143aacd811d0cab4e3351cb77d7d3e37c031c16 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 13 Jun 2020 10:25:25 +0200 Subject: [PATCH 016/120] [3.4] Small update in our internal terminology --- .../Handler/FingersCrossed/NotFoundActivationStrategy.php | 6 +++--- .../DependencyInjection/AddAnnotatedClassesToCachePass.php | 4 ++-- .../Component/Intl/Data/Generator/CurrencyDataGenerator.php | 4 ++-- .../Component/Intl/Data/Generator/RegionDataGenerator.php | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php index ed41929a2cef3..e5ccf1afc57b4 100644 --- a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php +++ b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php @@ -23,7 +23,7 @@ */ class NotFoundActivationStrategy extends ErrorLevelActivationStrategy { - private $blacklist; + private $exclude; private $requestStack; public function __construct(RequestStack $requestStack, array $excludedUrls, $actionLevel) @@ -31,7 +31,7 @@ public function __construct(RequestStack $requestStack, array $excludedUrls, $ac parent::__construct($actionLevel); $this->requestStack = $requestStack; - $this->blacklist = '{('.implode('|', $excludedUrls).')}i'; + $this->exclude = '{('.implode('|', $excludedUrls).')}i'; } public function isHandlerActivated(array $record) @@ -45,7 +45,7 @@ public function isHandlerActivated(array $record) && 404 == $record['context']['exception']->getStatusCode() && ($request = $this->requestStack->getMasterRequest()) ) { - return !preg_match($this->blacklist, $request->getPathInfo()); + return !preg_match($this->exclude, $request->getPathInfo()); } return $isActivated; diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/AddAnnotatedClassesToCachePass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/AddAnnotatedClassesToCachePass.php index 8bb03bd0c78d0..b59949379dd07 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/AddAnnotatedClassesToCachePass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/AddAnnotatedClassesToCachePass.php @@ -136,10 +136,10 @@ private function patternsToRegexps($patterns) private function matchAnyRegexps($class, $regexps) { - $blacklisted = false !== strpos($class, 'Test'); + $isTest = false !== strpos($class, 'Test'); foreach ($regexps as $regex) { - if ($blacklisted && false === strpos($regex, 'Test')) { + if ($isTest && false === strpos($regex, 'Test')) { continue; } diff --git a/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php index b4543428ebb60..a5ed6d10268f2 100644 --- a/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php @@ -25,7 +25,7 @@ */ class CurrencyDataGenerator extends AbstractDataGenerator { - private static $blacklist = [ + private static $denylist = [ 'XBA' => true, // European Composite Unit 'XBB' => true, // European Monetary Unit 'XBC' => true, // European Unit of Account (XBC) @@ -136,7 +136,7 @@ private function generateSymbolNamePairs(ArrayAccessibleResourceBundle $rootBund $symbolNamePairs = iterator_to_array($rootBundle['Currencies']); // Remove unwanted currencies - $symbolNamePairs = array_diff_key($symbolNamePairs, self::$blacklist); + $symbolNamePairs = array_diff_key($symbolNamePairs, self::$denylist); return $symbolNamePairs; } diff --git a/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php index bab85b11b15d5..b50a585de6779 100644 --- a/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php @@ -27,7 +27,7 @@ */ class RegionDataGenerator extends AbstractDataGenerator { - private static $blacklist = [ + private static $denylist = [ // Look like countries, but are sub-continents 'QO' => true, // Outlying Oceania 'EU' => true, // European Union @@ -50,7 +50,7 @@ class RegionDataGenerator extends AbstractDataGenerator public static function isValidCountryCode($region) { - if (isset(self::$blacklist[$region])) { + if (isset(self::$denylist[$region])) { return false; } From 968d6c4276bb1540786bc4ba6ef2a49f913f8b10 Mon Sep 17 00:00:00 2001 From: kick-the-bucket Date: Thu, 4 Jun 2020 11:26:35 +0300 Subject: [PATCH 017/120] [PhpUnitBridge] Streamline ansi/no-ansi of composer according to phpunit --colors option --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index eae4cc3125147..90efc97658a0d 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -106,15 +106,21 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ } } + if (in_array('--colors=never', $argv, true) || (isset($argv[$i = array_search('never', $argv, true) - 1]) && '--colors' === $argv[$i])) { + $COMPOSER .= ' --no-ansi'; + } else { + $COMPOSER .= ' --ansi'; + } + $info += array( 'versions' => array(), 'requires' => array('php' => '*'), ); if (1 === \count($info['versions'])) { - $passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress --ansi -s dev phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); + $passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress -s dev phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); } else { - $passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress --ansi phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); + $passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); } @copy("phpunit-$PHPUNIT_VERSION/phpunit.xsd", 'phpunit.xsd'); @@ -144,7 +150,7 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ putenv("COMPOSER_ROOT_VERSION=$PHPUNIT_VERSION.99"); $q = '\\' === DIRECTORY_SEPARATOR ? '"' : ''; // --no-suggest is not in the list to keep compat with composer 1.0, which is shipped with Ubuntu 16.04LTS - $exit = proc_close(proc_open("$q$COMPOSER install --no-dev --prefer-dist --no-progress --ansi$q", array(), $p, getcwd())); + $exit = proc_close(proc_open("$q$COMPOSER install --no-dev --prefer-dist --no-progress$q", array(), $p, getcwd())); putenv('COMPOSER_ROOT_VERSION'.(false !== $prevRoot ? '='.$prevRoot : '')); if ($exit) { exit($exit); From e09372bcbf3de62acf139c203f4492b6c8e41d07 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 15 Jun 2020 16:43:28 +0200 Subject: [PATCH 018/120] [3.4] Fix support for PHP8 union types --- .../Resource/ReflectionClassResource.php | 6 ++- .../LazyProxy/ProxyHelper.php | 42 ++++++++++++------- .../OptionsResolver/OptionsResolver.php | 2 +- .../PropertyAccess/PropertyAccessor.php | 3 +- .../Extractor/ReflectionExtractor.php | 42 ++++++++++--------- .../Normalizer/AbstractNormalizer.php | 2 +- .../VarDumper/Caster/ReflectionCaster.php | 6 +-- 7 files changed, 60 insertions(+), 43 deletions(-) diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index cfab1f6c10a65..294da3e10cef4 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -177,6 +177,7 @@ private function generateSignature(\ReflectionClass $class) if (!$parametersWithUndefinedConstants) { yield preg_replace('/^ @@.*/m', '', $m); } else { + $t = \PHP_VERSION_ID >= 70000 ? $m->getReturnType() : ''; $stack = [ $m->getDocComment(), $m->getName(), @@ -187,15 +188,16 @@ private function generateSignature(\ReflectionClass $class) $m->isPrivate(), $m->isProtected(), $m->returnsReference(), - \PHP_VERSION_ID >= 70000 && $m->hasReturnType() ? (\PHP_VERSION_ID >= 70100 ? $m->getReturnType()->getName() : (string) $m->getReturnType()) : '', + $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t, ]; foreach ($m->getParameters() as $p) { if (!isset($parametersWithUndefinedConstants[$p->name])) { $stack[] = (string) $p; } else { + $t = \PHP_VERSION_ID >= 70000 ? $p->getType() : ''; $stack[] = $p->isOptional(); - $stack[] = \PHP_VERSION_ID >= 70000 && $p->hasType() ? (\PHP_VERSION_ID >= 70100 ? $p->getType()->getName() : (string) $p->getType()) : ''; + $stack[] = $t instanceof \ReflectionNamedType ? $t->getName() : (string) $t; $stack[] = $p->isPassedByReference(); $stack[] = \PHP_VERSION_ID >= 50600 ? $p->isVariadic() : ''; $stack[] = $p->getName(); diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/ProxyHelper.php b/src/Symfony/Component/DependencyInjection/LazyProxy/ProxyHelper.php index cb19c729c100c..bfa65f56f0a44 100644 --- a/src/Symfony/Component/DependencyInjection/LazyProxy/ProxyHelper.php +++ b/src/Symfony/Component/DependencyInjection/LazyProxy/ProxyHelper.php @@ -39,26 +39,36 @@ public static function getTypeHint(\ReflectionFunctionAbstract $r, \ReflectionPa if (!$type) { return null; } - if (!\is_string($type)) { - $name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); - if ($type->isBuiltin()) { - return $noBuiltin ? null : $name; + $types = []; + + foreach ($type instanceof \ReflectionUnionType ? $type->getTypes() : [$type] as $type) { + $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; + + if (!\is_string($type) && $type->isBuiltin()) { + if (!$noBuiltin) { + $types[] = $name; + } + continue; } - } - $lcName = strtolower($name); - $prefix = $noBuiltin ? '' : '\\'; - if ('self' !== $lcName && 'parent' !== $lcName) { - return $prefix.$name; - } - if (!$r instanceof \ReflectionMethod) { - return null; - } - if ('self' === $lcName) { - return $prefix.$r->getDeclaringClass()->name; + $lcName = strtolower($name); + $prefix = $noBuiltin ? '' : '\\'; + + if ('self' !== $lcName && 'parent' !== $lcName) { + $types[] = '' !== $prefix ? $prefix.$name : $name; + continue; + } + if (!$r instanceof \ReflectionMethod) { + continue; + } + if ('self' === $lcName) { + $types[] = $prefix.$r->getDeclaringClass()->name; + } else { + $types[] = ($parent = $r->getDeclaringClass()->getParentClass()) ? $prefix.$parent->name : null; + } } - return ($parent = $r->getDeclaringClass()->getParentClass()) ? $prefix.$parent->name : null; + return $types ? implode('|', $types) : null; } } diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index 7354caf8a6fe7..ffb101e512ff8 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -1076,7 +1076,7 @@ private function getParameterClassName(\ReflectionParameter $parameter) return ($class = $parameter->getClass()) ? $class->name : null; } - if (!($type = $parameter->getType()) || $type->isBuiltin()) { + if (!($type = $parameter->getType()) instanceof \ReflectionNamedType || $type->isBuiltin()) { return null; } diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 99aa9a3ebc32a..07e0204cd26c0 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -519,8 +519,9 @@ private function readProperty($zval, $property) // handle uninitialized properties in PHP >= 7.4 if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property ([\w\\\]+)::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) { $r = new \ReflectionProperty($matches[1], $matches[2]); + $type = ($type = $r->getType()) instanceof \ReflectionNamedType ? $type->getName() : (string) $type; - throw new AccessException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $r->getDeclaringClass()->getName(), $r->getName(), $r->getType()->getName()), 0, $e); + throw new AccessException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $r->getDeclaringClass()->getName(), $r->getName(), $type), 0, $e); } throw $e; diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 3306946a9b337..cbcb349d2e110 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -187,26 +187,26 @@ private function extractFromMutator($class, $property) $type = $this->extractFromReflectionType($reflectionType, $reflectionMethod); // HHVM reports variadics with "array" but not builtin type hints - if (!$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type->getBuiltinType()) { + if (1 === \count($type) && !$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type[0]->getBuiltinType()) { return null; } } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $reflectionParameter, $info)) { if (Type::BUILTIN_TYPE_ARRAY === $info[1]) { - $type = new Type(Type::BUILTIN_TYPE_ARRAY, $reflectionParameter->allowsNull(), null, true); + $type = [new Type(Type::BUILTIN_TYPE_ARRAY, $reflectionParameter->allowsNull(), null, true)]; } elseif (Type::BUILTIN_TYPE_CALLABLE === $info[1]) { - $type = new Type(Type::BUILTIN_TYPE_CALLABLE, $reflectionParameter->allowsNull()); + $type = [new Type(Type::BUILTIN_TYPE_CALLABLE, $reflectionParameter->allowsNull())]; } else { - $type = new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $this->resolveTypeName($info[1], $reflectionMethod)); + $type = [new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $this->resolveTypeName($info[1], $reflectionMethod))]; } } else { return null; } - if (\in_array($prefix, $this->arrayMutatorPrefixes)) { - $type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type); + if (1 === \count($type) && \in_array($prefix, $this->arrayMutatorPrefixes)) { + $type = [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type[0])]; } - return [$type]; + return $type; } /** @@ -225,7 +225,7 @@ private function extractFromAccessor($class, $property) } if ($this->supportsParameterType && $reflectionType = $reflectionMethod->getReturnType()) { - return [$this->extractFromReflectionType($reflectionType, $reflectionMethod)]; + return $this->extractFromReflectionType($reflectionType, $reflectionMethod); } return \in_array($prefix, ['is', 'can']) ? [new Type(Type::BUILTIN_TYPE_BOOL)] : null; @@ -234,24 +234,28 @@ private function extractFromAccessor($class, $property) /** * Extracts data from the PHP 7 reflection type. * - * @return Type + * @return Type[] */ private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionMethod $reflectionMethod) { - $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : $reflectionType->__toString(); + $types = []; $nullable = $reflectionType->allowsNull(); - if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { - $type = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true); - } elseif ('void' === $phpTypeOrClass) { - $type = new Type(Type::BUILTIN_TYPE_NULL, $nullable); - } elseif ($reflectionType->isBuiltin()) { - $type = new Type($phpTypeOrClass, $nullable); - } else { - $type = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod)); + foreach ($reflectionType instanceof \ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType] as $type) { + $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type; + + if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { + $types[] = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true); + } elseif ('void' === $phpTypeOrClass || 'null' === $phpTypeOrClass) { + $types[] = new Type(Type::BUILTIN_TYPE_NULL, $nullable); + } elseif ($reflectionType->isBuiltin()) { + $types[] = new Type($phpTypeOrClass, $nullable); + } else { + $types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod)); + } } - return $type; + return $types; } private function resolveTypeName($name, \ReflectionMethod $reflectionMethod) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 71b1e38d37bd4..e88b5a2110b8b 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -388,7 +388,7 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara try { if (\PHP_VERSION_ID < 70100 && null !== $parameterClass = $parameter->getClass()) { $parameterClass = $parameterClass->name; - } elseif (\PHP_VERSION_ID >= 70100 && ($parameterType = $parameter->getType()) && !$parameterType->isBuiltin()) { + } elseif (\PHP_VERSION_ID >= 70100 && ($parameterType = $parameter->getType()) instanceof \ReflectionNamedType && !$parameterType->isBuiltin()) { $parameterClass = $parameterType->getName(); new \ReflectionClass($parameterClass); // throws a \ReflectionException if the class doesn't exist } else { diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index 067da6bbd3d9d..31de78e961db0 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -91,7 +91,7 @@ public static function castType(\ReflectionType $c, array $a, Stub $stub, $isNes $prefix = Caster::PREFIX_VIRTUAL; $a += [ - $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : $c->__toString(), + $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c, $prefix.'allowsNull' => $c->allowsNull(), $prefix.'isBuiltin' => $c->isBuiltin(), ]; @@ -178,7 +178,7 @@ public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, arra if (isset($a[$prefix.'returnType'])) { $v = $a[$prefix.'returnType']; - $v = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString(); + $v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType']->allowsNull() ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); } if (isset($a[$prefix.'class'])) { @@ -247,7 +247,7 @@ public static function castParameter(\ReflectionParameter $c, array $a, Stub $st if (method_exists($c, 'getType')) { if ($v = $c->getType()) { - $a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString(); + $a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; } } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $c, $v)) { $a[$prefix.'typeHint'] = $v[1]; From 3d0d59de20a5ee2cc2bb4d6038b26577072463cd Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 13 Jun 2020 17:57:51 +0200 Subject: [PATCH 019/120] [FrameworkBundle] preserve dots in query-string when redirecting --- .../Controller/RedirectController.php | 57 ++++++++++++++++++- .../Controller/RedirectControllerTest.php | 22 ++++--- 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php index 67be757db308b..58f06d5df9f05 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php @@ -62,7 +62,17 @@ public function redirectAction(Request $request, string $route, bool $permanent $attributes = []; if (false === $ignoreAttributes || \is_array($ignoreAttributes)) { $attributes = $request->attributes->get('_route_params'); - $attributes = $keepQueryParams ? array_merge($request->query->all(), $attributes) : $attributes; + + if ($keepQueryParams) { + if ($query = $request->server->get('QUERY_STRING')) { + $query = self::parseQuery($query); + } else { + $query = $request->query->all(); + } + + $attributes = array_merge($query, $attributes); + } + unset($attributes['route'], $attributes['permanent'], $attributes['ignoreAttributes'], $attributes['keepRequestMethod'], $attributes['keepQueryParams']); if ($ignoreAttributes) { $attributes = array_diff_key($attributes, array_flip($ignoreAttributes)); @@ -175,4 +185,49 @@ public function __invoke(Request $request): Response throw new \RuntimeException(sprintf('The parameter "path" or "route" is required to configure the redirect action in "%s" routing configuration.', $request->attributes->get('_route'))); } + + private static function parseQuery(string $query) + { + $q = []; + + foreach (explode('&', $query) as $v) { + if (false !== $i = strpos($v, "\0")) { + $v = substr($v, 0, $i); + } + + if (false === $i = strpos($v, '=')) { + $k = urldecode($v); + $v = ''; + } else { + $k = urldecode(substr($v, 0, $i)); + $v = substr($v, $i); + } + + if (false !== $i = strpos($k, "\0")) { + $k = substr($k, 0, $i); + } + + $k = ltrim($k, ' '); + + if (false === $i = strpos($k, '[')) { + $q[] = bin2hex($k).$v; + } else { + $q[] = substr_replace($k, bin2hex(substr($k, 0, $i)), 0, $i).$v; + } + } + + parse_str(implode('&', $q), $q); + + $query = []; + + foreach ($q as $k => $v) { + if (false !== $i = strpos($k, '_')) { + $query[substr_replace($k, hex2bin(substr($k, 0, $i)).'[', 0, 1 + $i)] = $v; + } else { + $query[hex2bin($k)] = $v; + } + } + + return $query; + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php index 5920cfc37ae86..732ac3e2d6e7a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php @@ -302,17 +302,16 @@ public function testRedirectWithQuery() $baseUrl = '/base'; $port = 80; - $request = $this->createRequestObject($scheme, $host, $port, $baseUrl, 'base=zaza'); - $request->query = new ParameterBag(['base' => 'zaza']); + $request = $this->createRequestObject($scheme, $host, $port, $baseUrl, 'b.se=zaza'); $request->attributes = new ParameterBag(['_route_params' => ['base2' => 'zaza']]); $urlGenerator = $this->getMockBuilder(UrlGeneratorInterface::class)->getMock(); - $urlGenerator->expects($this->exactly(2))->method('generate')->willReturn('/test?base=zaza&base2=zaza')->with('/test', ['base' => 'zaza', 'base2' => 'zaza'], UrlGeneratorInterface::ABSOLUTE_URL); + $urlGenerator->expects($this->exactly(2))->method('generate')->willReturn('/test?b.se=zaza&base2=zaza')->with('/test', ['b.se' => 'zaza', 'base2' => 'zaza'], UrlGeneratorInterface::ABSOLUTE_URL); $controller = new RedirectController($urlGenerator); - $this->assertRedirectUrl($controller->redirectAction($request, '/test', false, false, false, true), '/test?base=zaza&base2=zaza'); + $this->assertRedirectUrl($controller->redirectAction($request, '/test', false, false, false, true), '/test?b.se=zaza&base2=zaza'); $request->attributes->set('_route_params', ['base2' => 'zaza', 'route' => '/test', 'ignoreAttributes' => false, 'keepRequestMethod' => false, 'keepQueryParams' => true]); - $this->assertRedirectUrl($controller($request), '/test?base=zaza&base2=zaza'); + $this->assertRedirectUrl($controller($request), '/test?b.se=zaza&base2=zaza'); } public function testRedirectWithQueryWithRouteParamsOveriding() @@ -322,17 +321,16 @@ public function testRedirectWithQueryWithRouteParamsOveriding() $baseUrl = '/base'; $port = 80; - $request = $this->createRequestObject($scheme, $host, $port, $baseUrl, 'base=zaza'); - $request->query = new ParameterBag(['base' => 'zaza']); - $request->attributes = new ParameterBag(['_route_params' => ['base' => 'zouzou']]); + $request = $this->createRequestObject($scheme, $host, $port, $baseUrl, 'b.se=zaza'); + $request->attributes = new ParameterBag(['_route_params' => ['b.se' => 'zouzou']]); $urlGenerator = $this->getMockBuilder(UrlGeneratorInterface::class)->getMock(); - $urlGenerator->expects($this->exactly(2))->method('generate')->willReturn('/test?base=zouzou')->with('/test', ['base' => 'zouzou'], UrlGeneratorInterface::ABSOLUTE_URL); + $urlGenerator->expects($this->exactly(2))->method('generate')->willReturn('/test?b.se=zouzou')->with('/test', ['b.se' => 'zouzou'], UrlGeneratorInterface::ABSOLUTE_URL); $controller = new RedirectController($urlGenerator); - $this->assertRedirectUrl($controller->redirectAction($request, '/test', false, false, false, true), '/test?base=zouzou'); + $this->assertRedirectUrl($controller->redirectAction($request, '/test', false, false, false, true), '/test?b.se=zouzou'); - $request->attributes->set('_route_params', ['base' => 'zouzou', 'route' => '/test', 'ignoreAttributes' => false, 'keepRequestMethod' => false, 'keepQueryParams' => true]); - $this->assertRedirectUrl($controller($request), '/test?base=zouzou'); + $request->attributes->set('_route_params', ['b.se' => 'zouzou', 'route' => '/test', 'ignoreAttributes' => false, 'keepRequestMethod' => false, 'keepQueryParams' => true]); + $this->assertRedirectUrl($controller($request), '/test?b.se=zouzou'); } public function testMissingPathOrRouteParameter() From da68e66a9913cd0bef7cbf98bdd01ebf13220457 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 15 Jun 2020 16:43:28 +0200 Subject: [PATCH 020/120] Fix support for PHP8 union types --- .../Compiler/CheckTypeDeclarationsPass.php | 23 +++++++++++++--- .../DependencyInjection/Dumper/Preloader.php | 27 ++++++++++++------- .../InvalidParameterTypeException.php | 5 +++- .../RegisterListenersPass.php | 2 +- .../ArgumentMetadataFactory.php | 2 +- .../EventListener/ErrorListener.php | 2 +- .../DependencyInjection/MessengerPass.php | 15 ++++++++++- .../OptionsResolver/OptionsResolver.php | 2 +- .../Contracts/Service/ServiceLocatorTrait.php | 2 +- .../Service/ServiceSubscriberTrait.php | 2 +- 10 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php index cf255640c2258..ae1a2ec204969 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php @@ -153,9 +153,26 @@ private function checkTypeDeclarations(Definition $checkedDefinition, \Reflectio /** * @throws InvalidParameterTypeException When a parameter is not compatible with the declared type */ - private function checkType(Definition $checkedDefinition, $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix): void + private function checkType(Definition $checkedDefinition, $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix, string $type = null): void { - $type = $parameter->getType()->getName(); + if (null === $type) { + $type = $parameter->getType(); + + if ($type instanceof \ReflectionUnionType) { + foreach ($type->getTypes() as $type) { + try { + $this->checkType($checkedDefinition, $value, $parameter, $envPlaceholderUniquePrefix, $type); + + return; + } catch (InvalidParameterTypeException $e) { + } + } + + throw new InvalidParameterTypeException($this->currentId, $e->getCode(), $parameter); + } + + $type = $type->getName(); + } if ($value instanceof Reference) { if (!$this->container->has($value = (string) $value)) { @@ -266,7 +283,7 @@ private function checkType(Definition $checkedDefinition, $value, \ReflectionPar return; } - $checkFunction = sprintf('is_%s', $parameter->getType()->getName()); + $checkFunction = sprintf('is_%s', $type); if (!$parameter->getType()->isBuiltin() || !$checkFunction($value)) { throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : \gettype($value), $parameter); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php index abb7d90ff52bc..f9d2716e7d64d 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php @@ -48,7 +48,7 @@ public static function preload(array $classes) } } - private static function doPreload(string $class, array &$preloaded) + private static function doPreload(string $class, array &$preloaded): void { if (isset($preloaded[$class]) || \in_array($class, ['self', 'static', 'parent'], true)) { return; @@ -68,9 +68,7 @@ private static function doPreload(string $class, array &$preloaded) if (\PHP_VERSION_ID >= 70400) { foreach ($r->getProperties(\ReflectionProperty::IS_PUBLIC) as $p) { - if (($t = $p->getType()) && !$t->isBuiltin()) { - self::doPreload($t->getName(), $preloaded); - } + self::preloadType($p->getType(), $preloaded); } } @@ -84,17 +82,26 @@ private static function doPreload(string $class, array &$preloaded) } } - if (($t = $p->getType()) && !$t->isBuiltin()) { - self::doPreload($t->getName(), $preloaded); - } + self::preloadType($p->getType(), $preloaded); } - if (($t = $m->getReturnType()) && !$t->isBuiltin()) { - self::doPreload($t->getName(), $preloaded); - } + self::preloadType($p->getReturnType(), $preloaded); } } catch (\ReflectionException $e) { // ignore missing classes } } + + private static function preloadType(?\ReflectionType $t, array &$preloaded): void + { + if (!$t || $t->isBuiltin()) { + return; + } + + foreach ($t instanceof \ReflectionUnionType ? $t->getTypes() : [$t] as $t) { + if (!$t->isBuiltin()) { + self::doPreload($t instanceof \ReflectionNamedType ? $t->getName() : $t, $preloaded); + } + } + } } diff --git a/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php b/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php index 206561fa95a8a..05fdb4a779adb 100644 --- a/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php +++ b/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php @@ -21,6 +21,9 @@ class InvalidParameterTypeException extends InvalidArgumentException { public function __construct(string $serviceId, string $type, \ReflectionParameter $parameter) { - parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s::%s" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $parameter->getType()->getName(), $type)); + $acceptedType = $parameter->getType(); + $acceptedType = $acceptedType instanceof \ReflectionNamedType ? $acceptedType->getName() : (string) $acceptedType; + + parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s::%s" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $acceptedType, $type), $type); } } diff --git a/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php b/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php index 3ae1136c4c976..4b27d3b23aef4 100644 --- a/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php +++ b/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php @@ -138,7 +138,7 @@ private function getEventFromTypeDeclaration(ContainerBuilder $container, string || !($r = $container->getReflectionClass($class, false)) || !$r->hasMethod($method) || 1 > ($m = $r->getMethod($method))->getNumberOfParameters() - || !($type = $m->getParameters()[0]->getType()) + || !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType || $type->isBuiltin() || Event::class === ($name = $type->getName()) || LegacyEvent::class === $name diff --git a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php index 9370174c253a0..6c192a6f5f177 100644 --- a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php +++ b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php @@ -45,7 +45,7 @@ public function createArgumentMetadata($controller): array */ private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function): ?string { - if (!$type = $parameter->getType()) { + if (!($type = $parameter->getType()) instanceof \ReflectionNamedType) { return null; } $name = $type->getName(); diff --git a/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php b/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php index 26c361f754e53..1ca6c9b458e41 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php @@ -99,7 +99,7 @@ public function onControllerArguments(ControllerArgumentsEvent $event) $r = new \ReflectionFunction(\Closure::fromCallable($event->getController())); $r = $r->getParameters()[$k] ?? null; - if ($r && (!$r->hasType() || \in_array($r->getType()->getName(), [FlattenException::class, LegacyFlattenException::class], true))) { + if ($r && (!($r = $r->getType()) instanceof \ReflectionNamedType || \in_array($r->getName(), [FlattenException::class, LegacyFlattenException::class], true))) { $arguments = $event->getArguments(); $arguments[$k] = FlattenException::createFromThrowable($e); $event->setArguments($arguments); diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php index bf62b4c87e953..888155dea994b 100644 --- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php +++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php @@ -228,11 +228,24 @@ private function guessHandledClasses(\ReflectionClass $handlerClass, string $ser throw new RuntimeException(sprintf('Invalid handler service "%s": argument "$%s" of method "%s::__invoke()" must have a type-hint corresponding to the message class it handles.', $serviceId, $parameters[0]->getName(), $handlerClass->getName())); } + if ($type instanceof \ReflectionUnionType) { + $types = []; + foreach ($type->getTypes() as $type) { + if (!$type->isBuiltin()) { + $types[] = (string) $type; + } + } + + if ($types) { + return $types; + } + } + if ($type->isBuiltin()) { throw new RuntimeException(sprintf('Invalid handler service "%s": type-hint of argument "$%s" in method "%s::__invoke()" must be a class , "%s" given.', $serviceId, $parameters[0]->getName(), $handlerClass->getName(), $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type)); } - return [$parameters[0]->getType()->getName()]; + return [$type->getName()]; } private function registerReceivers(ContainerBuilder $container, array $busIds) diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index e40583dd5f03c..3fb3c06f92cd9 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -201,7 +201,7 @@ public function setDefault($option, $value) return $this; } - if (isset($params[0]) && null !== ($type = $params[0]->getType()) && self::class === $type->getName() && (!isset($params[1]) || (null !== ($type = $params[1]->getType()) && Options::class === $type->getName()))) { + if (isset($params[0]) && null !== ($type = $params[0]->getType()) && self::class === $type->getName() && (!isset($params[1]) || (($type = $params[1]->getType()) instanceof \ReflectionNamedType && Options::class === $type->getName()))) { // Store closure for later evaluation $this->nested[$option][] = $value; $this->defaults[$option] = []; diff --git a/src/Symfony/Contracts/Service/ServiceLocatorTrait.php b/src/Symfony/Contracts/Service/ServiceLocatorTrait.php index 0b4d60affa5e1..1737f50e997ab 100644 --- a/src/Symfony/Contracts/Service/ServiceLocatorTrait.php +++ b/src/Symfony/Contracts/Service/ServiceLocatorTrait.php @@ -87,7 +87,7 @@ public function getProvidedServices(): array } else { $type = (new \ReflectionFunction($factory))->getReturnType(); - $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').$type->getName() : '?'; + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; } } } diff --git a/src/Symfony/Contracts/Service/ServiceSubscriberTrait.php b/src/Symfony/Contracts/Service/ServiceSubscriberTrait.php index 5d9d456d0c6d1..82fb5ab361559 100644 --- a/src/Symfony/Contracts/Service/ServiceSubscriberTrait.php +++ b/src/Symfony/Contracts/Service/ServiceSubscriberTrait.php @@ -40,7 +40,7 @@ public static function getSubscribedServices(): array } if (self::class === $method->getDeclaringClass()->name && ($returnType = $method->getReturnType()) && !$returnType->isBuiltin()) { - $services[self::class.'::'.$method->name] = '?'.$returnType->getName(); + $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $type); } } From 2eb3c0eb7fcc6e732f2451c0367afa5625f153fb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Jun 2020 20:15:32 +0200 Subject: [PATCH 021/120] [VarDumper] fix typo --- src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index c0e9e5c03b1bd..81a2da7298cfe 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -326,7 +326,7 @@ public static function getSignature(array $a) if (!$param->isOptional() && $param->allowsNull()) { $signature .= '?'; } - $signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1); + $signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' '; } } $signature .= $k; From 8bbbdbe74576639224d7019d90d80f4f2a4b5737 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Jun 2020 21:30:53 +0200 Subject: [PATCH 022/120] Fix --- .../Component/Config/Resource/ReflectionClassResource.php | 2 +- .../DependencyInjection/Compiler/FactoryReturnTypePass.php | 2 +- .../HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php | 2 +- src/Symfony/Component/OptionsResolver/OptionsResolver.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index 294da3e10cef4..79b21fbf4c218 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -197,7 +197,7 @@ private function generateSignature(\ReflectionClass $class) } else { $t = \PHP_VERSION_ID >= 70000 ? $p->getType() : ''; $stack[] = $p->isOptional(); - $stack[] = $t instanceof \ReflectionNamedType ? $t->getName() : (string) $t; + $stack[] = $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t; $stack[] = $p->isPassedByReference(); $stack[] = \PHP_VERSION_ID >= 50600 ? $p->isVariadic() : ''; $stack[] = $p->getName(); diff --git a/src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php b/src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php index d688fb59fd1fd..6b1277e26a6bc 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php @@ -93,7 +93,7 @@ private function updateDefinition(ContainerBuilder $container, $id, Definition $ $returnType = $m->getReturnType(); if (null !== $returnType && !$returnType->isBuiltin()) { - $returnType = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType->__toString(); + $returnType = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; if (null !== $class) { $declaringClass = $m->getDeclaringClass()->getName(); if ('self' === strtolower($returnType)) { diff --git a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php index 2548a2a083c39..14e7ca3d11405 100644 --- a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php +++ b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php @@ -105,7 +105,7 @@ private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbs if (!$type = $parameter->getType()) { return null; } - $name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); + $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; if ('array' === $name && !$type->isBuiltin()) { // Special case for HHVM with variadics return null; diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index ffb101e512ff8..7354caf8a6fe7 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -1076,7 +1076,7 @@ private function getParameterClassName(\ReflectionParameter $parameter) return ($class = $parameter->getClass()) ? $class->name : null; } - if (!($type = $parameter->getType()) instanceof \ReflectionNamedType || $type->isBuiltin()) { + if (!($type = $parameter->getType()) || $type->isBuiltin()) { return null; } From 03b9ff177d84258a959a8fa5ec113289f0b1e982 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Jun 2020 21:44:11 +0200 Subject: [PATCH 023/120] Use "composer/package-versions-deprecated" when possible --- composer.json | 1 + src/Symfony/Bridge/Doctrine/composer.json | 1 + src/Symfony/Component/Messenger/composer.json | 2 +- src/Symfony/Contracts/composer.json | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 84692253ea65a..3c75a0e70e6e6 100644 --- a/composer.json +++ b/composer.json @@ -100,6 +100,7 @@ }, "require-dev": { "cache/integration-tests": "dev-master", + "composer/package-versions-deprecated": "^1.8", "doctrine/annotations": "~1.0", "doctrine/cache": "~1.6", "doctrine/collections": "~1.0", diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index fde197dedb493..82848c2ad6e35 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -24,6 +24,7 @@ "symfony/service-contracts": "^1.1|^2" }, "require-dev": { + "composer/package-versions-deprecated": "^1.8", "symfony/stopwatch": "^3.4|^4.0|^5.0", "symfony/config": "^4.2|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index bbc5e5e3ff053..3537c7d3179d8 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -22,8 +22,8 @@ }, "require-dev": { "doctrine/dbal": "^2.6|^3.0", - "psr/cache": "~1.0", "doctrine/persistence": "^1.3", + "psr/cache": "~1.0", "symfony/console": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4.19|^4.1.8|^5.0", "symfony/event-dispatcher": "^4.3|^5.0", diff --git a/src/Symfony/Contracts/composer.json b/src/Symfony/Contracts/composer.json index 4ac096ed11c0e..f823bf30d6fc9 100644 --- a/src/Symfony/Contracts/composer.json +++ b/src/Symfony/Contracts/composer.json @@ -45,6 +45,7 @@ ] }, "minimum-stability": "dev", + "version": "1.99", "extra": { "branch-alias": { "dev-master": "1.1-dev" From d2efe50eee1e125cdaf88c88e37ad084c1ccb0e2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Jun 2020 21:50:30 +0200 Subject: [PATCH 024/120] [DI] fix --- .../Exception/InvalidParameterTypeException.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php b/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php index 05fdb4a779adb..f6f12ad604b54 100644 --- a/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php +++ b/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php @@ -23,7 +23,8 @@ public function __construct(string $serviceId, string $type, \ReflectionParamete { $acceptedType = $parameter->getType(); $acceptedType = $acceptedType instanceof \ReflectionNamedType ? $acceptedType->getName() : (string) $acceptedType; + $this->code = $type; - parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s::%s" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $acceptedType, $type), $type); + parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s::%s" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $acceptedType, $type)); } } From 2ca8ecdb7461377ffc1a572d9e80c64bdd1eb70a Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 18 Jun 2020 22:18:19 +0200 Subject: [PATCH 025/120] Added Unit tests for php 8 union types. --- .../Tests/Compiler/AutowirePassTest.php | 68 +++++++++++++++++++ .../Fixtures/includes/autowiring_classes.php | 4 ++ .../Fixtures/includes/uniontype_classes.php | 24 +++++++ .../Extractor/ReflectionExtractor.php | 7 +- .../Extractor/ReflectionExtractorTest.php | 20 ++++++ .../Tests/Fixtures/Php80Dummy.php | 26 +++++++ 6 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index e11154889c297..2482db631403b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -254,6 +254,25 @@ public function testTypeNotGuessableNoServicesFound() $pass->process($container); } + /** + * @requires PHP 8 + */ + public function testTypeNotGuessableUnionType() + { + $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); + $this->expectExceptionMessage('Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\UnionClasses::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionA|Symfony\Component\DependencyInjection\Tests\Compiler\CollisionB" but this class was not found.'); + $container = new ContainerBuilder(); + + $container->register(CollisionA::class); + $container->register(CollisionB::class); + + $aDefinition = $container->register('a', UnionClasses::class); + $aDefinition->setAutowired(true); + + $pass = new AutowirePass(); + $pass->process($container); + } + public function testTypeNotGuessableWithTypeSet() { $container = new ContainerBuilder(); @@ -350,6 +369,40 @@ public function testOptionalParameter() $this->assertEquals(Foo::class, $definition->getArgument(2)); } + /** + * @requires PHP 8 + */ + public function testParameterWithNullUnionIsSkipped() + { + $container = new ContainerBuilder(); + + $optDefinition = $container->register('opt', UnionNull::class); + $optDefinition->setAutowired(true); + + (new AutowirePass())->process($container); + + $definition = $container->getDefinition('opt'); + $this->assertNull($definition->getArgument(0)); + } + + /** + * @requires PHP 8 + */ + public function testParameterWithNullUnionIsAutowired() + { + $container = new ContainerBuilder(); + + $container->register(CollisionInterface::class, CollisionA::class); + + $optDefinition = $container->register('opt', UnionNull::class); + $optDefinition->setAutowired(true); + + (new AutowirePass())->process($container); + + $definition = $container->getDefinition('opt'); + $this->assertEquals(CollisionInterface::class, $definition->getArgument(0)); + } + public function testDontTriggerAutowiring() { $container = new ContainerBuilder(); @@ -459,6 +512,21 @@ public function testScalarArgsCannotBeAutowired() (new AutowirePass())->process($container); } + /** + * @requires PHP 8 + */ + public function testUnionScalarArgsCannotBeAutowired() + { + $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); + $this->expectExceptionMessage('Cannot autowire service "union_scalars": argument "$timeout" of method "Symfony\Component\DependencyInjection\Tests\Compiler\UnionScalars::__construct()" is type-hinted "int|float", you should configure its value explicitly.'); + $container = new ContainerBuilder(); + + $container->register('union_scalars', UnionScalars::class) + ->setAutowired(true); + + (new AutowirePass())->process($container); + } + public function testNoTypeArgsCannotBeAutowired() { $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php index 8db7edf1a126e..42545c9c2b71c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php @@ -2,6 +2,10 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler; +if (PHP_VERSION_ID >= 80000) { + require __DIR__.'/uniontype_classes.php'; +} + class Foo { } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php new file mode 100644 index 0000000000000..3a0c77c53941c --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php @@ -0,0 +1,24 @@ +getTypes() : [$reflectionType] as $type) { $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type; + if ('null' === $phpTypeOrClass) { + continue; + } if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { $types[] = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true); - } elseif ('void' === $phpTypeOrClass || 'null' === $phpTypeOrClass) { + } elseif ('void' === $phpTypeOrClass) { $types[] = new Type(Type::BUILTIN_TYPE_NULL, $nullable); - } elseif ($reflectionType->isBuiltin()) { + } elseif ($type->isBuiltin()) { $types[] = new Type($phpTypeOrClass, $nullable); } else { $types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod)); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 36fc9d55e37f8..bac036aa5bf90 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -204,6 +204,26 @@ public function php71TypesProvider() ]; } + /** + * @dataProvider php80TypesProvider + * @requires PHP 8 + */ + public function testExtractPhp80Type($property, array $type = null) + { + $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php80Dummy', $property, [])); + } + + public function php80TypesProvider() + { + return [ + ['foo', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)]], + ['bar', [new Type(Type::BUILTIN_TYPE_INT, true)]], + ['timeout', [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_FLOAT)]], + ['optional', [new Type(Type::BUILTIN_TYPE_INT, true), new Type(Type::BUILTIN_TYPE_FLOAT, true)]], + ['string', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Stringable'), new Type(Type::BUILTIN_TYPE_STRING)]], + ]; + } + /** * @dataProvider getReadableProperties */ diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php new file mode 100644 index 0000000000000..484498f4a6c0e --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php @@ -0,0 +1,26 @@ + Date: Thu, 18 Jun 2020 23:16:36 +0200 Subject: [PATCH 026/120] fix test --- .github/patch-types.php | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/patch-types.php b/.github/patch-types.php index 2df0774bec4c6..cbe209c6b54bb 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -30,6 +30,7 @@ case false !== strpos($file, '/src/Symfony/Component/Config/Tests/Fixtures/ParseError.php'): case false !== strpos($file, '/src/Symfony/Component/Debug/Tests/Fixtures/'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Compiler/OptionalServiceClass.php'): + case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ParentNotExists.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/BadClasses/MissingParent.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/'): From 6f3d054f0bbd0484d4fc55d6cae067cb6f8d2053 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Jun 2020 23:27:56 +0200 Subject: [PATCH 027/120] fix test --- .github/patch-types.php | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/patch-types.php b/.github/patch-types.php index cbe209c6b54bb..78e2fe99821e9 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -31,6 +31,7 @@ case false !== strpos($file, '/src/Symfony/Component/Debug/Tests/Fixtures/'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Compiler/OptionalServiceClass.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php'): + case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ParentNotExists.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/BadClasses/MissingParent.php'): case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/'): From a2c23935744f9d7105eb0334b1e6038949438acd Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Jun 2020 23:39:07 +0200 Subject: [PATCH 028/120] fix tests --- .github/patch-types.php | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/patch-types.php b/.github/patch-types.php index 78e2fe99821e9..5c68a66c89c79 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -38,6 +38,7 @@ case false !== strpos($file, '/src/Symfony/Component/ErrorHandler/Tests/Fixtures/'): case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php'): case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php'): + case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php'): case false !== strpos($file, '/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ObjectOuter.php'): case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/NotLoadableClass.php'): case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php') && \PHP_VERSION_ID < 70400: From a9987ce3411f0f268b16b081994dc7fdad313441 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 18 Jun 2020 21:22:57 +0200 Subject: [PATCH 029/120] collect all transformation failures --- .../Validator/Constraints/FormValidator.php | 5 +- .../FormValidatorFunctionalTest.php | 60 +++++++++++++++++++ .../Constraints/FormValidatorTest.php | 34 ----------- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 4447b2e54aa88..8f7acb35d86b7 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -147,7 +147,10 @@ public function validate($form, Constraint $formConstraint) foreach ($form as $child) { if (!$child->isSynchronized()) { $childrenSynchronized = false; - break; + + $fieldFormConstraint = new Form(); + $this->context->setNode($this->context->getValue(), $child, $this->context->getMetadata(), $this->context->getPropertyPath()); + $validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $fieldFormConstraint); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php index b51b34bb32ab0..d4ca0cb1bfe21 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php @@ -13,6 +13,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; @@ -329,6 +332,63 @@ public function testContextIsPopulatedWithFormBeingValidatedUsingGroupSequence() $this->assertCount(0, $violations); } + + public function testSubmitFormChoiceInvalid() + { + $form = $this->formFactory->create(DateType::class, null, [ + 'widget' => 'choice', + 'years' => [2021], + ]); + + $form->submit([ + 'year' => '2020', + 'month' => '13', + 'day' => '13', + ]); + + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isValid()); + $this->assertCount(2, $form->getErrors()); + $this->assertSame('This value is not valid.', $form->getErrors()[0]->getMessage()); + $this->assertSame($form->get('year'), $form->getErrors()[0]->getOrigin()); + $this->assertSame('This value is not valid.', $form->getErrors()[1]->getMessage()); + $this->assertSame($form->get('month'), $form->getErrors()[1]->getOrigin()); + } + + public function testDoNotAddInvalidMessageIfChildFormIsAlreadyNotSynchronized() + { + $formBuilder = $this->formFactory->createBuilder() + ->add('field1') + ->add('field2') + ->addModelTransformer(new CallbackTransformer( + function () { + }, + function () { + throw new TransformationFailedException('This value is invalid.'); + } + )); + $formBuilder->get('field2')->addModelTransformer(new CallbackTransformer( + function () { + }, + function () { + throw new TransformationFailedException('This value is invalid.'); + } + )); + $form = $formBuilder->getForm(); + + $form->submit([ + 'field1' => 'foo', + 'field2' => 'bar', + ]); + + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isValid()); + $this->assertCount(0, $form->getErrors()); + $this->assertTrue($form->get('field1')->isValid()); + $this->assertCount(0, $form->get('field1')->getErrors()); + $this->assertFalse($form->get('field2')->isValid()); + $this->assertCount(1, $form->get('field2')->getErrors()); + } } class Foo diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index f789fbe1e408d..69f4efac171fa 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -362,40 +362,6 @@ function () { throw new TransformationFailedException(); } ->assertRaised(); } - // https://github.com/symfony/symfony/issues/4359 - public function testDontMarkInvalidIfAnyChildIsNotSynchronized() - { - $object = new \stdClass(); - $object->child = 'bar'; - - $failingTransformer = new CallbackTransformer( - function ($data) { return $data; }, - function () { throw new TransformationFailedException(); } - ); - - $form = $this->getBuilder('name', '\stdClass') - ->setData($object) - ->addViewTransformer($failingTransformer) - ->setCompound(true) - ->setDataMapper(new PropertyPathMapper()) - ->add( - $this->getBuilder('child') - ->addViewTransformer($failingTransformer) - ) - ->getForm(); - - // Launch transformer - $form->submit(['child' => 'foo']); - - $this->assertTrue($form->isSubmitted()); - $this->assertFalse($form->isSynchronized()); - $this->expectNoValidate(); - - $this->validator->validate($form, new Form()); - - $this->assertNoViolation(); - } - public function testHandleGroupSequenceValidationGroups() { $object = new \stdClass(); From 50ccf2f1b20a565039463997fefc53351e92bdc9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 19 Jun 2020 15:00:29 +0200 Subject: [PATCH 030/120] [DI] disable preload.php on the CLI --- .../Component/DependencyInjection/Dumper/PhpDumper.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index ef7cb29aa3daf..d8b31dc18ddf3 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -319,6 +319,10 @@ public function dump(array $options = []) use Symfony\Component\DependencyInjection\Dumper\Preloader; +if (in_array(PHP_SAPI, ['cli', 'phpdbg'], true)) { + return; +} + require $autoloadFile; require __DIR__.'/Container{$hash}/{$options['class']}.php'; From bc96693331592222d5257437f1b7c02fa1fdee47 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 19 Jun 2020 18:14:07 +0200 Subject: [PATCH 031/120] [SecurityBundle] Drop cache.security_expression_language definition if invalid --- .../AddExpressionLanguageProvidersPass.php | 4 ++++ .../Resources/config/security.xml | 2 +- .../CompleteConfigurationTest.php | 21 +++++++++++++------ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddExpressionLanguageProvidersPass.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddExpressionLanguageProvidersPass.php index 898402d35939c..0393e6c616b79 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddExpressionLanguageProvidersPass.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddExpressionLanguageProvidersPass.php @@ -33,5 +33,9 @@ public function process(ContainerBuilder $container) $definition->addMethodCall('registerProvider', [new Reference($id)]); } } + + if (!$container->hasDefinition('cache.system')) { + $container->removeDefinition('cache.security_expression_language'); + } } } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index 2ea2c3fa7d732..3491383b8bba6 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -87,7 +87,7 @@ - + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index e358cb9945809..3098f42872674 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -56,7 +56,7 @@ public function testUserProviders() // chain provider $this->assertEquals([new IteratorArgument([ - new Reference('security.user.provider.concrete.service'), + new Reference('user.manager'), new Reference('security.user.provider.concrete.basic'), ])], $container->getDefinition('security.user.provider.concrete.chain')->getArguments()); } @@ -70,9 +70,9 @@ public function testFirewalls() foreach (array_keys($arguments[1]->getValues()) as $contextId) { $contextDef = $container->getDefinition($contextId); $arguments = $contextDef->getArguments(); - $listeners[] = array_map('strval', $arguments['index_0']->getValues()); + $listeners[] = array_map('strval', $arguments[0]->getValues()); - $configDef = $container->getDefinition((string) $arguments['index_3']); + $configDef = $container->getDefinition((string) $arguments[3]); $configs[] = array_values($configDef->getArguments()); } @@ -87,6 +87,14 @@ public function testFirewalls() 'security.user_checker', '.security.request_matcher.xmi9dcw', false, + false, + '', + '', + '', + '', + '', + [], + null, ], [ 'secure', @@ -657,9 +665,9 @@ public function testSimpleAuth() foreach (array_keys($arguments[1]->getValues()) as $contextId) { $contextDef = $container->getDefinition($contextId); $arguments = $contextDef->getArguments(); - $listeners[] = array_map('strval', $arguments['index_0']->getValues()); + $listeners[] = array_map('strval', $arguments[0]->getValues()); - $configDef = $container->getDefinition((string) $arguments['index_3']); + $configDef = $container->getDefinition((string) $arguments[3]); $configs[] = array_values($configDef->getArguments()); } @@ -708,6 +716,8 @@ protected function getContainer($file) $container = new ContainerBuilder(); $container->setParameter('kernel.debug', false); + $container->setParameter('request_listener.http_port', 80); + $container->setParameter('request_listener.https_port', 443); $security = new SecurityExtension(); $container->registerExtension($security); @@ -716,7 +726,6 @@ protected function getContainer($file) $bundle->build($container); // Attach all default factories $this->getLoader($container)->load($file); - $container->getCompilerPassConfig()->setOptimizationPasses([]); $container->getCompilerPassConfig()->setRemovingPasses([]); $container->getCompilerPassConfig()->setAfterRemovingPasses([]); $container->compile(); From 1f224763f444f586eb6b01f47e279223c818fa7d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 21 Jun 2020 16:44:07 +0200 Subject: [PATCH 032/120] [DI] fix typo in Preloader --- src/Symfony/Component/DependencyInjection/Dumper/Preloader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php index f9d2716e7d64d..fb39645022edf 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php @@ -85,7 +85,7 @@ private static function doPreload(string $class, array &$preloaded): void self::preloadType($p->getType(), $preloaded); } - self::preloadType($p->getReturnType(), $preloaded); + self::preloadType($m->getReturnType(), $preloaded); } } catch (\ReflectionException $e) { // ignore missing classes From 90f6e11ee84710541db9a77a35f375e56bb0ac9b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 21 Jun 2020 18:08:20 +0200 Subject: [PATCH 033/120] [DI] fix dumping deprecated private aliases --- .../Component/DependencyInjection/Dumper/YamlDumper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index ccb68ee8f1ee1..2effbe57119a6 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -163,8 +163,8 @@ private function addServiceAlias(string $alias, Alias $id): string { $deprecated = $id->isDeprecated() ? sprintf(" deprecated: %s\n", $id->getDeprecationMessage('%alias_id%')) : ''; - if ($id->isPrivate()) { - return sprintf(" %s: '@%s'\n%s", $alias, $id, $deprecated); + if (!$id->isDeprecated() && $id->isPrivate()) { + return sprintf(" %s: '@%s'\n", $alias, $id); } return sprintf(" %s:\n alias: %s\n public: %s\n%s", $alias, $id, $id->isPublic() ? 'true' : 'false', $deprecated); From 223b405168f1355460b80203c9d3e42f57bda012 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sun, 21 Jun 2020 18:44:56 +0200 Subject: [PATCH 034/120] Avoid accessibility errors on debug toolbar --- .../Resources/views/Profiler/toolbar_js.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig index 9da75d0559219..7366808d114d0 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig @@ -1,4 +1,4 @@ -
+
{{ include('@WebProfiler/Profiler/base_js.html.twig') }} {{ include('@WebProfiler/Profiler/toolbar.css.twig', { 'position': position, 'floatable': true }) }} From eec12ecd23ad735544bd4e4f819602373571eb28 Mon Sep 17 00:00:00 2001 From: Tristan Pouliquen Date: Fri, 19 Jun 2020 16:38:35 +0200 Subject: [PATCH 035/120] Use the driverConnection executeUpdate method --- .../Transport/Doctrine/Connection.php | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index de6d144e45089..e7a669a7113d1 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -126,7 +126,7 @@ public function send(string $body, array $headers, int $delay = 0): string 'available_at' => '?', ]); - $this->executeQuery($queryBuilder->getSQL(), [ + $this->executeUpdate($queryBuilder->getSQL(), [ $body, json_encode($headers), $this->configuration['queue_name'], @@ -179,7 +179,7 @@ public function get(): ?array ->set('delivered_at', '?') ->where('id = ?'); $now = new \DateTime(); - $this->executeQuery($queryBuilder->getSQL(), [ + $this->executeUpdate($queryBuilder->getSQL(), [ $now, $doctrineEnvelope['id'], ], [ @@ -329,6 +329,25 @@ private function executeQuery(string $sql, array $parameters = [], array $types return $stmt; } + private function executeUpdate(string $sql, array $parameters = [], array $types = []) + { + try { + $stmt = $this->driverConnection->executeUpdate($sql, $parameters, $types); + } catch (TableNotFoundException $e) { + if ($this->driverConnection->isTransactionActive()) { + throw $e; + } + + // create table + if ($this->autoSetup) { + $this->setup(); + } + $stmt = $this->driverConnection->executeUpdate($sql, $parameters, $types); + } + + return $stmt; + } + private function getSchema(): Schema { $schema = new Schema([], [], $this->driverConnection->getSchemaManager()->createSchemaConfig()); From afe596e16a0e161fce72236f412c97029ae130fc Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 22 Jun 2020 09:47:42 +0200 Subject: [PATCH 036/120] Relax tests to unlock change on master --- .../DependencyInjection/Compiler/CachePoolClearerPassTest.php | 3 +++ .../Component/Form/Tests/DependencyInjection/FormPassTest.php | 4 +++- .../DependencyInjection/AddConstraintValidatorsPassTest.php | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php index 728595ae9f2b1..e690aa8651e7d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php @@ -32,9 +32,11 @@ public function testPoolRefsAreWeak() $container->setParameter('kernel.root_dir', 'foo'); $globalClearer = new Definition(Psr6CacheClearer::class); + $globalClearer->setPublic(true); $container->setDefinition('cache.global_clearer', $globalClearer); $publicPool = new Definition(); + $publicPool->setPublic(true); $publicPool->addArgument('namespace'); $publicPool->addTag('cache.pool', ['clearer' => 'clearer_alias']); $container->setDefinition('public.pool', $publicPool); @@ -46,6 +48,7 @@ public function testPoolRefsAreWeak() $container->setDefinition('private.pool', $privatePool); $clearer = new Definition(); + $clearer->setPublic(true); $container->setDefinition('clearer', $clearer); $container->setAlias('clearer_alias', 'clearer'); diff --git a/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php b/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php index 64393a049840a..d3856a5c57543 100644 --- a/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php +++ b/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php @@ -57,12 +57,14 @@ public function testAddTaggedTypes() $extDefinition = $container->getDefinition('form.extension'); + $locator = $extDefinition->getArgument(0); + $this->assertTrue(!$locator->isPublic() || $locator->isPrivate()); $this->assertEquals( (new Definition(ServiceLocator::class, [[ __CLASS__.'_Type1' => new ServiceClosureArgument(new Reference('my.type1')), __CLASS__.'_Type2' => new ServiceClosureArgument(new Reference('my.type2')), ]]))->addTag('container.service_locator')->setPublic(false), - $extDefinition->getArgument(0) + $locator->setPublic(false) ); } diff --git a/src/Symfony/Component/Validator/Tests/DependencyInjection/AddConstraintValidatorsPassTest.php b/src/Symfony/Component/Validator/Tests/DependencyInjection/AddConstraintValidatorsPassTest.php index 9a2958364df17..45e73fc4341e3 100644 --- a/src/Symfony/Component/Validator/Tests/DependencyInjection/AddConstraintValidatorsPassTest.php +++ b/src/Symfony/Component/Validator/Tests/DependencyInjection/AddConstraintValidatorsPassTest.php @@ -35,12 +35,14 @@ public function testThatConstraintValidatorServicesAreProcessed() $addConstraintValidatorsPass = new AddConstraintValidatorsPass(); $addConstraintValidatorsPass->process($container); + $locator = $container->getDefinition((string) $validatorFactory->getArgument(0)); + $this->assertTrue(!$locator->isPublic() || $locator->isPrivate()); $expected = (new Definition(ServiceLocator::class, [[ Validator1::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')), 'my_constraint_validator_alias1' => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')), Validator2::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service2')), ]]))->addTag('container.service_locator')->setPublic(false); - $this->assertEquals($expected, $container->getDefinition((string) $validatorFactory->getArgument(0))); + $this->assertEquals($expected, $locator->setPublic(false)); } public function testAbstractConstraintValidator() From 12ab96ec9b2c8520b62e545c0e66acfd081bc450 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Mon, 22 Jun 2020 10:53:03 +0200 Subject: [PATCH 037/120] [DI][FrameworkBundle] Remove whitelist occurrences --- .../DependencyInjection/Compiler/UnusedTagsPass.php | 8 ++++---- ...sed-tags-whitelist.php => check-unused-known-tags.php} | 2 +- .../DependencyInjection/Compiler/UnusedTagsPassTest.php | 8 ++++---- .../Component/DependencyInjection/ContainerBuilder.php | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) rename src/Symfony/Bundle/FrameworkBundle/Resources/bin/{check-unused-tags-whitelist.php => check-unused-known-tags.php} (82%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php index 3cbe534fb99ed..f49f6a18c041f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php @@ -21,7 +21,7 @@ */ class UnusedTagsPass implements CompilerPassInterface { - private $whitelist = [ + private $knownTags = [ 'annotations.cached_reader', 'auto_alias', 'cache.pool', @@ -70,11 +70,11 @@ class UnusedTagsPass implements CompilerPassInterface public function process(ContainerBuilder $container) { - $tags = array_unique(array_merge($container->findTags(), $this->whitelist)); + $tags = array_unique(array_merge($container->findTags(), $this->knownTags)); foreach ($container->findUnusedTags() as $tag) { - // skip whitelisted tags - if (\in_array($tag, $this->whitelist)) { + // skip known tags + if (\in_array($tag, $this->knownTags)) { continue; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-tags-whitelist.php b/src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-known-tags.php similarity index 82% rename from src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-tags-whitelist.php rename to src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-known-tags.php index 7f24973cd8f14..ec9ae1f97c0ff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-tags-whitelist.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-known-tags.php @@ -15,5 +15,5 @@ $target = dirname(__DIR__, 2).'/DependencyInjection/Compiler/UnusedTagsPass.php'; $contents = file_get_contents($target); -$contents = preg_replace('{private \$whitelist = \[(.+?)\];}sm', "private \$whitelist = [\n '".implode("',\n '", UnusedTagsPassUtils::getDefinedTags())."',\n ];", $contents); +$contents = preg_replace('{private \$knownTags = \[(.+?)\];}sm', "private \$knownTags = [\n '".implode("',\n '", UnusedTagsPassUtils::getDefinedTags())."',\n ];", $contents); file_put_contents($target, $contents); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php index a73cdd167133d..8343d0d997fc8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php @@ -35,21 +35,21 @@ public function testProcess() $this->assertSame([sprintf('%s: Tag "kenrel.event_subscriber" was defined on service(s) "foo", "bar", but was never used. Did you mean "kernel.event_subscriber"?', UnusedTagsPass::class)], $container->getCompiler()->getLog()); } - public function testMissingWhitelistTags() + public function testMissingKnownTags() { if (\dirname((new \ReflectionClass(ContainerBuilder::class))->getFileName(), 3) !== \dirname(__DIR__, 5)) { $this->markTestSkipped('Tests are not run from the root symfony/symfony metapackage.'); } - $this->assertSame(UnusedTagsPassUtils::getDefinedTags(), $this->getWhitelistTags(), 'The src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php file must be updated; run src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-tags-whitelist.php.'); + $this->assertSame(UnusedTagsPassUtils::getDefinedTags(), $this->getKnownTags(), 'The src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php file must be updated; run src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-known-tags.php.'); } - private function getWhitelistTags() + private function getKnownTags() { // get tags in UnusedTagsPass $target = \dirname(__DIR__, 3).'/DependencyInjection/Compiler/UnusedTagsPass.php'; $contents = file_get_contents($target); - preg_match('{private \$whitelist = \[(.+?)\];}sm', $contents, $matches); + preg_match('{private \$knownTags = \[(.+?)\];}sm', $contents, $matches); $tags = array_values(array_filter(array_map(function ($str) { return trim(preg_replace('{^ +\'(.+)\',}', '$1', $str)); }, explode("\n", $matches[1])))); diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 7c9860b4dc47a..f6568b3ea3c77 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -1176,9 +1176,9 @@ private function createService(Definition $definition, array &$inlineServices, $ $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments); // don't trigger deprecations for internal uses // @deprecated since version 3.3, to be removed in 4.0 along with the deprecated class - $deprecationWhitelist = ['event_dispatcher' => ContainerAwareEventDispatcher::class]; + $deprecationAllowlist = ['event_dispatcher' => ContainerAwareEventDispatcher::class]; - if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ") && (!isset($deprecationWhitelist[$id]) || $deprecationWhitelist[$id] !== $class)) { + if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ") && (!isset($deprecationAllowlist[$id]) || $deprecationAllowlist[$id] !== $class)) { @trigger_error(sprintf('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name), E_USER_DEPRECATED); } } From 9e3670e140579c8331779776125e88af68269ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Frei?= <37588173+freiondrej@users.noreply.github.com> Date: Wed, 1 Apr 2020 17:33:44 +0200 Subject: [PATCH 038/120] Check whether path is file in DataPart::fromPath() --- src/Symfony/Component/Mime/Part/DataPart.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Mime/Part/DataPart.php b/src/Symfony/Component/Mime/Part/DataPart.php index c6f1cb9742eff..17e3e3c0d38ef 100644 --- a/src/Symfony/Component/Mime/Part/DataPart.php +++ b/src/Symfony/Component/Mime/Part/DataPart.php @@ -56,6 +56,10 @@ public static function fromPath(string $path, string $name = null, string $conte $contentType = self::$mimeTypes->getMimeTypes($ext)[0] ?? 'application/octet-stream'; } + if (false === is_readable($path)) { + throw new InvalidArgumentException(sprintf('Path "%s" is not readable.', $path)); + } + if (false === $handle = @fopen($path, 'r', false)) { throw new InvalidArgumentException(sprintf('Unable to open path "%s".', $path)); } From 39c1a6373b52903d37106c784bd95ada48f6bb7e Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 22 Jun 2020 16:52:42 +0200 Subject: [PATCH 039/120] [VarDumper] Support for cURL handler objects. --- src/Symfony/Component/VarDumper/Caster/ResourceCaster.php | 5 +++++ src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php index 3cdb27c30879b..eb11aee1f0264 100644 --- a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php @@ -20,6 +20,11 @@ */ class ResourceCaster { + /** + * @param \CurlHandle|resource $h + * + * @return array + */ public static function castCurl($h, array $a, Stub $stub, $isNested) { return curl_getinfo($h); diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index f424cc4866d21..2e1af1d77625a 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -117,7 +117,9 @@ abstract class AbstractCloner implements ClonerInterface 'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'], 'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'], + 'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], ':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], + ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], From 76a744ad91f979d87d021d1bb165db73204d1401 Mon Sep 17 00:00:00 2001 From: YaFou <33806646+YaFou@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:49:14 +0200 Subject: [PATCH 040/120] [HttpFondation] Change file extension of "audio/mpeg" from "mpga" to "mp3" --- .../HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php index c0f9140c800a2..5a809a248630f 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php @@ -619,7 +619,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'audio/basic' => 'au', 'audio/midi' => 'mid', 'audio/mp4' => 'm4a', - 'audio/mpeg' => 'mpga', + 'audio/mpeg' => 'mp3', 'audio/ogg' => 'oga', 'audio/s3m' => 's3m', 'audio/silk' => 'sil', From 5b74bbd288b95dc70d10208064e18e709eb79082 Mon Sep 17 00:00:00 2001 From: Marco Pfeiffer Date: Tue, 23 Jun 2020 11:57:07 +0200 Subject: [PATCH 041/120] add .body wrapper element This change makes the notification email responsive. --- .../Email/zurb_2/notification/body.html.twig | 90 ++++++++++--------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Email/zurb_2/notification/body.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Email/zurb_2/notification/body.html.twig index 662791aba6027..2f3a346df5903 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Email/zurb_2/notification/body.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Email/zurb_2/notification/body.html.twig @@ -10,54 +10,56 @@ - - - - - {% block lead %} - {{ importance|upper }} -

- {{ email.subject }} -

- {% endblock %} + + + + + + {% block lead %} + {{ importance|upper }} +

+ {{ email.subject }} +

+ {% endblock %} - {% block content %} - {% if markdown %} - {{ include('@email/zurb_2/notification/content_markdown.html.twig') }} - {% else %} - {{ (raw ? content|raw : content)|nl2br }} - {% endif %} - {% endblock %} + {% block content %} + {% if markdown %} + {{ include('@email/zurb_2/notification/content_markdown.html.twig') }} + {% else %} + {{ (raw ? content|raw : content)|nl2br }} + {% endif %} + {% endblock %} - {% block action %} - {% if action_url %} - - - {% endif %} - {% endblock %} + {% block action %} + {% if action_url %} + + + {% endif %} + {% endblock %} - {% block exception %} - {% if exception %} - -

Exception stack trace attached.

- {% endif %} - {% endblock %} -
-
+ {% block exception %} + {% if exception %} + +

Exception stack trace attached.

+ {% endif %} + {% endblock %} +
+
- - - {% block footer %} - - - {% block footer_content %} -

Notification e-mail sent by Symfony

- {% endblock %} -
-
- {% endblock %} -
-
+ + + {% block footer %} + + + {% block footer_content %} +

Notification e-mail sent by Symfony

+ {% endblock %} +
+
+ {% endblock %} +
+ + {% endapply %} From 968bd0ffec807e153fb7dd6b642d8a5d6432f0db Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Tue, 23 Jun 2020 14:31:34 +0200 Subject: [PATCH 042/120] Fixed typo in test name --- .../Component/Console/Tests/Helper/QuestionHelperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index 93b762c26186d..f1a7676a07e64 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -1014,7 +1014,7 @@ public function testTraversableAutocomplete() $this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); } - public function testDisableSttby() + public function testDisableStty() { if (!Terminal::hasSttyAvailable()) { $this->markTestSkipped('`stty` is required to test autocomplete functionality'); From b249f00519787f4bb2ed56ebc568277b4bec669d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 23 Jun 2020 20:33:34 +0200 Subject: [PATCH 043/120] [HttpClient] unset activity list when creating CurlResponse --- src/Symfony/Component/HttpClient/Response/CurlResponse.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index e7de360a8e410..c356f86c78f6b 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -43,6 +43,7 @@ public function __construct(CurlClientState $multi, $ch, array $options = null, $this->multi = $multi; if (\is_resource($ch)) { + unset($multi->handlesActivity[(int) $ch]); $this->handle = $ch; $this->debugBuffer = fopen('php://temp', 'w+'); if (0x074000 === $curlVersion) { From 7ccc2e1f28e62acaaa27ab2d6bc44daa0ee67310 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 22 Jun 2020 14:59:33 +0200 Subject: [PATCH 044/120] [HttpClient] Support for cURL handler objects. --- src/Symfony/Component/HttpClient/CurlHttpClient.php | 4 ++-- src/Symfony/Component/HttpClient/Internal/CurlClientState.php | 2 +- src/Symfony/Component/HttpClient/Response/CurlResponse.php | 4 +++- src/Symfony/Component/HttpClient/Response/ResponseTrait.php | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 0fda8c604c3dd..ae82703ec1187 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -337,7 +337,7 @@ public function reset() $this->multi->dnsCache->evictions = $this->multi->dnsCache->evictions ?: $this->multi->dnsCache->removals; $this->multi->dnsCache->removals = $this->multi->dnsCache->hostnames = []; - if (\is_resource($this->multi->handle)) { + if (\is_resource($this->multi->handle) || $this->multi->handle instanceof \CurlMultiHandle) { if (\defined('CURLMOPT_PUSHFUNCTION')) { curl_multi_setopt($this->multi->handle, CURLMOPT_PUSHFUNCTION, null); } @@ -347,7 +347,7 @@ public function reset() } foreach ($this->multi->openHandles as [$ch]) { - if (\is_resource($ch)) { + if (\is_resource($ch) || $ch instanceof \CurlHandle) { curl_setopt($ch, CURLOPT_VERBOSE, false); } } diff --git a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php index 1c2e6c8eed48d..af2e6869b37b3 100644 --- a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php +++ b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php @@ -20,7 +20,7 @@ */ final class CurlClientState extends ClientState { - /** @var resource */ + /** @var \CurlMultiHandle|resource */ public $handle; /** @var PushedResponse[] */ public $pushedResponses = []; diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index c356f86c78f6b..2856e004db7eb 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -36,13 +36,15 @@ final class CurlResponse implements ResponseInterface private $debugBuffer; /** + * @param \CurlHandle|resource|string $ch + * * @internal */ public function __construct(CurlClientState $multi, $ch, array $options = null, LoggerInterface $logger = null, string $method = 'GET', callable $resolveRedirect = null, int $curlVersion = null) { $this->multi = $multi; - if (\is_resource($ch)) { + if (\is_resource($ch) || $ch instanceof \CurlHandle) { unset($multi->handlesActivity[(int) $ch]); $this->handle = $ch; $this->debugBuffer = fopen('php://temp', 'w+'); diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 8d4fe59ae6872..e5fb0556930b7 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -50,7 +50,7 @@ trait ResponseTrait 'canceled' => false, ]; - /** @var resource */ + /** @var object|resource */ private $handle; private $id; private $timeout = 0; From 550ab6fd8c1c05d08235f542c38b5f906dc168b8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 24 Jun 2020 15:38:36 +0200 Subject: [PATCH 045/120] Fix merge --- src/Symfony/Component/Mime/MimeTypes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mime/MimeTypes.php b/src/Symfony/Component/Mime/MimeTypes.php index 398e021482a09..ecb475ad9b3f8 100644 --- a/src/Symfony/Component/Mime/MimeTypes.php +++ b/src/Symfony/Component/Mime/MimeTypes.php @@ -1113,7 +1113,7 @@ public function guessMimeType(string $path): ?string 'audio/mp2' => ['mp2'], 'audio/mp3' => ['mp3', 'mpga'], 'audio/mp4' => ['m4a', 'mp4a', 'f4a'], - 'audio/mpeg' => ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'], + 'audio/mpeg' => ['mp3', 'mpga', 'mp2', 'mp2a', 'm2a', 'm3a'], 'audio/mpegurl' => ['m3u', 'm3u8', 'vlc'], 'audio/ogg' => ['oga', 'ogg', 'spx', 'opus'], 'audio/prs.sid' => ['sid', 'psid'], From 2f23b01b0b600fca4d1c3ae5acdca7c6ffdcc3a9 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Wed, 24 Jun 2020 17:18:50 +0200 Subject: [PATCH 046/120] fix merge --- .../Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php index b8e4f2c05d753..89a35285ba234 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php @@ -41,7 +41,7 @@ public function testMissingKnownTags() $this->assertSame(UnusedTagsPassUtils::getDefinedTags(), $this->getKnownTags(), 'The src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php file must be updated; run src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-known-tags.php.'); } - private function getWhitelistTags(): array + private function getKnownTags(): array { // get tags in UnusedTagsPass $target = \dirname(__DIR__, 3).'/DependencyInjection/Compiler/UnusedTagsPass.php'; From 4a66a6098f6072df94edfbe074c15880db4931e2 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 23 Jun 2020 10:33:22 +0200 Subject: [PATCH 047/120] fix handling typed properties as constraint options --- .../Component/Validator/Constraint.php | 2 +- .../Validator/Tests/ConstraintTest.php | 24 +++++++++++++++++++ .../Fixtures/ConstraintWithStaticProperty.php | 10 ++++++++ .../Fixtures/ConstraintWithTypedProperty.php | 10 ++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithStaticProperty.php create mode 100644 src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithTypedProperty.php diff --git a/src/Symfony/Component/Validator/Constraint.php b/src/Symfony/Component/Validator/Constraint.php index 693689b912c34..ab2d8822903e4 100644 --- a/src/Symfony/Component/Validator/Constraint.php +++ b/src/Symfony/Component/Validator/Constraint.php @@ -108,7 +108,7 @@ public function __construct($options = null) $defaultOption = $this->getDefaultOption(); $invalidOptions = []; $missingOptions = array_flip((array) $this->getRequiredOptions()); - $knownOptions = get_object_vars($this); + $knownOptions = get_class_vars(static::class); // The "groups" option is added to the object lazily $knownOptions['groups'] = true; diff --git a/src/Symfony/Component/Validator/Tests/ConstraintTest.php b/src/Symfony/Component/Validator/Tests/ConstraintTest.php index 6c481b00888ed..26cc460d39c8a 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintTest.php @@ -13,10 +13,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidOptionsException; use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint; use Symfony\Component\Validator\Tests\Fixtures\ConstraintA; use Symfony\Component\Validator\Tests\Fixtures\ConstraintB; use Symfony\Component\Validator\Tests\Fixtures\ConstraintC; +use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithStaticProperty; +use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithTypedProperty; use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithValue; use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithValueAsDefault; @@ -245,4 +248,25 @@ public function testAnnotationSetUndefinedDefaultOption() $this->expectExceptionMessage('No default option is configured for constraint "Symfony\Component\Validator\Tests\Fixtures\ConstraintB".'); new ConstraintB(['value' => 1]); } + + public function testStaticPropertiesAreNoOptions() + { + $this->expectException(InvalidOptionsException::class); + + new ConstraintWithStaticProperty([ + 'foo' => 'bar', + ]); + } + + /** + * @requires PHP 7.4 + */ + public function testSetTypedProperty() + { + $constraint = new ConstraintWithTypedProperty([ + 'foo' => 'bar', + ]); + + $this->assertSame('bar', $constraint->foo); + } } diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithStaticProperty.php b/src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithStaticProperty.php new file mode 100644 index 0000000000000..f8b21694089b3 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithStaticProperty.php @@ -0,0 +1,10 @@ + Date: Fri, 26 Jun 2020 14:15:21 +0200 Subject: [PATCH 048/120] fix guessing form types for DateTime types --- .../Validator/ValidatorTypeGuesser.php | 1 + .../Validator/ValidatorTypeGuesserTest.php | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index 80ec926a94b29..17009d205dd3f 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -97,6 +97,7 @@ public function guessTypeForConstraint(Constraint $constraint) case 'long': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\IntegerType', [], Guess::MEDIUM_CONFIDENCE); + case \DateTime::class: case '\DateTime': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', [], Guess::MEDIUM_CONFIDENCE); diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index 878bbfad21bc5..3ac27cdef73b4 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -12,9 +12,17 @@ namespace Symfony\Component\Form\Tests\Extension\Validator; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\CollectionType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser; use Symfony\Component\Form\Guess\Guess; +use Symfony\Component\Form\Guess\TypeGuess; use Symfony\Component\Form\Guess\ValueGuess; +use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\IsTrue; use Symfony\Component\Validator\Constraints\Length; @@ -59,6 +67,35 @@ protected function setUp() $this->guesser = new ValidatorTypeGuesser($this->metadataFactory); } + /** + * @dataProvider guessTypeProvider + */ + public function testGuessType(Constraint $constraint, TypeGuess $guess) + { + $this->metadata->addPropertyConstraint(self::TEST_PROPERTY, $constraint); + + $this->assertEquals($guess, $this->guesser->guessType(self::TEST_CLASS, self::TEST_PROPERTY)); + } + + public function guessTypeProvider() + { + return [ + [new Type('array'), new TypeGuess(CollectionType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('bool'), new TypeGuess(CheckboxType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('boolean'), new TypeGuess(CheckboxType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('double'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('float'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('numeric'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('real'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('int'), new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('integer'), new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('long'), new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('string'), new TypeGuess(TextType::class, [], Guess::LOW_CONFIDENCE)], + [new Type(\DateTime::class), new TypeGuess(DateType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('\DateTime'), new TypeGuess(DateType::class, [], Guess::MEDIUM_CONFIDENCE)], + ]; + } + public function guessRequiredProvider() { return [ From 70b6a001489607b24ade9afdd81251a2e2eeb48e Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Fri, 26 Jun 2020 19:49:20 +0200 Subject: [PATCH 049/120] [DI] fix parsing of argument type=binary in xml --- .../Loader/schema/dic/services/services-1.0.xsd | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd index 2f745c3326d49..208f5118ec7b3 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd +++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd @@ -265,6 +265,7 @@ + From 7cb29c8b4b2990a2555d739ec11d7b9d0d46aff8 Mon Sep 17 00:00:00 2001 From: Juan Mrad Date: Tue, 23 Jun 2020 11:04:58 -0500 Subject: [PATCH 050/120] [MimeType] Duplicated MimeType due to PHP Bug --- .../File/MimeType/FileinfoMimeTypeGuesser.php | 8 +++++++- .../HttpFoundation/Tests/File/Fixtures/test.docx | Bin 0 -> 6062 bytes .../Tests/File/MimeType/MimeTypeTest.php | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/HttpFoundation/Tests/File/Fixtures/test.docx diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php index fc4bc45024b11..fa4c962d7dd82 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php @@ -63,7 +63,13 @@ public function guess($path) if (!$finfo = new \finfo(FILEINFO_MIME_TYPE, $this->magicFile)) { return null; } + $mimeType = $finfo->file($path); - return $finfo->file($path); + if ($mimeType && 0 === (\strlen($mimeType) % 2)) { + $mimeStart = substr($mimeType, 0, \strlen($mimeType) >> 1); + $mimeType = $mimeStart.$mimeStart === $mimeType ? $mimeStart : $mimeType; + } + + return $mimeType; } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/Fixtures/test.docx b/src/Symfony/Component/HttpFoundation/Tests/File/Fixtures/test.docx new file mode 100644 index 0000000000000000000000000000000000000000..2e86b6fcea03c679370c996ba200ccb39d1dd83b GIT binary patch literal 6062 zcma)A2Q*x3*B)Z@=q=Gj38IH6K@bcvdMC>0WiUF4PK+91h#o{2(OdN1d$iG_iy9?L zw4dDXem6J&fA9MDS!>qJS+mbRXTSS7&+|UY&u*cS05CBz0i7xn%79;j==!^xy`w3Y zoeLCV=4fSS!RZdQ&58jlwsI2$DK$|u>`pV1(vk3Q`(q1i`QECIjM1(T9iNn2--abM zsxl&8X)K4&A9pOReLs5EowjNTTt~F^!qN2kx&k>>_fPjq-5LB`)GgHgS6PJ|pH(K+ zy2Px@ZwvkK@{_epx*r!kA`}ytZpNhbnX}npJ4`4oV}Pp!leAsRj0_i%uDBIMvP1DP zWBrXY1xPMP_$vVp6NP`!ObR2`a*a{l*&%lF;XOBT6J{!Qw!_i(VbosE$xlu<5C=@s7iwBrx8w{ zKty4bY)u~#*&~$fW@v&w{4NYlRC@Jo@|F%;O@dBqj7p;%cX{%k7QShRYh%BPD9v~D z0;T7N8Vg?rV)C)<66}9)V9#}a8y=EAGm(}Fjj!}$-pTSXA*RcDO|!`8{%!Lx*|zP; z8YRa`RIb`9%lF(B;{}5OFb4Cl;pj(jR)`|jgpd>yYJ4*Hg~N<*_6+;G7q&90kqD%Ec@ium-qTM*?x5xew5stfD=))kKf)z@6su8-{#A+ zh&Z?%!kv2?E|__wc4Zqk7v9@|0=`#xDUMWnuS?zO<%Pf9PZ%7;-<1gVy#fj?va}@-Yp*N^ihX$1c4kzKR|O zl)3^uB%m^l4xP5?*HLRtc>F^k(4x;BH=w}sez?ORaF+Ap~r?x&owhi50ea(3Fm&Efo}BX}i4 z(Zs?JE+nEMI`W*KWQ)>R8)Un0?aSaSHBy-nu^sw$jE#Is&0ZUkEZL#2Z4@XO%{QDt zvf2S9C`^$PNGXYc0 z1gjZ|Bx}T~^yv&kCZJgzmRfnm#eLNP(tCwJXtzU(OH5{pR)-oc{0cS?0B=R{#e|$9g>^mRguxL z?|vf~ges+CrBSgVkhhUtQR^FE0@vuQw8iN8=soa=F_w2n0GA>I&{)A&2I8|M#~A;IzXy2tV(s0+1(B z@69+vF*JyQD&W&HD&J_$GA}wb(b24v&X5@9=l$cfd`u9QH3_PJkeM@Syh=d3v#7oRBPkj=oLo=1kS!Iz@KTIy|2xEUX} zB#@z0q1@78E2D5ANy#ZiFVrHRu~p3t^Wh$E8o^QPa;zuxlB?r|j7B~7sF|*JDG&`BXs(jO9BO0k zBC)DIVE5arY1MXjYSj8EfR$_}@mV~z@!_+{8J3m2U=+A15h61fc_Ca8+OZp$2w+Sk zFU^RWB`wv{FMZJhS})}OifX#SMVOVZGx6HNPBhEAZ=8BHVU?|if)5U>p^C%rv9ZX5 zdfdhdJ70dZZ}F0bdw#_mYJ?2Ix(MwnG0x$Uz%Rv!uG5IBL@+B*brmpdIn~*5n=||%t zI*sx<^3wH$8pY#k?{l$t&P|C_z)c~YbwvY>&V)A}J9OqOFJp@oW?kO9Bq2B5clYt? z++wdje;2<&7JNV&m--d}Fn`UQ{|{OPY(4XyPHwHBLmP@Su?K?1)wq zq5;}n88hP??u%6x(Gy%!HOA!Qtyoasm@if<4CSsT*UMeI(Yv2d=$8z%d89#(;A}6`#?N@+7H^?Y`T%$MMPH5eZG4_jJLHjq9ZRLy z^tM$vxovySlu~K6)DuoMC-CWHq2Iccz_1^I^N3*LY|$YZ0@?oOWq5hqdHT zIW(nJN)uz*Ommy+$ml28hvqakq#YLZ%wFU#oYgYxaB6`)Kqo-~pXyx|&m_Q_(6~|a zhiJXCmMC03#AT-Oyj;hf zy4;)O*F;N(@o!T__2>KA(9z7+iR;(d;=DOi7!9`mDX)h_;8PQ&qqOoN$zV)Vy_sA0 z_fLX#@6m(hz0N`rjCg3HL2q|MJP!K9$CGG9;P$vBZkcIajs&2NG0_Tav4YtpN_bbI zwWy#Z@Se;h0)G>q>S0deuzBi7~i^hsc*-$yV3~ z4b9@spLoQu9#!}k7vT_$t?!9XeYEln(6fjn3)wA?O19L9(``M|8K@q$bZd~*)#16q-BH&(M0_zbV zy^Hh;KxHwTuwP2f{qV@t2+-DKd3J13vrXg5{3yKJy)!M(nr=N)tHTO?ZJ~M&MNUVM z$$U4e*&j=|!CFZ$Oy70HRFVM*3u#6;O{yg>2Wn>aU^tuc{;-thH2eGz(}VEt*X)l~ z4;v_(#1%%^(Mz;$M;T+Cyx#5{20eE7s94{BO>7v#5SGisSACY7>se9Ig1W+S;r`|i zQs=N7WGK0Q4z_Dz|K}$q{c}j1EzO{2Tt7c~ZeBmzI?wE<1*jVFC*A0r?aih%H_%){ zCrhRa!IX@4!8BGOag)j!Pe$ZkQX-dpQCdG42a`@hgN^n4$R@MS9!?3{QV$gsH`2th zCJnp?SK$@n3&>qu?qbND?#H&m)4doNS76hQoZ}CkLSCOe#6ym6OI%6zN~$hQc7}Im zLc#Fzj~{$an$7C6C5Z^p4omb~q3r5xI%UwW&Af5s9+D7ufklQE>}-Z&FF$-=`?f95 z!b*s2d5%c#=w@tnRFxD61dQQ+&4=Ug$lYNpyggK|F0PhAt9oW)mg zL@gZzpa`jxLA2T2hbpb7I!h}sL@;+i+$42!jN*xX{(k2qVSl!6#kMT3C`#y>3bUq%4Wt#d|UTI?qsxbyl= zRo3kN5uU*L&Ve^T)lpa4u@0op^SBO6yXtIqCFfB2nK%P_pe|%jbL!@>KzWikUjPhP=4MDOH->qxeRNh^$NZ8+@B2# zHcZ%4?Yz1iwP?Kfk##56`O85O?bY7l-hsW?)j@DD`pK&%DQdAa!Z+*8LQg~S$z0 zzmTncXbl?9-pqS2i?bxijYDoiT@|p`Am{4F*-#Hdtx*6!sHM-#t?8#*7Np}*x$o6+ zjL8!`lDI)T-+c6RD0)o2@MTdG6nA`yXTwhH3stWV`;!AMn2TuRKU>69P>y--Xxhc|$8)va{C2yuF#s)U9sNtk3#P62SOiCCMWlh}6 zozp`DHq2_{yV$hj``&s=VPwgiGnz5%cqzrPbvhJ140pHg?y=Qc^mEzU^~=!g zhXcbT$FuxQ{rZCM1kSfc&}yrj?)MK@wg+JgIj1vb8W=V;yz54-CqPK&6G6V>tgCC4 zif`%(y{_v9rX$l)h)9G}uz~c``Naol=8DhfX>!6t#nkfIW6s?`M_81ZW3|yp`*a5+ z7+cn~`ZR4Sd*d$pMb*idk(XH!7RF3TBpcU#xT)ZeJ#Vr<7AXd&+D8VJK0L9`UTL>Oy<&nC%dU83EC$0F7Pb`M}j zdy59MQy-frcJ@A2l0W-AzC%A{yYTwHSRF>`qXkbs^V3iTqd5FZY4dMUXEBg2(>WqX zSp_}eFt;vDl`Dt4<3g{=t_~4Nr;40(74?j^$qL$EERsNS`r--InelUb@{3z!7LX?M zXs4GnE2YwLsgS+R>MfF+bEBWONc=p3Z}VE0o@=`I2r$tIsiV5(_&k@mM3y0* zUt!!3E4^+;;DhUp|1|Z#(GBr6-RMbOZ~U)CuA#bzgPGIw8?vd00o%3QIDJDRPvMicGh2a?7^tCCbApKVP49kZmk-r z;n&=Te5H{kMqczDLxVsnx4GRn7I`o4bj$qHBul1b;w=s9{$!d8<}w+4^^QOZ1hYB* zgU-4UtUmG&%JUJO$H=xO3ir0c;6(7d62FM0#jg(Yx?0$(j^hBFw`6=8bz4s#8&z6d zgf&2O2aRN8qj=wMT3bSiXHzlY^3axA1?K6yS0sc<9d|#xpK`ZiZ8Z6)7Kt8WnmZR8 z*jFl&?fqo+(KkrJw7i#U@6x?si7)l7Hh>fX%a`{IaI}T%6oz^OBm*N1A#oRGa042W z46VnL4tFxSPG#}pUVECIq&RD{jNO23M)8!`D; zMB)BTTK=B+D~xWm* Inm-Hw4?2y0ApigX literal 0 HcmV?d00001 diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php index 0418726b5b905..e38816687fec7 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php @@ -60,6 +60,14 @@ public function testGuessFileWithUnknownExtension() $this->assertEquals('application/octet-stream', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension')); } + /** + * @requires PHP 7.0 + */ + public function testGuessWithDuplicatedFileType() + { + $this->assertEquals('application/vnd.openxmlformats-officedocument.wordprocessingml.document', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')); + } + public function testGuessWithIncorrectPath() { $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); From 9ccf043c7cff0d58547fd25c41a5005fffd7ad72 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 28 Jun 2020 16:40:16 +0200 Subject: [PATCH 051/120] [DoctrineBridge] work around Connection::ping() deprecation --- .../Messenger/DoctrinePingConnectionMiddleware.php | 5 ++++- .../Messenger/DoctrinePingConnectionMiddlewareTest.php | 9 +++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php index f6febb2a7e673..3ec525d2cfd41 100644 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Messenger; +use Doctrine\DBAL\DBALException; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Middleware\StackInterface; @@ -36,7 +37,9 @@ private function pingConnection(EntityManagerInterface $entityManager) { $connection = $entityManager->getConnection(); - if (!$connection->ping()) { + try { + $connection->query($connection->getDatabasePlatform()->getDummySelectSQL()); + } catch (DBALException $e) { $connection->close(); $connection->connect(); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php index a0932371dfbfd..e491558a2addf 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Messenger; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\DBALException; use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; use Symfony\Bridge\Doctrine\Messenger\DoctrinePingConnectionMiddleware; @@ -47,8 +48,8 @@ protected function setUp(): void public function testMiddlewarePingOk() { $this->connection->expects($this->once()) - ->method('ping') - ->willReturn(false); + ->method('getDatabasePlatform') + ->will($this->throwException(new DBALException())); $this->connection->expects($this->once()) ->method('close') @@ -65,6 +66,10 @@ public function testMiddlewarePingOk() public function testMiddlewarePingResetEntityManager() { + $this->connection->expects($this->once()) + ->method('getDatabasePlatform') + ->will($this->throwException(new DBALException())); + $this->entityManager->expects($this->once()) ->method('isOpen') ->willReturn(false) From de71a12f3bc4d7f3f13289f172776fee8bde0f52 Mon Sep 17 00:00:00 2001 From: Gennadi Janzen Date: Thu, 25 Jun 2020 21:17:33 +0200 Subject: [PATCH 052/120] Fix: compatibility with phpunit 9.3 --- src/Symfony/Bridge/PhpUnit/Legacy/CommandForV9.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV9.php b/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV9.php index aa48ca5f2487a..2511380257fd8 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV9.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/CommandForV9.php @@ -12,9 +12,11 @@ namespace Symfony\Bridge\PhpUnit\Legacy; use PHPUnit\TextUI\Command as BaseCommand; -use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\Configuration as LegacyConfiguration; use PHPUnit\TextUI\Configuration\Registry; use PHPUnit\TextUI\TestRunner as BaseRunner; +use PHPUnit\TextUI\XmlConfiguration\Configuration; +use PHPUnit\TextUI\XmlConfiguration\Loader; use Symfony\Bridge\PhpUnit\SymfonyTestsListener; /** @@ -43,9 +45,13 @@ protected function createRunner(): BaseRunner if (isset($this->arguments['configuration'])) { $configuration = $this->arguments['configuration']; - if (!$configuration instanceof Configuration) { + + if (!class_exists(Configuration::class) && !$configuration instanceof LegacyConfiguration) { $configuration = Registry::getInstance()->get($this->arguments['configuration']); + } elseif (class_exists(Configuration::class) && !$configuration instanceof Configuration) { + $configuration = (new Loader())->load($this->arguments['configuration']); } + foreach ($configuration->listeners() as $registeredListener) { if ('Symfony\Bridge\PhpUnit\SymfonyTestsListener' === ltrim($registeredListener->className(), '\\')) { $registeredLocally = true; From b344f6d7db29f8b6c52a9425af84c29c798b5ed6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 28 Jun 2020 17:22:27 +0200 Subject: [PATCH 053/120] Fix test that fails on old distros --- .../HttpFoundation/Tests/File/MimeType/MimeTypeTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php index e38816687fec7..aca05f2d96ca0 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php @@ -65,7 +65,13 @@ public function testGuessFileWithUnknownExtension() */ public function testGuessWithDuplicatedFileType() { - $this->assertEquals('application/vnd.openxmlformats-officedocument.wordprocessingml.document', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')); + if ('application/zip' === MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')) { + $this->addToAssertionCount(1); + + return; + } + + $this->assertSame('application/vnd.openxmlformats-officedocument.wordprocessingml.document', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')); } public function testGuessWithIncorrectPath() From 776daf28b4e5240a830ff0c724604a4968e51b24 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 29 Jun 2020 12:48:16 +0200 Subject: [PATCH 054/120] fix validating lazy properties that evaluate to null --- .../Validator/Tests/Fixtures/EntityParent.php | 6 +++++ .../Validator/RecursiveValidatorTest.php | 27 +++++++++++++++++++ .../RecursiveContextualValidator.php | 4 +++ 3 files changed, 37 insertions(+) diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php b/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php index 4674f8b35a226..eb09e5a4b2375 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php @@ -18,6 +18,7 @@ class EntityParent implements EntityInterfaceA protected $firstName; private $internal; private $data = 'Data'; + private $child; /** * @NotNull @@ -28,4 +29,9 @@ public function getData() { return 'Data'; } + + public function getChild() + { + return $this->child; + } } diff --git a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php index 484236241c7fa..c9e30b458780f 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php @@ -21,6 +21,7 @@ use Symfony\Component\Validator\Constraints\NotNull; use Symfony\Component\Validator\Constraints\Optional; use Symfony\Component\Validator\Constraints\Required; +use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\ConstraintValidatorFactory; use Symfony\Component\Validator\Context\ExecutionContextFactory; use Symfony\Component\Validator\Mapping\ClassMetadata; @@ -28,6 +29,7 @@ use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildA; use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildB; use Symfony\Component\Validator\Tests\Fixtures\Entity; +use Symfony\Component\Validator\Tests\Fixtures\EntityParent; use Symfony\Component\Validator\Tests\Fixtures\EntityWithGroupedConstraintOnMethods; use Symfony\Component\Validator\Validator\RecursiveValidator; @@ -143,6 +145,31 @@ public function testGroupedMethodConstraintValidateInSequence() $this->assertInstanceOf(IsTrue::class, $violations->get(1)->getConstraint()); } + public function testValidConstraintOnGetterReturningNull() + { + $metadata = new ClassMetadata(EntityParent::class); + $metadata->addGetterConstraint('child', new Valid()); + + $this->metadataFactory->addMetadata($metadata); + + $violations = $this->validator->validate(new EntityParent()); + + $this->assertCount(0, $violations); + } + + public function testNotNullConstraintOnGetterReturningNull() + { + $metadata = new ClassMetadata(EntityParent::class); + $metadata->addGetterConstraint('child', new NotNull()); + + $this->metadataFactory->addMetadata($metadata); + + $violations = $this->validator->validate(new EntityParent()); + + $this->assertCount(1, $violations); + $this->assertInstanceOf(NotNull::class, $violations->get(0)->getConstraint()); + } + public function testAllConstraintValidateAllGroupsForNestedConstraints() { $this->metadata->addPropertyConstraint('data', new All(['constraints' => [ diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index 24206bfc27d92..a51e66d2906d0 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -680,6 +680,10 @@ private function validateGenericNode($value, $object, $cacheKey, MetadataInterfa if ($value instanceof LazyProperty) { $value = $value->getPropertyValue(); + + if (null === $value) { + return; + } } if (\is_array($value)) { From 02c9ac68a4fb5e0a5223aa9528ef8eb1dcfaf996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me?= Date: Mon, 29 Jun 2020 15:31:43 +0200 Subject: [PATCH 055/120] Fix caching of parent locales file in translator --- src/Symfony/Component/Translation/Translator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index b404b549198a9..c4c58f054d1a7 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -460,7 +460,7 @@ private function loadFallbackCatalogues(string $locale): void protected function computeFallbackLocales($locale) { if (null === $this->parentLocales) { - $parentLocales = json_decode(file_get_contents(__DIR__.'/Resources/data/parents.json'), true); + $this->parentLocales = json_decode(file_get_contents(__DIR__.'/Resources/data/parents.json'), true); } $locales = []; @@ -473,7 +473,7 @@ protected function computeFallbackLocales($locale) } while ($locale) { - $parent = $parentLocales[$locale] ?? null; + $parent = $this->parentLocales[$locale] ?? null; if ($parent) { $locale = 'root' !== $parent ? $parent : null; From 3b77abea6586ea2664e83755c9917a12ff9ec395 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 29 Jun 2020 15:46:05 +0200 Subject: [PATCH 056/120] skip test if guesser is not supported --- .../Component/Mime/Tests/AbstractMimeTypeGuesserTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php b/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php index 6b5de034b3244..7d5656054acb8 100644 --- a/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php +++ b/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php @@ -81,6 +81,10 @@ public function testGuessFileWithUnknownExtension() public function testGuessWithDuplicatedFileType() { + if (!$this->getGuesser()->isGuesserSupported()) { + $this->markTestSkipped('Guesser is not supported'); + } + $this->assertEquals('application/vnd.openxmlformats-officedocument.wordprocessingml.document', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/test.docx')); } From b17df8cdd75607f2bbd897be98f782466d4b410c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 29 Jun 2020 15:08:02 +0200 Subject: [PATCH 057/120] fix compatibility with Doctrine DBAL 3.0 --- .../Tests/Transport/Doctrine/DoctrineReceiverTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineReceiverTest.php index 45e4dd3b91ce3..cf84a36006e72 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineReceiverTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineReceiverTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; +use Doctrine\DBAL\Driver\PDO\Exception; use Doctrine\DBAL\Driver\PDOException; use Doctrine\DBAL\Exception\DeadlockException; use PHPUnit\Framework\TestCase; @@ -75,7 +76,7 @@ public function testOccursRetryableExceptionFromConnection() { $serializer = $this->createSerializer(); $connection = $this->createMock(Connection::class); - $driverException = new PDOException(new \PDOException('Deadlock', 40001)); + $driverException = class_exists(Exception::class) ? Exception::new(new \PDOException('Deadlock', 40001)) : new PDOException(new \PDOException('Deadlock', 40001)); $connection->method('get')->willThrowException(new DeadlockException('Deadlock', $driverException)); $receiver = new DoctrineReceiver($connection, $serializer); $this->assertSame([], $receiver->get()); From 5c5ea7500eea9c04b12f8d14adafb2f537b41e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 30 Jun 2020 14:50:28 +0200 Subject: [PATCH 058/120] Removed comments and requirements relative to php <5.5 (not supported anymore) --- src/Symfony/Component/Console/Command/Command.php | 2 -- .../DateTimeToHtml5LocalDateTimeTransformerTest.php | 1 - src/Symfony/Component/HttpFoundation/Tests/CookieTest.php | 3 --- 3 files changed, 6 deletions(-) diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index 311fdb6a144ef..e39cc3ba41815 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -437,8 +437,6 @@ public function setName($name) * This feature should be used only when creating a long process command, * like a daemon. * - * PHP 5.5+ or the proctitle PECL library is required - * * @param string $title The process title * * @return $this diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php index 5fd6c69f5e11b..aef3e68829b13 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php @@ -63,7 +63,6 @@ public function testTransform($fromTz, $toTz, $from, $to) /** * @dataProvider transformProvider - * @requires PHP 5.5 */ public function testTransformDateTimeImmutable($fromTz, $toTz, $from, $to) { diff --git a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php index 169f9178751d4..637cff0d09ae4 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php @@ -115,9 +115,6 @@ public function testConstructorWithDateTime() $this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); } - /** - * @requires PHP 5.5 - */ public function testConstructorWithDateTimeImmutable() { $expire = new \DateTimeImmutable(); From aeb46373410d168b995aeab34f725092616a67f0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 Jun 2020 19:26:29 +0200 Subject: [PATCH 059/120] [ErrorHandler] fix throwing from __toString() --- src/Symfony/Component/Debug/ErrorHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index 40a4b1758ce7c..1e60b5ca9803d 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -401,7 +401,7 @@ public function handleError($type, $message, $file, $line) $scope = $this->scopedErrors & $type; if (4 < $numArgs = \func_num_args()) { - $context = $scope ? (func_get_arg(4) ?: []) : []; + $context = func_get_arg(4) ?: []; $backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM } else { $context = []; From 91f30e0b62dcc7bfa5c37c49cc2d25cfcab3419f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 Jun 2020 19:58:29 +0200 Subject: [PATCH 060/120] [Bridge/Twig] Relax tests --- src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php index 273ca922d6fe8..3125b88aad7fd 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php @@ -82,6 +82,7 @@ public function testDump($context, $args, $expectedOutput, $debug = true) $this->assertStringStartsWith('