Merge branch '4.3' into 4.4

This commit is contained in:
Tobias Schultze 2019-07-29 18:17:34 +02:00
commit f45350338c
22 changed files with 333 additions and 177 deletions

View File

@ -1,6 +1,6 @@
| Q | A | Q | A
| ------------- | --- | ------------- | ---
| Branch? | 4.4 for features / 3.4, 4.2 or 4.3 for bug fixes <!-- see below --> | Branch? | 4.4 for features / 3.4 or 4.3 for bug fixes <!-- see below -->
| Bug fix? | yes/no | Bug fix? | yes/no
| New feature? | yes/no <!-- please update src/**/CHANGELOG.md files --> | New feature? | yes/no <!-- please update src/**/CHANGELOG.md files -->
| BC breaks? | no <!-- see https://symfony.com/bc --> | BC breaks? | no <!-- see https://symfony.com/bc -->

View File

@ -7,6 +7,64 @@ in 4.3 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.3.0...v4.3.1 To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.3.0...v4.3.1
* 4.3.3 (2019-07-28)
* bug #32726 [Messenger] Fix redis last error not cleared between calls (chalasr)
* bug #32760 [HttpKernel] clarify error handler restoring process (xabbuh)
* bug #32730 [Inflector] Fix pluralizing words ending with "son" (norkunas)
* bug #32715 [DI] fix perf issue with lazy autowire error messages (nicolas-grekas)
* bug #32503 Fix multiSelect ChoiceQuestion when answers have spaces (IceMaD)
* bug #32688 [Yaml] fix inline handling when dumping tagged values (xabbuh)
* bug #32710 [Security/Core] align defaults for sodium with PHP 7.4 (nicolas-grekas)
* bug #32644 [WebProfileBundle] Avoid getting right to left style (Arman-Hosseini)
* bug #32689 [HttpClient] rewind stream when using Psr18Client (nicolas-grekas)
* bug #32700 [Messenger] Flatten collection of stamps collected by the traceable middleware (ogizanagi)
* bug #32699 [HttpClient] fix canceling responses in a streaming loop (nicolas-grekas)
* bug #32679 [Intl] relax some date parser patterns (xabbuh)
* bug #31303 [VarDumper] Use \ReflectionReference for determining if a key is a reference (php >= 7.4) (dorumd, nicolas-grekas)
* bug #32485 [Validator] Added support for validation of giga values (kernig)
* bug #32567 [Messenger] pass transport name to factory (Tobion)
* bug #32568 [Messenger] Fix UnrecoverableExceptionInterface handling (LanaiGrunt)
* bug #32604 Properly handle optional tag attributes for !tagged_iterator (apfelbox)
* bug #32571 [HttpClient] fix debug output added to stderr at shutdown (nicolas-grekas)
* bug #32443 [PHPUnitBridge] Mute deprecations triggered from phpunit (greg0ire)
* bug #32572 Bump minimum version of symfony/phpunit-bridge (fancyweb)
* bug #32438 [Serializer] XmlEncoder: don't cast padded strings (ogizanagi)
* bug #32579 [Config] Do not use absolute path when computing the vendor freshness (lyrixx)
* bug #32563 Container*::getServiceIds() should return strings (mathroc)
* bug #32553 [Mailer] Allow register mailer configuration in xml format (Koc)
* bug #32442 Adding missing event_dispatcher wiring for messenger.middleware.send_message (weaverryan)
* bug #32466 [Config] Fix for signatures of typed properties (tvandervorm)
* bug #32501 [FrameworkBundle] Fix descriptor of routes described as callable array (ribeiropaulor)
* bug #32500 [Debug][DebugClassLoader] Include found files instead of requiring them (fancyweb)
* bug #32464 [WebProfilerBundle] Fix Twig 1.x compatibility (yceruto)
* bug #31620 [FrameworkBundle] Inform the user when save_path will be ignored (gnat42)
* bug #32096 Don't assume port 0 for X-Forwarded-Port (alexbowers, xabbuh)
* bug #31820 [SecurityBundle] Fix profiler dump for non-invokable security listeners (chalasr)
* bug #32392 [Messenger] Doctrine Transport: Support setting auto_setup from DSN (bendavies)
* bug #31267 [Translator] Load plurals from mo files properly (Stadly)
* bug #31266 [Translator] Load plurals from po files properly (Stadly)
* bug #32383 [Serializer] AbstractObjectNormalizer ignores the property types of discriminated classes (sandergo90)
* bug #32413 [Messenger] fix publishing headers set on AmqpStamp (Tobion)
* bug #32421 [EventDispatcher] Add tag kernel.rest on 'debug.event_dispatcher' service (lyrixx)
* bug #32398 [Messenger] Removes deprecated call to ReflectionType::__toString() on MessengerPass (brunowowk)
* bug #32379 [SecurityBundle] conditionally register services (xabbuh)
* bug #32380 [Messenger] fix broken key normalization (Tobion)
* bug #32363 [FrameworkBundle] reset cache pools between requests (nicolas-grekas)
* bug #32365 [DI] fix processing of regular parameter bags by MergeExtensionConfigurationPass (nicolas-grekas)
* bug #32187 [PHPUnit] Fixed composer error on Windows (misterx)
* bug #32299 [Lock] Stores must implement `putOffExpiration` (jderusse)
* bug #32302 [Mime] Remove @internal annotations for the serialize methods (francoispluchino)
* bug #32334 [Messenger] Fix authentication for redis transport (alexander-schranz)
* bug #32309 Fixing validation for messenger transports retry_strategy service key (weaverryan)
* bug #32331 [Workflow] only decorate when an event dispatcher was passed (xabbuh)
* bug #32236 [Cache] work aroung PHP memory leak (nicolas-grekas)
* bug #32206 Catch JsonException and rethrow in JsonEncode (phil-davis)
* bug #32211 [Mailer] Fix error message when connecting to a stream raises an error before connect() (fabpot)
* bug #32210 [Mailer] Fix timeout type hint (fabpot)
* bug #32199 [EventDispatcher] improve error messages in the event dispatcher (xabbuh)
* bug #32200 [Security/Core] work around sodium_compat issue (nicolas-grekas)
* 4.3.2 (2019-06-26) * 4.3.2 (2019-06-26)
* bug #31954 [PhpunitBridge] Read environment variable from superglobals (greg0ire) * bug #31954 [PhpunitBridge] Read environment variable from superglobals (greg0ire)

View File

@ -16,9 +16,9 @@ Symfony is the result of the work of many people who made the code better
- Kévin Dunglas (dunglas) - Kévin Dunglas (dunglas)
- Maxime Steinhausser (ogizanagi) - Maxime Steinhausser (ogizanagi)
- Ryan Weaver (weaverryan) - Ryan Weaver (weaverryan)
- Javier Eguiluz (javier.eguiluz)
- Jakub Zalas (jakubzalas) - Jakub Zalas (jakubzalas)
- Johannes S (johannes) - Johannes S (johannes)
- Javier Eguiluz (javier.eguiluz)
- Roland Franssen (ro0) - Roland Franssen (ro0)
- Kris Wallsmith (kriswallsmith) - Kris Wallsmith (kriswallsmith)
- Grégoire Pineau (lyrixx) - Grégoire Pineau (lyrixx)
@ -28,52 +28,53 @@ Symfony is the result of the work of many people who made the code better
- Romain Neutron (romain) - Romain Neutron (romain)
- Pascal Borreli (pborreli) - Pascal Borreli (pborreli)
- Wouter De Jong (wouterj) - Wouter De Jong (wouterj)
- Yonel Ceruto (yonelceruto)
- Joseph Bielawski (stloyd) - Joseph Bielawski (stloyd)
- Karma Dordrak (drak) - Karma Dordrak (drak)
- Lukas Kahwe Smith (lsmith) - Lukas Kahwe Smith (lsmith)
- Yonel Ceruto (yonelceruto)
- Martin Hasoň (hason) - Martin Hasoň (hason)
- Hamza Amrouche (simperfit)
- Jeremy Mikola (jmikola) - Jeremy Mikola (jmikola)
- Jean-François Simon (jfsimon) - Jean-François Simon (jfsimon)
- Jules Pietri (heah) - Jules Pietri (heah)
- Benjamin Eberlei (beberlei) - Benjamin Eberlei (beberlei)
- Igor Wiedler (igorw) - Igor Wiedler (igorw)
- Eriksen Costa (eriksencosta) - Eriksen Costa (eriksencosta)
- Hamza Amrouche (simperfit)
- Guilhem Niot (energetick) - Guilhem Niot (energetick)
- Alexander M. Turek (derrabus)
- Sarah Khalil (saro0h) - Sarah Khalil (saro0h)
- Jonathan Wage (jwage) - Jonathan Wage (jwage)
- Tobias Nyholm (tobias) - Tobias Nyholm (tobias)
- Lynn van der Berg (kjarli)
- Jérémy DERUSSÉ (jderusse) - Jérémy DERUSSÉ (jderusse)
- Lynn van der Berg (kjarli)
- Diego Saint Esteben (dosten) - Diego Saint Esteben (dosten)
- Alexandre Salomé (alexandresalome) - Alexandre Salomé (alexandresalome)
- William Durand (couac) - William Durand (couac)
- ornicar - ornicar
- Alexander M. Turek (derrabus)
- Dany Maillard (maidmaid) - Dany Maillard (maidmaid)
- Francis Besset (francisbesset) - Francis Besset (francisbesset)
- stealth35 (stealth35) - stealth35 (stealth35)
- Alexander Mols (asm89) - Alexander Mols (asm89)
- Matthias Pigulla (mpdude) - Matthias Pigulla (mpdude)
- Bulat Shakirzyanov (avalanche123) - Bulat Shakirzyanov (avalanche123)
- Konstantin Myakshin (koc)
- Pierre du Plessis (pierredup)
- Grégoire Paris (greg0ire)
- Saša Stamenković (umpirsky) - Saša Stamenković (umpirsky)
- Peter Rehm (rpet) - Peter Rehm (rpet)
- Pierre du Plessis (pierredup)
- Kevin Bond (kbond) - Kevin Bond (kbond)
- Henrik Bjørnskov (henrikbjorn) - Henrik Bjørnskov (henrikbjorn)
- Miha Vrhovnik - Miha Vrhovnik
- Diego Saint Esteben (dii3g0) - Diego Saint Esteben (dii3g0)
- Grégoire Paris (greg0ire)
- Konstantin Kudryashov (everzet)
- Gábor Egyed (1ed) - Gábor Egyed (1ed)
- Thomas Calvet (fancyweb)
- Konstantin Kudryashov (everzet)
- Titouan Galopin (tgalopin) - Titouan Galopin (tgalopin)
- Konstantin Myakshin (koc) - Valentin Udaltsov (vudaltsov)
- Bilal Amarni (bamarni) - Bilal Amarni (bamarni)
- Mathieu Piot (mpiot) - Mathieu Piot (mpiot)
- David Maicher (dmaicher) - David Maicher (dmaicher)
- Florin Patan (florinpatan) - Florin Patan (florinpatan)
- Valentin Udaltsov (vudaltsov)
- Gabriel Ostrolucký (gadelat) - Gabriel Ostrolucký (gadelat)
- Vladimir Reznichenko (kalessil) - Vladimir Reznichenko (kalessil)
- Jáchym Toušek (enumag) - Jáchym Toušek (enumag)
@ -89,13 +90,13 @@ Symfony is the result of the work of many people who made the code better
- Dariusz Górecki (canni) - Dariusz Górecki (canni)
- Douglas Greenshields (shieldo) - Douglas Greenshields (shieldo)
- David Buchmann (dbu) - David Buchmann (dbu)
- Jan Schädlich (jschaedl)
- Dariusz Ruminski - Dariusz Ruminski
- Lee McDermott - Lee McDermott
- Brandon Turner - Brandon Turner
- Luis Cordova (cordoval) - Luis Cordova (cordoval)
- Graham Campbell (graham) - Graham Campbell (graham)
- Daniel Holmes (dholmes) - Daniel Holmes (dholmes)
- Thomas Calvet (fancyweb)
- Toni Uebernickel (havvg) - Toni Uebernickel (havvg)
- Bart van den Burg (burgov) - Bart van den Burg (burgov)
- Jordan Alliot (jalliot) - Jordan Alliot (jalliot)
@ -120,7 +121,7 @@ Symfony is the result of the work of many people who made the code better
- Peter Kokot (maastermedia) - Peter Kokot (maastermedia)
- Jacob Dreesen (jdreesen) - Jacob Dreesen (jdreesen)
- Florian Voutzinos (florianv) - Florian Voutzinos (florianv)
- Jan Schädlich (jschaedl) - Sebastiaan Stok (sstok)
- Colin Frei - Colin Frei
- Javier Spagnoletti (phansys) - Javier Spagnoletti (phansys)
- Adrien Brault (adrienbrault) - Adrien Brault (adrienbrault)
@ -128,30 +129,29 @@ Symfony is the result of the work of many people who made the code better
- Daniel Wehner (dawehner) - Daniel Wehner (dawehner)
- excelwebzone - excelwebzone
- Gordon Franke (gimler) - Gordon Franke (gimler)
- Sebastiaan Stok (sstok)
- Fabien Pennequin (fabienpennequin) - Fabien Pennequin (fabienpennequin)
- Théo FIDRY (theofidry) - Théo FIDRY (theofidry)
- Teoh Han Hui (teohhanhui)
- Oskar Stark (oskarstark)
- Eric GELOEN (gelo) - Eric GELOEN (gelo)
- Joel Wurtz (brouznouf) - Joel Wurtz (brouznouf)
- Lars Strojny (lstrojny) - Lars Strojny (lstrojny)
- Tugdual Saunier (tucksaun) - Tugdual Saunier (tucksaun)
- Alex Pott
- Jannik Zschiesche (apfelbox)
- Robert Schönthal (digitalkaoz) - Robert Schönthal (digitalkaoz)
- Florian Lonqueu-Brochard (florianlb) - Florian Lonqueu-Brochard (florianlb)
- Oskar Stark (oskarstark) - Gabriel Caruso (carusogabriel)
- Stefano Sala (stefano.sala) - Stefano Sala (stefano.sala)
- Evgeniy (ewgraf) - Evgeniy (ewgraf)
- Alex Pott
- Vincent AUBERT (vincent) - Vincent AUBERT (vincent)
- Juti Noppornpitak (shiroyuki) - Juti Noppornpitak (shiroyuki)
- Teoh Han Hui (teohhanhui)
- Anthony MARTIN (xurudragon) - Anthony MARTIN (xurudragon)
- Tigran Azatyan (tigranazatyan) - Tigran Azatyan (tigranazatyan)
- Sebastian Hörl (blogsh) - Sebastian Hörl (blogsh)
- Daniel Gomes (danielcsgomes) - Daniel Gomes (danielcsgomes)
- Gabriel Caruso
- Hidenori Goto (hidenorigoto) - Hidenori Goto (hidenorigoto)
- Arnaud Kleinpeter (nanocom) - Arnaud Kleinpeter (nanocom)
- Jannik Zschiesche (apfelbox)
- Guilherme Blanco (guilhermeblanco) - Guilherme Blanco (guilhermeblanco)
- SpacePossum - SpacePossum
- Pablo Godel (pgodel) - Pablo Godel (pgodel)
@ -164,18 +164,19 @@ Symfony is the result of the work of many people who made the code better
- jwdeitch - jwdeitch
- Mikael Pajunen - Mikael Pajunen
- François-Xavier de Guillebon (de-gui_f) - François-Xavier de Guillebon (de-gui_f)
- Alessandro Chitolina (alekitto)
- Massimiliano Arione (garak)
- Niels Keurentjes (curry684) - Niels Keurentjes (curry684)
- Vyacheslav Pavlov - Vyacheslav Pavlov
- Richard van Laak (rvanlaak) - Richard van Laak (rvanlaak)
- Richard Shank (iampersistent) - Richard Shank (iampersistent)
- Thomas Rabaix (rande) - Thomas Rabaix (rande)
- Rouven Weßling (realityking) - Rouven Weßling (realityking)
- Alexander Schranz (alexander-schranz)
- Clemens Tolboom - Clemens Tolboom
- Helmer Aaviksoo - Helmer Aaviksoo
- Alessandro Chitolina (alekitto)
- Hiromi Hishida (77web) - Hiromi Hishida (77web)
- Matthieu Ouellette-Vachon (maoueh) - Matthieu Ouellette-Vachon (maoueh)
- Massimiliano Arione (garak)
- Michał Pipa (michal.pipa) - Michał Pipa (michal.pipa)
- Dawid Nowak - Dawid Nowak
- George Mponos (gmponos) - George Mponos (gmponos)
@ -186,7 +187,7 @@ Symfony is the result of the work of many people who made the code better
- GDIBass - GDIBass
- Samuel NELA (snela) - Samuel NELA (snela)
- Vincent Touzet (vincenttouzet) - Vincent Touzet (vincenttouzet)
- Alexander Schranz (alexander-schranz) - Jérôme Parmentier (lctrs)
- jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent) - jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent)
- James Halsall (jaitsu) - James Halsall (jaitsu)
- Matthieu Napoli (mnapoli) - Matthieu Napoli (mnapoli)
@ -194,6 +195,7 @@ Symfony is the result of the work of many people who made the code better
- Warnar Boekkooi (boekkooi) - Warnar Boekkooi (boekkooi)
- Dmitrii Chekaliuk (lazyhammer) - Dmitrii Chekaliuk (lazyhammer)
- Clément JOBEILI (dator) - Clément JOBEILI (dator)
- Yanick Witschi (toflar)
- Marek Štípek (maryo) - Marek Štípek (maryo)
- Daniel Espendiller - Daniel Espendiller
- Possum - Possum
@ -213,7 +215,7 @@ Symfony is the result of the work of many people who made the code better
- Andreas Hucks (meandmymonkey) - Andreas Hucks (meandmymonkey)
- Tom Van Looy (tvlooy) - Tom Van Looy (tvlooy)
- Noel Guilbert (noel) - Noel Guilbert (noel)
- Yanick Witschi (toflar) - Stadly
- Stepan Anchugov (kix) - Stepan Anchugov (kix)
- bronze1man - bronze1man
- sun (sun) - sun (sun)
@ -231,6 +233,7 @@ Symfony is the result of the work of many people who made the code better
- Michael Lee (zerustech) - Michael Lee (zerustech)
- Matthieu Auger (matthieuauger) - Matthieu Auger (matthieuauger)
- Leszek Prabucki (l3l0) - Leszek Prabucki (l3l0)
- Ben Davies (bendavies)
- Fabien Bourigault (fbourigault) - Fabien Bourigault (fbourigault)
- François Zaninotto (fzaninotto) - François Zaninotto (fzaninotto)
- Dustin Whittle (dustinwhittle) - Dustin Whittle (dustinwhittle)
@ -299,6 +302,7 @@ Symfony is the result of the work of many people who made the code better
- Jan Sorgalla (jsor) - Jan Sorgalla (jsor)
- Ray - Ray
- Chekote - Chekote
- François Pluchino (francoispluchino)
- Antoine Makdessi (amakdessi) - Antoine Makdessi (amakdessi)
- Thomas Adam - Thomas Adam
- Jhonny Lidfors (jhonne) - Jhonny Lidfors (jhonne)
@ -316,7 +320,6 @@ Symfony is the result of the work of many people who made the code better
- Giorgio Premi - Giorgio Premi
- renanbr - renanbr
- Alex Rock (pierstoval) - Alex Rock (pierstoval)
- Ben Davies (bendavies)
- Beau Simensen (simensen) - Beau Simensen (simensen)
- Michael Hirschler (mvhirsch) - Michael Hirschler (mvhirsch)
- Robert Kiss (kepten) - Robert Kiss (kepten)
@ -325,18 +328,18 @@ Symfony is the result of the work of many people who made the code better
- Kim Hemsø Rasmussen (kimhemsoe) - Kim Hemsø Rasmussen (kimhemsoe)
- Pascal Luna (skalpa) - Pascal Luna (skalpa)
- Wouter Van Hecke - Wouter Van Hecke
- Jérôme Parmentier (lctrs)
- Peter Kruithof (pkruithof) - Peter Kruithof (pkruithof)
- Michael Holm (hollo) - Michael Holm (hollo)
- Andreas Braun
- Mathieu Lechat - Mathieu Lechat
- Marc Weistroff (futurecat) - Marc Weistroff (futurecat)
- Simon Mönch (sm)
- Christian Schmidt - Christian Schmidt
- Patrick Landolt (scube) - Patrick Landolt (scube)
- MatTheCat - MatTheCat
- Chad Sikorra (chadsikorra) - Chad Sikorra (chadsikorra)
- Chris Smith (cs278) - Chris Smith (cs278)
- Florian Klein (docteurklein) - Florian Klein (docteurklein)
- Stadly
- Manuel Kiessling (manuelkiessling) - Manuel Kiessling (manuelkiessling)
- Atsuhiro KUBO (iteman) - Atsuhiro KUBO (iteman)
- Quynh Xuan Nguyen (xuanquynh) - Quynh Xuan Nguyen (xuanquynh)
@ -344,6 +347,7 @@ Symfony is the result of the work of many people who made the code better
- Serkan Yildiz (srknyldz) - Serkan Yildiz (srknyldz)
- Andrew Moore (finewolf) - Andrew Moore (finewolf)
- Bertrand Zuchuat (garfield-fr) - Bertrand Zuchuat (garfield-fr)
- Tomas Norkūnas (norkunas)
- Sullivan SENECHAL (soullivaneuh) - Sullivan SENECHAL (soullivaneuh)
- Gabor Toth (tgabi333) - Gabor Toth (tgabi333)
- realmfoo - realmfoo
@ -354,7 +358,6 @@ Symfony is the result of the work of many people who made the code better
- Wouter J - Wouter J
- Ismael Ambrosi (iambrosi) - Ismael Ambrosi (iambrosi)
- Emmanuel BORGES (eborges78) - Emmanuel BORGES (eborges78)
- François Pluchino (francoispluchino)
- Aurelijus Valeiša (aurelijus) - Aurelijus Valeiša (aurelijus)
- Jan Decavele (jandc) - Jan Decavele (jandc)
- Gustavo Piltcher - Gustavo Piltcher
@ -394,7 +397,6 @@ Symfony is the result of the work of many people who made the code better
- Christian Gärtner (dagardner) - Christian Gärtner (dagardner)
- Tomasz Kowalczyk (thunderer) - Tomasz Kowalczyk (thunderer)
- Artur Eshenbrener - Artur Eshenbrener
- Andreas Braun
- Arjen van der Meijden - Arjen van der Meijden
- Damien Alexandre (damienalexandre) - Damien Alexandre (damienalexandre)
- Thomas Perez (scullwm) - Thomas Perez (scullwm)
@ -407,6 +409,7 @@ Symfony is the result of the work of many people who made the code better
- David Badura (davidbadura) - David Badura (davidbadura)
- hossein zolfi (ocean) - hossein zolfi (ocean)
- Clément Gautier (clementgautier) - Clément Gautier (clementgautier)
- Thomas Bisignani (toma)
- Sanpi - Sanpi
- Eduardo Gulias (egulias) - Eduardo Gulias (egulias)
- giulio de donato (liuggio) - giulio de donato (liuggio)
@ -418,11 +421,13 @@ Symfony is the result of the work of many people who made the code better
- Kirill chEbba Chebunin (chebba) - Kirill chEbba Chebunin (chebba)
- Greg Thornton (xdissent) - Greg Thornton (xdissent)
- Martin Hujer (martinhujer) - Martin Hujer (martinhujer)
- Alex Bowers
- Philipp Cordes - Philipp Cordes
- Costin Bereveanu (schniper) - Costin Bereveanu (schniper)
- Loïc Chardonnet (gnusat) - Loïc Chardonnet (gnusat)
- Marek Kalnik (marekkalnik) - Marek Kalnik (marekkalnik)
- Vyacheslav Salakhutdinov (megazoll) - Vyacheslav Salakhutdinov (megazoll)
- Sébastien Alfaiate (seb33300)
- Hassan Amouhzi - Hassan Amouhzi
- Tamas Szijarto - Tamas Szijarto
- Michele Locati - Michele Locati
@ -445,6 +450,7 @@ Symfony is the result of the work of many people who made the code better
- Krzysztof Piasecki (krzysztek) - Krzysztof Piasecki (krzysztek)
- Maximilian Reichel (phramz) - Maximilian Reichel (phramz)
- Loick Piera (pyrech) - Loick Piera (pyrech)
- Alain Hippolyte (aloneh)
- Karoly Negyesi (chx) - Karoly Negyesi (chx)
- Ivan Kurnosov - Ivan Kurnosov
- Xavier HAUSHERR - Xavier HAUSHERR
@ -453,6 +459,7 @@ Symfony is the result of the work of many people who made the code better
- Miha Vrhovnik - Miha Vrhovnik
- Alessandro Desantis - Alessandro Desantis
- hubert lecorche (hlecorche) - hubert lecorche (hlecorche)
- Arman Hosseini
- Marc Morales Valldepérez (kuert) - Marc Morales Valldepérez (kuert)
- Jean-Baptiste GOMOND (mjbgo) - Jean-Baptiste GOMOND (mjbgo)
- Vadim Kharitonov (virtuozzz) - Vadim Kharitonov (virtuozzz)
@ -483,6 +490,7 @@ Symfony is the result of the work of many people who made the code better
- Alessandro Lai (jean85) - Alessandro Lai (jean85)
- Arturs Vonda - Arturs Vonda
- Josip Kruslin - Josip Kruslin
- Matthew Smeets
- Asmir Mustafic (goetas) - Asmir Mustafic (goetas)
- vagrant - vagrant
- Aurimas Niekis (gcds) - Aurimas Niekis (gcds)
@ -521,6 +529,7 @@ Symfony is the result of the work of many people who made the code better
- Rhodri Pugh (rodnaph) - Rhodri Pugh (rodnaph)
- Sam Fleming (sam_fleming) - Sam Fleming (sam_fleming)
- Alex Bakhturin - Alex Bakhturin
- Patrick Reimers (preimers)
- Pol Dellaiera (drupol) - Pol Dellaiera (drupol)
- insekticid - insekticid
- Alexander Obuhovich (aik099) - Alexander Obuhovich (aik099)
@ -533,6 +542,7 @@ Symfony is the result of the work of many people who made the code better
- Frank Neff (fneff) - Frank Neff (fneff)
- Roman Lapin (memphys) - Roman Lapin (memphys)
- Yoshio HANAWA - Yoshio HANAWA
- Jan van Thoor (janvt)
- Gladhon - Gladhon
- Haralan Dobrev (hkdobrev) - Haralan Dobrev (hkdobrev)
- Sebastian Bergmann - Sebastian Bergmann
@ -542,8 +552,9 @@ Symfony is the result of the work of many people who made the code better
- Sergio Santoro - Sergio Santoro
- Robin van der Vleuten (robinvdvleuten) - Robin van der Vleuten (robinvdvleuten)
- Philipp Rieber (bicpi) - Philipp Rieber (bicpi)
- Tomas Norkūnas (norkunas)
- Manuel de Ruiter (manuel) - Manuel de Ruiter (manuel)
- Nathanael Noblet (gnat)
- nikos.sotiropoulos
- Eduardo Oliveira (entering) - Eduardo Oliveira (entering)
- Ilya Antipenko (aivus) - Ilya Antipenko (aivus)
- Ricardo Oliveira (ricardolotr) - Ricardo Oliveira (ricardolotr)
@ -551,7 +562,6 @@ Symfony is the result of the work of many people who made the code better
- ondrowan - ondrowan
- Barry vd. Heuvel (barryvdh) - Barry vd. Heuvel (barryvdh)
- Craig Duncan (duncan3dc) - Craig Duncan (duncan3dc)
- Sébastien Alfaiate (seb33300)
- Evan S Kaufman (evanskaufman) - Evan S Kaufman (evanskaufman)
- mcben - mcben
- Jérôme Vieilledent (lolautruche) - Jérôme Vieilledent (lolautruche)
@ -607,7 +617,6 @@ Symfony is the result of the work of many people who made the code better
- NothingWeAre - NothingWeAre
- Ryan - Ryan
- Alexander Deruwe (aderuwe) - Alexander Deruwe (aderuwe)
- Alain Hippolyte (aloneh)
- Dave Hulbert (dave1010) - Dave Hulbert (dave1010)
- Ivan Rey (ivanrey) - Ivan Rey (ivanrey)
- Marcin Chyłek (songoq) - Marcin Chyłek (songoq)
@ -629,6 +638,7 @@ Symfony is the result of the work of many people who made the code better
- Geoffrey Tran (geoff) - Geoffrey Tran (geoff)
- Jan Behrens - Jan Behrens
- Mantas Var (mvar) - Mantas Var (mvar)
- Chris Tanaskoski
- Sebastian Krebs - Sebastian Krebs
- Piotr Stankowski - Piotr Stankowski
- Baptiste Leduc (bleduc) - Baptiste Leduc (bleduc)
@ -640,6 +650,7 @@ Symfony is the result of the work of many people who made the code better
- vitaliytv - vitaliytv
- Dalibor Karlović (dkarlovi) - Dalibor Karlović (dkarlovi)
- Sebastian Blum - Sebastian Blum
- Alexis Lefebvre
- aubx - aubx
- Marvin Butkereit - Marvin Butkereit
- Renan - Renan
@ -751,7 +762,6 @@ Symfony is the result of the work of many people who made the code better
- Tiago Brito (blackmx) - Tiago Brito (blackmx)
- -
- Richard van den Brand (ricbra) - Richard van den Brand (ricbra)
- Thomas Bisignani (toma)
- develop - develop
- flip111 - flip111
- Greg Anderson - Greg Anderson
@ -781,7 +791,6 @@ Symfony is the result of the work of many people who made the code better
- Dominik Ritter (dritter) - Dominik Ritter (dritter)
- Sebastian Grodzicki (sgrodzicki) - Sebastian Grodzicki (sgrodzicki)
- Jeroen van den Enden (stoefke) - Jeroen van den Enden (stoefke)
- nikos.sotiropoulos
- Pascal Helfenstein - Pascal Helfenstein
- Anthony GRASSIOT (antograssiot) - Anthony GRASSIOT (antograssiot)
- Baldur Rensch (brensch) - Baldur Rensch (brensch)
@ -795,6 +804,7 @@ Symfony is the result of the work of many people who made the code better
- Tarjei Huse (tarjei) - Tarjei Huse (tarjei)
- Besnik Br - Besnik Br
- Jose Gonzalez - Jose Gonzalez
- Jonathan (jls-esokia)
- Oleksii Zhurbytskyi - Oleksii Zhurbytskyi
- Dariusz Ruminski - Dariusz Ruminski
- Joshua Nye - Joshua Nye
@ -822,6 +832,7 @@ Symfony is the result of the work of many people who made the code better
- Marc Morera (mmoreram) - Marc Morera (mmoreram)
- Saif Eddin Gmati (azjezz) - Saif Eddin Gmati (azjezz)
- BENOIT POLASZEK (bpolaszek) - BENOIT POLASZEK (bpolaszek)
- Mathieu Rochette (mathroc)
- Andrew Hilobok (hilobok) - Andrew Hilobok (hilobok)
- Noah Heck (myesain) - Noah Heck (myesain)
- Christian Soronellas (theunic) - Christian Soronellas (theunic)
@ -887,7 +898,6 @@ Symfony is the result of the work of many people who made the code better
- Sergey Zolotov (enleur) - Sergey Zolotov (enleur)
- Maksim Kotlyar (makasim) - Maksim Kotlyar (makasim)
- Neil Ferreira - Neil Ferreira
- Nathanael Noblet (gnat)
- Indra Gunawan (indragunawan) - Indra Gunawan (indragunawan)
- Julie Hourcade (juliehde) - Julie Hourcade (juliehde)
- Dmitry Parnas (parnas) - Dmitry Parnas (parnas)
@ -914,6 +924,7 @@ Symfony is the result of the work of many people who made the code better
- Stefan Kruppa - Stefan Kruppa
- mmokhi - mmokhi
- corphi - corphi
- JoppeDC
- grizlik - grizlik
- Derek ROTH - Derek ROTH
- Ben Johnson - Ben Johnson
@ -921,6 +932,7 @@ Symfony is the result of the work of many people who made the code better
- Dmytro Boiko (eagle) - Dmytro Boiko (eagle)
- Shin Ohno (ganchiku) - Shin Ohno (ganchiku)
- Geert De Deckere (geertdd) - Geert De Deckere (geertdd)
- Ion Bazan (ionbazan)
- Jacek Jędrzejewski (jacek.jedrzejewski) - Jacek Jędrzejewski (jacek.jedrzejewski)
- Jan Kramer (jankramer) - Jan Kramer (jankramer)
- abdul malik ikhsan (samsonasik) - abdul malik ikhsan (samsonasik)
@ -977,12 +989,12 @@ Symfony is the result of the work of many people who made the code better
- Benoît Merlet (trompette) - Benoît Merlet (trompette)
- Koen Kuipers - Koen Kuipers
- datibbaw - datibbaw
- Pablo Lozano (arkadis)
- Erik Saunier (snickers) - Erik Saunier (snickers)
- Rootie - Rootie
- Kyle - Kyle
- Daniel Alejandro Castro Arellano (lexcast) - Daniel Alejandro Castro Arellano (lexcast)
- sensio - sensio
- Chris Tanaskoski
- Thomas Jarrand - Thomas Jarrand
- Antoine Bluchet (soyuka) - Antoine Bluchet (soyuka)
- Sebastien Morel (plopix) - Sebastien Morel (plopix)
@ -1006,7 +1018,6 @@ Symfony is the result of the work of many people who made the code better
- Mikkel Paulson - Mikkel Paulson
- ergiegonzaga - ergiegonzaga
- Farhad Safarov - Farhad Safarov
- Alexis Lefebvre
- Liverbool (liverbool) - Liverbool (liverbool)
- Sam Malone - Sam Malone
- Phan Thanh Ha (haphan) - Phan Thanh Ha (haphan)
@ -1058,6 +1069,7 @@ Symfony is the result of the work of many people who made the code better
- dantleech - dantleech
- Bastien DURAND (deamon) - Bastien DURAND (deamon)
- Xavier Leune - Xavier Leune
- Sander Goossens (sandergo90)
- Rudy Onfroy - Rudy Onfroy
- Tero Alén (tero) - Tero Alén (tero)
- Stanislav Kocanda - Stanislav Kocanda
@ -1068,6 +1080,7 @@ Symfony is the result of the work of many people who made the code better
- Silvio Ginter - Silvio Ginter
- MGDSoft - MGDSoft
- Vadim Tyukov (vatson) - Vadim Tyukov (vatson)
- Arman
- David Wolter (davewww) - David Wolter (davewww)
- Sortex - Sortex
- chispita - chispita
@ -1099,6 +1112,7 @@ Symfony is the result of the work of many people who made the code better
- Mert Simsek (mrtsmsk0) - Mert Simsek (mrtsmsk0)
- Lin Clark - Lin Clark
- Jeremy David (jeremy.david) - Jeremy David (jeremy.david)
- Timo Bakx (timobakx)
- Jordi Rejas - Jordi Rejas
- Troy McCabe - Troy McCabe
- Ville Mattila - Ville Mattila
@ -1113,7 +1127,6 @@ Symfony is the result of the work of many people who made the code better
- nacho - nacho
- Piotr Antosik (antek88) - Piotr Antosik (antek88)
- Artem Lopata - Artem Lopata
- Patrick Reimers (preimers)
- Sergey Novikov (s12v) - Sergey Novikov (s12v)
- Marcos Quesada (marcos_quesada) - Marcos Quesada (marcos_quesada)
- Matthew Vickery (mattvick) - Matthew Vickery (mattvick)
@ -1139,6 +1152,7 @@ Symfony is the result of the work of many people who made the code better
- Michał Strzelecki - Michał Strzelecki
- Soner Sayakci - Soner Sayakci
- hugofonseca (fonsecas72) - hugofonseca (fonsecas72)
- Marc Duboc (icemad)
- Martynas Narbutas - Martynas Narbutas
- Toon Verwerft (veewee) - Toon Verwerft (veewee)
- Bailey Parker - Bailey Parker
@ -1182,7 +1196,6 @@ Symfony is the result of the work of many people who made the code better
- Jochen Bayer (jocl) - Jochen Bayer (jocl)
- Patrick Carlo-Hickman - Patrick Carlo-Hickman
- Bruno MATEU - Bruno MATEU
- Alex Bowers
- Jeremy Bush - Jeremy Bush
- wizhippo - wizhippo
- Mathias STRASSER (roukmoute) - Mathias STRASSER (roukmoute)
@ -1237,7 +1250,9 @@ Symfony is the result of the work of many people who made the code better
- Max Voloshin (maxvoloshin) - Max Voloshin (maxvoloshin)
- Nicolas Fabre (nfabre) - Nicolas Fabre (nfabre)
- Raul Rodriguez (raul782) - Raul Rodriguez (raul782)
- Piet Steinhart
- mshavliuk - mshavliuk
- Rémy LESCALLIER
- WybrenKoelmans - WybrenKoelmans
- Derek Lambert - Derek Lambert
- MightyBranch - MightyBranch
@ -1263,10 +1278,10 @@ Symfony is the result of the work of many people who made the code better
- Marco - Marco
- Marc Torres - Marc Torres
- Alberto Aldegheri - Alberto Aldegheri
- Philippe Segatori
- Dmitri Petmanson - Dmitri Petmanson
- heccjj - heccjj
- Alexandre Melard - Alexandre Melard
- Jonathan (jls-esokia)
- Jay Klehr - Jay Klehr
- Sergey Yuferev - Sergey Yuferev
- Tobias Stöckler - Tobias Stöckler
@ -1385,6 +1400,7 @@ Symfony is the result of the work of many people who made the code better
- Tom Corrigan (tomcorrigan) - Tom Corrigan (tomcorrigan)
- Luis Galeas - Luis Galeas
- Martin Pärtel - Martin Pärtel
- Bastien Jaillot (bastnic)
- Frédéric Bouchery (fbouchery) - Frédéric Bouchery (fbouchery)
- Patrick Daley (padrig) - Patrick Daley (padrig)
- Xavier Briand (xavierbriand) - Xavier Briand (xavierbriand)
@ -1408,7 +1424,6 @@ Symfony is the result of the work of many people who made the code better
- Dāvis Zālītis (k0d3r1s) - Dāvis Zālītis (k0d3r1s)
- Carsten Nielsen (phreaknerd) - Carsten Nielsen (phreaknerd)
- Roger Guasch (rogerguasch) - Roger Guasch (rogerguasch)
- Mathieu Rochette
- Jay Severson - Jay Severson
- René Kerner - René Kerner
- Nathaniel Catchpole - Nathaniel Catchpole
@ -1456,6 +1471,7 @@ Symfony is the result of the work of many people who made the code better
- Ergie Gonzaga - Ergie Gonzaga
- Matthew J Mucklo - Matthew J Mucklo
- AnrDaemon - AnrDaemon
- Emre Akinci (emre)
- fdgdfg (psampaz) - fdgdfg (psampaz)
- Stéphane Seng - Stéphane Seng
- Maxwell Vandervelde - Maxwell Vandervelde
@ -1567,6 +1583,7 @@ Symfony is the result of the work of many people who made the code better
- Arnau González (arnaugm) - Arnau González (arnaugm)
- Simon Bouland (bouland) - Simon Bouland (bouland)
- Jibé Barth (jibbarth) - Jibé Barth (jibbarth)
- Julien Montel (julienmgel)
- Matthew Foster (mfoster) - Matthew Foster (mfoster)
- Reyo Stallenberg (reyostallenberg) - Reyo Stallenberg (reyostallenberg)
- Paul Seiffert (seiffert) - Paul Seiffert (seiffert)
@ -1587,6 +1604,7 @@ Symfony is the result of the work of many people who made the code better
- Ulugbek Miniyarov - Ulugbek Miniyarov
- Jeremy Benoist - Jeremy Benoist
- Michal Gebauer - Michal Gebauer
- Phil Davis
- Gleb Sidora - Gleb Sidora
- David Stone - David Stone
- Jovan Perovic (jperovic) - Jovan Perovic (jperovic)
@ -1601,6 +1619,7 @@ Symfony is the result of the work of many people who made the code better
- Andreas - Andreas
- Markus - Markus
- Daniel Gorgan - Daniel Gorgan
- kernig
- Thomas Chmielowiec - Thomas Chmielowiec
- shdev - shdev
- Andrey Ryaguzov - Andrey Ryaguzov
@ -1611,6 +1630,7 @@ Symfony is the result of the work of many people who made the code better
- Mickael GOETZ - Mickael GOETZ
- Maciej Schmidt - Maciej Schmidt
- Dennis Væversted - Dennis Væversted
- Timon van der Vorm
- nuncanada - nuncanada
- flack - flack
- František Bereň - František Bereň
@ -1634,6 +1654,7 @@ Symfony is the result of the work of many people who made the code better
- me_shaon - me_shaon
- 蝦米 - 蝦米
- Grayson Koonce (breerly) - Grayson Koonce (breerly)
- Mardari Dorel (dorumd)
- Andrey Helldar (helldar) - Andrey Helldar (helldar)
- Karim Cassam Chenaï (ka) - Karim Cassam Chenaï (ka)
- Maksym Slesarenko (maksym_slesarenko) - Maksym Slesarenko (maksym_slesarenko)
@ -1683,7 +1704,6 @@ Symfony is the result of the work of many people who made the code better
- Brian Graham (incognito) - Brian Graham (incognito)
- Kevin Vergauwen (innocenzo) - Kevin Vergauwen (innocenzo)
- Alessio Baglio (ioalessio) - Alessio Baglio (ioalessio)
- Jan van Thoor (janvt)
- Johannes Müller (johmue) - Johannes Müller (johmue)
- Jordi Llonch (jordillonch) - Jordi Llonch (jordillonch)
- Nicholas Ruunu (nicholasruunu) - Nicholas Ruunu (nicholasruunu)
@ -1754,6 +1774,7 @@ Symfony is the result of the work of many people who made the code better
- thib92 - thib92
- Rudolf Ratusiński - Rudolf Ratusiński
- Bertalan Attila - Bertalan Attila
- Amin Hosseini (aminh)
- AmsTaFF (amstaff) - AmsTaFF (amstaff)
- Simon Müller (boscho) - Simon Müller (boscho)
- Yannick Bensacq (cibou) - Yannick Bensacq (cibou)
@ -1830,7 +1851,6 @@ Symfony is the result of the work of many people who made the code better
- Marco Lipparini - Marco Lipparini
- Haritz - Haritz
- Matthieu Prat - Matthieu Prat
- Ion Bazan
- Grummfy - Grummfy
- Paul Le Corre - Paul Le Corre
- Filipe Guerra - Filipe Guerra
@ -1855,7 +1875,6 @@ Symfony is the result of the work of many people who made the code better
- Alexis MARQUIS - Alexis MARQUIS
- Gerrit Drost - Gerrit Drost
- Linnaea Von Lavia - Linnaea Von Lavia
- Simon Mönch
- Javan Eskander - Javan Eskander
- Lenar Lõhmus - Lenar Lõhmus
- Cristian Gonzalez - Cristian Gonzalez
@ -1873,6 +1892,7 @@ Symfony is the result of the work of many people who made the code better
- Klaas Naaijkens - Klaas Naaijkens
- Daniel González Cerviño - Daniel González Cerviño
- Rafał - Rafał
- Lctrs
- Achilles Kaloeridis (achilles) - Achilles Kaloeridis (achilles)
- Adria Lopez (adlpz) - Adria Lopez (adlpz)
- Aaron Scherer (aequasi) - Aaron Scherer (aequasi)
@ -1964,11 +1984,13 @@ Symfony is the result of the work of many people who made the code better
- goohib - goohib
- Chi-teck - Chi-teck
- Tom Counsell - Tom Counsell
- George Bateman
- Xavier HAUSHERR - Xavier HAUSHERR
- Ron Gähler - Ron Gähler
- Edwin Hageman - Edwin Hageman
- Mantas Urnieža - Mantas Urnieža
- temperatur - temperatur
- misterx
- Cas - Cas
- Dusan Kasan - Dusan Kasan
- Karolis - Karolis
@ -2015,6 +2037,7 @@ Symfony is the result of the work of many people who made the code better
- Alexandru Bucur - Alexandru Bucur
- cmfcmf - cmfcmf
- Drew Butler - Drew Butler
- Alexey Berezuev
- Steve Müller - Steve Müller
- Andras Ratz - Andras Ratz
- andreabreu98 - andreabreu98
@ -2059,6 +2082,7 @@ Symfony is the result of the work of many people who made the code better
- Sébastien HOUZE - Sébastien HOUZE
- Abdulkadir N. A. - Abdulkadir N. A.
- Adam Klvač - Adam Klvač
- Bruno Nogueira Nascimento Wowk
- Yevgen Kovalienia - Yevgen Kovalienia
- Lebnik - Lebnik
- nsbx - nsbx
@ -2068,6 +2092,7 @@ Symfony is the result of the work of many people who made the code better
- Elan Ruusamäe - Elan Ruusamäe
- Jon Dufresne - Jon Dufresne
- Thorsten Hallwas - Thorsten Hallwas
- Alex Nostadt
- Michael Squires - Michael Squires
- Egor Gorbachev - Egor Gorbachev
- Derek Stephen McLean - Derek Stephen McLean
@ -2187,6 +2212,7 @@ Symfony is the result of the work of many people who made the code better
- ollie harridge (ollietb) - ollie harridge (ollietb)
- Dimitri Gritsajuk (ottaviano) - Dimitri Gritsajuk (ottaviano)
- Paul Andrieux (paulandrieux) - Paul Andrieux (paulandrieux)
- Paulo Ribeiro (paulo)
- Paweł Szczepanek (pauluz) - Paweł Szczepanek (pauluz)
- Philippe Degeeter (pdegeeter) - Philippe Degeeter (pdegeeter)
- Christian López Espínola (penyaskito) - Christian López Espínola (penyaskito)
@ -2215,6 +2241,7 @@ Symfony is the result of the work of many people who made the code better
- Tom Newby (tomnewbyau) - Tom Newby (tomnewbyau)
- Andrew Clark (tqt_andrew_clark) - Andrew Clark (tqt_andrew_clark)
- David Lumaye (tux1124) - David Lumaye (tux1124)
- Roman Tymoshyk (tymoshyk)
- Tyler Stroud (tystr) - Tyler Stroud (tystr)
- Moritz Kraft (userfriendly) - Moritz Kraft (userfriendly)
- Víctor Mateo (victormateo) - Víctor Mateo (victormateo)
@ -2232,6 +2259,7 @@ Symfony is the result of the work of many people who made the code better
- simpson - simpson
- drublic - drublic
- Andreas Streichardt - Andreas Streichardt
- Alexandre Segura
- Pascal Hofmann - Pascal Hofmann
- smokeybear87 - smokeybear87
- Gustavo Adrian - Gustavo Adrian
@ -2255,7 +2283,6 @@ Symfony is the result of the work of many people who made the code better
- Mohamed Karnichi (amiral) - Mohamed Karnichi (amiral)
- Andrew Carter (andrewcarteruk) - Andrew Carter (andrewcarteruk)
- Adam Elsodaney (archfizz) - Adam Elsodaney (archfizz)
- Pablo Lozano (arkadis)
- Gregório Bonfante Borba (bonfante) - Gregório Bonfante Borba (bonfante)
- Bogdan Rancichi (devck) - Bogdan Rancichi (devck)
- Daniel Kolvik (dkvk) - Daniel Kolvik (dkvk)

View File

@ -77,7 +77,7 @@ Form
FrameworkBundle FrameworkBundle
--------------- ---------------
* Deprecated the `framework.templating` option, use Twig instead. * Deprecated the `framework.templating` option, configure the Twig bundle instead.
* Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will
be mandatory in 5.0. be mandatory in 5.0.
* Deprecated the "Psr\SimpleCache\CacheInterface" / "cache.app.simple" service, use "Symfony\Contracts\Cache\CacheInterface" / "cache.app" instead. * Deprecated the "Psr\SimpleCache\CacheInterface" / "cache.app.simple" service, use "Symfony\Contracts\Cache\CacheInterface" / "cache.app" instead.

View File

@ -217,7 +217,7 @@ FrameworkBundle
* Dropped support for booting the kernel before running `WebTestCase::createClient()`. `createClient()` will throw an * Dropped support for booting the kernel before running `WebTestCase::createClient()`. `createClient()` will throw an
exception if the kernel was already booted before. exception if the kernel was already booted before.
* Removed the `framework.templating` option, use Twig instead. * Removed the `framework.templating` option, configure the Twig bundle instead.
* The project dir argument of the constructor of `AssetsInstallCommand` is required. * The project dir argument of the constructor of `AssetsInstallCommand` is required.
* Removed support for `bundle:controller:action` syntax to reference controllers. Use `serviceOrFqcn::method` * Removed support for `bundle:controller:action` syntax to reference controllers. Use `serviceOrFqcn::method`
instead where `serviceOrFqcn` is either the service ID when using controllers as services or the FQCN of the controller. instead where `serviceOrFqcn` is either the service ID when using controllers as services or the FQCN of the controller.

View File

@ -15,7 +15,7 @@ CHANGELOG
4.3.0 4.3.0
----- -----
* Deprecated the `framework.templating` option, use Twig instead. * Deprecated the `framework.templating` option, configure the Twig bundle instead.
* Added `WebTestAssertionsTrait` (included by default in `WebTestCase`) * Added `WebTestAssertionsTrait` (included by default in `WebTestCase`)
* Renamed `Client` to `KernelBrowser` * Renamed `Client` to `KernelBrowser`
* Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will

View File

@ -605,7 +605,7 @@ class Configuration implements ConfigurationInterface
->arrayNode('templating') ->arrayNode('templating')
->info('templating configuration') ->info('templating configuration')
->canBeEnabled() ->canBeEnabled()
->setDeprecated('The "%path%.%node%" configuration is deprecated since Symfony 4.3. Use the "twig" service directly instead.') ->setDeprecated('The "%path%.%node%" configuration is deprecated since Symfony 4.3. Configure the "twig" section provided by the Twig Bundle instead.')
->beforeNormalization() ->beforeNormalization()
->ifTrue(function ($v) { return false === $v || \is_array($v) && false === $v['enabled']; }) ->ifTrue(function ($v) { return false === $v || \is_array($v) && false === $v['enabled']; })
->then(function () { return ['enabled' => false, 'engines' => false]; }) ->then(function () { return ['enabled' => false, 'engines' => false]; })

View File

@ -15,10 +15,9 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\Stopwatch\StopwatchEvent;
/** /**
* TimeDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*/ */
class TimeDataCollector extends DataCollector implements LateDataCollectorInterface class TimeDataCollector extends DataCollector implements LateDataCollectorInterface
@ -77,7 +76,7 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
/** /**
* Sets the request events. * Sets the request events.
* *
* @param array $events The request events * @param StopwatchEvent[] $events The request events
*/ */
public function setEvents(array $events) public function setEvents(array $events)
{ {
@ -91,7 +90,7 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
/** /**
* Gets the request events. * Gets the request events.
* *
* @return array The request events * @return StopwatchEvent[] The request events
*/ */
public function getEvents() public function getEvents()
{ {

View File

@ -41,6 +41,9 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
break; break;
case KernelEvents::TERMINATE: case KernelEvents::TERMINATE:
$token = $event->getResponse()->headers->get('X-Debug-Token'); $token = $event->getResponse()->headers->get('X-Debug-Token');
if (null === $token) {
break;
}
// There is a very special case when using built-in AppCache class as kernel wrapper, in the case // There is a very special case when using built-in AppCache class as kernel wrapper, in the case
// of an ESI request leading to a `stale` response [B] inside a `fresh` cached response [A]. // of an ESI request leading to a `stale` response [B] inside a `fresh` cached response [A].
// In this case, `$token` contains the [B] debug token, but the open `stopwatch` section ID // In this case, `$token` contains the [B] debug token, but the open `stopwatch` section ID
@ -65,12 +68,18 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
break; break;
case KernelEvents::RESPONSE: case KernelEvents::RESPONSE:
$token = $event->getResponse()->headers->get('X-Debug-Token'); $token = $event->getResponse()->headers->get('X-Debug-Token');
if (null === $token) {
break;
}
$this->stopwatch->stopSection($token); $this->stopwatch->stopSection($token);
break; break;
case KernelEvents::TERMINATE: case KernelEvents::TERMINATE:
// In the special case described in the `preDispatch` method above, the `$token` section // In the special case described in the `preDispatch` method above, the `$token` section
// does not exist, then closing it throws an exception which must be caught. // does not exist, then closing it throws an exception which must be caught.
$token = $event->getResponse()->headers->get('X-Debug-Token'); $token = $event->getResponse()->headers->get('X-Debug-Token');
if (null === $token) {
break;
}
try { try {
$this->stopwatch->stopSection($token); $this->stopwatch->stopSection($token);
} catch (\LogicException $e) { } catch (\LogicException $e) {

View File

@ -62,15 +62,13 @@ class TraceableEventDispatcherTest extends TestCase
public function testStopwatchStopControllerOnRequestEvent() public function testStopwatchStopControllerOnRequestEvent()
{ {
$stopwatch = $this->getMockBuilder('Symfony\Component\Stopwatch\Stopwatch') $stopwatch = $this->getMockBuilder('Symfony\Component\Stopwatch\Stopwatch')
->setMethods(['isStarted', 'stop', 'stopSection']) ->setMethods(['isStarted', 'stop'])
->getMock(); ->getMock();
$stopwatch->expects($this->once()) $stopwatch->expects($this->once())
->method('isStarted') ->method('isStarted')
->willReturn(true); ->willReturn(true);
$stopwatch->expects($this->once()) $stopwatch->expects($this->once())
->method('stop'); ->method('stop');
$stopwatch->expects($this->once())
->method('stopSection');
$dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch); $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch);

View File

@ -308,7 +308,7 @@ class ConnectionTest extends TestCase
); );
// makes sure the channel looks connected, so it's not re-created // makes sure the channel looks connected, so it's not re-created
$amqpChannel->expects($this->exactly(2))->method('isConnected')->willReturn(true); $amqpChannel->expects($this->any())->method('isConnected')->willReturn(true);
$amqpChannel->expects($this->exactly(2))->method('setPrefetchCount')->with(2); $amqpChannel->expects($this->exactly(2))->method('setPrefetchCount')->with(2);
$connection = Connection::fromDsn('amqp://localhost?prefetch_count=2', [], $factory); $connection = Connection::fromDsn('amqp://localhost?prefetch_count=2', [], $factory);
@ -317,30 +317,57 @@ class ConnectionTest extends TestCase
$connection->setup(); $connection->setup();
} }
public function testItDelaysTheMessage() public function testAutoSetupWithDelayDeclaresExchangeQueuesAndDelay()
{ {
$amqpConnection = $this->createMock(\AMQPConnection::class); $amqpConnection = $this->createMock(\AMQPConnection::class);
$amqpChannel = $this->createMock(\AMQPChannel::class); $amqpChannel = $this->createMock(\AMQPChannel::class);
$delayQueue = $this->createMock(\AMQPQueue::class);
$factory = $this->createMock(AmqpFactory::class); $factory = $this->createMock(AmqpFactory::class);
$factory->method('createConnection')->willReturn($amqpConnection); $factory->method('createConnection')->willReturn($amqpConnection);
$factory->method('createChannel')->willReturn($amqpChannel); $factory->method('createChannel')->willReturn($amqpChannel);
$factory->method('createQueue')->willReturn($delayQueue); $factory->method('createQueue')->will($this->onConsecutiveCalls(
$amqpQueue = $this->createMock(\AMQPQueue::class),
$delayQueue = $this->createMock(\AMQPQueue::class)
));
$factory->method('createExchange')->will($this->onConsecutiveCalls( $factory->method('createExchange')->will($this->onConsecutiveCalls(
$amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock(), $amqpExchange = $this->createMock(\AMQPExchange::class),
$delayExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() $delayExchange = $this->createMock(\AMQPExchange::class)
)); ));
$amqpExchange->expects($this->once())->method('setName')->with(self::DEFAULT_EXCHANGE_NAME); $amqpExchange->expects($this->once())->method('setName')->with(self::DEFAULT_EXCHANGE_NAME);
$amqpExchange->expects($this->once())->method('declareExchange'); $amqpExchange->expects($this->once())->method('declareExchange');
$amqpQueue->expects($this->once())->method('setName')->with(self::DEFAULT_EXCHANGE_NAME);
$amqpQueue->expects($this->once())->method('declareQueue');
$delayExchange->expects($this->once())->method('setName')->with('delay'); $delayExchange->expects($this->once())->method('setName')->with('delay');
$delayExchange->expects($this->once())->method('declareExchange'); $delayExchange->expects($this->once())->method('declareExchange');
$delayExchange->expects($this->once())->method('publish');
$delayQueue->expects($this->once())->method('setName')->with('delay_queue_messages__5000'); $connection = Connection::fromDsn('amqp://localhost', [], $factory);
$connection->publish('{}', ['x-some-headers' => 'foo'], 5000);
}
public function testItDelaysTheMessage()
{
$amqpConnection = $this->createMock(\AMQPConnection::class);
$amqpChannel = $this->createMock(\AMQPChannel::class);
$factory = $this->createMock(AmqpFactory::class);
$factory->method('createConnection')->willReturn($amqpConnection);
$factory->method('createChannel')->willReturn($amqpChannel);
$factory->method('createQueue')->will($this->onConsecutiveCalls(
$this->createMock(\AMQPQueue::class),
$delayQueue = $this->createMock(\AMQPQueue::class)
));
$factory->method('createExchange')->will($this->onConsecutiveCalls(
$this->createMock(\AMQPExchange::class),
$delayExchange = $this->createMock(\AMQPExchange::class)
));
$delayQueue->expects($this->once())->method('setName')->with('delay_messages__5000');
$delayQueue->expects($this->once())->method('setArguments')->with([ $delayQueue->expects($this->once())->method('setArguments')->with([
'x-message-ttl' => 5000, 'x-message-ttl' => 5000,
'x-expires' => 5000 + 10000,
'x-dead-letter-exchange' => self::DEFAULT_EXCHANGE_NAME, 'x-dead-letter-exchange' => self::DEFAULT_EXCHANGE_NAME,
'x-dead-letter-routing-key' => '', 'x-dead-letter-routing-key' => '',
]); ]);
@ -358,22 +385,18 @@ class ConnectionTest extends TestCase
{ {
$amqpConnection = $this->createMock(\AMQPConnection::class); $amqpConnection = $this->createMock(\AMQPConnection::class);
$amqpChannel = $this->createMock(\AMQPChannel::class); $amqpChannel = $this->createMock(\AMQPChannel::class);
$delayQueue = $this->createMock(\AMQPQueue::class);
$factory = $this->createMock(AmqpFactory::class); $factory = $this->createMock(AmqpFactory::class);
$factory->method('createConnection')->willReturn($amqpConnection); $factory->method('createConnection')->willReturn($amqpConnection);
$factory->method('createChannel')->willReturn($amqpChannel); $factory->method('createChannel')->willReturn($amqpChannel);
$factory->method('createQueue')->willReturn($delayQueue); $factory->method('createQueue')->will($this->onConsecutiveCalls(
$factory->method('createExchange')->will($this->onConsecutiveCalls( $this->createMock(\AMQPQueue::class),
$amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock(), $delayQueue = $this->createMock(\AMQPQueue::class)
$delayExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() ));
$factory->method('createExchange')->will($this->onConsecutiveCalls(
$this->createMock(\AMQPExchange::class),
$delayExchange = $this->createMock(\AMQPExchange::class)
)); ));
$amqpExchange->expects($this->once())->method('setName')->with(self::DEFAULT_EXCHANGE_NAME);
$amqpExchange->expects($this->once())->method('declareExchange');
$delayExchange->expects($this->once())->method('setName')->with('delay');
$delayExchange->expects($this->once())->method('declareExchange');
$connectionOptions = [ $connectionOptions = [
'retry' => [ 'retry' => [
@ -383,9 +406,10 @@ class ConnectionTest extends TestCase
$connection = Connection::fromDsn('amqp://localhost', $connectionOptions, $factory); $connection = Connection::fromDsn('amqp://localhost', $connectionOptions, $factory);
$delayQueue->expects($this->once())->method('setName')->with('delay_queue_messages__120000'); $delayQueue->expects($this->once())->method('setName')->with('delay_messages__120000');
$delayQueue->expects($this->once())->method('setArguments')->with([ $delayQueue->expects($this->once())->method('setArguments')->with([
'x-message-ttl' => 120000, 'x-message-ttl' => 120000,
'x-expires' => 120000 + 10000,
'x-dead-letter-exchange' => self::DEFAULT_EXCHANGE_NAME, 'x-dead-letter-exchange' => self::DEFAULT_EXCHANGE_NAME,
'x-dead-letter-routing-key' => '', 'x-dead-letter-routing-key' => '',
]); ]);
@ -467,23 +491,19 @@ class ConnectionTest extends TestCase
{ {
$amqpConnection = $this->createMock(\AMQPConnection::class); $amqpConnection = $this->createMock(\AMQPConnection::class);
$amqpChannel = $this->createMock(\AMQPChannel::class); $amqpChannel = $this->createMock(\AMQPChannel::class);
$delayQueue = $this->createMock(\AMQPQueue::class);
$factory = $this->createMock(AmqpFactory::class); $factory = $this->createMock(AmqpFactory::class);
$factory->method('createConnection')->willReturn($amqpConnection); $factory->method('createConnection')->willReturn($amqpConnection);
$factory->method('createChannel')->willReturn($amqpChannel); $factory->method('createChannel')->willReturn($amqpChannel);
$factory->method('createQueue')->willReturn($delayQueue); $factory->method('createQueue')->will($this->onConsecutiveCalls(
$this->createMock(\AMQPQueue::class),
$delayQueue = $this->createMock(\AMQPQueue::class)
));
$factory->method('createExchange')->will($this->onConsecutiveCalls( $factory->method('createExchange')->will($this->onConsecutiveCalls(
$amqpExchange = $this->createMock(\AMQPExchange::class), $this->createMock(\AMQPExchange::class),
$delayExchange = $this->createMock(\AMQPExchange::class) $delayExchange = $this->createMock(\AMQPExchange::class)
)); ));
$amqpExchange->expects($this->once())->method('setName')->with(self::DEFAULT_EXCHANGE_NAME);
$amqpExchange->expects($this->once())->method('declareExchange');
$delayExchange->expects($this->once())->method('setName')->with('delay');
$delayExchange->expects($this->once())->method('declareExchange');
$connectionOptions = [ $connectionOptions = [
'retry' => [ 'retry' => [
'dead_routing_key' => 'my_dead_routing_key', 'dead_routing_key' => 'my_dead_routing_key',
@ -492,9 +512,10 @@ class ConnectionTest extends TestCase
$connection = Connection::fromDsn('amqp://localhost', $connectionOptions, $factory); $connection = Connection::fromDsn('amqp://localhost', $connectionOptions, $factory);
$delayQueue->expects($this->once())->method('setName')->with('delay_queue_messages_routing_key_120000'); $delayQueue->expects($this->once())->method('setName')->with('delay_messages_routing_key_120000');
$delayQueue->expects($this->once())->method('setArguments')->with([ $delayQueue->expects($this->once())->method('setArguments')->with([
'x-message-ttl' => 120000, 'x-message-ttl' => 120000,
'x-expires' => 120000 + 10000,
'x-dead-letter-exchange' => self::DEFAULT_EXCHANGE_NAME, 'x-dead-letter-exchange' => self::DEFAULT_EXCHANGE_NAME,
'x-dead-letter-routing-key' => 'routing_key', 'x-dead-letter-routing-key' => 'routing_key',
]); ]);

View File

@ -15,6 +15,8 @@ use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Query\QueryBuilder;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\SchemaConfig;
use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer; use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
@ -102,25 +104,26 @@ class ConnectionTest extends TestCase
private function getDBALConnectionMock() private function getDBALConnectionMock()
{ {
$driverConnection = $this->getMockBuilder(\Doctrine\DBAL\Connection::class) $driverConnection = $this->createMock(\Doctrine\DBAL\Connection::class);
->disableOriginalConstructor() $platform = $this->createMock(AbstractPlatform::class);
->getMock();
$platform = $this->getMockBuilder(AbstractPlatform::class)
->getMock();
$platform->method('getWriteLockSQL')->willReturn('FOR UPDATE'); $platform->method('getWriteLockSQL')->willReturn('FOR UPDATE');
$configuration = $this->getMockBuilder(\Doctrine\DBAL\Configuration::class) $configuration = $this->createMock(\Doctrine\DBAL\Configuration::class);
->getMock();
$driverConnection->method('getDatabasePlatform')->willReturn($platform); $driverConnection->method('getDatabasePlatform')->willReturn($platform);
$driverConnection->method('getConfiguration')->willReturn($configuration); $driverConnection->method('getConfiguration')->willReturn($configuration);
$schemaManager = $this->createMock(AbstractSchemaManager::class);
$schemaConfig = $this->createMock(SchemaConfig::class);
$schemaConfig->method('getMaxIdentifierLength')->willReturn(63);
$schemaConfig->method('getDefaultTableOptions')->willReturn([]);
$schemaManager->method('createSchemaConfig')->willReturn($schemaConfig);
$driverConnection->method('getSchemaManager')->willReturn($schemaManager);
return $driverConnection; return $driverConnection;
} }
private function getQueryBuilderMock() private function getQueryBuilderMock()
{ {
$queryBuilder = $this->getMockBuilder(QueryBuilder::class) $queryBuilder = $this->createMock(QueryBuilder::class);
->disableOriginalConstructor()
->getMock();
$queryBuilder->method('select')->willReturn($queryBuilder); $queryBuilder->method('select')->willReturn($queryBuilder);
$queryBuilder->method('update')->willReturn($queryBuilder); $queryBuilder->method('update')->willReturn($queryBuilder);
@ -138,9 +141,7 @@ class ConnectionTest extends TestCase
private function getStatementMock($expectedResult) private function getStatementMock($expectedResult)
{ {
$stmt = $this->getMockBuilder(Statement::class) $stmt = $this->createMock(Statement::class);
->disableOriginalConstructor()
->getMock();
$stmt->expects($this->once()) $stmt->expects($this->once())
->method('fetch') ->method('fetch')
->willReturn($expectedResult); ->willReturn($expectedResult);
@ -150,8 +151,7 @@ class ConnectionTest extends TestCase
private function getSchemaSynchronizerMock() private function getSchemaSynchronizerMock()
{ {
return $this->getMockBuilder(SchemaSynchronizer::class) return $this->createMock(SchemaSynchronizer::class);
->getMock();
} }
/** /**
@ -307,9 +307,7 @@ class ConnectionTest extends TestCase
'headers' => json_encode(['type' => DummyMessage::class]), 'headers' => json_encode(['type' => DummyMessage::class]),
]; ];
$stmt = $this->getMockBuilder(Statement::class) $stmt = $this->createMock(Statement::class);
->disableOriginalConstructor()
->getMock();
$stmt->expects($this->once()) $stmt->expects($this->once())
->method('fetchAll') ->method('fetchAll')
->willReturn([$message1, $message2]); ->willReturn([$message1, $message2]);

View File

@ -32,7 +32,7 @@ class DoctrineReceiverTest extends TestCase
$serializer = $this->createSerializer(); $serializer = $this->createSerializer();
$doctrineEnvelope = $this->createDoctrineEnvelope(); $doctrineEnvelope = $this->createDoctrineEnvelope();
$connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); $connection = $this->createMock(Connection::class);
$connection->method('get')->willReturn($doctrineEnvelope); $connection->method('get')->willReturn($doctrineEnvelope);
$receiver = new DoctrineReceiver($connection, $serializer); $receiver = new DoctrineReceiver($connection, $serializer);
@ -62,7 +62,7 @@ class DoctrineReceiverTest extends TestCase
$serializer->method('decode')->willThrowException(new MessageDecodingFailedException()); $serializer->method('decode')->willThrowException(new MessageDecodingFailedException());
$doctrineEnvelop = $this->createDoctrineEnvelope(); $doctrineEnvelop = $this->createDoctrineEnvelope();
$connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); $connection = $this->createMock(Connection::class);
$connection->method('get')->willReturn($doctrineEnvelop); $connection->method('get')->willReturn($doctrineEnvelop);
$connection->expects($this->once())->method('reject'); $connection->expects($this->once())->method('reject');

View File

@ -27,12 +27,10 @@ class DoctrineSenderTest extends TestCase
$envelope = new Envelope(new DummyMessage('Oy')); $envelope = new Envelope(new DummyMessage('Oy'));
$encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]]; $encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]];
$connection = $this->getMockBuilder(Connection::class) $connection = $this->createMock(Connection::class);
->disableOriginalConstructor()
->getMock();
$connection->expects($this->once())->method('send')->with($encoded['body'], $encoded['headers'])->willReturn(15); $connection->expects($this->once())->method('send')->with($encoded['body'], $encoded['headers'])->willReturn(15);
$serializer = $this->getMockBuilder(SerializerInterface::class)->getMock(); $serializer = $this->createMock(SerializerInterface::class);
$serializer->method('encode')->with($envelope)->willReturnOnConsecutiveCalls($encoded); $serializer->method('encode')->with($envelope)->willReturnOnConsecutiveCalls($encoded);
$sender = new DoctrineSender($connection, $serializer); $sender = new DoctrineSender($connection, $serializer);
@ -49,12 +47,10 @@ class DoctrineSenderTest extends TestCase
$envelope = (new Envelope(new DummyMessage('Oy')))->with(new DelayStamp(500)); $envelope = (new Envelope(new DummyMessage('Oy')))->with(new DelayStamp(500));
$encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]]; $encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]];
$connection = $this->getMockBuilder(Connection::class) $connection = $this->createMock(Connection::class);
->disableOriginalConstructor()
->getMock();
$connection->expects($this->once())->method('send')->with($encoded['body'], $encoded['headers'], 500); $connection->expects($this->once())->method('send')->with($encoded['body'], $encoded['headers'], 500);
$serializer = $this->getMockBuilder(SerializerInterface::class)->getMock(); $serializer = $this->createMock(SerializerInterface::class);
$serializer->method('encode')->with($envelope)->willReturnOnConsecutiveCalls($encoded); $serializer->method('encode')->with($envelope)->willReturnOnConsecutiveCalls($encoded);
$sender = new DoctrineSender($connection, $serializer); $sender = new DoctrineSender($connection, $serializer);

View File

@ -12,6 +12,8 @@
namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; namespace Symfony\Component\Messenger\Tests\Transport\Doctrine;
use Doctrine\Common\Persistence\ConnectionRegistry; use Doctrine\Common\Persistence\ConnectionRegistry;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\SchemaConfig;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Transport\Doctrine\Connection; use Symfony\Component\Messenger\Transport\Doctrine\Connection;
use Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransport; use Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransport;
@ -23,7 +25,7 @@ class DoctrineTransportFactoryTest extends TestCase
public function testSupports() public function testSupports()
{ {
$factory = new DoctrineTransportFactory( $factory = new DoctrineTransportFactory(
$this->getMockBuilder(ConnectionRegistry::class)->getMock() $this->createMock(ConnectionRegistry::class)
); );
$this->assertTrue($factory->supports('doctrine://default', [])); $this->assertTrue($factory->supports('doctrine://default', []));
@ -32,19 +34,22 @@ class DoctrineTransportFactoryTest extends TestCase
public function testCreateTransport() public function testCreateTransport()
{ {
$connection = $this->getMockBuilder(\Doctrine\DBAL\Connection::class) $driverConnection = $this->createMock(\Doctrine\DBAL\Connection::class);
->disableOriginalConstructor() $schemaManager = $this->createMock(AbstractSchemaManager::class);
->getMock(); $schemaConfig = $this->createMock(SchemaConfig::class);
$registry = $this->getMockBuilder(ConnectionRegistry::class)->getMock(); $schemaManager->method('createSchemaConfig')->willReturn($schemaConfig);
$driverConnection->method('getSchemaManager')->willReturn($schemaManager);
$registry = $this->createMock(ConnectionRegistry::class);
$registry->expects($this->once()) $registry->expects($this->once())
->method('getConnection') ->method('getConnection')
->willReturn($connection); ->willReturn($driverConnection);
$factory = new DoctrineTransportFactory($registry); $factory = new DoctrineTransportFactory($registry);
$serializer = $this->createMock(SerializerInterface::class); $serializer = $this->createMock(SerializerInterface::class);
$this->assertEquals( $this->assertEquals(
new DoctrineTransport(new Connection(Connection::buildConfiguration('doctrine://default'), $connection), $serializer), new DoctrineTransport(new Connection(Connection::buildConfiguration('doctrine://default'), $driverConnection), $serializer),
$factory->createTransport('doctrine://default', [], $serializer) $factory->createTransport('doctrine://default', [], $serializer)
); );
} }
@ -55,7 +60,7 @@ class DoctrineTransportFactoryTest extends TestCase
*/ */
public function testCreateTransportMustThrowAnExceptionIfManagerIsNotFound() public function testCreateTransportMustThrowAnExceptionIfManagerIsNotFound()
{ {
$registry = $this->getMockBuilder(ConnectionRegistry::class)->getMock(); $registry = $this->createMock(ConnectionRegistry::class);
$registry->expects($this->once()) $registry->expects($this->once())
->method('getConnection') ->method('getConnection')
->willReturnCallback(function () { ->willReturnCallback(function () {

View File

@ -31,8 +31,8 @@ class DoctrineTransportTest extends TestCase
public function testReceivesMessages() public function testReceivesMessages()
{ {
$transport = $this->getTransport( $transport = $this->getTransport(
$serializer = $this->getMockBuilder(SerializerInterface::class)->getMock(), $serializer = $this->createMock(SerializerInterface::class),
$connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock() $connection = $this->createMock(Connection::class)
); );
$decodedMessage = new DummyMessage('Decoded.'); $decodedMessage = new DummyMessage('Decoded.');
@ -52,8 +52,8 @@ class DoctrineTransportTest extends TestCase
private function getTransport(SerializerInterface $serializer = null, Connection $connection = null) private function getTransport(SerializerInterface $serializer = null, Connection $connection = null)
{ {
$serializer = $serializer ?: $this->getMockBuilder(SerializerInterface::class)->getMock(); $serializer = $serializer ?: $this->createMock(SerializerInterface::class);
$connection = $connection ?: $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); $connection = $connection ?: $this->createMock(Connection::class);
return new DoctrineTransport($connection, $serializer); return new DoctrineTransport($connection, $serializer);
} }

View File

@ -16,7 +16,7 @@ use Symfony\Component\Messenger\Exception\TransportException;
use Symfony\Component\Messenger\Transport\RedisExt\Connection; use Symfony\Component\Messenger\Transport\RedisExt\Connection;
/** /**
* @requires extension redis * @requires extension redis >= 4.3.0
*/ */
class ConnectionTest extends TestCase class ConnectionTest extends TestCase
{ {
@ -119,7 +119,7 @@ class ConnectionTest extends TestCase
$redis->expects($this->once())->method('xreadgroup')->willReturn(false); $redis->expects($this->once())->method('xreadgroup')->willReturn(false);
$redis->expects($this->once())->method('getLastError')->willReturn('Redis error happens'); $redis->expects($this->once())->method('getLastError')->willReturn('Redis error happens');
$connection = Connection::fromDsn('redis://localhost/queue', [], $redis); $connection = Connection::fromDsn('redis://localhost/queue', ['auto_setup' => false], $redis);
$connection->get(); $connection->get();
} }
@ -164,4 +164,31 @@ class ConnectionTest extends TestCase
$connection = Connection::fromDsn('redis://localhost/queue?stream_max_entries=20000', [], $redis); // 1 = always $connection = Connection::fromDsn('redis://localhost/queue?stream_max_entries=20000', [], $redis); // 1 = always
$connection->add('1', []); $connection->add('1', []);
} }
public function testLastErrorGetsCleared()
{
$redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock();
$redis->expects($this->once())->method('xadd')->willReturn(0);
$redis->expects($this->once())->method('xack')->willReturn(0);
$redis->method('getLastError')->willReturnOnConsecutiveCalls('xadd error', 'xack error');
$redis->expects($this->exactly(2))->method('clearLastError');
$connection = Connection::fromDsn('redis://localhost/messenger-clearlasterror', ['auto_setup' => false], $redis);
try {
$connection->add('message', []);
} catch (TransportException $e) {
}
$this->assertSame('xadd error', $e->getMessage());
try {
$connection->ack('1');
} catch (TransportException $e) {
}
$this->assertSame('xack error', $e->getMessage());
}
} }

View File

@ -43,10 +43,7 @@ class AmqpSender implements SenderInterface
/** @var DelayStamp|null $delayStamp */ /** @var DelayStamp|null $delayStamp */
$delayStamp = $envelope->last(DelayStamp::class); $delayStamp = $envelope->last(DelayStamp::class);
$delay = 0; $delay = $delayStamp ? $delayStamp->getDelay() : 0;
if (null !== $delayStamp) {
$delay = $delayStamp->getDelay();
}
$amqpStamp = $envelope->last(AmqpStamp::class); $amqpStamp = $envelope->last(AmqpStamp::class);
if (isset($encodedMessage['headers']['Content-Type'])) { if (isset($encodedMessage['headers']['Content-Type'])) {

View File

@ -60,9 +60,8 @@ class Connection
{ {
$this->connectionOptions = array_replace_recursive([ $this->connectionOptions = array_replace_recursive([
'delay' => [ 'delay' => [
'routing_key_pattern' => 'delay_%exchange_name%_%routing_key%_%delay%',
'exchange_name' => 'delay', 'exchange_name' => 'delay',
'queue_name_pattern' => 'delay_queue_%exchange_name%_%routing_key%_%delay%', 'queue_name_pattern' => 'delay_%exchange_name%_%routing_key%_%delay%',
], ],
], $connectionOptions); ], $connectionOptions);
$this->exchangeOptions = $exchangeOptions; $this->exchangeOptions = $exchangeOptions;
@ -91,9 +90,8 @@ class Connection
* * flags: Exchange flags (Default: AMQP_DURABLE) * * flags: Exchange flags (Default: AMQP_DURABLE)
* * arguments: Extra arguments * * arguments: Extra arguments
* * delay: * * delay:
* * routing_key_pattern: The pattern of the routing key (Default: "delay_%exchange_name%_%routing_key%_%delay%") * * queue_name_pattern: Pattern to use to create the queues (Default: "delay_%exchange_name%_%routing_key%_%delay%")
* * queue_name_pattern: Pattern to use to create the queues (Default: "delay_queue_%exchange_name%_%routing_key%_%delay%") * * exchange_name: Name of the exchange to be used for the delayed/retried messages (Default: "delay")
* * exchange_name: Name of the exchange to be used for the retried messages (Default: "delay")
* * auto_setup: Enable or not the auto-setup of queues and exchanges (Default: true) * * auto_setup: Enable or not the auto-setup of queues and exchanges (Default: true)
* * prefetch_count: set channel prefetch count * * prefetch_count: set channel prefetch count
*/ */
@ -169,20 +167,20 @@ class Connection
} }
/** /**
* @param int $delay The delay in milliseconds
*
* @throws \AMQPException * @throws \AMQPException
*/ */
public function publish(string $body, array $headers = [], int $delay = 0, AmqpStamp $amqpStamp = null): void public function publish(string $body, array $headers = [], int $delayInMs = 0, AmqpStamp $amqpStamp = null): void
{ {
if (0 !== $delay) { $this->clearWhenDisconnected();
$this->publishWithDelay($body, $headers, $delay, $amqpStamp);
if (0 !== $delayInMs) {
$this->publishWithDelay($body, $headers, $delayInMs, $amqpStamp);
return; return;
} }
if ($this->shouldSetup()) { if ($this->shouldSetup()) {
$this->setup(); $this->setupExchangeAndQueues();
} }
$this->publishOnExchange( $this->publishOnExchange(
@ -211,9 +209,7 @@ class Connection
{ {
$routingKey = $this->getRoutingKeyForMessage($amqpStamp); $routingKey = $this->getRoutingKeyForMessage($amqpStamp);
if ($this->shouldSetup()) {
$this->setupDelay($delay, $routingKey); $this->setupDelay($delay, $routingKey);
}
$this->publishOnExchange( $this->publishOnExchange(
$this->getDelayExchange(), $this->getDelayExchange(),
@ -239,15 +235,12 @@ class Connection
private function setupDelay(int $delay, ?string $routingKey) private function setupDelay(int $delay, ?string $routingKey)
{ {
if (!$this->channel()->isConnected()) { if ($this->shouldSetup()) {
$this->clear(); $this->setup(); // setup delay exchange and normal exchange for delay queue to DLX messages to
} }
$this->exchange()->declareExchange(); // setup normal exchange for delay queue to DLX messages to
$this->getDelayExchange()->declareExchange();
$queue = $this->createDelayQueue($delay, $routingKey); $queue = $this->createDelayQueue($delay, $routingKey);
$queue->declareQueue(); $queue->declareQueue(); // the delay queue always need to be declared because the name is dynamic and cannot be declared in advance
$queue->bind($this->connectionOptions['delay']['exchange_name'], $this->getRoutingKeyForDelay($delay, $routingKey)); $queue->bind($this->connectionOptions['delay']['exchange_name'], $this->getRoutingKeyForDelay($delay, $routingKey));
} }
@ -281,6 +274,9 @@ class Connection
)); ));
$queue->setArguments([ $queue->setArguments([
'x-message-ttl' => $delay, 'x-message-ttl' => $delay,
// delete the delay queue 10 seconds after the message expires
// publishing another message redeclares the queue which renews the lease
'x-expires' => $delay + 10000,
'x-dead-letter-exchange' => $this->exchangeOptions['name'], 'x-dead-letter-exchange' => $this->exchangeOptions['name'],
// after being released from to DLX, make sure the original routing key will be used // after being released from to DLX, make sure the original routing key will be used
// we must use an empty string instead of null for the argument to be picked up // we must use an empty string instead of null for the argument to be picked up
@ -295,7 +291,7 @@ class Connection
return str_replace( return str_replace(
['%delay%', '%exchange_name%', '%routing_key%'], ['%delay%', '%exchange_name%', '%routing_key%'],
[$delay, $this->exchangeOptions['name'], $finalRoutingKey ?? ''], [$delay, $this->exchangeOptions['name'], $finalRoutingKey ?? ''],
$this->connectionOptions['delay']['routing_key_pattern'] $this->connectionOptions['delay']['queue_name_pattern']
); );
} }
@ -306,8 +302,10 @@ class Connection
*/ */
public function get(string $queueName): ?\AMQPEnvelope public function get(string $queueName): ?\AMQPEnvelope
{ {
$this->clearWhenDisconnected();
if ($this->shouldSetup()) { if ($this->shouldSetup()) {
$this->setup(); $this->setupExchangeAndQueues();
} }
try { try {
@ -317,7 +315,7 @@ class Connection
} catch (\AMQPQueueException $e) { } catch (\AMQPQueueException $e) {
if (404 === $e->getCode() && $this->shouldSetup()) { if (404 === $e->getCode() && $this->shouldSetup()) {
// If we get a 404 for the queue, it means we need to setup the exchange & queue. // If we get a 404 for the queue, it means we need to setup the exchange & queue.
$this->setup(); $this->setupExchangeAndQueues();
return $this->get(); return $this->get();
} }
@ -340,10 +338,12 @@ class Connection
public function setup(): void public function setup(): void
{ {
if (!$this->channel()->isConnected()) { $this->setupExchangeAndQueues();
$this->clear(); $this->getDelayExchange()->declareExchange();
} }
private function setupExchangeAndQueues(): void
{
$this->exchange()->declareExchange(); $this->exchange()->declareExchange();
foreach ($this->queuesOptions as $queueName => $queueConfig) { foreach ($this->queuesOptions as $queueName => $queueConfig) {
@ -422,13 +422,15 @@ class Connection
return $this->amqpExchange; return $this->amqpExchange;
} }
private function clear(): void private function clearWhenDisconnected(): void
{ {
if (!$this->channel()->isConnected()) {
$this->amqpChannel = null; $this->amqpChannel = null;
$this->amqpQueues = []; $this->amqpQueues = [];
$this->amqpExchange = null; $this->amqpExchange = null;
$this->amqpDelayExchange = null; $this->amqpDelayExchange = null;
} }
}
private function shouldSetup(): bool private function shouldSetup(): bool
{ {

View File

@ -302,7 +302,7 @@ class Connection
private function getSchema(): Schema private function getSchema(): Schema
{ {
$schema = new Schema(); $schema = new Schema([], [], $this->driverConnection->getSchemaManager()->createSchemaConfig());
$table = $schema->createTable($this->configuration['table_name']); $table = $schema->createTable($this->configuration['table_name']);
$table->addColumn('id', Type::BIGINT) $table->addColumn('id', Type::BIGINT)
->setAutoincrement(true) ->setAutoincrement(true)

View File

@ -127,12 +127,15 @@ class Connection
1 1
); );
} catch (\RedisException $e) { } catch (\RedisException $e) {
throw new TransportException($e->getMessage(), 0, $e);
} }
if ($e || false === $messages) { if (false === $messages) {
throw new TransportException( if ($error = $this->connection->getLastError() ?: null) {
($e ? $e->getMessage() : $this->connection->getLastError()) ?? 'Could not read messages from the redis stream.' $this->connection->clearLastError();
); }
throw new TransportException($error ?? 'Could not read messages from the redis stream.');
} }
if ($this->couldHavePendingMessages && empty($messages[$this->stream])) { if ($this->couldHavePendingMessages && empty($messages[$this->stream])) {
@ -157,28 +160,34 @@ class Connection
public function ack(string $id): void public function ack(string $id): void
{ {
$e = null;
try { try {
$acknowledged = $this->connection->xack($this->stream, $this->group, [$id]); $acknowledged = $this->connection->xack($this->stream, $this->group, [$id]);
} catch (\RedisException $e) { } catch (\RedisException $e) {
throw new TransportException($e->getMessage(), 0, $e);
} }
if ($e || !$acknowledged) { if (!$acknowledged) {
throw new TransportException(($e ? $e->getMessage() : $this->connection->getLastError()) ?? sprintf('Could not acknowledge redis message "%s".', $id), 0, $e); if ($error = $this->connection->getLastError() ?: null) {
$this->connection->clearLastError();
}
throw new TransportException($error ?? sprintf('Could not acknowledge redis message "%s".', $id));
} }
} }
public function reject(string $id): void public function reject(string $id): void
{ {
$e = null;
try { try {
$deleted = $this->connection->xack($this->stream, $this->group, [$id]); $deleted = $this->connection->xack($this->stream, $this->group, [$id]);
$deleted = $this->connection->xdel($this->stream, [$id]) && $deleted; $deleted = $this->connection->xdel($this->stream, [$id]) && $deleted;
} catch (\RedisException $e) { } catch (\RedisException $e) {
throw new TransportException($e->getMessage(), 0, $e);
} }
if ($e || !$deleted) { if (!$deleted) {
throw new TransportException(($e ? $e->getMessage() : $this->connection->getLastError()) ?? sprintf('Could not delete message "%s" from the redis stream.', $id), 0, $e); if ($error = $this->connection->getLastError() ?: null) {
$this->connection->clearLastError();
}
throw new TransportException($error ?? sprintf('Could not delete message "%s" from the redis stream.', $id));
} }
} }
@ -188,7 +197,6 @@ class Connection
$this->setup(); $this->setup();
} }
$e = null;
try { try {
if ($this->maxEntries) { if ($this->maxEntries) {
$added = $this->connection->xadd($this->stream, '*', ['message' => json_encode( $added = $this->connection->xadd($this->stream, '*', ['message' => json_encode(
@ -200,10 +208,14 @@ class Connection
)]); )]);
} }
} catch (\RedisException $e) { } catch (\RedisException $e) {
throw new TransportException($e->getMessage(), 0, $e);
} }
if ($e || !$added) { if (!$added) {
throw new TransportException(($e ? $e->getMessage() : $this->connection->getLastError()) ?? 'Could not add a message to the redis stream.', 0, $e); if ($error = $this->connection->getLastError() ?: null) {
$this->connection->clearLastError();
}
throw new TransportException($error ?? 'Could not add a message to the redis stream.');
} }
} }
@ -215,6 +227,11 @@ class Connection
throw new TransportException($e->getMessage(), 0, $e); throw new TransportException($e->getMessage(), 0, $e);
} }
// group might already exist, ignore
if ($this->connection->getLastError()) {
$this->connection->clearLastError();
}
$this->autoSetup = false; $this->autoSetup = false;
} }
} }

View File

@ -71,6 +71,8 @@ class Section
return $child; return $child;
} }
} }
return null;
} }
/** /**
@ -115,7 +117,7 @@ class Section
* Starts an event. * Starts an event.
* *
* @param string $name The event name * @param string $name The event name
* @param string $category The event category * @param string|null $category The event category
* *
* @return StopwatchEvent The event * @return StopwatchEvent The event
*/ */