Merge branch '3.3' into 3.4

* 3.3: (31 commits)
  Using FQ name for PHP_VERSION_ID
  [EventDispatcher] Handle laziness internally instead of relying on ClosureProxyArgument
  Fix CacheCollectorPass priority
  [Form] Fix \IntlDateFormatter timezone parameter usage to bypass PHP bug #66323
  [Routing] Allow GET requests to be redirected. Fixes #23004
  [DI] Deal with inlined non-shared services
  [Cache] Ignore missing annotations.php
  [DI] Autowiring exception thrown when inlined service is removed
  Improving deprecation message when hitting the "deprecated type" lookup, but an alias is available
  Harden the debugging of Twig filters and functions
  Fixing a bug where an autowiring exception was thrown even when that service was removed
  Remove extra arg in call to TraceableAdapter::start()
  Support unknown compiler log format
  [Config] Allow empty globs
  Fix decorating TagAware adapters in dev
  [Profiler] Fix clicking on links inside toggle
  [Profiler] Fix text selection on exception pages
  bumped Symfony version to 3.3.1
  updated VERSION for 3.3.0
  updated CHANGELOG for 3.3.0
  ...
This commit is contained in:
Fabien Potencier 2017-06-01 14:02:15 -07:00
commit 69f1578d8c
59 changed files with 1153 additions and 152 deletions

View File

@ -11,7 +11,7 @@ array_shift($dirs);
$mergeBase = trim(shell_exec(sprintf('git merge-base %s HEAD', array_shift($dirs)))); $mergeBase = trim(shell_exec(sprintf('git merge-base %s HEAD', array_shift($dirs))));
$packages = array(); $packages = array();
$flags = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE : 0; $flags = \PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE : 0;
foreach ($dirs as $k => $dir) { foreach ($dirs as $k => $dir) {
if (!system("git diff --name-only $mergeBase -- $dir", $exitStatus)) { if (!system("git diff --name-only $mergeBase -- $dir", $exitStatus)) {

View File

@ -7,6 +7,29 @@ in 3.2 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff 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.2.0...v3.2.1 To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.2.0...v3.2.1
* 3.2.9 (2017-05-29)
* bug #22847 [Console] ChoiceQuestion must have choices (ro0NL)
* bug #22900 [FrameworkBundle][Console] Fix the override of a command registered by the kernel (aaa2000)
* bug #22910 [Filesystem] improve error handling in lock() (xabbuh)
* bug #22924 [Cache] Dont use pipelining with RedisCluster (nicolas-grekas)
* bug #22718 [Console] Fixed different behaviour of key and value user inputs in multiple choice question (borNfreee)
* bug #22829 [Yaml] fix colon without space deprecation (xabbuh)
* bug #22901 Fix missing abstract key in XmlDumper (weaverryan)
* bug #22912 [DI] Avoid private call to Container::has() (ro0NL)
* bug #22866 [DI] Check for privates before shared services (ro0NL)
* bug #22874 [WebProfilerBundle] Fix sub-requests display in time profiler panel (nicolas-grekas)
* bug #22817 [PhpUnitBridge] optional error handler arguments (xabbuh)
* bug #22752 Improved how profiler errors are displayed on small screens (javiereguiluz)
* bug #22715 [FrameworkBundle] remove Security deps from the require section (xabbuh)
* bug #22647 [VarDumper] Fix dumping of non-nested stubs (nicolas-grekas)
* bug #22409 [Yaml] respect inline level when dumping objects as maps (goetas, xabbuh)
* bug #22584 [Security] Avoid unnecessary route lookup for empty logout path (ro0NL)
* bug #22690 [Console] Fix errors not rethrown even if not handled by console.error listeners (chalasr)
* bug #22669 [FrameworkBundle] AbstractConfigCommand: do not try registering bundles twice (ogizanagi)
* bug #22676 [FrameworkBundle] Adding the extension XML (flug)
* bug #22652 [Workflow] Move twig extension registration to twig bundle (ogizanagi)
* 3.2.8 (2017-05-01) * 3.2.8 (2017-05-01)
* bug #22550 Allow Upper Case property names in ObjectNormalizer (insekticid) * bug #22550 Allow Upper Case property names in ObjectNormalizer (insekticid)

View File

@ -7,6 +7,45 @@ in 3.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/v3.3.0...v3.3.1 To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.3.0...v3.3.1
* 3.3.0 (2017-05-29)
* bug #22940 [Config] Fallback to regular import when glob fails (nicolas-grekas)
* bug #22847 [Console] ChoiceQuestion must have choices (ro0NL)
* bug #22900 [FrameworkBundle][Console] Fix the override of a command registered by the kernel (aaa2000)
* bug #22930 Revert "bug #22925 [PhpUnitBridge] Adjust PHPUnit class_alias check (nicolas-grekas)
* bug #22910 [Filesystem] improve error handling in lock() (xabbuh)
* bug #22924 [Cache] Dont use pipelining with RedisCluster (nicolas-grekas)
* bug #22928 [WebProfilerBundle] Fixed options stub values display in form profiler (HeahDude)
* feature #22838 Make the simple exception pages match the new style (javiereguiluz)
* bug #22925 [PhpUnitBridge] Adjust PHPUnit class_alias check to also check for namespaced class (GawainLynch)
* bug #22718 [Console] Fixed different behaviour of key and value user inputs in multiple choice question (borNfreee)
* bug #22921 [FrameworkBundle] Only override getProjectDir if it exists in the kernel (aschempp)
* feature #22905 [FrameworkBundle][Validator] Move the PSR-11 factory to the component (ogizanagi)
* bug #22728 [HttpKernel] Fix kernel.project_dir extensibility (chalasr)
* bug #22829 [Yaml] fix colon without space deprecation (xabbuh)
* bug #22901 Fix missing abstract key in XmlDumper (weaverryan)
* bug #22912 [DI] Avoid private call to Container::has() (ro0NL)
* feature #22904 [HttpFoundation] Add Request::HEADER_X_FORWARDED_AWS_ELB const (nicolas-grekas)
* bug #22878 [Yaml] parse PHP constants in mapping keys (xabbuh)
* bug #22873 [HttpKernel] don't call getTrustedHeaderName() if possible (xabbuh)
* feature #22892 [ProxyManager] Add FC layer (nicolas-grekas)
* bug #22866 [DI] Check for privates before shared services (ro0NL)
* feature #22884 [DI] Add missing deprecation on Extension::getClassesToCompile (nicolas-grekas)
* bug #22874 [WebProfilerBundle] Fix sub-requests display in time profiler panel (nicolas-grekas)
* bug #22853 [Yaml] fix multiline block handling (xabbuh)
* bug #22872 [FrameworkBundle] Handle project dir in cache:clear command (nicolas-grekas)
* feature #22808 [FrameworkBundle][Validator] Deprecate passing validator instances/aliases over using the service locator (ogizanagi)
* bug #22857 [DI] Fix autowire error for inlined services (weaverryan)
* bug #22858 [SecurityBundle] Prevent auto-registration of UserPasswordEncoderCommand (chalasr)
* bug #22859 [Profiler][VarDumper] Fix searchbar css when in toolbar (ogizanagi)
* bug #22614 [Process] Fixed escaping arguments on Windows when inheritEnvironmentVariables is set to false (maryo)
* bug #22817 [PhpUnitBridge] optional error handler arguments (xabbuh)
* bug #22781 [DI][Serializer] Fix missing de(normalizer|coder) autoconfig (ogizanagi)
* bug #22790 [DependencyInjection] Fix dumping of RewindableGenerator with empty IteratorArgument (meyerbaptiste)
* bug #22787 [MonologBridge] Fix the Monlog ServerLogHandler from Hanging on Windows (ChadSikorra)
* bug #22768 Use 0.0.0.0 as the server log command host default. (ChadSikorra)
* bug #22752 Improved how profiler errors are displayed on small screens (javiereguiluz)
* 3.3.0-RC1 (2017-05-17) * 3.3.0-RC1 (2017-05-17)
* bug #22715 [FrameworkBundle] remove Security deps from the require section (xabbuh) * bug #22715 [FrameworkBundle] remove Security deps from the require section (xabbuh)

View File

@ -24,20 +24,20 @@ Symfony is the result of the work of many people who made the code better
- Wouter De Jong (wouterj) - Wouter De Jong (wouterj)
- Romain Neutron (romain) - Romain Neutron (romain)
- Grégoire Pineau (lyrixx) - Grégoire Pineau (lyrixx)
- Joseph Bielawski (stloyd)
- Karma Dordrak (drak)
- Robin Chalas (chalas_r) - Robin Chalas (chalas_r)
- Joseph Bielawski (stloyd)
- Maxime Steinhausser (ogizanagi)
- Karma Dordrak (drak)
- Lukas Kahwe Smith (lsmith) - Lukas Kahwe Smith (lsmith)
- Martin Hasoň (hason) - Martin Hasoň (hason)
- Maxime Steinhausser (ogizanagi)
- Jeremy Mikola (jmikola) - Jeremy Mikola (jmikola)
- Jean-François Simon (jfsimon) - Jean-François Simon (jfsimon)
- Benjamin Eberlei (beberlei) - Benjamin Eberlei (beberlei)
- Igor Wiedler (igorw) - Igor Wiedler (igorw)
- Eriksen Costa (eriksencosta) - Eriksen Costa (eriksencosta)
- Jules Pietri (heah) - Jules Pietri (heah)
- Sarah Khalil (saro0h)
- Roland Franssen (ro0) - Roland Franssen (ro0)
- Sarah Khalil (saro0h)
- Jonathan Wage (jwage) - Jonathan Wage (jwage)
- Guilhem Niot (energetick) - Guilhem Niot (energetick)
- Diego Saint Esteben (dosten) - Diego Saint Esteben (dosten)
@ -49,10 +49,10 @@ Symfony is the result of the work of many people who made the code better
- Alexander Mols (asm89) - Alexander Mols (asm89)
- Bulat Shakirzyanov (avalanche123) - Bulat Shakirzyanov (avalanche123)
- Peter Rehm (rpet) - Peter Rehm (rpet)
- Iltar van der Berg (kjarli)
- Saša Stamenković (umpirsky) - Saša Stamenković (umpirsky)
- Henrik Bjørnskov (henrikbjorn) - Henrik Bjørnskov (henrikbjorn)
- Miha Vrhovnik - Miha Vrhovnik
- Roland Franssen (ro0)
- Diego Saint Esteben (dii3g0) - Diego Saint Esteben (dii3g0)
- Konstantin Kudryashov (everzet) - Konstantin Kudryashov (everzet)
- Bilal Amarni (bamarni) - Bilal Amarni (bamarni)
@ -64,8 +64,8 @@ Symfony is the result of the work of many people who made the code better
- Michel Weimerskirch (mweimerskirch) - Michel Weimerskirch (mweimerskirch)
- Eric Clemmons (ericclemmons) - Eric Clemmons (ericclemmons)
- Charles Sarrazin (csarrazi) - Charles Sarrazin (csarrazi)
- Pierre du Plessis (pierredup)
- Christian Raue - Christian Raue
- Pierre du Plessis (pierredup)
- Arnout Boks (aboks) - Arnout Boks (aboks)
- Deni - Deni
- Henrik Westphal (snc) - Henrik Westphal (snc)
@ -77,12 +77,12 @@ Symfony is the result of the work of many people who made the code better
- Lee McDermott - Lee McDermott
- Brandon Turner - Brandon Turner
- Luis Cordova (cordoval) - Luis Cordova (cordoval)
- Jérémy DERUSSÉ (jderusse)
- Graham Campbell (graham) - Graham Campbell (graham)
- Daniel Holmes (dholmes) - Daniel Holmes (dholmes)
- Toni Uebernickel (havvg) - Toni Uebernickel (havvg)
- Bart van den Burg (burgov) - Bart van den Burg (burgov)
- Jordan Alliot (jalliot) - Jordan Alliot (jalliot)
- Jérémy DERUSSÉ (jderusse)
- John Wards (johnwards) - John Wards (johnwards)
- Dariusz Ruminski - Dariusz Ruminski
- Fran Moreno (franmomu) - Fran Moreno (franmomu)
@ -92,8 +92,8 @@ Symfony is the result of the work of many people who made the code better
- Arnaud Le Blanc (arnaud-lb) - Arnaud Le Blanc (arnaud-lb)
- Maxime STEINHAUSSER - Maxime STEINHAUSSER
- Michal Piotrowski (eventhorizon) - Michal Piotrowski (eventhorizon)
- Tim Nagel (merk)
- Issei Murasawa (issei_m) - Issei Murasawa (issei_m)
- Tim Nagel (merk)
- Brice BERNARD (brikou) - Brice BERNARD (brikou)
- Alexander M. Turek (derrabus) - Alexander M. Turek (derrabus)
- Baptiste Clavié (talus) - Baptiste Clavié (talus)
@ -115,6 +115,7 @@ Symfony is the result of the work of many people who made the code better
- Fabien Pennequin (fabienpennequin) - Fabien Pennequin (fabienpennequin)
- Gordon Franke (gimler) - Gordon Franke (gimler)
- Eric GELOEN (gelo) - Eric GELOEN (gelo)
- Yonel Ceruto González (yonelceruto)
- Daniel Wehner (dawehner) - Daniel Wehner (dawehner)
- Tugdual Saunier (tucksaun) - Tugdual Saunier (tucksaun)
- Théo FIDRY (theofidry) - Théo FIDRY (theofidry)
@ -122,7 +123,6 @@ Symfony is the result of the work of many people who made the code better
- Florian Lonqueu-Brochard (florianlb) - Florian Lonqueu-Brochard (florianlb)
- Sebastiaan Stok (sstok) - Sebastiaan Stok (sstok)
- Stefano Sala (stefano.sala) - Stefano Sala (stefano.sala)
- Yonel Ceruto González (yonelceruto)
- Evgeniy (ewgraf) - Evgeniy (ewgraf)
- Juti Noppornpitak (shiroyuki) - Juti Noppornpitak (shiroyuki)
- Tigran Azatyan (tigranazatyan) - Tigran Azatyan (tigranazatyan)
@ -157,6 +157,7 @@ Symfony is the result of the work of many people who made the code better
- Amal Raghav (kertz) - Amal Raghav (kertz)
- Jonathan Ingram (jonathaningram) - Jonathan Ingram (jonathaningram)
- Artur Kotyrba - Artur Kotyrba
- David Maicher (dmaicher)
- jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent) - jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent)
- James Halsall (jaitsu) - James Halsall (jaitsu)
- Warnar Boekkooi (boekkooi) - Warnar Boekkooi (boekkooi)
@ -166,6 +167,7 @@ Symfony is the result of the work of many people who made the code better
- Possum - Possum
- Dorian Villet (gnutix) - Dorian Villet (gnutix)
- Richard Miller (mr_r_miller) - Richard Miller (mr_r_miller)
- Julien Falque (julienfalque)
- Mario A. Alvarez Garcia (nomack84) - Mario A. Alvarez Garcia (nomack84)
- Dennis Benkert (denderello) - Dennis Benkert (denderello)
- Benjamin Dulau (dbenjamin) - Benjamin Dulau (dbenjamin)
@ -180,7 +182,6 @@ Symfony is the result of the work of many people who made the code better
- Daniel Espendiller - Daniel Espendiller
- sun (sun) - sun (sun)
- Larry Garfield (crell) - Larry Garfield (crell)
- Julien Falque (julienfalque)
- Martin Schuhfuß (usefulthink) - Martin Schuhfuß (usefulthink)
- apetitpa - apetitpa
- Matthieu Bontemps (mbontemps) - Matthieu Bontemps (mbontemps)
@ -203,6 +204,7 @@ Symfony is the result of the work of many people who made the code better
- Tom Van Looy (tvlooy) - Tom Van Looy (tvlooy)
- Sven Paulus (subsven) - Sven Paulus (subsven)
- Rui Marinho (ruimarinho) - Rui Marinho (ruimarinho)
- Marek Štípek (maryo)
- SpacePossum - SpacePossum
- Eugene Wissner - Eugene Wissner
- Julien Brochet (mewt) - Julien Brochet (mewt)
@ -217,7 +219,6 @@ Symfony is the result of the work of many people who made the code better
- julien pauli (jpauli) - julien pauli (jpauli)
- Lorenz Schori - Lorenz Schori
- Sébastien Lavoie (lavoiesl) - Sébastien Lavoie (lavoiesl)
- David Maicher (dmaicher)
- Francois Zaninotto - Francois Zaninotto
- Alexander Kotynia (olden) - Alexander Kotynia (olden)
- Daniel Tschinder - Daniel Tschinder
@ -254,6 +255,7 @@ Symfony is the result of the work of many people who made the code better
- Albert Casademont (acasademont) - Albert Casademont (acasademont)
- Jhonny Lidfors (jhonne) - Jhonny Lidfors (jhonne)
- Diego Agulló (aeoris) - Diego Agulló (aeoris)
- Andreas Schempp (aschempp)
- jdhoek - jdhoek
- Pavel Batanov (scaytrase) - Pavel Batanov (scaytrase)
- Nikita Konstantinov - Nikita Konstantinov
@ -272,8 +274,8 @@ Symfony is the result of the work of many people who made the code better
- Michael Holm (hollo) - Michael Holm (hollo)
- Marc Weistroff (futurecat) - Marc Weistroff (futurecat)
- Christian Schmidt - Christian Schmidt
- Marek Štípek (maryo)
- Hidde Wieringa (hiddewie) - Hidde Wieringa (hiddewie)
- Chad Sikorra (chadsikorra)
- Jordan Samouh (jordansamouh) - Jordan Samouh (jordansamouh)
- Chris Smith (cs278) - Chris Smith (cs278)
- Florian Klein (docteurklein) - Florian Klein (docteurklein)
@ -303,10 +305,10 @@ Symfony is the result of the work of many people who made the code better
- Francesc Rosàs (frosas) - Francesc Rosàs (frosas)
- Massimiliano Arione (garak) - Massimiliano Arione (garak)
- Julien Galenski (ruian) - Julien Galenski (ruian)
- Andreas Schempp (aschempp)
- Bongiraud Dominique - Bongiraud Dominique
- janschoenherr - janschoenherr
- Thomas Schulz (king2500) - Thomas Schulz (king2500)
- Dariusz Rumiński
- Berny Cantos (xphere81) - Berny Cantos (xphere81)
- Ricard Clau (ricardclau) - Ricard Clau (ricardclau)
- Mark Challoner (markchalloner) - Mark Challoner (markchalloner)
@ -385,7 +387,6 @@ Symfony is the result of the work of many people who made the code better
- Christophe L. (christophelau) - Christophe L. (christophelau)
- Anthon Pang (robocoder) - Anthon Pang (robocoder)
- Emanuele Gaspari (inmarelibero) - Emanuele Gaspari (inmarelibero)
- Dariusz Rumiński
- Sébastien Santoro (dereckson) - Sébastien Santoro (dereckson)
- Brian King - Brian King
- Michel Salib (michelsalib) - Michel Salib (michelsalib)
@ -402,6 +403,7 @@ Symfony is the result of the work of many people who made the code better
- Jan Rosier (rosier) - Jan Rosier (rosier)
- Thomas Royer (cydonia7) - Thomas Royer (cydonia7)
- Josip Kruslin - Josip Kruslin
- Asmir Mustafic (goetas)
- vagrant - vagrant
- EdgarPE - EdgarPE
- Florian Pfitzer (marmelatze) - Florian Pfitzer (marmelatze)
@ -420,7 +422,6 @@ Symfony is the result of the work of many people who made the code better
- Marcin Sikoń (marphi) - Marcin Sikoń (marphi)
- Dominik Zogg (dominik.zogg) - Dominik Zogg (dominik.zogg)
- Marek Pietrzak - Marek Pietrzak
- Chad Sikorra (chadsikorra)
- franek (franek) - franek (franek)
- Christian Wahler - Christian Wahler
- Gintautas Miselis - Gintautas Miselis
@ -544,7 +545,6 @@ Symfony is the result of the work of many people who made the code better
- Andre Rømcke (andrerom) - Andre Rømcke (andrerom)
- Nahuel Cuesta (ncuesta) - Nahuel Cuesta (ncuesta)
- Chris Boden (cboden) - Chris Boden (cboden)
- Asmir Mustafic (goetas)
- Stefan Gehrig (sgehrig) - Stefan Gehrig (sgehrig)
- Hany el-Kerdany - Hany el-Kerdany
- Wang Jingyu - Wang Jingyu
@ -582,6 +582,7 @@ Symfony is the result of the work of many people who made the code better
- Sergey Kolodyazhnyy (skolodyazhnyy) - Sergey Kolodyazhnyy (skolodyazhnyy)
- umpirski - umpirski
- Denis Brumann (dbrumann) - Denis Brumann (dbrumann)
- Michael Babker (mbabker)
- Quentin de Longraye (quentinus95) - Quentin de Longraye (quentinus95)
- Chris Heng (gigablah) - Chris Heng (gigablah)
- Richard Bradley - Richard Bradley
@ -629,6 +630,7 @@ Symfony is the result of the work of many people who made the code better
- twifty - twifty
- Indra Gunawan (guind) - Indra Gunawan (guind)
- Peter Ward - Peter Ward
- insekticid
- Julien DIDIER (juliendidier) - Julien DIDIER (juliendidier)
- Dominik Ritter (dritter) - Dominik Ritter (dritter)
- Sebastian Grodzicki (sgrodzicki) - Sebastian Grodzicki (sgrodzicki)
@ -745,6 +747,7 @@ Symfony is the result of the work of many people who made the code better
- Jan Kramer (jankramer) - Jan Kramer (jankramer)
- abdul malik ikhsan (samsonasik) - abdul malik ikhsan (samsonasik)
- Henry Snoek (snoek09) - Henry Snoek (snoek09)
- Jérémy M (th3mouk)
- Simone Di Maulo (toretto460) - Simone Di Maulo (toretto460)
- Christian Morgan - Christian Morgan
- Alexander Miehe (engerim) - Alexander Miehe (engerim)
@ -761,6 +764,7 @@ Symfony is the result of the work of many people who made the code better
- Douglas Reith (douglas_reith) - Douglas Reith (douglas_reith)
- Harry Walter (haswalt) - Harry Walter (haswalt)
- Johnson Page (jwpage) - Johnson Page (jwpage)
- Ruben Gonzalez (rubenruateltek)
- Michael Roterman (wtfzdotnet) - Michael Roterman (wtfzdotnet)
- Arno Geurts - Arno Geurts
- Adán Lobato (adanlobato) - Adán Lobato (adanlobato)
@ -886,6 +890,7 @@ Symfony is the result of the work of many people who made the code better
- Eddie Jaoude - Eddie Jaoude
- Antanas Arvasevicius - Antanas Arvasevicius
- Haritz Iturbe (hizai) - Haritz Iturbe (hizai)
- Baptiste Meyer (meyerbaptiste)
- Nerijus Arlauskas (nercury) - Nerijus Arlauskas (nercury)
- SPolischook - SPolischook
- Diego Sapriza - Diego Sapriza
@ -914,6 +919,7 @@ Symfony is the result of the work of many people who made the code better
- Jeremy Bush - Jeremy Bush
- wizhippo - wizhippo
- Viacheslav Sychov - Viacheslav Sychov
- Tyson Andre
- Carlos Ortega Huetos - Carlos Ortega Huetos
- rpg600 - rpg600
- Péter Buri (burci) - Péter Buri (burci)
@ -1014,6 +1020,7 @@ Symfony is the result of the work of many people who made the code better
- Conrad Kleinespel - Conrad Kleinespel
- Sebastian Utz - Sebastian Utz
- Adrien Gallou (agallou) - Adrien Gallou (agallou)
- Maks Rafalko (bornfree)
- Karol Sójko (karolsojko) - Karol Sójko (karolsojko)
- Grzegorz Zdanowski (kiler129) - Grzegorz Zdanowski (kiler129)
- sl_toto (sl_toto) - sl_toto (sl_toto)
@ -1048,7 +1055,6 @@ Symfony is the result of the work of many people who made the code better
- Kim Laï Trinh - Kim Laï Trinh
- Jason Desrosiers - Jason Desrosiers
- m.chwedziak - m.chwedziak
- insekticid
- Philip Frank - Philip Frank
- Lance McNearney - Lance McNearney
- Giorgio Premi - Giorgio Premi
@ -1058,6 +1064,7 @@ Symfony is the result of the work of many people who made the code better
- Alberto Pirovano (geezmo) - Alberto Pirovano (geezmo)
- Pete Mitchell (peterjmit) - Pete Mitchell (peterjmit)
- Tom Corrigan (tomcorrigan) - Tom Corrigan (tomcorrigan)
- adev
- Luis Galeas - Luis Galeas
- Martin Pärtel - Martin Pärtel
- George Mponos (gmponos) - George Mponos (gmponos)
@ -1226,6 +1233,7 @@ Symfony is the result of the work of many people who made the code better
- Romain Dorgueil - Romain Dorgueil
- Grayson Koonce (breerly) - Grayson Koonce (breerly)
- Fabien LUCAS (flucas2) - Fabien LUCAS (flucas2)
- Indra Gunawan (indragunawan)
- Karim Cassam Chenaï (ka) - Karim Cassam Chenaï (ka)
- Nicolas Bastien (nicolas_bastien) - Nicolas Bastien (nicolas_bastien)
- Denis (yethee) - Denis (yethee)
@ -1273,6 +1281,7 @@ Symfony is the result of the work of many people who made the code better
- Daan van Renterghem - Daan van Renterghem
- Nicole Cordes - Nicole Cordes
- Bram Van der Sype (brammm) - Bram Van der Sype (brammm)
- Christopher Hertel (chertel)
- Guile (guile) - Guile (guile)
- Julien Moulin (lizjulien) - Julien Moulin (lizjulien)
- Mauro Foti (skler) - Mauro Foti (skler)
@ -1291,6 +1300,7 @@ Symfony is the result of the work of many people who made the code better
- Johann Pardanaud - Johann Pardanaud
- Trevor Suarez - Trevor Suarez
- gedrox - gedrox
- Alan Bondarchuk
- dropfen - dropfen
- Andrey Chernykh - Andrey Chernykh
- Edvinas Klovas - Edvinas Klovas
@ -1303,6 +1313,7 @@ Symfony is the result of the work of many people who made the code better
- bertillon - bertillon
- Bertalan Attila - Bertalan Attila
- Yannick Bensacq (cibou) - Yannick Bensacq (cibou)
- Gawain Lynch (gawain)
- Luca Genuzio (genuzio) - Luca Genuzio (genuzio)
- Hans Nilsson (hansnilsson) - Hans Nilsson (hansnilsson)
- Andrew Marcinkevičius (ifdattic) - Andrew Marcinkevičius (ifdattic)
@ -1312,7 +1323,6 @@ Symfony is the result of the work of many people who made the code better
- Dan Patrick (mdpatrick) - Dan Patrick (mdpatrick)
- Rares Vlaseanu (raresvla) - Rares Vlaseanu (raresvla)
- tante kinast (tante) - tante kinast (tante)
- Jérémy M (th3mouk)
- Vincent LEFORT (vlefort) - Vincent LEFORT (vlefort)
- Sadicov Vladimir (xtech) - Sadicov Vladimir (xtech)
- Kevin EMO (zarcox) - Kevin EMO (zarcox)
@ -1336,7 +1346,6 @@ Symfony is the result of the work of many people who made the code better
- Jonny Schmid (schmidjon) - Jonny Schmid (schmidjon)
- Götz Gottwald - Götz Gottwald
- Veres Lajos - Veres Lajos
- Michael Babker
- grifx - grifx
- Robert Campbell - Robert Campbell
- Matt Lehner - Matt Lehner
@ -1415,9 +1424,11 @@ Symfony is the result of the work of many people who made the code better
- Yanick Witschi - Yanick Witschi
- Ondrej Mirtes - Ondrej Mirtes
- akimsko - akimsko
- Ben Scott
- Youpie - Youpie
- srsbiz - srsbiz
- Taylan Kasap - Taylan Kasap
- Michael Orlitzky
- Nicolas A. Bérard-Nault - Nicolas A. Bérard-Nault
- Saem Ghani - Saem Ghani
- Stefan Oderbolz - Stefan Oderbolz
@ -1430,6 +1441,7 @@ Symfony is the result of the work of many people who made the code better
- Ben - Ben
- Evgeniy Tetenchuk - Evgeniy Tetenchuk
- dasmfm - dasmfm
- Mathias Geat
- Arnaud Buathier (arnapou) - Arnaud Buathier (arnapou)
- chesteroni (chesteroni) - chesteroni (chesteroni)
- Mauricio Lopez (diaspar) - Mauricio Lopez (diaspar)
@ -1516,6 +1528,7 @@ Symfony is the result of the work of many people who made the code better
- Abdulkadir N. A. - Abdulkadir N. A.
- Yevgen Kovalienia - Yevgen Kovalienia
- Lebnik - Lebnik
- Ondřej Führer
- Sema - Sema
- Elan Ruusamäe - Elan Ruusamäe
- Thorsten Hallwas - Thorsten Hallwas
@ -1568,6 +1581,7 @@ Symfony is the result of the work of many people who made the code better
- Bill Hance (billhance) - Bill Hance (billhance)
- Bernd Matzner (bmatzner) - Bernd Matzner (bmatzner)
- Bram Tweedegolf (bram_tweedegolf) - Bram Tweedegolf (bram_tweedegolf)
- Brandon Kelly (brandonkelly)
- Choong Wei Tjeng (choonge) - Choong Wei Tjeng (choonge)
- Kousuke Ebihara (co3k) - Kousuke Ebihara (co3k)
- Loïc Vernet (coil) - Loïc Vernet (coil)
@ -1675,6 +1689,7 @@ Symfony is the result of the work of many people who made the code better
- Andrew Carter (andrewcarteruk) - Andrew Carter (andrewcarteruk)
- Adam Elsodaney (archfizz) - Adam Elsodaney (archfizz)
- Daniel Kolvik (dkvk) - Daniel Kolvik (dkvk)
- Marc Lemay (flug)
- Jeroen De Dauw (jeroendedauw) - Jeroen De Dauw (jeroendedauw)
- Maxime COLIN (maximecolin) - Maxime COLIN (maximecolin)
- Muharrem Demirci (mdemirci) - Muharrem Demirci (mdemirci)

View File

@ -7,7 +7,7 @@ if (!file_exists(__DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit')) {
echo "Unable to find the `simple-phpunit` script in `vendor/symfony/phpunit-bridge/bin/`.\nPlease run `composer update` before running this command.\n"; echo "Unable to find the `simple-phpunit` script in `vendor/symfony/phpunit-bridge/bin/`.\nPlease run `composer update` before running this command.\n";
exit(1); exit(1);
} }
if (PHP_VERSION_ID >= 70000 && !getenv('SYMFONY_PHPUNIT_VERSION')) { if (\PHP_VERSION_ID >= 70000 && !getenv('SYMFONY_PHPUNIT_VERSION')) {
putenv('SYMFONY_PHPUNIT_VERSION=6.0'); putenv('SYMFONY_PHPUNIT_VERSION=6.0');
} }
putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit'); putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit');

View File

@ -156,14 +156,20 @@ EOF
throw new \UnexpectedValueException('Unsupported callback type'); throw new \UnexpectedValueException('Unsupported callback type');
} }
// filter out context/environment args $args = $refl->getParameters();
$args = array_filter($refl->getParameters(), function ($param) use ($entity) {
if ($entity->needsContext() && $param->getName() === 'context') {
return false;
}
return !$param->getClass() || $param->getClass()->getName() !== 'Twig_Environment'; // filter out context/environment args
}); if ($entity->needsEnvironment()) {
array_shift($args);
}
if ($entity->needsContext()) {
array_shift($args);
}
if ($type === 'filters') {
// remove the value the filter is applied on
array_shift($args);
}
// format args // format args
$args = array_map(function ($param) { $args = array_map(function ($param) {
@ -174,11 +180,6 @@ EOF
return $param->getName(); return $param->getName();
}, $args); }, $args);
if ($type === 'filters') {
// remove the value the filter is applied on
array_shift($args);
}
return $args; return $args;
} }
} }

View File

@ -113,7 +113,7 @@ if ($this->env->isDebug()) {
EOTXT; EOTXT;
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
$expected = preg_replace('/%(.*?)%/', '($context["$1"] ?? null)', $expected); $expected = preg_replace('/%(.*?)%/', '($context["$1"] ?? null)', $expected);
} else { } else {
$expected = preg_replace('/%(.*?)%/', '(isset($context["$1"]) ? $context["$1"] : null)', $expected); $expected = preg_replace('/%(.*?)%/', '(isset($context["$1"]) ? $context["$1"] : null)', $expected);

View File

@ -67,7 +67,7 @@ class FormThemeTest extends TestCase
protected function getVariableGetter($name) protected function getVariableGetter($name)
{ {
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
return sprintf('($context["%s"] ?? null)', $name, $name); return sprintf('($context["%s"] ?? null)', $name, $name);
} }

View File

@ -264,7 +264,7 @@ class SearchAndRenderBlockNodeTest extends TestCase
protected function getVariableGetter($name) protected function getVariableGetter($name)
{ {
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
return sprintf('($context["%s"] ?? null)', $name, $name); return sprintf('($context["%s"] ?? null)', $name, $name);
} }

View File

@ -40,7 +40,7 @@ class TransNodeTest extends TestCase
protected function getVariableGetterWithoutStrictCheck($name) protected function getVariableGetterWithoutStrictCheck($name)
{ {
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
return sprintf('($context["%s"] ?? null)', $name, $name); return sprintf('($context["%s"] ?? null)', $name, $name);
} }
@ -53,7 +53,7 @@ class TransNodeTest extends TestCase
return sprintf('(isset($context["%s"]) || array_key_exists("%s", $context) ? $context["%s"] : (function () { throw new Twig_Error_Runtime(\'Variable "%s" does not exist.\', 0, $this->getSourceContext()); })())', $name, $name, $name, $name); return sprintf('(isset($context["%s"]) || array_key_exists("%s", $context) ? $context["%s"] : (function () { throw new Twig_Error_Runtime(\'Variable "%s" does not exist.\', 0, $this->getSourceContext()); })())', $name, $name, $name, $name);
} }
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
return sprintf('($context["%s"] ?? $this->getContext($context, "%s"))', $name, $name, $name); return sprintf('($context["%s"] ?? $this->getContext($context, "%s"))', $name, $name, $name);
} }

View File

@ -11,9 +11,12 @@
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
use Symfony\Component\Cache\Adapter\TraceableAdapter; use Symfony\Component\Cache\Adapter\TraceableAdapter;
use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
/** /**
@ -34,17 +37,30 @@ class CacheCollectorPass implements CompilerPassInterface
$collectorDefinition = $container->getDefinition('data_collector.cache'); $collectorDefinition = $container->getDefinition('data_collector.cache');
foreach ($container->findTaggedServiceIds('cache.pool') as $id => $attributes) { foreach ($container->findTaggedServiceIds('cache.pool') as $id => $attributes) {
if ($container->getDefinition($id)->isAbstract()) { $definition = $container->getDefinition($id);
if ($definition->isAbstract()) {
continue; continue;
} }
$container->register($id.'.recorder', TraceableAdapter::class) $recorder = new Definition(is_subclass_of($definition->getClass(), TagAwareAdapterInterface::class) ? TraceableTagAwareAdapter::class : TraceableAdapter::class);
->setDecoratedService($id) $recorder->setTags($definition->getTags());
->addArgument(new Reference($id.'.recorder.inner')) $recorder->setPublic($definition->isPublic());
->setPublic(false); $recorder->setArguments(array(new Reference($innerId = $id.'.recorder_inner')));
$definition->setTags(array());
$definition->setPublic(false);
if ($types = $definition->getAutowiringTypes(false)) {
$recorder->setAutowiringTypes($types);
$definition->setAutowiringTypes(array());
}
$container->setDefinition($innerId, $definition);
$container->setDefinition($id, $recorder);
// Tell the collector to add the new instance // Tell the collector to add the new instance
$collectorDefinition->addMethodCall('addInstance', array($id, new Reference($id))); $collectorDefinition->addMethodCall('addInstance', array($id, new Reference($id)));
$collectorDefinition->setPublic(false);
} }
} }
} }

View File

@ -115,7 +115,7 @@ class FrameworkBundle extends Bundle
$container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_BEFORE_REMOVING, -255); $container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_BEFORE_REMOVING, -255);
$this->addCompilerPassIfExists($container, ConfigCachePass::class); $this->addCompilerPassIfExists($container, ConfigCachePass::class);
$container->addCompilerPass(new CacheCollectorPass()); $container->addCompilerPass(new CacheCollectorPass(), PassConfig::TYPE_BEFORE_REMOVING);
} }
} }

View File

@ -7,8 +7,8 @@
<services> <services>
<defaults public="false" /> <defaults public="false" />
<!-- DataCollector --> <!-- DataCollector (public to prevent inlining, made private in CacheCollectorPass) -->
<service id="data_collector.cache" class="Symfony\Component\Cache\DataCollector\CacheDataCollector"> <service id="data_collector.cache" class="Symfony\Component\Cache\DataCollector\CacheDataCollector" public="true">
<tag name="data_collector" template="@WebProfiler/Collector/cache.html.twig" id="cache" priority="275" /> <tag name="data_collector" template="@WebProfiler/Collector/cache.html.twig" id="cache" priority="275" />
</service> </service>
</services> </services>

View File

@ -0,0 +1,49 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CacheCollectorPass;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Symfony\Component\Cache\Adapter\TraceableAdapter;
use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;
use Symfony\Component\Cache\DataCollector\CacheDataCollector;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class CacheCollectorPassTest extends TestCase
{
public function testProcess()
{
$container = new ContainerBuilder();
$container
->register('fs', FilesystemAdapter::class)
->addTag('cache.pool');
$container
->register('tagged_fs', TagAwareAdapter::class)
->addArgument(new Reference('fs'))
->addTag('cache.pool');
$collector = $container->register('data_collector.cache', CacheDataCollector::class);
(new CacheCollectorPass())->process($container);
$this->assertEquals(array(
array('addInstance', array('fs', new Reference('fs'))),
array('addInstance', array('tagged_fs', new Reference('tagged_fs'))),
), $collector->getMethodCalls());
$this->assertSame(TraceableAdapter::class, $container->findDefinition('fs')->getClass());
$this->assertSame(TraceableTagAwareAdapter::class, $container->getDefinition('tagged_fs')->getClass());
$this->assertFalse($collector->isPublic(), 'The "data_collector.cache" should be private after processing');
}
}

View File

@ -85,7 +85,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
foreach ($files as $file) { foreach ($files as $file) {
$this->parseTokens(token_get_all(file_get_contents($file)), $catalog); $this->parseTokens(token_get_all(file_get_contents($file)), $catalog);
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches(); gc_mem_caches();
} }

View File

@ -478,6 +478,11 @@
addEventListener(toggles[i], 'click', function(e) { addEventListener(toggles[i], 'click', function(e) {
e.preventDefault(); e.preventDefault();
if ('' !== window.getSelection().toString()) {
/* Don't do anything on text selection */
return;
}
var toggle = e.target || e.srcElement; var toggle = e.target || e.srcElement;
/* needed because when the toggle contains HTML contents, user can click */ /* needed because when the toggle contains HTML contents, user can click */
@ -507,6 +512,14 @@
var altContent = toggle.getAttribute('data-toggle-alt-content'); var altContent = toggle.getAttribute('data-toggle-alt-content');
toggle.innerHTML = currentContent !== altContent ? altContent : originalContent; toggle.innerHTML = currentContent !== altContent ? altContent : originalContent;
}); });
/* Prevents from disallowing clicks on links inside toggles */
var toggleLinks = document.querySelectorAll('.sf-toggle a');
for (var i = 0; i < toggleLinks.length; i++) {
addEventListener(toggleLinks[i], 'click', function(e) {
e.stopPropagation();
});
}
} }
} }
}; };

View File

@ -89,7 +89,6 @@ header .container { display: flex; justify-content: space-between; }
.exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; } .exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; }
.trace + .trace { margin-top: 30px; } .trace + .trace { margin-top: 30px; }
.trace-head { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
.trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; } .trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; }
.trace-head .trace-namespace { color: #999; display: block; font-size: 13px; } .trace-head .trace-namespace { color: #999; display: block; font-size: 13px; }
.trace-head .icon { position: absolute; right: 0; top: 0; } .trace-head .icon { position: absolute; right: 0; top: 0; }

View File

@ -478,6 +478,11 @@
addEventListener(toggles[i], 'click', function(e) { addEventListener(toggles[i], 'click', function(e) {
e.preventDefault(); e.preventDefault();
if ('' !== window.getSelection().toString()) {
/* Don't do anything on text selection */
return;
}
var toggle = e.target || e.srcElement; var toggle = e.target || e.srcElement;
/* needed because when the toggle contains HTML contents, user can click */ /* needed because when the toggle contains HTML contents, user can click */
@ -508,6 +513,14 @@
toggle.innerHTML = currentContent !== altContent ? altContent : originalContent; toggle.innerHTML = currentContent !== altContent ? altContent : originalContent;
}); });
} }
/* Prevents from disallowing clicks on links inside toggles */
var toggleLinks = document.querySelectorAll('.sf-toggle a');
for (var i = 0; i < toggleLinks.length; i++) {
addEventListener(toggleLinks[i], 'click', function(e) {
e.stopPropagation();
});
}
} }
}; };
})(); })();

View File

@ -22,7 +22,7 @@ use Psr\Cache\CacheItemInterface;
*/ */
class TraceableAdapter implements AdapterInterface class TraceableAdapter implements AdapterInterface
{ {
private $pool; protected $pool;
private $calls = array(); private $calls = array();
public function __construct(AdapterInterface $pool) public function __construct(AdapterInterface $pool)
@ -107,7 +107,7 @@ class TraceableAdapter implements AdapterInterface
*/ */
public function getItems(array $keys = array()) public function getItems(array $keys = array())
{ {
$event = $this->start(__FUNCTION__, $keys); $event = $this->start(__FUNCTION__);
try { try {
$result = $this->pool->getItems($keys); $result = $this->pool->getItems($keys);
} finally { } finally {
@ -177,7 +177,7 @@ class TraceableAdapter implements AdapterInterface
} }
} }
private function start($name) protected function start($name)
{ {
$this->calls[] = $event = new TraceableAdapterEvent(); $this->calls[] = $event = new TraceableAdapterEvent();
$event->name = $name; $event->name = $name;

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
/**
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface
{
public function __construct(TagAwareAdapterInterface $pool)
{
parent::__construct($pool);
}
/**
* {@inheritdoc}
*/
public function invalidateTags(array $tags)
{
$event = $this->start(__FUNCTION__);
try {
return $event->result = $this->pool->invalidateTags($tags);
} finally {
$event->end = microtime(true);
}
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;
class TraceableTagAwareAdapterTest extends TraceableAdapterTest
{
public function testInvalidateTags()
{
$pool = new TraceableTagAwareAdapter(new TagAwareAdapter(new FilesystemAdapter()));
$pool->invalidateTags(array('foo'));
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('invalidateTags', $call->name);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
}

View File

@ -126,6 +126,6 @@ EOF;
*/ */
private function initialize() private function initialize()
{ {
$this->values = @(include $this->file) ?: array(); $this->values = file_exists($this->file) ? (include $this->file ?: array()) : array();
} }
} }

View File

@ -262,7 +262,7 @@ REGEX;
$output .= self::compressCode($rawChunk); $output .= self::compressCode($rawChunk);
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
unset($tokens, $rawChunk); unset($tokens, $rawChunk);
gc_mem_caches(); gc_mem_caches();

View File

@ -68,7 +68,7 @@ class ClassMapGenerator
$classes = self::findClasses($path); $classes = self::findClasses($path);
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches(); gc_mem_caches();
} }

View File

@ -83,13 +83,18 @@ abstract class FileLoader extends Loader
*/ */
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null) public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
{ {
if (is_string($resource) && false !== strpbrk($resource, '*?{[')) { if (is_string($resource) && strlen($resource) !== $i = strcspn($resource, '*?{[')) {
$ret = array(); $ret = array();
foreach ($this->glob($resource, false, $_, true) as $path => $info) { $isSubpath = 0 !== $i && false !== strpos(substr($resource, 0, $i), '/');
$ret[] = $this->doImport($path, $type, $ignoreErrors, $sourceResource); foreach ($this->glob($resource, false, $_, $ignoreErrors || !$isSubpath) as $path => $info) {
if (null !== $res = $this->doImport($path, $type, $ignoreErrors, $sourceResource)) {
$ret[] = $res;
}
$isSubpath = true;
} }
if ($ret) {
return count($ret) > 1 ? $ret : $ret[0]; if ($isSubpath) {
return isset($ret[1]) ? $ret : (isset($ret[0]) ? $ret[0] : null);
} }
} }
@ -104,7 +109,7 @@ abstract class FileLoader extends Loader
if (strlen($pattern) === $i = strcspn($pattern, '*?{[')) { if (strlen($pattern) === $i = strcspn($pattern, '*?{[')) {
$prefix = $pattern; $prefix = $pattern;
$pattern = ''; $pattern = '';
} elseif (0 === $i) { } elseif (0 === $i || false === strpos(substr($pattern, 0, $i), '/')) {
$prefix = '.'; $prefix = '.';
$pattern = '/'.$pattern; $pattern = '/'.$pattern;
} else { } else {

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Config\Tests\Loader; namespace Symfony\Component\Config\Tests\Loader;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\FileLoader; use Symfony\Component\Config\Loader\FileLoader;
use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\Config\Loader\LoaderResolver;
@ -74,6 +75,21 @@ class FileLoaderTest extends TestCase
$this->assertSame('[foo]', $loader->import('[foo]')); $this->assertSame('[foo]', $loader->import('[foo]'));
} }
public function testImportWithNoGlobMatch()
{
$locatorMock = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock();
$loader = new TestFileLoader($locatorMock);
$this->assertNull($loader->import('./*.abc'));
}
public function testImportWithSimpleGlob()
{
$loader = new TestFileLoader(new FileLocator(__DIR__));
$this->assertSame(__FILE__, strtr($loader->import('FileLoaderTest.*'), '/', DIRECTORY_SEPARATOR));
}
} }
class TestFileLoader extends FileLoader class TestFileLoader extends FileLoader

View File

@ -316,7 +316,6 @@ EOF;
.exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; } .exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; }
.trace + .trace { margin-top: 30px; } .trace + .trace { margin-top: 30px; }
.trace-head { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
.trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; } .trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; }
.trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; } .trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; }

View File

@ -61,7 +61,7 @@ class DebugClassLoaderTest extends TestCase
public function testUnsilencing() public function testUnsilencing()
{ {
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
$this->markTestSkipped('PHP7 throws exceptions, unsilencing is not required anymore.'); $this->markTestSkipped('PHP7 throws exceptions, unsilencing is not required anymore.');
} }
if (defined('HHVM_VERSION')) { if (defined('HHVM_VERSION')) {
@ -109,7 +109,7 @@ class DebugClassLoaderTest extends TestCase
} catch (\ErrorException $exception) { } catch (\ErrorException $exception) {
// if an exception is thrown, the test passed // if an exception is thrown, the test passed
$this->assertStringStartsWith(__FILE__, $exception->getFile()); $this->assertStringStartsWith(__FILE__, $exception->getFile());
if (PHP_VERSION_ID < 70000) { if (\PHP_VERSION_ID < 70000) {
$this->assertRegExp('/^Runtime Notice: Declaration/', $exception->getMessage()); $this->assertRegExp('/^Runtime Notice: Declaration/', $exception->getMessage());
$this->assertEquals(E_STRICT, $exception->getSeverity()); $this->assertEquals(E_STRICT, $exception->getSeverity());
} else { } else {
@ -245,7 +245,7 @@ class DebugClassLoaderTest extends TestCase
public function testReservedForPhp7() public function testReservedForPhp7()
{ {
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
$this->markTestSkipped('PHP7 already prevents using reserved names.'); $this->markTestSkipped('PHP7 already prevents using reserved names.');
} }

View File

@ -44,9 +44,27 @@ class AutowireExceptionPass implements CompilerPassInterface
$this->inlineServicePass = null; $this->inlineServicePass = null;
foreach ($exceptions as $exception) { foreach ($exceptions as $exception) {
if ($container->hasDefinition($exception->getServiceId()) || in_array($exception->getServiceId(), $inlinedIds)) { if ($this->doesServiceExistInTheContainer($exception->getServiceId(), $container, $inlinedIds)) {
throw $exception; throw $exception;
} }
} }
} }
private function doesServiceExistInTheContainer($serviceId, ContainerBuilder $container, array $inlinedIds)
{
if ($container->hasDefinition($serviceId)) {
return true;
}
// was the service inlined? Of so, does its parent service exist?
if (isset($inlinedIds[$serviceId])) {
foreach ($inlinedIds[$serviceId] as $parentId) {
if ($this->doesServiceExistInTheContainer($parentId, $container, $inlinedIds)) {
return true;
}
}
}
return false;
}
} }

View File

@ -114,7 +114,7 @@ class AutowirePass extends AbstractRecursivePass
private function doProcessValue($value, $isRoot = false) private function doProcessValue($value, $isRoot = false)
{ {
if ($value instanceof TypedReference) { if ($value instanceof TypedReference) {
if ($ref = $this->getAutowiredReference($value)) { if ($ref = $this->getAutowiredReference($value, $value->getRequiringClass() ? sprintf('for "%s" in "%s"', $value->getType(), $value->getRequiringClass()) : '')) {
return $ref; return $ref;
} }
$this->container->log($this, $this->createTypeNotFoundMessage($value, 'it')); $this->container->log($this, $this->createTypeNotFoundMessage($value, 'it'));
@ -133,7 +133,13 @@ class AutowirePass extends AbstractRecursivePass
$autowiredMethods = $this->getMethodsToAutowire($reflectionClass); $autowiredMethods = $this->getMethodsToAutowire($reflectionClass);
$methodCalls = $value->getMethodCalls(); $methodCalls = $value->getMethodCalls();
if ($constructor = $this->getConstructor($value, false)) { try {
$constructor = $this->getConstructor($value, false);
} catch (RuntimeException $e) {
throw new AutowiringFailedException($this->currentId, $e->getMessage(), 0, $e);
}
if ($constructor) {
array_unshift($methodCalls, array($constructor, $value->getArguments())); array_unshift($methodCalls, array($constructor, $value->getArguments()));
} }
@ -242,7 +248,7 @@ class AutowirePass extends AbstractRecursivePass
* *
* @return array The autowired arguments * @return array The autowired arguments
* *
* @throws RuntimeException * @throws AutowiringFailedException
*/ */
private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments) private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments)
{ {
@ -276,7 +282,7 @@ class AutowirePass extends AbstractRecursivePass
continue; continue;
} }
if (!$value = $this->getAutowiredReference($ref = new TypedReference($type, $type, !$parameter->isOptional() ? $class : ''))) { if (!$value = $this->getAutowiredReference($ref = new TypedReference($type, $type, !$parameter->isOptional() ? $class : ''), 'for '.sprintf('argument "$%s" of method "%s()"', $parameter->name, $class.'::'.$method))) {
$failureMessage = $this->createTypeNotFoundMessage($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); $failureMessage = $this->createTypeNotFoundMessage($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
if ($parameter->isDefaultValueAvailable()) { if ($parameter->isDefaultValueAvailable()) {
@ -310,7 +316,7 @@ class AutowirePass extends AbstractRecursivePass
/** /**
* @return TypedReference|null A reference to the service matching the given type, if any * @return TypedReference|null A reference to the service matching the given type, if any
*/ */
private function getAutowiredReference(TypedReference $reference) private function getAutowiredReference(TypedReference $reference, $deprecationMessage)
{ {
$this->lastFailure = null; $this->lastFailure = null;
$type = $reference->getType(); $type = $reference->getType();
@ -328,7 +334,14 @@ class AutowirePass extends AbstractRecursivePass
} }
if (isset($this->types[$type])) { if (isset($this->types[$type])) {
@trigger_error(sprintf('Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won\'t be supported in version 4.0. You should %s the "%s" service to "%s" instead.', isset($this->types[$this->types[$type]]) ? 'alias' : 'rename (or alias)', $this->types[$type], $type), E_USER_DEPRECATED); $message = 'Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won\'t be supported in version 4.0.';
if ($aliasSuggestion = $this->getAliasesSuggestionForType($type = $reference->getType(), $deprecationMessage)) {
$message .= ' '.$aliasSuggestion;
} else {
$message .= sprintf(' You should %s the "%s" service to "%s" instead.', isset($this->types[$this->types[$type]]) ? 'alias' : 'rename (or alias)', $this->types[$type], $type);
}
@trigger_error($message, E_USER_DEPRECATED);
return new TypedReference($this->types[$type], $type); return new TypedReference($this->types[$type], $type);
} }
@ -484,25 +497,9 @@ class AutowirePass extends AbstractRecursivePass
private function createTypeAlternatives(TypedReference $reference) private function createTypeAlternatives(TypedReference $reference)
{ {
$type = $reference->getType(); // try suggesting available aliases first
$aliases = array(); if ($message = $this->getAliasesSuggestionForType($type = $reference->getType())) {
foreach (class_parents($type) + class_implements($type) as $parent) { return ' '.$message;
if ($this->container->has($parent) && !$this->container->findDefinition($parent)->isAbstract()) {
$aliases[] = $parent;
}
}
if (1 < $len = count($aliases)) {
$message = ' Try changing the type-hint to one of its parents: ';
for ($i = 0, --$len; $i < $len; ++$i) {
$message .= sprintf('%s "%s", ', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
}
$message .= sprintf('or %s "%s".', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
return $message;
}
if ($aliases) {
return sprintf(' Try changing the type-hint to "%s" instead.', $aliases[0]);
} }
if (isset($this->ambiguousServiceTypes[$type])) { if (isset($this->ambiguousServiceTypes[$type])) {
@ -542,4 +539,29 @@ class AutowirePass extends AbstractRecursivePass
return $methodArgumentsMetadata; return $methodArgumentsMetadata;
} }
private function getAliasesSuggestionForType($type, $extraContext = null)
{
$aliases = array();
foreach (class_parents($type) + class_implements($type) as $parent) {
if ($this->container->has($parent) && !$this->container->findDefinition($parent)->isAbstract()) {
$aliases[] = $parent;
}
}
$extraContext = $extraContext ? ' '.$extraContext : '';
if (1 < $len = count($aliases)) {
$message = sprintf('Try changing the type-hint%s to one of its parents: ', $extraContext);
for ($i = 0, --$len; $i < $len; ++$i) {
$message .= sprintf('%s "%s", ', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
}
$message .= sprintf('or %s "%s".', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
return $message;
}
if ($aliases) {
return sprintf('Try changing the type-hint%s to "%s" instead.', $extraContext, $aliases[0]);
}
}
} }

View File

@ -36,7 +36,9 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe
/** /**
* Returns an array of all services inlined by this pass. * Returns an array of all services inlined by this pass.
* *
* @return array Service id strings * The key is the inlined service id and its value is the list of services it was inlined into.
*
* @return array
*/ */
public function getInlinedServiceIds() public function getInlinedServiceIds()
{ {
@ -57,7 +59,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe
if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) { if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
$this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId)); $this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
$this->inlinedServiceIds[] = $id; $this->inlinedServiceIds[$id][] = $this->currentId;
if ($definition->isShared()) { if ($definition->isShared()) {
return $definition; return $definition;

View File

@ -18,7 +18,7 @@ class AutowiringFailedException extends RuntimeException
{ {
private $serviceId; private $serviceId;
public function __construct($serviceId, $message = '', $code = 0, Exception $previous = null) public function __construct($serviceId, $message = '', $code = 0, \Exception $previous = null)
{ {
$this->serviceId = $serviceId; $this->serviceId = $serviceId;

View File

@ -54,7 +54,7 @@ class AutowireExceptionPassTest extends TestCase
$autowirePass = $this->getMockBuilder(AutowirePass::class) $autowirePass = $this->getMockBuilder(AutowirePass::class)
->getMock(); ->getMock();
$autowireException = new AutowiringFailedException('foo_service_id', 'An autowiring exception message'); $autowireException = new AutowiringFailedException('a_service', 'An autowiring exception message');
$autowirePass->expects($this->any()) $autowirePass->expects($this->any())
->method('getAutowiringExceptions') ->method('getAutowiringExceptions')
->will($this->returnValue(array($autowireException))); ->will($this->returnValue(array($autowireException)));
@ -63,10 +63,16 @@ class AutowireExceptionPassTest extends TestCase
->getMock(); ->getMock();
$inlinePass->expects($this->any()) $inlinePass->expects($this->any())
->method('getInlinedServiceIds') ->method('getInlinedServiceIds')
->will($this->returnValue(array('foo_service_id'))); ->will($this->returnValue(array(
// a_service inlined into b_service
'a_service' => array('b_service'),
// b_service inlined into c_service
'b_service' => array('c_service'),
)));
// don't register the foo_service_id service
$container = new ContainerBuilder(); $container = new ContainerBuilder();
// ONLY register c_service in the final container
$container->register('c_service', 'stdClass');
$pass = new AutowireExceptionPass($autowirePass, $inlinePass); $pass = new AutowireExceptionPass($autowirePass, $inlinePass);
@ -78,6 +84,37 @@ class AutowireExceptionPassTest extends TestCase
} }
} }
public function testDoNotThrowExceptionIfServiceInlinedButRemoved()
{
$autowirePass = $this->getMockBuilder(AutowirePass::class)
->getMock();
$autowireException = new AutowiringFailedException('a_service', 'An autowiring exception message');
$autowirePass->expects($this->any())
->method('getAutowiringExceptions')
->will($this->returnValue(array($autowireException)));
$inlinePass = $this->getMockBuilder(InlineServiceDefinitionsPass::class)
->getMock();
$inlinePass->expects($this->any())
->method('getInlinedServiceIds')
->will($this->returnValue(array(
// a_service inlined into b_service
'a_service' => array('b_service'),
// b_service inlined into c_service
'b_service' => array('c_service'),
)));
// do NOT register c_service in the container
$container = new ContainerBuilder();
$pass = new AutowireExceptionPass($autowirePass, $inlinePass);
$pass->process($container);
// mark the test as passed
$this->assertTrue(true);
}
public function testNoExceptionIfServiceRemoved() public function testNoExceptionIfServiceRemoved()
{ {
$autowirePass = $this->getMockBuilder(AutowirePass::class) $autowirePass = $this->getMockBuilder(AutowirePass::class)

View File

@ -78,6 +78,28 @@ class AutowirePassTest extends TestCase
$this->assertEquals(B::class, (string) $container->getDefinition('c')->getArgument(0)); $this->assertEquals(B::class, (string) $container->getDefinition('c')->getArgument(0));
} }
/**
* @group legacy
* @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" to "Symfony\Component\DependencyInjection\Tests\Compiler\AInterface" instead.
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessageInSymfony4 Cannot autowire service "c": argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\B" service.
*/
public function testProcessLegacyAutowireWithAvailableInterface()
{
$container = new ContainerBuilder();
$container->setAlias(AInterface::class, B::class);
$container->register(B::class);
$cDefinition = $container->register('c', __NAMESPACE__.'\C');
$cDefinition->setAutowired(true);
(new ResolveClassPass())->process($container);
(new AutowirePass())->process($container);
$this->assertCount(1, $container->getDefinition('c')->getArguments());
$this->assertEquals(B::class, (string) $container->getDefinition('c')->getArgument(0));
}
/** /**
* @group legacy * @group legacy
* @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should alias the "Symfony\Component\DependencyInjection\Tests\Compiler\F" service to "Symfony\Component\DependencyInjection\Tests\Compiler\DInterface" instead. * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should alias the "Symfony\Component\DependencyInjection\Tests\Compiler\F" service to "Symfony\Component\DependencyInjection\Tests\Compiler\DInterface" instead.
@ -151,7 +173,21 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Unable to resolve service "private_service": constructor of class "Symfony\Component\DependencyInjection\Tests\Compiler\PrivateConstructor" must be public.
*/
public function testPrivateConstructorThrowsAutowireException()
{
$container = new ContainerBuilder();
$container->autowire('private_service', __NAMESPACE__.'\PrivateConstructor');
$pass = new AutowirePass(true);
$pass->process($container);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2", "c3". * @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2", "c3".
*/ */
public function testTypeCollision() public function testTypeCollision()
@ -169,7 +205,7 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgument::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2". * @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgument::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".
*/ */
public function testTypeNotGuessable() public function testTypeNotGuessable()
@ -186,7 +222,7 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgumentForSubclass::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2". * @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgumentForSubclass::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".
*/ */
public function testTypeNotGuessableWithSubclass() public function testTypeNotGuessableWithSubclass()
@ -203,7 +239,7 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. * @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists.
*/ */
public function testTypeNotGuessableNoServicesFound() public function testTypeNotGuessableNoServicesFound()
@ -322,7 +358,7 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist. * @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.
*/ */
public function testClassNotFoundThrowsException() public function testClassNotFoundThrowsException()
@ -337,7 +373,7 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class does not exist. * @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class does not exist.
*/ */
public function testParentClassNotFoundThrowsException() public function testParentClassNotFoundThrowsException()
@ -354,7 +390,7 @@ class AutowirePassTest extends TestCase
/** /**
* @group legacy * @group legacy
* @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead. * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead.
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessageInSymfony4 Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but this service is abstract. You should maybe alias this class to the existing "foo" service. * @expectedExceptionMessageInSymfony4 Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but this service is abstract. You should maybe alias this class to the existing "foo" service.
*/ */
public function testDontUseAbstractServices() public function testDontUseAbstractServices()
@ -399,7 +435,7 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" must have a type-hint or be given a value explicitly. * @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" must have a type-hint or be given a value explicitly.
*/ */
public function testScalarArgsCannotBeAutowired() public function testScalarArgsCannotBeAutowired()
@ -607,7 +643,7 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "setter_injection_collision": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\SetterInjectionCollision::setMultipleInstancesForOneArg()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2". * @expectedExceptionMessage Cannot autowire service "setter_injection_collision": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\SetterInjectionCollision::setMultipleInstancesForOneArg()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2".
*/ */
public function testSetterInjectionCollisionThrowsException() public function testSetterInjectionCollisionThrowsException()
@ -626,7 +662,7 @@ class AutowirePassTest extends TestCase
/** /**
* @group legacy * @group legacy
* @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead. * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead.
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessageInSymfony4 Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to the existing "foo" service. * @expectedExceptionMessageInSymfony4 Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to the existing "foo" service.
*/ */
public function testProcessDoesNotTriggerDeprecations() public function testProcessDoesNotTriggerDeprecations()
@ -677,7 +713,7 @@ class AutowirePassTest extends TestCase
/** /**
* @dataProvider provideNotWireableCalls * @dataProvider provideNotWireableCalls
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
*/ */
public function testNotWireableCalls($method, $expectedMsg) public function testNotWireableCalls($method, $expectedMsg)
{ {
@ -716,8 +752,8 @@ class AutowirePassTest extends TestCase
/** /**
* @group legacy * @group legacy
* @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "i" service to "Symfony\Component\DependencyInjection\Tests\Compiler\I" instead. * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.
* @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessageInSymfony4 Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead. * @expectedExceptionMessageInSymfony4 Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.
*/ */
public function testByIdAlternative() public function testByIdAlternative()
@ -734,7 +770,26 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @group legacy
* @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for "Symfony\Component\DependencyInjection\Tests\Compiler\A" in "Symfony\Component\DependencyInjection\Tests\Compiler\Bar" to "Symfony\Component\DependencyInjection\Tests\Compiler\AInterface" instead.
*/
public function testTypedReferenceDeprecationNotice()
{
$container = new ContainerBuilder();
$container->register('aClass', A::class);
$container->setAlias(AInterface::class, 'aClass');
$container
->register('bar', Bar::class)
->setProperty('a', array(new TypedReference(A::class, A::class, Bar::class)))
;
$pass = new AutowirePass();
$pass->process($container);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead. * @expectedExceptionMessage Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.
*/ */
public function testExceptionWhenAliasExists() public function testExceptionWhenAliasExists()
@ -754,7 +809,7 @@ class AutowirePassTest extends TestCase
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
* @expectedExceptionMessage Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. You should maybe alias this class to one of these existing services: "i", "i2". * @expectedExceptionMessage Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. You should maybe alias this class to one of these existing services: "i", "i2".
*/ */
public function testExceptionWhenAliasDoesNotExist() public function testExceptionWhenAliasDoesNotExist()
@ -784,7 +839,11 @@ class Bar
} }
} }
class A interface AInterface
{
}
class A implements AInterface
{ {
public static function create(Foo $foo) public static function create(Foo $foo)
{ {
@ -1091,3 +1150,10 @@ class NotWireable
{ {
} }
} }
class PrivateConstructor
{
private function __construct()
{
}
}

View File

@ -252,7 +252,7 @@ class InlineServiceDefinitionsPassTest extends TestCase
$this->assertSame('inline', (string) $values[0]); $this->assertSame('inline', (string) $values[0]);
} }
public function testGetInlinedServiceIds() public function testGetInlinedServiceIdData()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container $container
@ -265,7 +265,7 @@ class InlineServiceDefinitionsPassTest extends TestCase
; ;
$container $container
->register('service') ->register('other_service')
->setArguments(array(new Reference('inlinable.service'))) ->setArguments(array(new Reference('inlinable.service')))
; ;
@ -273,7 +273,7 @@ class InlineServiceDefinitionsPassTest extends TestCase
$repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), $inlinePass)); $repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), $inlinePass));
$repeatedPass->process($container); $repeatedPass->process($container);
$this->assertEquals(array('inlinable.service'), $inlinePass->getInlinedServiceIds()); $this->assertEquals(array('inlinable.service' => array('other_service')), $inlinePass->getInlinedServiceIds());
} }
protected function process(ContainerBuilder $container) protected function process(ContainerBuilder $container)

View File

@ -116,7 +116,7 @@ class ContainerAwareEventDispatcher extends EventDispatcher
public function hasListeners($eventName = null) public function hasListeners($eventName = null)
{ {
if (null === $eventName) { if (null === $eventName) {
return (bool) count($this->listenerIds) || (bool) count($this->listeners); return count($this->listenerIds) || count($this->listeners) || parent::hasListeners();
} }
if (isset($this->listenerIds[$eventName])) { if (isset($this->listenerIds[$eventName])) {

View File

@ -11,10 +11,11 @@
namespace Symfony\Component\EventDispatcher\DependencyInjection; namespace Symfony\Component\EventDispatcher\DependencyInjection;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@ -78,7 +79,7 @@ class RegisterListenersPass implements CompilerPassInterface
$event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']); $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']);
} }
$definition->addMethodCall('addListener', array($event['event'], new ClosureProxyArgument($id, $event['method']), $priority)); $definition->addMethodCall('addListener', array($event['event'], array(new ServiceClosureArgument(new Reference($id)), $event['method']), $priority));
} }
} }
@ -103,7 +104,7 @@ class RegisterListenersPass implements CompilerPassInterface
ExtractingEventDispatcher::$subscriber = $class; ExtractingEventDispatcher::$subscriber = $class;
$extractingDispatcher->addSubscriber($extractingDispatcher); $extractingDispatcher->addSubscriber($extractingDispatcher);
foreach ($extractingDispatcher->listeners as $args) { foreach ($extractingDispatcher->listeners as $args) {
$args[1] = new ClosureProxyArgument($id, $args[1]); $args[1] = array(new ServiceClosureArgument(new Reference($id)), $args[1]);
$definition->addMethodCall('addListener', $args); $definition->addMethodCall('addListener', $args);
} }
$extractingDispatcher->listeners = array(); $extractingDispatcher->listeners = array();

View File

@ -24,6 +24,7 @@ namespace Symfony\Component\EventDispatcher;
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
* @author Jordan Alliot <jordan.alliot@gmail.com> * @author Jordan Alliot <jordan.alliot@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*/ */
class EventDispatcher implements EventDispatcherInterface class EventDispatcher implements EventDispatcherInterface
{ {
@ -52,7 +53,7 @@ class EventDispatcher implements EventDispatcherInterface
public function getListeners($eventName = null) public function getListeners($eventName = null)
{ {
if (null !== $eventName) { if (null !== $eventName) {
if (!isset($this->listeners[$eventName])) { if (empty($this->listeners[$eventName])) {
return array(); return array();
} }
@ -77,13 +78,23 @@ class EventDispatcher implements EventDispatcherInterface
*/ */
public function getListenerPriority($eventName, $listener) public function getListenerPriority($eventName, $listener)
{ {
if (!isset($this->listeners[$eventName])) { if (empty($this->listeners[$eventName])) {
return; return;
} }
if (is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
$listener[0] = $listener[0]();
}
foreach ($this->listeners[$eventName] as $priority => $listeners) { foreach ($this->listeners[$eventName] as $priority => $listeners) {
if (false !== in_array($listener, $listeners, true)) { foreach ($listeners as $k => $v) {
return $priority; if ($v !== $listener && is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
$v[0] = $v[0]();
$this->listeners[$eventName][$priority][$k] = $v;
}
if ($v === $listener) {
return $priority;
}
} }
} }
} }
@ -93,7 +104,17 @@ class EventDispatcher implements EventDispatcherInterface
*/ */
public function hasListeners($eventName = null) public function hasListeners($eventName = null)
{ {
return (bool) $this->getListeners($eventName); if (null !== $eventName) {
return !empty($this->listeners[$eventName]);
}
foreach ($this->listeners as $eventListeners) {
if ($eventListeners) {
return true;
}
}
return false;
} }
/** /**
@ -110,13 +131,30 @@ class EventDispatcher implements EventDispatcherInterface
*/ */
public function removeListener($eventName, $listener) public function removeListener($eventName, $listener)
{ {
if (!isset($this->listeners[$eventName])) { if (empty($this->listeners[$eventName])) {
return; return;
} }
if (is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
$listener[0] = $listener[0]();
}
foreach ($this->listeners[$eventName] as $priority => $listeners) { foreach ($this->listeners[$eventName] as $priority => $listeners) {
if (false !== ($key = array_search($listener, $listeners, true))) { foreach ($listeners as $k => $v) {
unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]); if ($v !== $listener && is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
$v[0] = $v[0]();
}
if ($v === $listener) {
unset($listeners[$k], $this->sorted[$eventName]);
} else {
$listeners[$k] = $v;
}
}
if ($listeners) {
$this->listeners[$eventName][$priority] = $listeners;
} else {
unset($this->listeners[$eventName][$priority]);
} }
} }
} }
@ -183,6 +221,16 @@ class EventDispatcher implements EventDispatcherInterface
private function sortListeners($eventName) private function sortListeners($eventName)
{ {
krsort($this->listeners[$eventName]); krsort($this->listeners[$eventName]);
$this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]); $this->sorted[$eventName] = array();
foreach ($this->listeners[$eventName] as $priority => $listeners) {
foreach ($listeners as $k => $listener) {
if (is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
$listener[0] = $listener[0]();
$this->listeners[$eventName][$priority][$k] = $listener;
}
$this->sorted[$eventName][] = $listener;
}
}
} }
} }

View File

@ -302,6 +302,73 @@ abstract class AbstractEventDispatcherTest extends TestCase
$this->assertFalse($this->dispatcher->hasListeners('foo')); $this->assertFalse($this->dispatcher->hasListeners('foo'));
$this->assertFalse($this->dispatcher->hasListeners()); $this->assertFalse($this->dispatcher->hasListeners());
} }
public function testHasListenersIsLazy()
{
$called = 0;
$listener = array(function () use (&$called) { ++$called; }, 'onFoo');
$this->dispatcher->addListener('foo', $listener);
$this->assertTrue($this->dispatcher->hasListeners());
$this->assertTrue($this->dispatcher->hasListeners('foo'));
$this->assertSame(0, $called);
}
public function testDispatchLazyListener()
{
$called = 0;
$factory = function () use (&$called) {
++$called;
return new TestWithDispatcher();
};
$this->dispatcher->addListener('foo', array($factory, 'foo'));
$this->assertSame(0, $called);
$this->dispatcher->dispatch('foo', new Event());
$this->dispatcher->dispatch('foo', new Event());
$this->assertSame(1, $called);
}
public function testRemoveFindsLazyListeners()
{
$test = new TestWithDispatcher();
$factory = function () use ($test) { return $test; };
$this->dispatcher->addListener('foo', array($factory, 'foo'));
$this->assertTrue($this->dispatcher->hasListeners('foo'));
$this->dispatcher->removeListener('foo', array($test, 'foo'));
$this->assertFalse($this->dispatcher->hasListeners('foo'));
$this->dispatcher->addListener('foo', array($test, 'foo'));
$this->assertTrue($this->dispatcher->hasListeners('foo'));
$this->dispatcher->removeListener('foo', array($factory, 'foo'));
$this->assertFalse($this->dispatcher->hasListeners('foo'));
}
public function testPriorityFindsLazyListeners()
{
$test = new TestWithDispatcher();
$factory = function () use ($test) { return $test; };
$this->dispatcher->addListener('foo', array($factory, 'foo'), 3);
$this->assertSame(3, $this->dispatcher->getListenerPriority('foo', array($test, 'foo')));
$this->dispatcher->removeListener('foo', array($factory, 'foo'));
$this->dispatcher->addListener('foo', array($test, 'foo'), 5);
$this->assertSame(5, $this->dispatcher->getListenerPriority('foo', array($factory, 'foo')));
}
public function testGetLazyListeners()
{
$test = new TestWithDispatcher();
$factory = function () use ($test) { return $test; };
$this->dispatcher->addListener('foo', array($factory, 'foo'), 3);
$this->assertSame(array(array($test, 'foo')), $this->dispatcher->getListeners('foo'));
$this->dispatcher->removeListener('foo', array($test, 'foo'));
$this->dispatcher->addListener('bar', array($factory, 'foo'), 3);
$this->assertSame(array('bar' => array(array($test, 'foo'))), $this->dispatcher->getListeners());
}
} }
class CallableClass class CallableClass

View File

@ -12,8 +12,9 @@
namespace Symfony\Component\EventDispatcher\Tests\DependencyInjection; namespace Symfony\Component\EventDispatcher\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
class RegisterListenersPassTest extends TestCase class RegisterListenersPassTest extends TestCase
@ -127,17 +128,17 @@ class RegisterListenersPassTest extends TestCase
$registerListenersPass->process($container); $registerListenersPass->process($container);
$definition = $container->getDefinition('event_dispatcher'); $definition = $container->getDefinition('event_dispatcher');
$expected_calls = array( $expectedCalls = array(
array( array(
'addListener', 'addListener',
array( array(
'event', 'event',
new ClosureProxyArgument('foo', 'onEvent'), array(new ServiceClosureArgument(new Reference('foo')), 'onEvent'),
0, 0,
), ),
), ),
); );
$this->assertEquals($expected_calls, $definition->getMethodCalls()); $this->assertEquals($expectedCalls, $definition->getMethodCalls());
} }
/** /**

View File

@ -31,7 +31,7 @@ abstract class FilterIterator extends \FilterIterator
*/ */
public function rewind() public function rewind()
{ {
if (PHP_VERSION_ID > 50607 || (PHP_VERSION_ID > 50523 && PHP_VERSION_ID < 50600)) { if (\PHP_VERSION_ID > 50607 || (\PHP_VERSION_ID > 50523 && \PHP_VERSION_ID < 50600)) {
parent::rewind(); parent::rewind();
return; return;

View File

@ -119,7 +119,7 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
} }
// @see https://bugs.php.net/68557 // @see https://bugs.php.net/68557
if (PHP_VERSION_ID < 50523 || PHP_VERSION_ID >= 50600 && PHP_VERSION_ID < 50607) { if (\PHP_VERSION_ID < 50523 || \PHP_VERSION_ID >= 50600 && \PHP_VERSION_ID < 50607) {
parent::next(); parent::next();
} }

View File

@ -162,6 +162,10 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
$dateFormat = $this->dateFormat; $dateFormat = $this->dateFormat;
$timeFormat = $this->timeFormat; $timeFormat = $this->timeFormat;
$timezone = $ignoreTimezone ? 'UTC' : $this->outputTimezone; $timezone = $ignoreTimezone ? 'UTC' : $this->outputTimezone;
if (class_exists('IntlTimeZone', false)) {
// see https://bugs.php.net/bug.php?id=66323
$timezone = \IntlTimeZone::createTimeZone($timezone);
}
$calendar = $this->calendar; $calendar = $this->calendar;
$pattern = $this->pattern; $pattern = $this->pattern;

View File

@ -82,7 +82,8 @@ class DateType extends AbstractType
\Locale::getDefault(), \Locale::getDefault(),
$dateFormat, $dateFormat,
$timeFormat, $timeFormat,
null, // see https://bugs.php.net/bug.php?id=66323
class_exists('IntlTimeZone', false) ? \IntlTimeZone::createDefault() : null,
$calendar, $calendar,
$pattern $pattern
); );

View File

@ -18,19 +18,14 @@ namespace Symfony\Component\Form\Guess;
*/ */
class ValueGuess extends Guess class ValueGuess extends Guess
{ {
/**
* The guessed value.
*
* @var array
*/
private $value; private $value;
/** /**
* Constructor. * Constructor.
* *
* @param string $value The guessed value * @param string|int|bool|null $value The guessed value
* @param int $confidence The confidence that the guessed class name * @param int $confidence The confidence that the guessed class name
* is correct * is correct
*/ */
public function __construct($value, $confidence) public function __construct($value, $confidence)
{ {
@ -42,7 +37,7 @@ class ValueGuess extends Guess
/** /**
* Returns the guessed value. * Returns the guessed value.
* *
* @return mixed * @return string|int|bool|null
*/ */
public function getValue() public function getValue()
{ {

View File

@ -1577,7 +1577,7 @@ class Request
public function getContent($asResource = false) public function getContent($asResource = false)
{ {
$currentContentIsResource = is_resource($this->content); $currentContentIsResource = is_resource($this->content);
if (PHP_VERSION_ID < 50600 && false === $this->content) { if (\PHP_VERSION_ID < 50600 && false === $this->content) {
throw new \LogicException('getContent() can only be called once when using the resource return type and PHP below 5.6.'); throw new \LogicException('getContent() can only be called once when using the resource return type and PHP below 5.6.');
} }

View File

@ -1057,7 +1057,7 @@ class RequestTest extends TestCase
*/ */
public function testGetContentCantBeCalledTwiceWithResources($first, $second) public function testGetContentCantBeCalledTwiceWithResources($first, $second)
{ {
if (PHP_VERSION_ID >= 50600) { if (\PHP_VERSION_ID >= 50600) {
$this->markTestSkipped('PHP >= 5.6 allows to open php://input several times.'); $this->markTestSkipped('PHP >= 5.6 allows to open php://input several times.');
} }

View File

@ -138,6 +138,9 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
$logs = array(); $logs = array();
foreach (file($file, FILE_IGNORE_NEW_LINES) as $log) { foreach (file($file, FILE_IGNORE_NEW_LINES) as $log) {
$log = explode(': ', $log, 2); $log = explode(': ', $log, 2);
if (!isset($log[1]) || !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $log[0])) {
$log = array('Unknown Compiler Pass', implode(': ', $log));
}
$logs[$log[0]][] = array('message' => $log[1]); $logs[$log[0]][] = array('message' => $log[1]);
} }

View File

@ -822,7 +822,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface
$output .= $rawChunk; $output .= $rawChunk;
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
unset($tokens, $rawChunk); unset($tokens, $rawChunk);
gc_mem_caches(); gc_mem_caches();

View File

@ -0,0 +1,4 @@
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Psr\Container\ContainerInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\DependencyInjection\ContainerInterface"; reason: private alias.
Some custom logging message
With ending :

View File

@ -17,6 +17,27 @@ use Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector;
class LoggerDataCollectorTest extends TestCase class LoggerDataCollectorTest extends TestCase
{ {
public function testCollectWithUnexpectedFormat()
{
$logger = $this->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface')->getMock();
$logger->expects($this->once())->method('countErrors')->will($this->returnValue('foo'));
$logger->expects($this->exactly(2))->method('getLogs')->will($this->returnValue(array()));
$c = new LoggerDataCollector($logger, __DIR__.'/');
$c->lateCollect();
$compilerLogs = $c->getCompilerLogs()->getValue('message');
$this->assertSame(array(
array('message' => 'Removed service "Psr\Container\ContainerInterface"; reason: private alias.'),
array('message' => 'Removed service "Symfony\Component\DependencyInjection\ContainerInterface"; reason: private alias.'),
), $compilerLogs['Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass']);
$this->assertSame(array(
array('message' => 'Some custom logging message'),
array('message' => 'With ending :'),
), $compilerLogs['Unknown Compiler Pass']);
}
/** /**
* @dataProvider getCollectTestData * @dataProvider getCollectTestData
*/ */

View File

@ -435,7 +435,7 @@ abstract class AbstractIntlDateFormatterTest extends TestCase
public function testFormatWithDateTimeZoneGmtOffset() public function testFormatWithDateTimeZoneGmtOffset()
{ {
if (defined('HHVM_VERSION_ID') || PHP_VERSION_ID <= 50509) { if (defined('HHVM_VERSION_ID') || \PHP_VERSION_ID <= 50509) {
$this->markTestSkipped('DateTimeZone GMT offsets are supported since 5.5.10. See https://github.com/facebook/hhvm/issues/5875 for HHVM.'); $this->markTestSkipped('DateTimeZone GMT offsets are supported since 5.5.10. See https://github.com/facebook/hhvm/issues/5875 for HHVM.');
} }

View File

@ -195,7 +195,7 @@ class PropertyAccessor implements PropertyAccessorInterface
$overwrite = true; $overwrite = true;
try { try {
if (PHP_VERSION_ID < 70000 && false === self::$previousErrorHandler) { if (\PHP_VERSION_ID < 70000 && false === self::$previousErrorHandler) {
self::$previousErrorHandler = set_error_handler(self::$errorHandler); self::$previousErrorHandler = set_error_handler(self::$errorHandler);
} }

View File

@ -64,7 +64,7 @@ class AnnotationFileLoader extends FileLoader
$collection->addResource(new FileResource($path)); $collection->addResource(new FileResource($path));
$collection->addCollection($this->loader->load($class, $type)); $collection->addCollection($this->loader->load($class, $type));
} }
if (PHP_VERSION_ID >= 70000) { if (\PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches(); gc_mem_caches();
} }

View File

@ -238,7 +238,7 @@ EOF;
$hostMatches = false; $hostMatches = false;
$methods = $route->getMethods(); $methods = $route->getMethods();
$supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('HEAD', $methods)); $supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('HEAD', $methods) || in_array('GET', $methods));
$regex = $compiledRoute->getRegex(); $regex = $compiledRoute->getRegex();
if (!count($compiledRoute->getPathVariables()) && false !== preg_match('#^(.)\^(?P<url>.*?)\$\1#'.(substr($regex, -1) === 'u' ? 'u' : ''), $regex, $m)) { if (!count($compiledRoute->getPathVariables()) && false !== preg_match('#^(.)\^(?P<url>.*?)\$\1#'.(substr($regex, -1) === 'u' ? 'u' : ''), $regex, $m)) {

View File

@ -0,0 +1,204 @@
<?php
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\RequestContext;
/**
* ProjectUrlMatcher.
*
* This class has been auto-generated
* by the Symfony Routing Component.
*/
class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
{
/**
* Constructor.
*/
public function __construct(RequestContext $context)
{
$this->context = $context;
}
public function match($pathinfo)
{
$allow = array();
$pathinfo = rawurldecode($pathinfo);
$trimmedPathinfo = rtrim($pathinfo, '/');
$context = $this->context;
$request = $this->request;
$requestMethod = $canonicalMethod = $context->getMethod();
$scheme = $context->getScheme();
if ('HEAD' === $requestMethod) {
$canonicalMethod = 'GET';
}
if (0 === strpos($pathinfo, '/trailing/simple')) {
// simple_trailing_slash_no_methods
if ('/trailing/simple/no-methods/' === $pathinfo) {
return array('_route' => 'simple_trailing_slash_no_methods');
}
// simple_trailing_slash_GET_method
if ('/trailing/simple/get-method/' === $pathinfo) {
if ('GET' !== $canonicalMethod) {
$allow[] = 'GET';
goto not_simple_trailing_slash_GET_method;
}
return array('_route' => 'simple_trailing_slash_GET_method');
}
not_simple_trailing_slash_GET_method:
// simple_trailing_slash_HEAD_method
if ('/trailing/simple/head-method/' === $pathinfo) {
if ('HEAD' !== $requestMethod) {
$allow[] = 'HEAD';
goto not_simple_trailing_slash_HEAD_method;
}
return array('_route' => 'simple_trailing_slash_HEAD_method');
}
not_simple_trailing_slash_HEAD_method:
// simple_trailing_slash_POST_method
if ('/trailing/simple/post-method/' === $pathinfo) {
if ('POST' !== $canonicalMethod) {
$allow[] = 'POST';
goto not_simple_trailing_slash_POST_method;
}
return array('_route' => 'simple_trailing_slash_POST_method');
}
not_simple_trailing_slash_POST_method:
}
elseif (0 === strpos($pathinfo, '/trailing/regex')) {
// regex_trailing_slash_no_methods
if (0 === strpos($pathinfo, '/trailing/regex/no-methods') && preg_match('#^/trailing/regex/no\\-methods/(?P<param>[^/]++)/$#s', $pathinfo, $matches)) {
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_trailing_slash_no_methods')), array ());
}
// regex_trailing_slash_GET_method
if (0 === strpos($pathinfo, '/trailing/regex/get-method') && preg_match('#^/trailing/regex/get\\-method/(?P<param>[^/]++)/$#s', $pathinfo, $matches)) {
if ('GET' !== $canonicalMethod) {
$allow[] = 'GET';
goto not_regex_trailing_slash_GET_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_trailing_slash_GET_method')), array ());
}
not_regex_trailing_slash_GET_method:
// regex_trailing_slash_HEAD_method
if (0 === strpos($pathinfo, '/trailing/regex/head-method') && preg_match('#^/trailing/regex/head\\-method/(?P<param>[^/]++)/$#s', $pathinfo, $matches)) {
if ('HEAD' !== $requestMethod) {
$allow[] = 'HEAD';
goto not_regex_trailing_slash_HEAD_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_trailing_slash_HEAD_method')), array ());
}
not_regex_trailing_slash_HEAD_method:
// regex_trailing_slash_POST_method
if (0 === strpos($pathinfo, '/trailing/regex/post-method') && preg_match('#^/trailing/regex/post\\-method/(?P<param>[^/]++)/$#s', $pathinfo, $matches)) {
if ('POST' !== $canonicalMethod) {
$allow[] = 'POST';
goto not_regex_trailing_slash_POST_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_trailing_slash_POST_method')), array ());
}
not_regex_trailing_slash_POST_method:
}
elseif (0 === strpos($pathinfo, '/not-trailing/simple')) {
// simple_not_trailing_slash_no_methods
if ('/not-trailing/simple/no-methods' === $pathinfo) {
return array('_route' => 'simple_not_trailing_slash_no_methods');
}
// simple_not_trailing_slash_GET_method
if ('/not-trailing/simple/get-method' === $pathinfo) {
if ('GET' !== $canonicalMethod) {
$allow[] = 'GET';
goto not_simple_not_trailing_slash_GET_method;
}
return array('_route' => 'simple_not_trailing_slash_GET_method');
}
not_simple_not_trailing_slash_GET_method:
// simple_not_trailing_slash_HEAD_method
if ('/not-trailing/simple/head-method' === $pathinfo) {
if ('HEAD' !== $requestMethod) {
$allow[] = 'HEAD';
goto not_simple_not_trailing_slash_HEAD_method;
}
return array('_route' => 'simple_not_trailing_slash_HEAD_method');
}
not_simple_not_trailing_slash_HEAD_method:
// simple_not_trailing_slash_POST_method
if ('/not-trailing/simple/post-method' === $pathinfo) {
if ('POST' !== $canonicalMethod) {
$allow[] = 'POST';
goto not_simple_not_trailing_slash_POST_method;
}
return array('_route' => 'simple_not_trailing_slash_POST_method');
}
not_simple_not_trailing_slash_POST_method:
}
elseif (0 === strpos($pathinfo, '/not-trailing/regex')) {
// regex_not_trailing_slash_no_methods
if (0 === strpos($pathinfo, '/not-trailing/regex/no-methods') && preg_match('#^/not\\-trailing/regex/no\\-methods/(?P<param>[^/]++)$#s', $pathinfo, $matches)) {
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_not_trailing_slash_no_methods')), array ());
}
// regex_not_trailing_slash_GET_method
if (0 === strpos($pathinfo, '/not-trailing/regex/get-method') && preg_match('#^/not\\-trailing/regex/get\\-method/(?P<param>[^/]++)$#s', $pathinfo, $matches)) {
if ('GET' !== $canonicalMethod) {
$allow[] = 'GET';
goto not_regex_not_trailing_slash_GET_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_not_trailing_slash_GET_method')), array ());
}
not_regex_not_trailing_slash_GET_method:
// regex_not_trailing_slash_HEAD_method
if (0 === strpos($pathinfo, '/not-trailing/regex/head-method') && preg_match('#^/not\\-trailing/regex/head\\-method/(?P<param>[^/]++)$#s', $pathinfo, $matches)) {
if ('HEAD' !== $requestMethod) {
$allow[] = 'HEAD';
goto not_regex_not_trailing_slash_HEAD_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_not_trailing_slash_HEAD_method')), array ());
}
not_regex_not_trailing_slash_HEAD_method:
// regex_not_trailing_slash_POST_method
if (0 === strpos($pathinfo, '/not-trailing/regex/post-method') && preg_match('#^/not\\-trailing/regex/post\\-method/(?P<param>[^/]++)$#s', $pathinfo, $matches)) {
if ('POST' !== $canonicalMethod) {
$allow[] = 'POST';
goto not_regex_not_trailing_slash_POST_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_not_trailing_slash_POST_method')), array ());
}
not_regex_not_trailing_slash_POST_method:
}
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
}

View File

@ -0,0 +1,228 @@
<?php
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\RequestContext;
/**
* ProjectUrlMatcher.
*
* This class has been auto-generated
* by the Symfony Routing Component.
*/
class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher
{
/**
* Constructor.
*/
public function __construct(RequestContext $context)
{
$this->context = $context;
}
public function match($pathinfo)
{
$allow = array();
$pathinfo = rawurldecode($pathinfo);
$trimmedPathinfo = rtrim($pathinfo, '/');
$context = $this->context;
$request = $this->request;
$requestMethod = $canonicalMethod = $context->getMethod();
$scheme = $context->getScheme();
if ('HEAD' === $requestMethod) {
$canonicalMethod = 'GET';
}
if (0 === strpos($pathinfo, '/trailing/simple')) {
// simple_trailing_slash_no_methods
if ('/trailing/simple/no-methods' === $trimmedPathinfo) {
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', 'simple_trailing_slash_no_methods');
}
return array('_route' => 'simple_trailing_slash_no_methods');
}
// simple_trailing_slash_GET_method
if ('/trailing/simple/get-method' === $trimmedPathinfo) {
if ('GET' !== $canonicalMethod) {
$allow[] = 'GET';
goto not_simple_trailing_slash_GET_method;
}
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', 'simple_trailing_slash_GET_method');
}
return array('_route' => 'simple_trailing_slash_GET_method');
}
not_simple_trailing_slash_GET_method:
// simple_trailing_slash_HEAD_method
if ('/trailing/simple/head-method' === $trimmedPathinfo) {
if ('HEAD' !== $requestMethod) {
$allow[] = 'HEAD';
goto not_simple_trailing_slash_HEAD_method;
}
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', 'simple_trailing_slash_HEAD_method');
}
return array('_route' => 'simple_trailing_slash_HEAD_method');
}
not_simple_trailing_slash_HEAD_method:
// simple_trailing_slash_POST_method
if ('/trailing/simple/post-method/' === $pathinfo) {
if ('POST' !== $canonicalMethod) {
$allow[] = 'POST';
goto not_simple_trailing_slash_POST_method;
}
return array('_route' => 'simple_trailing_slash_POST_method');
}
not_simple_trailing_slash_POST_method:
}
elseif (0 === strpos($pathinfo, '/trailing/regex')) {
// regex_trailing_slash_no_methods
if (0 === strpos($pathinfo, '/trailing/regex/no-methods') && preg_match('#^/trailing/regex/no\\-methods/(?P<param>[^/]++)/?$#s', $pathinfo, $matches)) {
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', 'regex_trailing_slash_no_methods');
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_trailing_slash_no_methods')), array ());
}
// regex_trailing_slash_GET_method
if (0 === strpos($pathinfo, '/trailing/regex/get-method') && preg_match('#^/trailing/regex/get\\-method/(?P<param>[^/]++)/?$#s', $pathinfo, $matches)) {
if ('GET' !== $canonicalMethod) {
$allow[] = 'GET';
goto not_regex_trailing_slash_GET_method;
}
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', 'regex_trailing_slash_GET_method');
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_trailing_slash_GET_method')), array ());
}
not_regex_trailing_slash_GET_method:
// regex_trailing_slash_HEAD_method
if (0 === strpos($pathinfo, '/trailing/regex/head-method') && preg_match('#^/trailing/regex/head\\-method/(?P<param>[^/]++)/?$#s', $pathinfo, $matches)) {
if ('HEAD' !== $requestMethod) {
$allow[] = 'HEAD';
goto not_regex_trailing_slash_HEAD_method;
}
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', 'regex_trailing_slash_HEAD_method');
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_trailing_slash_HEAD_method')), array ());
}
not_regex_trailing_slash_HEAD_method:
// regex_trailing_slash_POST_method
if (0 === strpos($pathinfo, '/trailing/regex/post-method') && preg_match('#^/trailing/regex/post\\-method/(?P<param>[^/]++)/$#s', $pathinfo, $matches)) {
if ('POST' !== $canonicalMethod) {
$allow[] = 'POST';
goto not_regex_trailing_slash_POST_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_trailing_slash_POST_method')), array ());
}
not_regex_trailing_slash_POST_method:
}
elseif (0 === strpos($pathinfo, '/not-trailing/simple')) {
// simple_not_trailing_slash_no_methods
if ('/not-trailing/simple/no-methods' === $pathinfo) {
return array('_route' => 'simple_not_trailing_slash_no_methods');
}
// simple_not_trailing_slash_GET_method
if ('/not-trailing/simple/get-method' === $pathinfo) {
if ('GET' !== $canonicalMethod) {
$allow[] = 'GET';
goto not_simple_not_trailing_slash_GET_method;
}
return array('_route' => 'simple_not_trailing_slash_GET_method');
}
not_simple_not_trailing_slash_GET_method:
// simple_not_trailing_slash_HEAD_method
if ('/not-trailing/simple/head-method' === $pathinfo) {
if ('HEAD' !== $requestMethod) {
$allow[] = 'HEAD';
goto not_simple_not_trailing_slash_HEAD_method;
}
return array('_route' => 'simple_not_trailing_slash_HEAD_method');
}
not_simple_not_trailing_slash_HEAD_method:
// simple_not_trailing_slash_POST_method
if ('/not-trailing/simple/post-method' === $pathinfo) {
if ('POST' !== $canonicalMethod) {
$allow[] = 'POST';
goto not_simple_not_trailing_slash_POST_method;
}
return array('_route' => 'simple_not_trailing_slash_POST_method');
}
not_simple_not_trailing_slash_POST_method:
}
elseif (0 === strpos($pathinfo, '/not-trailing/regex')) {
// regex_not_trailing_slash_no_methods
if (0 === strpos($pathinfo, '/not-trailing/regex/no-methods') && preg_match('#^/not\\-trailing/regex/no\\-methods/(?P<param>[^/]++)$#s', $pathinfo, $matches)) {
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_not_trailing_slash_no_methods')), array ());
}
// regex_not_trailing_slash_GET_method
if (0 === strpos($pathinfo, '/not-trailing/regex/get-method') && preg_match('#^/not\\-trailing/regex/get\\-method/(?P<param>[^/]++)$#s', $pathinfo, $matches)) {
if ('GET' !== $canonicalMethod) {
$allow[] = 'GET';
goto not_regex_not_trailing_slash_GET_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_not_trailing_slash_GET_method')), array ());
}
not_regex_not_trailing_slash_GET_method:
// regex_not_trailing_slash_HEAD_method
if (0 === strpos($pathinfo, '/not-trailing/regex/head-method') && preg_match('#^/not\\-trailing/regex/head\\-method/(?P<param>[^/]++)$#s', $pathinfo, $matches)) {
if ('HEAD' !== $requestMethod) {
$allow[] = 'HEAD';
goto not_regex_not_trailing_slash_HEAD_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_not_trailing_slash_HEAD_method')), array ());
}
not_regex_not_trailing_slash_HEAD_method:
// regex_not_trailing_slash_POST_method
if (0 === strpos($pathinfo, '/not-trailing/regex/post-method') && preg_match('#^/not\\-trailing/regex/post\\-method/(?P<param>[^/]++)$#s', $pathinfo, $matches)) {
if ('POST' !== $canonicalMethod) {
$allow[] = 'POST';
goto not_regex_not_trailing_slash_POST_method;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'regex_not_trailing_slash_POST_method')), array ());
}
not_regex_not_trailing_slash_POST_method:
}
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
}

View File

@ -345,12 +345,33 @@ class PhpMatcherDumperTest extends TestCase
$groupOptimisedCollection->add('slashed_b', new Route('/slashed/group/b/')); $groupOptimisedCollection->add('slashed_b', new Route('/slashed/group/b/'));
$groupOptimisedCollection->add('slashed_c', new Route('/slashed/group/c/')); $groupOptimisedCollection->add('slashed_c', new Route('/slashed/group/c/'));
$trailingSlashCollection = new RouteCollection();
$trailingSlashCollection->add('simple_trailing_slash_no_methods', new Route('/trailing/simple/no-methods/', array(), array(), array(), '', array(), array()));
$trailingSlashCollection->add('simple_trailing_slash_GET_method', new Route('/trailing/simple/get-method/', array(), array(), array(), '', array(), array('GET')));
$trailingSlashCollection->add('simple_trailing_slash_HEAD_method', new Route('/trailing/simple/head-method/', array(), array(), array(), '', array(), array('HEAD')));
$trailingSlashCollection->add('simple_trailing_slash_POST_method', new Route('/trailing/simple/post-method/', array(), array(), array(), '', array(), array('POST')));
$trailingSlashCollection->add('regex_trailing_slash_no_methods', new Route('/trailing/regex/no-methods/{param}/', array(), array(), array(), '', array(), array()));
$trailingSlashCollection->add('regex_trailing_slash_GET_method', new Route('/trailing/regex/get-method/{param}/', array(), array(), array(), '', array(), array('GET')));
$trailingSlashCollection->add('regex_trailing_slash_HEAD_method', new Route('/trailing/regex/head-method/{param}/', array(), array(), array(), '', array(), array('HEAD')));
$trailingSlashCollection->add('regex_trailing_slash_POST_method', new Route('/trailing/regex/post-method/{param}/', array(), array(), array(), '', array(), array('POST')));
$trailingSlashCollection->add('simple_not_trailing_slash_no_methods', new Route('/not-trailing/simple/no-methods', array(), array(), array(), '', array(), array()));
$trailingSlashCollection->add('simple_not_trailing_slash_GET_method', new Route('/not-trailing/simple/get-method', array(), array(), array(), '', array(), array('GET')));
$trailingSlashCollection->add('simple_not_trailing_slash_HEAD_method', new Route('/not-trailing/simple/head-method', array(), array(), array(), '', array(), array('HEAD')));
$trailingSlashCollection->add('simple_not_trailing_slash_POST_method', new Route('/not-trailing/simple/post-method', array(), array(), array(), '', array(), array('POST')));
$trailingSlashCollection->add('regex_not_trailing_slash_no_methods', new Route('/not-trailing/regex/no-methods/{param}', array(), array(), array(), '', array(), array()));
$trailingSlashCollection->add('regex_not_trailing_slash_GET_method', new Route('/not-trailing/regex/get-method/{param}', array(), array(), array(), '', array(), array('GET')));
$trailingSlashCollection->add('regex_not_trailing_slash_HEAD_method', new Route('/not-trailing/regex/head-method/{param}', array(), array(), array(), '', array(), array('HEAD')));
$trailingSlashCollection->add('regex_not_trailing_slash_POST_method', new Route('/not-trailing/regex/post-method/{param}', array(), array(), array(), '', array(), array('POST')));
return array( return array(
array($collection, 'url_matcher1.php', array()), array($collection, 'url_matcher1.php', array()),
array($redirectCollection, 'url_matcher2.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')), array($redirectCollection, 'url_matcher2.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')),
array($rootprefixCollection, 'url_matcher3.php', array()), array($rootprefixCollection, 'url_matcher3.php', array()),
array($headMatchCasesCollection, 'url_matcher4.php', array()), array($headMatchCasesCollection, 'url_matcher4.php', array()),
array($groupOptimisedCollection, 'url_matcher5.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')), array($groupOptimisedCollection, 'url_matcher5.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')),
array($trailingSlashCollection, 'url_matcher6.php', array()),
array($trailingSlashCollection, 'url_matcher7.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')),
); );
} }
} }

View File

@ -476,7 +476,7 @@ EOTXT
*/ */
public function testBuggyRefs() public function testBuggyRefs()
{ {
if (PHP_VERSION_ID >= 50600) { if (\PHP_VERSION_ID >= 50600) {
$this->markTestSkipped('PHP 5.6 fixed refs counting'); $this->markTestSkipped('PHP 5.6 fixed refs counting');
} }