diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000000..b03e61ef338c1 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,11 @@ +| Q | A +| ------------- | --- +| Branch | master for features and deprecations / lowest applicable and maintained version otherwise +| Bug fix? | yes/no +| New feature? | yes/no +| BC breaks? | yes/no +| Deprecations? | yes/no +| Tests pass? | yes/no +| Fixed tickets | comma-separated list of tickets fixed by the PR, if any +| License | MIT +| Doc PR | reference to the documentation PR, if any diff --git a/.travis.yml b/.travis.yml index 25897fabe6f78..46572d8dd8b0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,9 @@ language: php sudo: false +git: + depth: 1 + addons: apt_packages: - parallel @@ -31,15 +34,18 @@ cache: services: mongodb before_install: + # Matrix lines for intermediate PHP versions are skipped for pull requests - if [[ ! $deps && ! $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && $TRAVIS_PHP_VERSION != hhvm && $TRAVIS_PULL_REQUEST != false ]]; then deps=skip; fi; + # A sigchild-enabled-PHP is used to test the Process component on the lowest PHP matrix line - if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then wget http://museum.php.net/php5/php-$MIN_PHP.tar.bz2 -O - | tar -xj; (cd php-$MIN_PHP; ./configure --enable-sigchild --enable-pcntl; make -j2); fi; - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; else INI_FILE=/etc/hhvm/php.ini; fi; - echo memory_limit = -1 >> $INI_FILE - echo session.gc_probability = 0 >> $INI_FILE - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo extension = mongo.so >> $INI_FILE; fi; - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo extension = memcache.so >> $INI_FILE; fi; - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.10 && echo apc.enable_cli = 1 >> $INI_FILE) || echo "Let's continue without apcu extension"; fi; - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then pecl install -f memcached-2.1.0 || echo "Let's continue without memcached extension"; fi; + - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.10 && echo apc.enable_cli = 1 >> $INI_FILE); fi; + - if [[ $TRAVIS_PHP_VERSION = 7.* ]]; then (echo yes | pecl install -f apcu-5.1.2 && echo apc.enable_cli = 1 >> $INI_FILE); fi; + - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then pecl install -f memcached-2.1.0; fi; - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then echo extension = ldap.so >> $INI_FILE; fi; - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then phpenv config-rm xdebug.ini; fi; - if [[ $TRAVIS_REPO_SLUG = symfony/symfony ]]; then cp .composer-auth.json ~/.composer/auth.json; fi; @@ -49,9 +55,12 @@ before_install: install: - if [[ $deps != skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi; + # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components - if [[ $deps != skip && $deps ]]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $COMPONENTS; fi; + # For the master branch when deps=high, the version before master is checked out and tested with the locally patched components - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//); else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*'); fi; - - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; fi; + - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi; + # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number than the next one - if [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]]; then LEGACY=,legacy; fi; - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev; - if [[ ! $deps ]]; then composer update --prefer-dist; else export SYMFONY_DEPRECATIONS_HELPER=weak; fi; diff --git a/CHANGELOG-2.3.md b/CHANGELOG-2.3.md index bdc4cb0ef6468..5d22ee314f31b 100644 --- a/CHANGELOG-2.3.md +++ b/CHANGELOG-2.3.md @@ -7,6 +7,52 @@ in 2.3 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.3.0...v2.3.1 +* 2.3.38 (2016-02-28) + + * bug #17947 Fix - #17676 (backport #17919 to 2.3) (Ocramius) + * bug #17942 Fix bug when using an private aliased factory service (WouterJ) + * bug #17542 ChoiceFormField of type "select" could be "disabled" (bouland) + * bug #17602 [HttpFoundation] Fix BinaryFileResponse incorrect behavior with if-range header (bburnichon) + * bug #17914 [Console] Fix escaping of trailing backslashes (nicolas-grekas) + * bug #17074 Fix constraint validator alias being required (Triiistan) + * bug #17867 [DependencyInjection] replace alias in factory services (xabbuh) + * bug #17569 [FrameworkBundle] read commands from bundles when accessing list (havvg) + * bug #16987 [FileSystem] Windows fix (flip111) + * bug #17835 [Yaml] fix default timezone to be UTC (xabbuh) + * bug #17823 [DependencyInjection] fix dumped YAML string (xabbuh) + * bug #17814 [DependencyInjection] fix dumped YAML snytax (xabbuh) + * bug #17099 [Form] Fixed violation mapping if multiple forms are using the same (or part of the same) property path (alekitto) + * bug #17719 [DependencyInjection] fixed exceptions thrown by get method of ContainerBuilder (lukaszmakuch) + * bug #17742 [DependencyInjection] Fix #16461 Container::set() replace aliases (mnapoli) + * bug #17745 Added more exceptions to singularify method (javiereguiluz) + * bug #17766 Fixed (string) catchable fatal error for PHP Incomplete Class instances (yceruto) + * bug #17757 [HttpFoundation] BinaryFileResponse sendContent return as parent. (2.3) (SpacePossum) + * bug #17702 [TwigBridge] forward compatibility with Yaml 3.1 (xabbuh) + * bug #17672 [DependencyInjection][Routing] add files used in FileResource objects (xabbuh) + * bug #17596 [Translation] Add resources from fallback locale to parent catalogue (c960657) + * bug #16956 [DependencyInjection] XmlFileLoader: enforce tags to have a name (xabbuh) + * bug #16265 [BrowserKit] Corrected HTTP_HOST logic (Naktibalda) + * bug #17555 [DependencyInjection] resolve aliases in factory services (xabbuh) + * bug #15272 [FrameworkBundle] Fix template location for PHP templates (jakzal) + * bug #11232 [Routing] Fixes fatal errors with object resources in AnnotationDirectoryLoader::supports (Tischoi) + * bug #17526 Escape the delimiter in Glob::toRegex (javiereguiluz) + * bug #17527 fixed undefined variable (fabpot) + * bug #15706 [framework-bundle] Added support for the `0.0.0.0/0` trusted proxy (zerkms) + * bug #16274 [HttpKernel] Lookup the response even if the lock was released after two second wait (jakzal) + * bug #17355 [DoctrineBridge][Validator] >= 2.3 Pass association instead of ID as argument (xavismeh) + * bug #16736 [Request] Ignore invalid IP addresses sent by proxies (GromNaN) + * bug #16873 Able to load big xml files with DomCrawler (zorn-v) + * bug #16897 [Form] Fix constraints could be null if not set (DZunke) + * bug #17505 sort bundles in config:dump-reference command (xabbuh) + * bug #17478 [HttpFoundation] Do not overwrite the Authorization header if it is already set (jakzal) + * bug #17461 [Yaml] tag for dumped PHP objects must be a local one (xabbuh) + * bug #17423 [Process] Use stream based storage to avoid memory issues (romainneutron) + * bug #17373 [SecurityBundle] fix SecureRandom service constructor args (Tobion) + * bug #17377 Fix performance (PHP5) and memory (PHP7) issues when using token_get_all (nicolas-grekas, peteward) + * bug #17389 [Routing] Fixed correct class name in thrown exception (fixes #17388) (robinvdvleuten) + * bug #17358 [ClassLoader] Use symfony/polyfill-apcu (nicolas-grekas) + * bug #17370 [HttpFoundation][Cookie] Cookie DateTimeInterface fix (wildewouter) + * 2.3.37 (2016-01-14) * security #17359 do not ship with a custom rng implementation (xabbuh, fabpot) @@ -29,7 +75,7 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c * bug #17129 [Config] Fix array sort on normalization in edge case (romainneutron) * bug #17094 [Process] More robustness and deterministic tests (nicolas-grekas) * bug #17112 [PropertyAccess] Reorder elements array after PropertyPathBuilder::replace (alekitto) - * bug #16797 [Filesystem] Recursivly widen non-executable directories (Slamdunk) + * bug #16797 [Filesystem] Recursively widen non-executable directories (Slamdunk) * bug #17040 [Console] Avoid extra blank lines when rendering exceptions (ogizanagi) * bug #17055 [Security] Verify if a password encoded with bcrypt is no longer than 72 characters (jakzal) * bug #16959 [Form] fix #15544 when a collection type attribute "required" is false, "prototype" should too (HeahDude) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 123d5aa755911..ae18925cb6e20 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,29 +5,20 @@ Symfony is an open source, community-driven project. If you'd like to contribute, please read the following documents: -* [Contributing Code][1]: The document index related to contributions; - -* [Submitting a Patch][2]: Guidelines for submitting a pull request; - -* [Pull Request Template][3]: Template header to use in your pull request - description; - -```markdown -| Q | A -| ------------- | --- -| Bug fix? | yes/no -| New feature? | yes/no -| BC breaks? | no -| Deprecations? | no -| Tests pass? | yes -| Fixed tickets | #1234 -| License | MIT -| Doc PR | symfony/symfony-docs#1234 -``` - -* [Backwards Compatibility][4]: Backward compatibility rules. - -[1]: https://symfony.com/doc/current/contributing/code/index.html -[2]: https://symfony.com/doc/current/contributing/code/patches.html#check-list -[3]: https://symfony.com/doc/current/contributing/code/patches.html#make-a-pull-request -[4]: https://symfony.com/doc/current/contributing/code/bc.html#working-on-symfony-code +* [Reporting a Bug][1] +* [Submitting a Patch][2] +* [Symfony Core Team][3] +* [Security Issues][4] +* [Running Symfony Tests][5] +* [Our Backwards Compatibility Promise][6] +* [Coding Standards][7] +* [Conventions][8] + +[1]: https://symfony.com/doc/current/contributing/code/bugs.html +[2]: https://symfony.com/doc/current/contributing/code/patches.html +[3]: https://symfony.com/doc/current/contributing/code/core_team.html +[4]: https://symfony.com/doc/current/contributing/code/security.html +[5]: https://symfony.com/doc/current/contributing/code/tests.html +[6]: https://symfony.com/doc/current/contributing/code/bc.html +[7]: https://symfony.com/doc/current/contributing/code/standards.html +[8]: https://symfony.com/doc/current/contributing/code/conventions.html diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5786f19dde7d6..fdf163f5d8e0c 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -5,122 +5,136 @@ Symfony is the result of the work of many people who made the code better (see https://symfony.com/contributors for more information): - Fabien Potencier (fabpot) - - Bernhard Schussek (bschussek) - Nicolas Grekas (nicolas-grekas) + - Bernhard Schussek (bschussek) - Tobias Schultze (tobion) - - Victor Berchet (victor) - - Jordi Boggiano (seldaek) - Christophe Coevoet (stof) + - Jordi Boggiano (seldaek) + - Victor Berchet (victor) + - Christian Flothmann (xabbuh) - Johannes S (johannes) - Kris Wallsmith (kriswallsmith) - - Christian Flothmann (xabbuh) - Jakub Zalas (jakubzalas) - Ryan Weaver (weaverryan) - - Pascal Borreli (pborreli) - Hugo Hamon (hhamon) + - Javier Eguiluz (javier.eguiluz) + - Abdellatif Ait boudad (aitboudad) + - Pascal Borreli (pborreli) + - Kévin Dunglas (dunglas) - Joseph Bielawski (stloyd) + - Wouter De Jong (wouterj) - Karma Dordrak (drak) - - Lukas Kahwe Smith (lsmith) - Romain Neutron (romain) - - Abdellatif Ait boudad (aitboudad) + - Lukas Kahwe Smith (lsmith) - Jeremy Mikola (jmikola) + - Martin Hasoň (hason) - Jean-François Simon (jfsimon) - Benjamin Eberlei (beberlei) - Igor Wiedler (igorw) - - Martin Hasoň (hason) - - Wouter De Jong (wouterj) - - Eriksen Costa (eriksencosta) - - Javier Eguiluz (javier.eguiluz) - Grégoire Pineau (lyrixx) - - Kévin Dunglas (dunglas) + - Eriksen Costa (eriksencosta) + - Sarah Khalil (saro0h) - Jonathan Wage (jwage) + - Maxime Steinhausser (ogizanagi) + - Diego Saint Esteben (dosten) - Alexandre Salomé (alexandresalome) - William Durand (couac) - ornicar - stealth35 ‏ (stealth35) - Alexander Mols (asm89) - - Bulat Shakirzyanov (avalanche123) - Francis Besset (francisbesset) + - Bulat Shakirzyanov (avalanche123) - Saša Stamenković (umpirsky) - Henrik Bjørnskov (henrikbjorn) - Miha Vrhovnik - Diego Saint Esteben (dii3g0) - - Sarah Khalil (saro0h) - Konstantin Kudryashov (everzet) - Bilal Amarni (bamarni) - Florin Patan (florinpatan) - - Maxime Steinhausser (ogizanagi) + - Kevin Bond (kbond) + - Gábor Egyed (1ed) + - Michel Weimerskirch (mweimerskirch) - Eric Clemmons (ericclemmons) - Andrej Hudec (pulzarraider) + - Matthias Pigulla (mpdude) + - Peter Rehm (rpet) - Deni - Henrik Westphal (snc) - Dariusz Górecki (canni) - - Gábor Egyed (1ed) - Christian Raue - - Michel Weimerskirch (mweimerskirch) - Arnout Boks (aboks) - - Kevin Bond (kbond) - Douglas Greenshields (shieldo) - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) - Daniel Holmes (dholmes) + - Pierre du Plessis (pierredup) - Bart van den Burg (burgov) - Jordan Alliot (jalliot) - - Matthias Pigulla (mpdude) - John Wards (johnwards) + - Toni Uebernickel (havvg) - Fran Moreno (franmomu) + - Graham Campbell (graham) - Antoine Hérault (herzult) - - Toni Uebernickel (havvg) + - Iltar van der Berg (kjarli) - Arnaud Le Blanc (arnaud-lb) + - Jérôme Tamarelle (gromnan) + - Michal Piotrowski (eventhorizon) - Tim Nagel (merk) - Brice BERNARD (brikou) - - Graham Campbell (graham) - - Jérôme Tamarelle (gromnan) + - Charles Sarrazin (csarrazi) + - Alexander M. Turek (derrabus) + - Dariusz Ruminski - marc.weistroff - - Michal Piotrowski (eventhorizon) - lenar - Włodzimierz Gajda (gajdaw) + - Paráda József (paradajozsef) + - Alexander Schwenn (xelaris) - Florian Voutzinos (florianv) - - Peter Rehm (rpet) - Colin Frei - - Dariusz Ruminski - Adrien Brault (adrienbrault) + - Joshua Thijssen + - Issei Murasawa (issei_m) + - Peter Kokot (maastermedia) - excelwebzone - Jacob Dreesen (jdreesen) - - Peter Kokot (maastermedia) + - Jérémy DERUSSÉ (jderusse) + - Vladimir Reznichenko (kalessil) + - Baptiste Clavié (talus) + - Ener-Getick (energetick) - Fabien Pennequin (fabienpennequin) - - Pierre du Plessis (pierredup) - - Alexander Schwenn (xelaris) - Gordon Franke (gimler) - - Iltar van der Berg (kjarli) + - Konstantin Myakshin (koc) + - Tomáš Votruba (tomas_votruba) + - Jáchym Toušek - Robert Schönthal (digitalkaoz) - - Jérémy DERUSSÉ (jderusse) - - Joshua Thijssen + - Florian Lonqueu-Brochard (florianlb) + - Eric GELOEN (gelo) - Stefano Sala (stefano.sala) - David Buchmann (dbu) - - Issei Murasawa (issei_m) - Juti Noppornpitak (shiroyuki) - - Eric GELOEN (gelo) + - Tigran Azatyan (tigranazatyan) - Sebastian Hörl (blogsh) - Daniel Gomes (danielcsgomes) - Hidenori Goto (hidenorigoto) - - Vladimir Reznichenko (kalessil) + - Jules Pietri (heah) + - Evgeniy (ewgraf) - Guilherme Blanco (guilhermeblanco) - Pablo Godel (pgodel) - - Tigran Azatyan (tigranazatyan) - Jérémie Augustin (jaugustin) - Sebastiaan Stok (sstok) + - Tugdual Saunier (tucksaun) + - Andréia Bohner (andreia) - Rafael Dohms (rdohms) - Arnaud Kleinpeter (nanocom) - - Alexander M. Turek (derrabus) + - Philipp Wahala (hifi) - Richard Shank (iampersistent) - - Charles Sarrazin (csarrazi) + - Thomas Rabaix (rande) + - Vincent AUBERT (vincent) + - Joel Wurtz (brouznouf) + - Mikael Pajunen - Clemens Tolboom - Helmer Aaviksoo - - Baptiste Clavié (talus) - - Tugdual Saunier (tucksaun) - - Andréia Bohner (andreia) - Hiromi Hishida (77web) - Matthieu Ouellette-Vachon (maoueh) - Michał Pipa (michal.pipa) @@ -131,93 +145,99 @@ Symfony is the result of the work of many people who made the code better - Warnar Boekkooi (boekkooi) - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) + - Daniel Wehner - Dorian Villet (gnutix) - Javier Spagnoletti (phansys) - Richard Miller (mr_r_miller) - - hacfi (hifi) - Mario A. Alvarez Garcia (nomack84) - - Thomas Rabaix (rande) - Dennis Benkert (denderello) - - Konstantin Myakshin (koc) - Benjamin Dulau (dbenjamin) - Andreas Hucks (meandmymonkey) - - Mikael Pajunen - Noel Guilbert (noel) - - Joel Wurtz (brouznouf) - - Evgeniy (ewgraf) + - Richard van Laak (rvanlaak) - bronze1man - sun (sun) - Larry Garfield (crell) + - Possum - Martin Schuhfuß (usefulthink) - - Jáchym Toušek - Matthieu Bontemps (mbontemps) - Pierre Minnieur (pminnieur) - fivestar - Dominique Bongiraud + - Jeremy Livingston (jeremylivingston) + - Matthieu Auger (matthieuauger) - Leszek Prabucki (l3l0) - François Zaninotto (fzaninotto) - Dustin Whittle (dustinwhittle) - jeff - John Kary (johnkary) - Justin Hileman (bobthecow) + - Blanchon Vincent (blanchonvincent) - Michele Orselli (orso) - Sven Paulus (subsven) - Lars Strojny (lstrojny) - - Daniel Wehner - Rui Marinho (ruimarinho) + - Stepan Anchugov (kix) + - Eugene Wissner - Julien Brochet (mewt) - Sergey Linnik (linniksa) + - Michaël Perrin (michael.perrin) - Marcel Beerta (mazen) - - Vincent AUBERT (vincent) + - Titouan Galopin (tgalopin) + - Loïc Faugeron + - Jannik Zschiesche (apfelbox) - julien pauli (jpauli) - - Florian Lonqueu-Brochard (florianlb) + - Michael Lee (zerustech) + - Lorenz Schori + - Sébastien Lavoie (lavoiesl) - Francois Zaninotto - Alexander Kotynia (olden) - Daniel Tschinder + - Marcos Sánchez - Elnur Abdurrakhimov (elnur) - Manuel Reinhard (sprain) - Danny Berger (dpb587) - - Diego Saint Esteben (dosten) + - Jérôme Vasseur - Roman Marintšenko (inori) - Xavier Montaña Carreras (xmontana) + - Tom Van Looy (tvlooy) - Chris Wilkinson (thewilkybarkid) + - Mickaël Andrieu (mickaelandrieu) - Xavier Perez - Arjen Brouwer (arjenjb) - Katsuhiro OGAWA - Alif Rachmawadi + - Kristen Gilden (kgilden) - Pierre-Yves LEBECQ (pylebecq) + - Jakub Kucharovic (jkucharovic) - Eugene Leonovich (rybakit) + - Filippo Tessarotto - Joseph Rouff (rouffj) - Félix Labrecque (woodspire) - - Tomáš Votruba (tomas_votruba) - GordonsLondon - Jan Sorgalla (jsor) - Ray - Chekote - Thomas Adam - Albert Casademont (acasademont) + - Diego Agulló (aeoris) - jdhoek - - Jeremy Livingston (jeremylivingston) - Nikita Konstantinov - Wodor Wodorski - - Matthieu Auger (matthieuauger) - - Michael Lee (zerustech) - - Sébastien Lavoie (lavoiesl) + - Thomas Lallement (raziel057) - Beau Simensen (simensen) + - Michael Hirschler (mvhirsch) - Robert Kiss (kepten) - Ruben Gonzalez (rubenrua) - - Marcos Sánchez + - Roumen Damianoff (roumen) + - Antonio J. García Lagar (ajgarlag) - Kim Hemsø Rasmussen (kimhemsoe) - - Tom Van Looy (tvlooy) - Wouter Van Hecke - Peter Kruithof (pkruithof) - Michael Holm (hollo) - Marc Weistroff (futurecat) - - Blanchon Vincent (blanchonvincent) - Dawid Nowak - - Kristen Gilden (kgilden) - Chris Smith (cs278) - - Richard van Laak (rvanlaak) - Florian Klein (docteurklein) - Manuel Kiessling (manuelkiessling) - Daniel Wehner @@ -228,6 +248,7 @@ Symfony is the result of the work of many people who made the code better - Grégoire Paris (greg0ire) - Alex Pott - realmfoo + - jeremyFreeAgent (jeremyfreeagent) - Thomas Tourlourat (armetiz) - Andrey Esaulov (andremaha) - Grégoire Passault (gregwar) @@ -235,26 +256,31 @@ Symfony is the result of the work of many people who made the code better - Uwe Jäger (uwej711) - Aurelijus Valeiša (aurelijus) - Jan Decavele (jandc) + - Yonel Ceruto González (yonelceruto) - Gustavo Piltcher - Stepan Tanasiychuk (stfalcon) - - Titouan Galopin (tgalopin) - Tiago Ribeiro (fixe) + - Hidde Boomsma (hboomsma) + - John Bafford (jbafford) - Bob den Otter (bopp) - Adrian Rudnik (kreischweide) - Francesc Rosàs (frosas) - Julien Galenski (ruian) - Bongiraud Dominique - janschoenherr - - Jannik Zschiesche (apfelbox) - Thomas Schulz (king2500) - Marco Pivetta (ocramius) + - Berny Cantos (xphere81) - Ricard Clau (ricardclau) - - Lorenz Schori + - Mark Challoner (markchalloner) + - Gregor Harlan (gharlan) + - Gennady Telegin (gtelegin) - Giorgio Premi + - Matthieu Napoli (mnapoli) + - Ben Davies (bendavies) - Erin Millard + - Artur Melo (restless) - Matthew Lewinski (lewinski) - - Antonio J. García Lagar (ajgarlag) - - Roumen Damianoff (roumen) - alquerci - Francesco Levorato - Vitaliy Zakharov (zakharovvi) @@ -264,9 +290,9 @@ Symfony is the result of the work of many people who made the code better - Christian Gärtner (dagardner) - Tomasz Kowalczyk (thunderer) - François-Xavier de Guillebon (de-gui_f) + - Damien Alexandre (damienalexandre) - Felix Labrecque - Yaroslav Kiliba - - Stepan Anchugov (kix) - Terje Bråten - Robbert Klarenbeek (robbertkl) - hossein zolfi (ocean) @@ -276,9 +302,7 @@ Symfony is the result of the work of many people who made the code better - Stéphane PY (steph_py) - Philipp Kräutli (pkraeutli) - Kirill chEbba Chebunin (chebba) - - Filippo Tessarotto - Greg Thornton (xdissent) - - jeremyFreeAgent (jeremyfreeagent) - Costin Bereveanu (schniper) - Loïc Chardonnet (gnusat) - Marek Kalnik (marekkalnik) @@ -286,26 +310,29 @@ Symfony is the result of the work of many people who made the code better - Vyacheslav Salakhutdinov (megazoll) - Hassan Amouhzi - Tamas Szijarto - - Michaël Perrin (michael.perrin) - Pavel Volokitin (pvolok) - Endre Fejes - Tobias Naumann (tna) - Shein Alexey - Joe Lencioni - Daniel Tschinder - - Diego Agulló (aeoris) - Kai - Lee Rowlands - Maximilian Reichel (phramz) - Karoly Negyesi (chx) + - Ivan Kurnosov - Xavier HAUSHERR - Albert Jessurum (ajessu) + - Oleg Voronkovich - Laszlo Korte + - Pavel Batanov (scaytrase) - Miha Vrhovnik - Alessandro Desantis - hubert lecorche (hlecorche) - Marc Morales Valldepérez (kuert) + - Jean-Baptiste GOMOND (mjbgo) - Vadim Kharitonov (virtuozzz) + - Andreas Schempp (aschempp) - Oscar Cubo Medina (ocubom) - Karel Souffriau - Christophe L. (christophelau) @@ -313,23 +340,23 @@ Symfony is the result of the work of many people who made the code better - Anthon Pang (robocoder) - Emanuele Gaspari (inmarelibero) - Dariusz Rumiński + - Sébastien Santoro (dereckson) - Brian King - Michel Salib (michelsalib) - geoffrey + - Valentin Jonovs (valentins-jonovs) - Jeanmonod David (jeanmonod) - - Berny Cantos (xphere81) - - Thomas Lallement (raziel057) - Jan Schumann - Niklas Fiekas - - Mark Challoner (markchalloner) - - Gregor Harlan (gharlan) - Markus Bachmann (baachi) - lancergr - Olivier Dolbeau (odolbeau) - - Ben Davies (bendavies) + - Jan Rosier (rosier) - vagrant + - EdgarPE + - Florian Pfitzer (marmelatze) - Asier Illarramendi (doup) - - Artur Melo (restless) + - Christian Schmidt - Chris Sedlmayr (catchamonkey) - Seb Koelen - Christoph Mewes (xrstf) @@ -339,27 +366,35 @@ Symfony is the result of the work of many people who made the code better - cedric lombardot (cedriclombardot) - Jonas Flodén (flojon) - Christian Schmidt - - Jakub Kucharovic (jkucharovic) + - Hidde Wieringa (hiddewie) + - Marek Štípek (maryo) - Marcin Sikoń (marphi) - Dominik Zogg (dominik.zogg) + - Marek Pietrzak + - Chad Sikorra (chadsikorra) - Mathieu Lemoine - franek (franek) - - Damien Alexandre (damienalexandre) + - Christian Wahler + - Gintautas Miselis + - Zander Baldwin - Adam Harvey - Alex Bakhturin + - Alessandro Chitolina - boombatower - Fabrice Bernhard (fabriceb) - Jérôme Macias (jeromemacias) - Fabian Lange (codingfabian) + - Frank Neff (fneff) + - Roman Lapin (memphys) - Yoshio HANAWA + - Gladhon - Sebastian Bergmann - Pablo Díez (pablodip) - Kevin McBride - - Ener-Getick (energetick) - Philipp Rieber (bicpi) - Manuel de Ruiter (manuel) - Eduardo Oliveira (entering) - - Eugene Wissner + - Ilya Antipenko (aivus) - Iker Ibarguren (ikerib) - Ricardo Oliveira (ricardolotr) - ondrowan @@ -372,6 +407,7 @@ Symfony is the result of the work of many people who made the code better - mmoreram - Markus Lanthaler (lanthaler) - Vicent Soria Durá (vicentgodella) + - Nicolas Dewez (nicolas_dewez) - Anthony Ferrara - Ioan Negulescu - Jakub Škvára (jskvara) @@ -381,26 +417,30 @@ Symfony is the result of the work of many people who made the code better - Tristan Darricau (nicofuma) - Erik Trapman (eriktrapman) - De Cock Xavier (xdecock) - - Possum + - Almog Baku (almogbaku) - Scott Arciszewski - Norbert Orzechowicz (norzechowicz) + - Denis Charrier (brucewouaigne) - Matthijs van den Bos (matthijs) - Loick Piera (pyrech) - Lenard Palko - Nils Adermann (naderman) - Gábor Fási + - DUPUCH (bdupuch) - Benjamin Leveque (benji07) - - Ivan Kurnosov - sasezaki - Dawid Pakuła (zulusx) - Florian Rey (nervo) + - Oskar Stark (oskarstark) - Rodrigo Borrego Bernabé (rodrigobb) - Leo Feyer - MatTheCat - - John Bafford (jbafford) - Denis Gorbachev (starfall) + - Peter van Dommelen + - Tim van Densen - Steven Surowiec - Kevin Saliou (kbsali) + - NothingWeAre - Ryan - Alexander Deruwe (aderuwe) - Alain Hippolyte (aloneh) @@ -413,47 +453,55 @@ Symfony is the result of the work of many people who made the code better - Lenar Lõhmus - Benjamin Laugueux (yzalis) - Zach Badgett (zachbadgett) - - Loïc Faugeron - Aurélien Fredouelle - Pavel Campr (pcampr) - Johnny Robeson (johnny) - Disquedur + - Michiel Boeckaert (milio) + - Baptiste Lafontaine - Geoffrey Tran (geoff) - Jan Behrens - Mantas Var (mvar) - Sebastian Krebs + - Jean-Christophe Cuvelier [Artack] - Christopher Davis (chrisguitarguy) - alcaeus - vitaliytv - Sebastian Blum - aubx + - Marvin Butkereit - Ricky Su (ricky) - Gildas Quéméner (gquemener) + - Charles-Henri Bruyand - Max Rath (drak3) - Stéphane Escandell (sescandell) + - Konstantin S. M. Möllers (ksmmoellers) - Sinan Eldem - - Gennady Telegin (gtelegin) - Alexandre Dupuy (satchette) - Nahuel Cuesta (ncuesta) - Chris Boden (cboden) - Asmir Mustafic (goetas) + - Stefan Gehrig (sgehrig) - Josip Kruslin - Hany el-Kerdany - Wang Jingyu - Åsmund Garfors - Maxime Douailin - - Michael Hirschler (mvhirsch) - Javier López (loalf) - Reinier Kip - Dustin Dobervich (dustin10) - Sebastian Marek (proofek) - Erkhembayar Gantulga (erheme318) + - Michal Trojanowski + - Mihai Stancu - David Fuhr - Kamil Kokot (pamil) + - Max Grigorian (maxakawizard) - Rostyslav Kinash - Maciej Malarz (malarzm) - Daisuke Ohata - Vincent Simonin + - Alex Bogomazov (alebo) - Stefan Warman - Tristan Maindron (tmaindron) - Ke WANG (yktd26) @@ -463,7 +511,6 @@ Symfony is the result of the work of many people who made the code better - umpirski - Chris Heng (gigablah) - Ulumuddin Yunus (joenoez) - - Florian Pfitzer (marmelatze) - Luc Vieillescazes (iamluc) - Johann Saunier (prophet777) - Antoine Corcy @@ -471,11 +518,12 @@ Symfony is the result of the work of many people who made the code better - Arturs Vonda - Sascha Grossenbacher - Szijarto Tamas + - Stephan Vock - Benjamin Zikarsky (bzikarsky) - - Mickaël Andrieu (mickaelandrieu) - Simon Schick (simonsimcity) - redstar504 - Hossein Bukhamsin + - Disparity - origaminal - Paweł Wacławczyk (pwc) - Oleg Zinchenko (cystbear) @@ -487,7 +535,6 @@ Symfony is the result of the work of many people who made the code better - Tiago Brito (blackmx) - Richard van den Brand (ricbra) - develop - - Hidde Wieringa - Mark Sonnabaum - Alexander Obuhovich (aik099) - jochenvdv @@ -495,19 +542,23 @@ Symfony is the result of the work of many people who made the code better - Alexander Volochnev (exelenz) - Michael Piecko - yclian + - twifty - Sergio Santoro + - Peter Ward + - Dominik Ritter (dritter) - Sebastian Grodzicki (sgrodzicki) - Martin Hujer (martinhujer) - Pascal Helfenstein - Baldur Rensch (brensch) - Vladyslav Petrovych - Alex Xandra Albert Sim + - Trent Steel (trsteel88) - Yuen-Chi Lian - Besnik Br + - Dariusz Ruminski - Joshua Nye - Dave Marshall (davedevelopment) - avorobiev - - Gladhon - Venu - Lars Vierbergen - Dennis Hotson @@ -517,20 +568,20 @@ Symfony is the result of the work of many people who made the code better - Leevi Graham (leevigraham) - Casper Valdemar Poulsen - Josiah (josiah) - - Marek Štípek (maryo) - John Bohn (jbohn) - Marc Morera (mmoreram) - Andrew Hilobok (hilobok) - Christian Soronellas (theunic) - Romain Gautier (mykiwi) - Yosmany Garcia (yosmanyga) + - Wouter de Wild - Degory Valentine - Benoit Lévêque (benoit_leveque) - Jeroen Fiege (fieg) - Krzysiek Łabuś - - Ilya Antipenko (aivus) - - Nicolas Dewez (nicolas_dewez) - Xavier Lacot (xavier) + - possum + - Denis Zunke (donalberto) - Olivier Maisonneuve (olineuve) - Francis Turmel (fturmel) - cgonzalez @@ -540,6 +591,7 @@ Symfony is the result of the work of many people who made the code better - fago - Harm van Tilborg - Jan Prieser + - Adrien Lucas (adrienlucas) - James Michael DuPont - Tom Klingenberg - Christopher Hall (mythmakr) @@ -547,11 +599,10 @@ Symfony is the result of the work of many people who made the code better - Rafał Wrzeszcz (rafalwrzeszcz) - Reen Lokum - Martin Parsiegla (spea) - - Denis Charrier (brucewouaigne) - Quentin Schuler - Pierre Vanliefland (pvanliefland) + - Sofiane HADDAG (sofhad) - frost-nzcr4 - - Oskar Stark (oskarstark) - Abhoryo - Fabian Vogler (fabian) - Korvin Szanto @@ -559,10 +610,12 @@ Symfony is the result of the work of many people who made the code better - Maksim Kotlyar (makasim) - Neil Ferreira - Dmitry Parnas (parnas) + - Paul LE CORRE - DQNEO - Emanuele Iannone - Tony Malzhacker - - DUPUCH (bdupuch) + - Mathieu MARCHOIS + - Benoît Burnichon (bburnichon) - Cyril Quintin (cyqui) - Gerard van Helden (drm) - Johnny Peck (johnnypeck) @@ -571,22 +624,26 @@ Symfony is the result of the work of many people who made the code better - Gustavo Falco (gfalco) - Matt Robinson (inanimatt) - Aleksey Podskrebyshev + - Calin Mihai Pristavu - Steffen Roßkamp - David Marín Carreño (davefx) - - Hidde Boomsma (hboomsma) - Jörn Lang (j.lang) + - Omar Yepez (oyepez003) - mwsaz + - Jelle Kapitein - Benoît Bourgeois + - mantulo - corphi - grizlik - Derek ROTH - Shin Ohno (ganchiku) - Geert De Deckere (geertdd) - Jan Kramer (jankramer) - - Jean-Baptiste GOMOND (mjbgo) - abdul malik ikhsan (samsonasik) - Henry Snoek (snoek09) + - Simone Di Maulo (toretto460) - Timothée Barray (tyx) + - Sander Toonen (xatoo) - Christian Morgan - Alexander Miehe (engerim) - Morgan Auchede (mauchede) @@ -605,25 +662,32 @@ Symfony is the result of the work of many people who made the code better - Adán Lobato (adanlobato) - Matthew Davis (mdavis1982) - Maks + - Antoine LA + - pawel-lewtak + - omerida - Gábor Tóth - Daniel Cestari + - Jeremy Benoist + - David Lima + - Jérôme Vasseur + - Krzysztof Piasecki (krzysztek) - Brunet Laurent (lbrunet) - Magnus Nordlander (magnusnordlander) - - Michiel Boeckaert (milio) - Mikhail Yurasov (mym) - LOUARDI Abdeltif (ouardisoft) - Robert Gruendler (pulse00) + - Robin van der Vleuten (robinvdvleuten) - Simon Terrien (sterrien) - Benoît Merlet (trompette) - Koen Kuipers - datibbaw - - Sébastien Santoro - Raul Fraile (raulfraile) - sensio - Patrick Kaufmann - Reece Fowell (reecefowell) + - Mátyás Somfai (smatyas) - stefan.r - - Matthieu Napoli (mnapoli) + - Valérian Galliat - Alexandru Furculita (afurculita) - Ben Ramsey (ramsey) - Christian Jul Jensen @@ -635,7 +699,6 @@ Symfony is the result of the work of many people who made the code better - Chris Jones (leek) - Colin O'Dell (colinodell) - xaav - - Jean-Christophe Cuvelier [Artack] - Mahmoud Mostafa (mahmoud) - Pieter - Michael Tibben @@ -644,23 +707,20 @@ Symfony is the result of the work of many people who made the code better - ttomor - Mei Gwilym (meigwilym) - Michael H. Arieli (excelwebzone) + - Fred Cox - Luciano Mammino (loige) - fabios - - Jérôme Vasseur - Sander Coolen (scoolen) - Nicolas Le Goff (nlegoff) - Anne-Sophie Bachelard (annesophie) - Manuele Menozzi - Anton Babenko (antonbabenko) - Irmantas Šiupšinskas (irmantas) - - Charles-Henri Bruyand - Danilo Silva - - Konstantin S. M. Möllers (ksmmoellers) - Zachary Tong (polyfractal) - Hryhorii Hrebiniuk - dantleech - Xavier Leune - - Christian Schmidt - Tero Alén (tero) - DerManoMann - Guillaume Royer @@ -671,8 +731,6 @@ Symfony is the result of the work of many people who made the code better - chispita - Wojciech Sznapka - Máximo Cuadros (mcuadros) - - Stefan Gehrig (sgehrig) - - Alex Bogomazov - tamirvs - julien.galenski - Christian Neff @@ -680,16 +738,13 @@ Symfony is the result of the work of many people who made the code better - Goran Juric - Laurent Ghirardotti (laurentg) - Nicolas Macherey - - Jan Rosier (rosier) - Lin Clark - Jeremy David (jeremy.david) - Troy McCabe - Ville Mattila - Boris Vujicic (boris.vujicic) - Max Beutel - - Michal Trojanowski - Catalin Dan - - Mihai Stancu - nacho - Piotr Antosik (antek88) - Artem Lopata @@ -699,10 +754,8 @@ Symfony is the result of the work of many people who made the code better - Matthew Vickery (mattvick) - Dan Finnie - Ken Marfilla (marfillaster) - - Max Grigorian (maxakawizard) - benatespina (benatespina) - Denis Kop - - EdgarPE - jfcixmedia - Martijn Evers - Benjamin Paap (benjaminpaap) @@ -745,7 +798,9 @@ Symfony is the result of the work of many people who made the code better - David Otton - Will Donohoe - peter + - flip111 - Jérémy Jourdin (jjk801) + - BRAMILLE Sébastien (oktapodia) - Artem Kolesnikov (tyomo4ka) - Gustavo Adrian - Yannick @@ -753,7 +808,6 @@ Symfony is the result of the work of many people who made the code better - Eduardo García Sanz (coma) - James Gilliland - Roy Van Ginneken - - Stephan Vock - David de Boer (ddeboer) - Gilles Doge (gido) - abulford @@ -776,10 +830,8 @@ Symfony is the result of the work of many people who made the code better - Philipp Strube - Christian Sciberras - Anton Bakai - - Chad Sikorra (chadsikorra) - Clement Herreman (clemherreman) - Nyro (nyro) - - Trent Steel (trsteel88) - Marco - Marc Torres - Alberto Aldegheri @@ -791,18 +843,19 @@ Symfony is the result of the work of many people who made the code better - Jakub Kulhan - Mo Di (modi) - Jeroen van den Enden (stoefke) - - Christian Wahler - Jelte Steijaert (jelte) - Quique Porta (quiqueporta) - Tomasz Szymczyk (karion) + - Xavier Coureau - ConneXNL - Aharon Perkel - Abdul.Mohsen B. A. A - - Gintautas Miselis + - SpacePossum - Benoît Burnichon - Remi Collet - pthompson - Malaney J. Hill + - Alexandre Pavy - Christian Flach (cmfcmf) - Cédric Girard (enk_) - Lars Ambrosius Wallenborn (larsborn) @@ -810,7 +863,6 @@ Symfony is the result of the work of many people who made the code better - Sebastian Göttschkes (sgoettschkes) - Tatsuya Tsuruoka - Ross Tuck - - Zander Baldwin - Kévin Gomez (kevin) - azine - Dawid Sajdak @@ -823,6 +875,7 @@ Symfony is the result of the work of many people who made the code better - Marc J. Schmidt (marcjs) - Marco Jantke - Saem Ghani + - Conrad Kleinespel - Sebastian Utz - Adrien Gallou (agallou) - Karol Sójko (karolsojko) @@ -837,11 +890,12 @@ Symfony is the result of the work of many people who made the code better - Cédric Lahouste (rapotor) - Samuel Vogel (samuelvogel) - Berat Doğan - - twifty - Anthony Ferrara - Klaas Cuvelier (kcuvelier) - ShiraNai7 + - Vašek Purchart (vasek-purchart) - Janusz Jabłoński (yanoosh) + - Łukasz Makuch - George Giannoulopoulos - Daniel Richter (richtermeister) - ChrisC @@ -850,14 +904,10 @@ Symfony is the result of the work of many people who made the code better - m.chwedziak - Philip Frank - Lance McNearney - - Dominik Ritter (dritter) - - Frank Neff (fneff) - - Roman Lapin (memphys) - Giorgio Premi - caponica - Matt Daum (daum) - Alberto Pirovano (geezmo) - - Jules Pietri (heah) - Pete Mitchell (peterjmit) - Tom Corrigan (tomcorrigan) - Martin Pärtel @@ -879,14 +929,15 @@ Symfony is the result of the work of many people who made the code better - Emmanuel Vella (emmanuel.vella) - Carsten Nielsen (phreaknerd) - Mathieu Rochette + - maxime.steinhausser - Jay Severson - René Kerner - Nathaniel Catchpole - Jose Gonzalez - Adrien Samson (adriensamson) + - Aurimas Niekis (gcds) - Samuel Gordalina (gordalina) - Max Romanovsky (maxromanovsky) - - Dariusz Ruminski - Mathieu Morlon - Daniel Tschinder - Rafał Muszyński (rafmus90) @@ -941,6 +992,7 @@ Symfony is the result of the work of many people who made the code better - César Suárez (csuarez) - Nicolas Badey (nico-b) - Shane Preece (shane) + - Geoff - wusuopu - povilas - Alessandro Tagliapietra (alex88) @@ -951,7 +1003,6 @@ Symfony is the result of the work of many people who made the code better - Jakub Simon - Bouke Haarsma - Martin Eckhardt - - Denis Zunke - Jonathan Poston - Adrian Olek (adrianolek) - Przemysław Piechota (kibao) @@ -961,13 +1012,13 @@ Symfony is the result of the work of many people who made the code better - victoria - Francisco Facioni (fran6co) - Iwan van Staveren (istaveren) + - Dany Maillard (maidmaid) - Povilas S. (povilas) - pborreli - Eric Caron - 2manypeople - Wing - Thomas Bibb - - Alessandro Chitolina - Matt Farmer - catch - Alexandre Segura @@ -985,7 +1036,7 @@ Symfony is the result of the work of many people who made the code better - Michal Gebauer - Gleb Sidora - David Stone - - Adrien Lucas (adrienlucas) + - Jovan Perovic (jperovic) - Pablo Maria Martelletti (pmartelletti) - Yassine Guedidi (yguedidi) - Luis Muñoz @@ -998,7 +1049,6 @@ Symfony is the result of the work of many people who made the code better - nuncanada - flack - František Bereň - - Almog Baku (almogbaku) - Christoph Nissle (derstoffel) - Ionel Scutelnicu (ionelscutelnicu) - Nicolas Tallefourtané (nicolab) @@ -1062,16 +1112,16 @@ Symfony is the result of the work of many people who made the code better - devel - Trevor Suarez - gedrox - - Mathieu MARCHOIS - dropfen - Andrey Chernykh - Edvinas Klovas - Drew Butler + - Tischoi - J Bruni - Alexey Prilipko - - Oleg Voronkovich - bertillon - Victor Bocharsky (bocharsky_bw) + - Yannick Bensacq (cibou) - Luca Genuzio (genuzio) - Hans Nilsson (hansnilsson) - Andrew Marcinkevičius (ifdattic) @@ -1080,11 +1130,9 @@ Symfony is the result of the work of many people who made the code better - Mark de Haan (markdehaan) - Dan Patrick (mdpatrick) - Rares Vlaseanu (raresvla) - - Sofiane HADDAG (sofhad) - tante kinast (tante) - Vincent LEFORT (vlefort) - Sadicov Vladimir (xtech) - - Peter van Dommelen - Alexander Zogheb - Rémi Blaise - Joel Marcey @@ -1097,13 +1145,13 @@ Symfony is the result of the work of many people who made the code better - adenkejawen - Ari Pringle (apringle) - Dan Ordille (dordille) + - Dmytro Boiko (eagle) - Jan Eichhorn (exeu) - Grégory Pelletier (ip512) - John Nickell (jrnickell) - Julien DIDIER (juliendidier) - Martin Mayer (martin) - Grzegorz Łukaszewicz (newicz) - - Omar Yepez (oyepez003) - Veres Lajos - grifx - Robert Campbell @@ -1116,7 +1164,6 @@ Symfony is the result of the work of many people who made the code better - Alex Pods - hadriengem - timaschew - - Jelle Kapitein - Ian Phillips - Haritz - Matthieu Prat @@ -1129,7 +1176,6 @@ Symfony is the result of the work of many people who made the code better - David Windell - Gabriel Birke - skafandri - - NothingWeAre - Alan Chen - Maerlyn - Even André Fiskvik @@ -1142,13 +1188,12 @@ Symfony is the result of the work of many people who made the code better - Juan M Martínez - Gilles Gauthier - ddebree + - Tomas Liubinas - Alex - Klaas Naaijkens - Daniel González Cerviño - - possum - Rafał - Adria Lopez (adlpz) - - Andreas Schempp (aschempp) - Rosio (ben-rosio) - Simon Paarlberg (blamh) - Jeroen Thora (bolle) @@ -1174,10 +1219,7 @@ Symfony is the result of the work of many people who made the code better - Cayetano Soriano Gallego (neoshadybeat) - Pablo Monterde Perez (plebs) - Jimmy Leger (redpanda) - - Pavel Batanov (scaytrase) - - Simone Di Maulo (toretto460) - Cyrille Jouineau (tuxosaurus) - - Sander Toonen (xatoo) - Yorkie Chadwick (yorkie76) - Yanick Witschi - Ondrej Mirtes @@ -1211,6 +1253,7 @@ Symfony is the result of the work of many people who made the code better - Mantas Urnieža - Cas - Dusan Kasan + - Carson Full - Myke79 - Brian Debuire - Piers Warmers @@ -1226,7 +1269,6 @@ Symfony is the result of the work of many people who made the code better - Vladimir Sazhin - lol768 - jamogon - - Antoine LA - Vyacheslav Slinko - Johannes - Jörg Rühl @@ -1239,7 +1281,6 @@ Symfony is the result of the work of many people who made the code better - Eric J. Duran - cmfcmf - Drew Butler - - pawel-lewtak - Steve Müller - Andras Ratz - andreabreu98 @@ -1271,14 +1312,16 @@ Symfony is the result of the work of many people who made the code better - Sébastien HOUZE - Abdulkadir N. A. - Yevgen Kovalienia + - Lebnik - Sema - Elan Ruusamäe - Thorsten Hallwas + - Tristan Roussel - Michael Squires - Norman Soetbeer + - zorn - Benjamin Long - Matt Janssen - - Jeremy Benoist - Peter Gribanov - kwiateusz - David Soria Parra @@ -1298,7 +1341,6 @@ Symfony is the result of the work of many people who made the code better - Dawid Nowak - Richard Quadling - Karolis Daužickas - - Baptiste Lafontaine - tirnanog06 - phc - Дмитрий Пацура @@ -1309,11 +1351,11 @@ Symfony is the result of the work of many people who made the code better - arduanov - sualko - Nicolas Roudaire - - Jérôme Vasseur - Alfonso (afgar) - Andreas Forsblom (aforsblo) - Alex Olmos (alexolmos) - Antonio Mansilla (amansilla) + - Robin Kanters (anddarerobin) - Juan Ases García (ases) - Siragusa (asiragusa) - Daniel Basten (axhm3a) @@ -1346,7 +1388,6 @@ Symfony is the result of the work of many people who made the code better - Ismail Faizi (kanafghan) - Sébastien Armand (khepin) - Krzysztof Menżyk (krymen) - - Krzysztof Piasecki (krzysztek) - samuel laulhau (lalop) - Laurent Bachelier (laurentb) - Jérôme Parmentier (lctrs) @@ -1387,7 +1428,6 @@ Symfony is the result of the work of many people who made the code better - Vincent (vincent1870) - Eugene Babushkin (warl) - Xavier Amado (xamado) - - Yonel Ceruto González (yonelceruto) - Jesper Søndergaard Pedersen (zerrvox) - Florent Cailhol - szymek @@ -1407,6 +1447,8 @@ Symfony is the result of the work of many people who made the code better - Philipp Scheit - max - Mohamed Karnichi (amiral) + - Andrew Carter (andrewcarteruk) + - Adam Elsodaney (archfizz) - Daniel Kolvik (dkvk) - Jeroen De Dauw (jeroendedauw) - Maxime COLIN (maximecolin) @@ -1415,6 +1457,8 @@ Symfony is the result of the work of many people who made the code better - Nicolas de Marqué (nicola) - Kevin (oxfouzer) - Pierre Geyer (ptheg) + - Sam Fleming (sam_fleming) + - Thomas BERTRAND (sevrahk) - Erik Saunier (snickers) - Matej Žilák (teo_sk) - Vladislav Vlastovskiy (vlastv) diff --git a/appveyor.yml b/appveyor.yml index 61e8b56353541..857ba04284f3d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,5 @@ build: false -shallow_clone: true -platform: x86 +clone_depth: 1 clone_folder: c:\projects\symfony cache: @@ -14,6 +13,7 @@ init: - SET PHP=1 - SET ANSICON=121x90 (121x90) - SET SYMFONY_PHPUNIT_SKIPPED_TESTS=phpunit.skipped + - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f install: - IF EXIST c:\php (SET PHP=0) ELSE (mkdir c:\php) @@ -57,7 +57,6 @@ install: test_script: - cd c:\projects\symfony - - Setlocal EnableDelayedExpansion - SET X=0 - copy /Y c:\php\php.ini-min c:\php\php.ini - php phpunit symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! diff --git a/composer.json b/composer.json index d460e34439cc9..39ff413e001c3 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "php": ">=5.3.3", "doctrine/common": "~2.4", "paragonie/random_compat": "~1.0", + "symfony/polyfill-apcu": "~1.1", "twig/twig": "~1.23|~2.0", "psr/log": "~1.0" }, @@ -71,7 +72,7 @@ "monolog/monolog": "~1.3", "propel/propel1": "~1.6", "ircmaxell/password-compat": "~1.0", - "ocramius/proxy-manager": "~0.3.1" + "ocramius/proxy-manager": "~0.3.1|~1.0|~2.0" }, "autoload": { "psr-0": { "Symfony\\": "src/" }, diff --git a/phpunit b/phpunit index 0517719add9e6..9cf03f071ecbf 100755 --- a/phpunit +++ b/phpunit @@ -27,7 +27,7 @@ if ('phpdbg' === PHP_SAPI) { $PHP .= ' -qrr'; } -$COMPOSER = file_exists($COMPOSER = __DIR__.'/composer.phar') || ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? `where.exe composer.phar` : `which composer.phar`)) +$COMPOSER = file_exists($COMPOSER = __DIR__.'/composer.phar') || ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar`)) ? $PHP.' '.ProcessUtils::escapeArgument($COMPOSER) : 'composer'; @@ -160,8 +160,8 @@ if (isset($argv[1]) && 'symfony' === $argv[1]) { unlink($file); } - // Fail on any individual component failures but ignore STATUS_STACK_BUFFER_OVERRUN (-1073740791) on Windows when APCu is enabled - if ($procStatus && ('\\' !== DIRECTORY_SEPARATOR || !extension_loaded('apcu') || !ini_get('apc.enable_cli') || -1073740791 !== $procStatus)) { + // Fail on any individual component failures but ignore STATUS_STACK_BUFFER_OVERRUN (-1073740791/0xC0000409) and STATUS_ACCESS_VIOLATION (-1073741819/0xC0000005) on Windows when APCu is enabled + if ($procStatus && ('\\' !== DIRECTORY_SEPARATOR || !extension_loaded('apcu') || !ini_get('apc.enable_cli') || (-1073740791 !== $procStatus && -1073741819 !== $procStatus))) { $exit = $procStatus; echo "\033[41mKO\033[0m $component\n\n"; } else { diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php index b3b0d60778825..442903c3dfeaa 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php @@ -153,7 +153,7 @@ protected function setMappingDriverConfig(array $mappingConfig, $mappingName) */ protected function getMappingDriverBundleConfigDefaults(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container) { - $bundleDir = dirname($bundle->getFilename()); + $bundleDir = dirname($bundle->getFileName()); if (!$bundleConfig['type']) { $bundleConfig['type'] = $this->detectMetadataDriver($bundleDir, $container); diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/DoctrineValidationPass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/DoctrineValidationPass.php index de35c55219f2e..96f05eb5b60c9 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/DoctrineValidationPass.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/DoctrineValidationPass.php @@ -60,7 +60,7 @@ private function updateValidatorMappingFiles(ContainerBuilder $container, $mappi foreach ($container->getParameter('kernel.bundles') as $bundle) { $reflection = new \ReflectionClass($bundle); - if (is_file($file = dirname($reflection->getFilename()).'/'.$validationPath)) { + if (is_file($file = dirname($reflection->getFileName()).'/'.$validationPath)) { $files[] = realpath($file); $container->addResource(new FileResource($file)); } diff --git a/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php b/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php index 2d834d7d404cd..acd8cc0fcd510 100644 --- a/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php +++ b/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php @@ -49,12 +49,8 @@ public function startQuery($sql, array $params = null, array $types = null) $this->stopwatch->start('doctrine', 'doctrine'); } - if (is_array($params)) { - $params = $this->normalizeParams($params); - } - if (null !== $this->logger) { - $this->log($sql, null === $params ? array() : $params); + $this->log($sql, null === $params ? array() : $this->normalizeParams($params)); } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index f5c37e6787ab4..7c061d7ac286b 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -16,7 +16,6 @@ use Doctrine\Common\Persistence\ObjectManager; use Doctrine\Common\Persistence\ObjectRepository; use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; -use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity; use Symfony\Component\Validator\Tests\Constraints\AbstractConstraintValidatorTest; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity; @@ -398,7 +397,7 @@ public function testAssociatedEntity() $this->buildViolation('myMessage') ->atPath('property.path.single') - ->setInvalidValue(1) + ->setInvalidValue($entity1) ->assertRaised(); } @@ -422,29 +421,6 @@ public function testAssociatedEntityWithNull() $this->assertNoViolation(); } - /** - * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException - * @expectedExceptionMessage Associated entities are not allowed to have more than one identifier field - */ - public function testAssociatedCompositeEntity() - { - $constraint = new UniqueEntity(array( - 'message' => 'myMessage', - 'fields' => array('composite'), - 'em' => self::EM_NAME, - )); - - $composite = new CompositeIntIdEntity(1, 1, 'test'); - $associated = new AssociationEntity(); - $associated->composite = $composite; - - $this->em->persist($composite); - $this->em->persist($associated); - $this->em->flush(); - - $this->validator->validate($associated, $constraint); - } - /** * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException * @expectedExceptionMessage Object manager "foo" does not exist. diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index 2ee3f1da2e737..5ae077dc9f20f 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -92,17 +92,6 @@ public function validate($entity, Constraint $constraint) * getter methods in the Proxy are being bypassed. */ $em->initializeObject($criteria[$fieldName]); - - $relatedClass = $em->getClassMetadata($class->getAssociationTargetClass($fieldName)); - $relatedId = $relatedClass->getIdentifierValues($criteria[$fieldName]); - - if (count($relatedId) > 1) { - throw new ConstraintDefinitionException( - 'Associated entities are not allowed to have more than one identifier field to be '. - 'part of a unique constraint in: '.$class->getName().'#'.$fieldName - ); - } - $criteria[$fieldName] = array_pop($relatedId); } } diff --git a/src/Symfony/Bridge/Propel1/Tests/Form/DataTransformer/CollectionToArrayTransformerTest.php b/src/Symfony/Bridge/Propel1/Tests/Form/DataTransformer/CollectionToArrayTransformerTest.php index f8424dda9c635..9426d5c09b6e8 100644 --- a/src/Symfony/Bridge/Propel1/Tests/Form/DataTransformer/CollectionToArrayTransformerTest.php +++ b/src/Symfony/Bridge/Propel1/Tests/Form/DataTransformer/CollectionToArrayTransformerTest.php @@ -27,7 +27,7 @@ public function testTransform() { $result = $this->transformer->transform(new \PropelObjectCollection()); - $this->assertTrue(is_array($result)); + $this->assertInternalType('array', $result); $this->assertCount(0, $result); } @@ -35,7 +35,7 @@ public function testTransformWithNull() { $result = $this->transformer->transform(null); - $this->assertTrue(is_array($result)); + $this->assertInternalType('array', $result); $this->assertCount(0, $result); } @@ -54,7 +54,7 @@ public function testTransformWithData() $result = $this->transformer->transform($coll); - $this->assertTrue(is_array($result)); + $this->assertInternalType('array', $result); $this->assertCount(2, $result); $this->assertEquals('foo', $result[0]); $this->assertEquals('bar', $result[1]); @@ -93,7 +93,7 @@ public function testReverseTransformWithData() $this->assertInstanceOf('\PropelObjectCollection', $result); - $this->assertTrue(is_array($data)); + $this->assertInternalType('array', $data); $this->assertCount(2, $data); $this->assertEquals('foo', $data[0]); $this->assertEquals('bar', $data[1]); diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php index bba5055d0085d..eb72a7d5d83cb 100644 --- a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php @@ -77,11 +77,17 @@ public function getProxyFactoryCode(Definition $definition, $id) $methodName = 'get'.Container::camelize($id).'Service'; $proxyClass = $this->getProxyClassName($definition); + $generatedClass = $this->generateProxyClass($definition); + + $constructorCall = $generatedClass->hasMethod('staticProxyConstructor') + ? $proxyClass.'::staticProxyConstructor' + : 'new '.$proxyClass; + return <<$methodName(false); @@ -101,11 +107,7 @@ function (&\$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface \$proxy) */ public function getProxyCode(Definition $definition) { - $generatedClass = new ClassGenerator($this->getProxyClassName($definition)); - - $this->proxyGenerator->generate(new \ReflectionClass($definition->getClass()), $generatedClass); - - return $this->classGenerator->generate($generatedClass); + return $this->classGenerator->generate($this->generateProxyClass($definition)); } /** @@ -119,4 +121,18 @@ private function getProxyClassName(Definition $definition) { return str_replace('\\', '', $definition->getClass()).'_'.spl_object_hash($definition).$this->salt; } + + /** + * @param Definition $definition + * + * @return ClassGenerator + */ + private function generateProxyClass(Definition $definition) + { + $generatedClass = new ClassGenerator($this->getProxyClassName($definition)); + + $this->proxyGenerator->generate(new \ReflectionClass($definition->getClass()), $generatedClass); + + return $generatedClass; + } } diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Dumper/PhpDumperTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Dumper/PhpDumperTest.php index 412674ee3f680..5e451c122f3c4 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Dumper/PhpDumperTest.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Dumper/PhpDumperTest.php @@ -49,7 +49,12 @@ public function testDumpContainerWithProxyService() */ public function testDumpContainerWithProxyServiceWillShareProxies() { - require_once __DIR__.'/../Fixtures/php/lazy_service.php'; + // detecting ProxyManager v2 + if (class_exists('ProxyManager\ProxyGenerator\LazyLoading\MethodGenerator\StaticProxyConstructor')) { + require_once __DIR__.'/../Fixtures/php/lazy_service_with_hints.php'; + } else { + require_once __DIR__.'/../Fixtures/php/lazy_service.php'; + } $container = new \LazyServiceProjectServiceContainer(); diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt index 6bc1c6883b7da..e2775cfa5f3d3 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt @@ -8,7 +8,7 @@ class ProjectServiceContainer extends Container if ($lazyLoad) { $container = $this; - return $this->services['foo'] = new stdClass_%s( + return $this->services['foo'] =%sstdClass_%s( function (&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) use ($container) { $wrappedInstance = $container->getFooService(false); @@ -23,5 +23,5 @@ class ProjectServiceContainer extends Container } } -class stdClass_%s extends \stdClass implements \ProxyManager\Proxy\LazyLoadingInterface, \ProxyManager\Proxy\ValueHolderInterface +class stdClass_%s extends \stdClass implements \ProxyManager\%s {%a}%A \ No newline at end of file diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php new file mode 100644 index 0000000000000..349d899649c92 --- /dev/null +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php @@ -0,0 +1,189 @@ +services = array(); + } + + /** + * Gets the 'foo' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @param bool $lazyLoad whether to try lazy-loading the service with a proxy + * + * @return stdClass A stdClass instance. + */ + public function getFooService($lazyLoad = true) + { + if ($lazyLoad) { + $container = $this; + + return $this->services['foo'] = new stdClass_c1d194250ee2e2b7d2eab8b8212368a8( + function (&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) use ($container) { + $wrappedInstance = $this->getFooService(false); + + $proxy->setProxyInitializer(null); + + return true; + } + ); + } + + return new \stdClass(); + } +} + +class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \ProxyManager\Proxy\LazyLoadingInterface, \ProxyManager\Proxy\ValueHolderInterface +{ + /** + * @var \Closure|null initializer responsible for generating the wrapped object + */ + private $valueHolder5157dd96e88c0 = null; + + /** + * @var \Closure|null initializer responsible for generating the wrapped object + */ + private $initializer5157dd96e8924 = null; + + /** + * @override constructor for lazy initialization + * + * @param \Closure|null $initializer + */ + public function __construct($initializer) + { + $this->initializer5157dd96e8924 = $initializer; + } + + /** + * @param string $name + */ + public function __get($name) + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__get', array('name' => $name)); + + return $this->valueHolder5157dd96e88c0->$name; + } + + /** + * @param string $name + * @param mixed $value + */ + public function __set($name, $value) + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__set', array('name' => $name, 'value' => $value)); + + $this->valueHolder5157dd96e88c0->$name = $value; + } + + /** + * @param string $name + * + * @return bool + */ + public function __isset($name) + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__isset', array('name' => $name)); + + return isset($this->valueHolder5157dd96e88c0->$name); + } + + /** + * @param string $name + */ + public function __unset($name) + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__unset', array('name' => $name)); + + unset($this->valueHolder5157dd96e88c0->$name); + } + + /** + * + */ + public function __clone() + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__clone', array()); + + $this->valueHolder5157dd96e88c0 = clone $this->valueHolder5157dd96e88c0; + } + + /** + * + */ + public function __sleep() + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__sleep', array()); + + return array('valueHolder5157dd96e88c0'); + } + + /** + * + */ + public function __wakeup() + { + } + + /** + * {@inheritdoc} + */ + public function setProxyInitializer(\Closure $initializer = null) + { + $this->initializer5157dd96e8924 = $initializer; + } + + /** + * {@inheritdoc} + */ + public function getProxyInitializer() + { + return $this->initializer5157dd96e8924; + } + + /** + * {@inheritdoc} + */ + public function initializeProxy() : bool + { + return $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, 'initializeProxy', array()); + } + + /** + * {@inheritdoc} + */ + public function isProxyInitialized() : bool + { + return null !== $this->valueHolder5157dd96e88c0; + } + + /** + * {@inheritdoc} + */ + public function getWrappedValueHolderValue() + { + return $this->valueHolder5157dd96e88c0; + } +} diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php index fd20192d86e4f..0b98419f16203 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php @@ -69,7 +69,7 @@ public function testGetProxyFactoryCode() $code = $this->dumper->getProxyFactoryCode($definition, 'foo'); $this->assertStringMatchesFormat( - '%wif ($lazyLoad) {%w$container = $this;%wreturn $this->services[\'foo\'] = new ' + '%wif ($lazyLoad) {%w$container = $this;%wreturn $this->services[\'foo\'] =%s' .'SymfonyBridgeProxyManagerTestsLazyProxyPhpDumperProxyDumperTest_%s(%wfunction ' .'(&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) use ($container) {' .'%w$wrappedInstance = $container->getFooService(false);%w$proxy->setProxyInitializer(null);' diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 82b119b164898..71059cc35bd2c 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=5.3.3", "symfony/dependency-injection": "~2.3", - "ocramius/proxy-manager": "~0.3.1" + "ocramius/proxy-manager": "~0.3.1|~1.0|~2.0" }, "require-dev": { "symfony/config": "~2.3" diff --git a/src/Symfony/Bridge/Twig/Extension/YamlExtension.php b/src/Symfony/Bridge/Twig/Extension/YamlExtension.php index fc9bf0e9e3308..2d46795b4a81e 100644 --- a/src/Symfony/Bridge/Twig/Extension/YamlExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/YamlExtension.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Twig\Extension; use Symfony\Component\Yaml\Dumper as YamlDumper; +use Symfony\Component\Yaml\Yaml; /** * Provides integration of the Yaml component with Twig. @@ -39,6 +40,10 @@ public function encode($input, $inline = 0, $dumpObjects = false) $dumper = new YamlDumper(); } + if (defined('Symfony\Component\Yaml\Yaml::DUMP_OBJECT')) { + return $dumper->dump($input, $inline, 0, is_bool($dumpObjects) ? Yaml::DUMP_OBJECT : 0); + } + return $dumper->dump($input, $inline, 0, false, $dumpObjects); } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php index 004cb8f57d23a..e8826f66a660b 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php @@ -88,17 +88,17 @@ public function getTransTests() // transchoice array('{% transchoice count from "messages" %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}', - 'There is no apples', array('count' => 0),), + 'There is no apples', array('count' => 0)), array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}', - 'There is 5 apples', array('count' => 5),), + 'There is 5 apples', array('count' => 5)), array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}', - 'There is 5 apples (Symfony)', array('count' => 5, 'name' => 'Symfony'),), + 'There is 5 apples (Symfony)', array('count' => 5, 'name' => 'Symfony')), array('{% transchoice count with { \'%name%\': \'Symfony\' } %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}', - 'There is 5 apples (Symfony)', array('count' => 5),), + 'There is 5 apples (Symfony)', array('count' => 5)), array('{% transchoice count into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}', - 'There is no apples', array('count' => 0),), + 'There is no apples', array('count' => 0)), array('{% transchoice 5 into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}', - 'There is 5 apples',), + 'There is 5 apples'), // trans filter array('{{ "Hello"|trans }}', 'Hello'), diff --git a/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php b/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php index 4399ca7728769..26ba94a1bf0bd 100644 --- a/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php @@ -36,6 +36,7 @@ public function testCompileStrict() trim($compiler->compile($node)->getSource()) ); } + protected function getVariableGetterWithoutStrictCheck($name) { if (PHP_VERSION_ID >= 50400) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php index fa978b3ba9d1e..e116d83e88bb4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php @@ -66,6 +66,11 @@ protected function execute(InputInterface $input, OutputInterface $output) if (empty($name)) { $output->writeln('Available registered bundles with their extension alias if available:'); + + usort($bundles, function($bundleA, $bundleB) { + return strcmp($bundleA->getName(), $bundleB->getName()); + }); + foreach ($bundles as $bundle) { $extension = $bundle->getContainerExtension(); $output->writeln($bundle->getName().($extension ? ': '.$extension->getAlias() : '')); diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 5bdc2f86e6e41..03f058dddcca1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -44,7 +44,7 @@ protected function configure() )) ->setDescription('Updates the translation file') ->setHelp(<<<'EOF' -The %command.name% command extract translation strings from templates +The %command.name% command extracts translation strings from templates of a given bundle. It can display them or merge the new ones into the translation files. When new translation strings are found it can automatically add a prefix to the translation message. @@ -95,7 +95,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $extractor = $this->getContainer()->get('translation.extractor'); $extractor->setPrefix($input->getOption('prefix')); foreach ($bundleTransPaths as $path) { - $path = $path.'views'; + $path .= 'views'; if (is_dir($path)) { $extractor->extract($path, $extractedCatalogue); } @@ -106,7 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln('Loading translation files'); $loader = $this->getContainer()->get('translation.loader'); foreach ($bundleTransPaths as $path) { - $path = $path.'translations'; + $path .= 'translations'; if (is_dir($path)) { $loader->loadMessages($path, $currentCatalogue); } @@ -151,7 +151,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln('Writing files'); $bundleTransPath = false; foreach ($bundleTransPaths as $path) { - $path = $path.'translations'; + $path .= 'translations'; if (is_dir($path)) { $bundleTransPath = $path; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php index 6b02d3c5d2d6a..ddbbf8eb371c0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php @@ -69,12 +69,6 @@ public function doRun(InputInterface $input, OutputInterface $output) { $this->kernel->boot(); - if (!$this->commandsRegistered) { - $this->registerCommands(); - - $this->commandsRegistered = true; - } - $container = $this->kernel->getContainer(); foreach ($this->all() as $command) { @@ -96,8 +90,34 @@ public function doRun(InputInterface $input, OutputInterface $output) return parent::doRun($input, $output); } + /** + * {@inheritdoc} + */ + public function get($name) + { + $this->registerCommands(); + + return parent::get($name); + } + + /** + * {@inheritdoc} + */ + public function all($namespace = null) + { + $this->registerCommands(); + + return parent::all($namespace); + } + protected function registerCommands() { + if ($this->commandsRegistered) { + return; + } + + $this->commandsRegistered = true; + foreach ($this->kernel->getBundles() as $bundle) { if ($bundle instanceof Bundle) { $bundle->registerCommands($this); diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddConstraintValidatorsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddConstraintValidatorsPass.php index 757c98b1e85df..e1e1edc416967 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddConstraintValidatorsPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddConstraintValidatorsPass.php @@ -27,6 +27,8 @@ public function process(ContainerBuilder $container) if (isset($attributes[0]['alias'])) { $validators[$attributes[0]['alias']] = $id; } + + $validators[$container->getDefinition($id)->getClass()] = $id; } $container->getDefinition('validator.validator_factory')->replaceArgument(1, $validators); diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 5126d27afaa1f..c7086f72c45c3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -52,6 +52,10 @@ public function getConfigTreeBuilder() } if (false !== strpos($v, '/')) { + if ('0.0.0.0/0' === $v) { + return false; + } + list($v, $mask) = explode('/', $v, 2); if (strcmp($mask, (int) $mask) || $mask < 1 || $mask > (false !== strpos($v, ':') ? 128 : 32)) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/meta/LICENSE b/src/Symfony/Bundle/FrameworkBundle/LICENSE similarity index 100% rename from src/Symfony/Bundle/FrameworkBundle/Resources/meta/LICENSE rename to src/Symfony/Bundle/FrameworkBundle/LICENSE diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/body.css b/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/body.css index 6b81755056337..c50c1a54c7868 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/body.css +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/body.css @@ -117,7 +117,7 @@ build: 56 background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAR1JREFUeNpiPHnyZCMDA8MNID5gZmb2nAEJMH7//v3N169fX969e/cYkL8WqGAHXPLv37//QYzfv39/fvPmzbUnT56sAXInmJub/2H5/x8sx8DCwsIrISFhDmQyPX78+CmQXs70798/BmQsKipqBNTgdvz4cWkmkE5kDATMioqKZkCFdiwg1eiAi4tLGqhQF24nMmBmZuYEigth1QkEbEBxTlySYPvJkwSJ00AnjYylgU6gxB8g/oFVEphkvgLF32KNMmCCewYUv4qhEyj47+HDhyeBzIMYOoEp8CxQw56wsLAncJ1//vz5/P79+2svX74EJc2V4BT58+fPd8CE/QKYHMGJOiIiAp6oWW7evDkNSF8DZYfIyEiU7AAQYACJ2vxVdJW4eQAAAABJRU5ErkJggg==) right top no-repeat; } .sf-button .btn-bg { - padding: 0px 14px; + padding: 0 14px; color: #636363; line-height: 28px; background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAcCAYAAACgXdXMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAClJREFUeNpiPnny5EKGf//+/Wf6//8/A4QAcrGzKCZwGc9sa2urBBBgAIbDUoYVp9lmAAAAAElFTkSuQmCC) repeat-x top left; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/exception.css b/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/exception.css index 7426d44f885d4..10480b0757c9f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/exception.css +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/exception.css @@ -7,7 +7,6 @@ padding: 5px 4px; list-style-type: decimal; margin-left: 20px; - white-space: break-word; } .sf-reset #logs .traces li.error { font-style: normal; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_widget_collapsed.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_widget_collapsed.html.php index 0e180577ffff8..0399e433929f0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_widget_collapsed.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_widget_collapsed.html.php @@ -7,7 +7,7 @@ )) ?> multiple="multiple" > - + 0): ?> block($form, 'choice_widget_options', array('choices' => $preferred_choices)) ?> 0 && null !== $separator): ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php index ea347bc820602..6faafc005e587 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php @@ -56,7 +56,7 @@ public function parse($name) throw new \RuntimeException(sprintf('Template name "%s" contains invalid characters.', $name)); } - if (!preg_match('/^([^:]*):([^:]*):(.+)\.([^\.]+)\.([^\.]+)$/', $name, $matches)) { + if (!preg_match('/^(?:([^:]*):)?(?:([^:]*):)?(.+)\.([^\.]+)\.([^\.]+)$/', $name, $matches)) { return parent::parse($name); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php index 42fcb6f597dd7..dbc8fb868ba49 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php @@ -11,8 +11,9 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Console; -use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Bundle\FrameworkBundle\Tests\TestCase; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Tester\ApplicationTester; @@ -38,6 +39,89 @@ public function testBundleCommandsAreRegistered() $application = new Application($kernel); $application->doRun(new ArrayInput(array('list')), new NullOutput()); + + // Calling twice: registration should only be done once. + $application->doRun(new ArrayInput(array('list')), new NullOutput()); + } + + public function testBundleCommandsAreRetrievable() + { + $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\Bundle'); + $bundle->expects($this->once())->method('registerCommands'); + + $kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface'); + $kernel + ->expects($this->any()) + ->method('getBundles') + ->will($this->returnValue(array($bundle))) + ; + + $application = new Application($kernel); + $application->all(); + + // Calling twice: registration should only be done once. + $application->all(); + } + + public function testBundleSingleCommandIsRetrievable() + { + $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\Bundle'); + $bundle->expects($this->once())->method('registerCommands'); + + $kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface'); + $kernel + ->expects($this->any()) + ->method('getBundles') + ->will($this->returnValue(array($bundle))) + ; + + $application = new Application($kernel); + + $command = new Command('example'); + $application->add($command); + + $this->assertSame($command, $application->get('example')); + } + + public function testBundleCommandCanBeFound() + { + $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\Bundle'); + $bundle->expects($this->once())->method('registerCommands'); + + $kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface'); + $kernel + ->expects($this->any()) + ->method('getBundles') + ->will($this->returnValue(array($bundle))) + ; + + $application = new Application($kernel); + + $command = new Command('example'); + $application->add($command); + + $this->assertSame($command, $application->find('example')); + } + + public function testBundleCommandCanBeFoundByAlias() + { + $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\Bundle'); + $bundle->expects($this->once())->method('registerCommands'); + + $kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface'); + $kernel + ->expects($this->any()) + ->method('getBundles') + ->will($this->returnValue(array($bundle))) + ; + + $application = new Application($kernel); + + $command = new Command('example'); + $command->setAliases(array('alias')); + $application->add($command); + + $this->assertSame($command, $application->find('alias')); } public function testBundleCommandsHaveRightContainer() diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddConstraintValidatorsPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddConstraintValidatorsPassTest.php new file mode 100644 index 0000000000000..0629d1ebafd1f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddConstraintValidatorsPassTest.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass; + +class AddConstraintValidatorsPassTest extends \PHPUnit_Framework_TestCase +{ + public function testThatConstraintValidatorServicesAreProcessed() + { + $services = array( + 'my_constraint_validator_service1' => array(0 => array('alias' => 'my_constraint_validator_alias1')), + 'my_constraint_validator_service2' => array(), + ); + + $validatorFactoryDefinition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $container = $this->getMock( + 'Symfony\Component\DependencyInjection\ContainerBuilder', + array('findTaggedServiceIds', 'getDefinition', 'hasDefinition') + ); + + $validatorDefinition1 = $this->getMock('Symfony\Component\DependencyInjection\Definition', array('getClass')); + $validatorDefinition2 = $this->getMock('Symfony\Component\DependencyInjection\Definition', array('getClass')); + + $validatorDefinition1->expects($this->atLeastOnce()) + ->method('getClass') + ->willReturn('My\Fully\Qualified\Class\Named\Validator1'); + $validatorDefinition2->expects($this->atLeastOnce()) + ->method('getClass') + ->willReturn('My\Fully\Qualified\Class\Named\Validator2'); + + $container->expects($this->any()) + ->method('getDefinition') + ->with($this->anything()) + ->will($this->returnValueMap(array( + array('my_constraint_validator_service1', $validatorDefinition1), + array('my_constraint_validator_service2', $validatorDefinition2), + array('validator.validator_factory', $validatorFactoryDefinition), + ))); + + $container->expects($this->atLeastOnce()) + ->method('findTaggedServiceIds') + ->will($this->returnValue($services)); + $container->expects($this->atLeastOnce()) + ->method('hasDefinition') + ->with('validator.validator_factory') + ->will($this->returnValue(true)); + + $validatorFactoryDefinition->expects($this->once()) + ->method('replaceArgument') + ->with(1, array( + 'My\Fully\Qualified\Class\Named\Validator1' => 'my_constraint_validator_service1', + 'my_constraint_validator_alias1' => 'my_constraint_validator_service1', + 'My\Fully\Qualified\Class\Named\Validator2' => 'my_constraint_validator_service2', + )); + + $addConstraintValidatorsPass = new AddConstraintValidatorsPass(); + $addConstraintValidatorsPass->process($container); + } + + public function testThatCompilerPassIsIgnoredIfThereIsNoConstraintValidatorFactoryDefinition() + { + $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $container = $this->getMock( + 'Symfony\Component\DependencyInjection\ContainerBuilder', + array('hasDefinition', 'findTaggedServiceIds', 'getDefinition') + ); + + $container->expects($this->never())->method('findTaggedServiceIds'); + $container->expects($this->never())->method('getDefinition'); + $container->expects($this->atLeastOnce()) + ->method('hasDefinition') + ->with('validator.validator_factory') + ->will($this->returnValue(false)); + $definition->expects($this->never())->method('replaceArgument'); + + $addConstraintValidatorsPass = new AddConstraintValidatorsPass(); + $addConstraintValidatorsPass->process($container); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index fba0fb2ab32aa..61eea7a0d0fd5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -66,6 +66,7 @@ public function getTestValidTrustedProxiesData() array(array(), array()), array(array('10.0.0.0/8'), array('10.0.0.0/8')), array(array('::ffff:0:0/96'), array('::ffff:0:0/96')), + array(array('0.0.0.0/0'), array('0.0.0.0/0')), ); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml index 0a159ddc34c2d..1e607e9bb6cd2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -13,7 +13,7 @@ framework: only_exceptions: true enabled: false router: - resource: %kernel.root_dir%/config/routing.xml + resource: '%kernel.root_dir%/config/routing.xml' type: xml session: storage_id: session.storage.native @@ -54,5 +54,5 @@ framework: annotations: cache: file debug: true - file_cache_dir: %kernel.cache_dir%/annotations + file_cache_dir: '%kernel.cache_dir%/annotations' ide: file%%link%%format diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 33b5fa7f3474e..caed2c2916a18 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -18,6 +18,8 @@ abstract class FrameworkExtensionTest extends TestCase { + private static $containerCache = array(); + abstract protected function loadFromFile(ContainerBuilder $container, $file); public function testCsrfProtection() @@ -307,6 +309,10 @@ protected function createContainer(array $data = array()) protected function createContainerFromFile($file, $data = array()) { + $cacheKey = md5(get_class($this).$file.serialize($data)); + if (isset(self::$containerCache[$cacheKey])) { + return self::$containerCache[$cacheKey]; + } $container = $this->createContainer($data); $container->registerExtension(new FrameworkExtension()); $this->loadFromFile($container, $file); @@ -315,6 +321,6 @@ protected function createContainerFromFile($file, $data = array()) $container->getCompilerPassConfig()->setRemovingPasses(array()); $container->compile(); - return $container; + return self::$containerCache[$cacheKey] = $container; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateNameParserTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateNameParserTest.php index ca10c3a8fe861..4ff824bf7ca82 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateNameParserTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateNameParserTest.php @@ -43,30 +43,33 @@ protected function tearDown() } /** - * @dataProvider getLogicalNameToTemplateProvider + * @dataProvider parseProvider */ - public function testParse($name, $ref) + public function testParse($name, $logicalName, $path, $ref) { $template = $this->parser->parse($name); - $this->assertEquals($template->getLogicalName(), $ref->getLogicalName()); - $this->assertEquals($template->getLogicalName(), $name); + $this->assertSame($ref->getLogicalName(), $template->getLogicalName()); + $this->assertSame($logicalName, $template->getLogicalName()); + $this->assertSame($path, $template->getPath()); } - public function getLogicalNameToTemplateProvider() + public function parseProvider() { return array( - array('FooBundle:Post:index.html.php', new TemplateReference('FooBundle', 'Post', 'index', 'html', 'php')), - array('FooBundle:Post:index.html.twig', new TemplateReference('FooBundle', 'Post', 'index', 'html', 'twig')), - array('FooBundle:Post:index.xml.php', new TemplateReference('FooBundle', 'Post', 'index', 'xml', 'php')), - array('SensioFooBundle:Post:index.html.php', new TemplateReference('SensioFooBundle', 'Post', 'index', 'html', 'php')), - array('SensioCmsFooBundle:Post:index.html.php', new TemplateReference('SensioCmsFooBundle', 'Post', 'index', 'html', 'php')), - array(':Post:index.html.php', new TemplateReference('', 'Post', 'index', 'html', 'php')), - array('::index.html.php', new TemplateReference('', '', 'index', 'html', 'php')), - array('FooBundle:Post:foo.bar.index.html.php', new TemplateReference('FooBundle', 'Post', 'foo.bar.index', 'html', 'php')), - array('/path/to/section/name.php', new BaseTemplateReference('/path/to/section/name.php', 'php')), - array('name.twig', new BaseTemplateReference('name.twig', 'twig')), - array('name', new BaseTemplateReference('name')), + array('FooBundle:Post:index.html.php', 'FooBundle:Post:index.html.php', '@FooBundle/Resources/views/Post/index.html.php', new TemplateReference('FooBundle', 'Post', 'index', 'html', 'php')), + array('FooBundle:Post:index.html.twig', 'FooBundle:Post:index.html.twig', '@FooBundle/Resources/views/Post/index.html.twig', new TemplateReference('FooBundle', 'Post', 'index', 'html', 'twig')), + array('FooBundle:Post:index.xml.php', 'FooBundle:Post:index.xml.php', '@FooBundle/Resources/views/Post/index.xml.php', new TemplateReference('FooBundle', 'Post', 'index', 'xml', 'php')), + array('SensioFooBundle:Post:index.html.php', 'SensioFooBundle:Post:index.html.php', '@SensioFooBundle/Resources/views/Post/index.html.php', new TemplateReference('SensioFooBundle', 'Post', 'index', 'html', 'php')), + array('SensioCmsFooBundle:Post:index.html.php', 'SensioCmsFooBundle:Post:index.html.php', '@SensioCmsFooBundle/Resources/views/Post/index.html.php', new TemplateReference('SensioCmsFooBundle', 'Post', 'index', 'html', 'php')), + array(':Post:index.html.php', ':Post:index.html.php', 'views/Post/index.html.php', new TemplateReference('', 'Post', 'index', 'html', 'php')), + array('::index.html.php', '::index.html.php', 'views/index.html.php', new TemplateReference('', '', 'index', 'html', 'php')), + array('index.html.php', '::index.html.php', 'views/index.html.php', new TemplateReference('', '', 'index', 'html', 'php')), + array('FooBundle:Post:foo.bar.index.html.php', 'FooBundle:Post:foo.bar.index.html.php', '@FooBundle/Resources/views/Post/foo.bar.index.html.php', new TemplateReference('FooBundle', 'Post', 'foo.bar.index', 'html', 'php')), + array('/path/to/section/name.php', '/path/to/section/name.php', '/path/to/section/name.php', new BaseTemplateReference('/path/to/section/name.php', 'php')), + array('name.twig', 'name.twig', 'name.twig', new BaseTemplateReference('name.twig', 'twig')), + array('name', 'name', 'name', new BaseTemplateReference('name')), + array('default/index.html.php', '::default/index.html.php', 'views/default/index.html.php', new TemplateReference(null, null, 'default/index', 'html', 'php')), ); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php b/src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php index e8479eb5cfde8..f68f8a7979ae4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php @@ -61,6 +61,11 @@ public function extract($directory, MessageCatalogue $catalog) $files = $finder->files()->name('*.php')->in($directory); foreach ($files as $file) { $this->parseTokens(token_get_all(file_get_contents($file)), $catalog); + + if (PHP_VERSION_ID >= 70000) { + // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 + gc_mem_caches(); + } } } @@ -81,7 +86,7 @@ public function setPrefix($prefix) */ protected function normalizeToken($token) { - if (is_array($token)) { + if (isset($token[1]) && 'b"' !== $token) { return $token[1]; } @@ -95,7 +100,7 @@ private function seekToNextRelevantToken(\Iterator $tokenIterator) { for (; $tokenIterator->valid(); $tokenIterator->next()) { $t = $tokenIterator->current(); - if (!is_array($t) || ($t[0] !== T_WHITESPACE)) { + if (T_WHITESPACE !== $t[0]) { break; } } @@ -112,7 +117,7 @@ private function getMessage(\Iterator $tokenIterator) for (; $tokenIterator->valid(); $tokenIterator->next()) { $t = $tokenIterator->current(); - if (!is_array($t)) { + if (!isset($t[1])) { break; } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/meta/LICENSE b/src/Symfony/Bundle/SecurityBundle/LICENSE similarity index 100% rename from src/Symfony/Bundle/SecurityBundle/Resources/meta/LICENSE rename to src/Symfony/Bundle/SecurityBundle/LICENSE diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index 0e65fcfe1530c..956bf89aa4ee2 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -141,10 +141,6 @@ - - - %kernel.cache_dir%/secure_random.seed - - + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index 86ddb828f5799..0e7736aa2b954 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -19,6 +19,8 @@ abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase { + private static $containerCache = array(); + abstract protected function loadFromFile(ContainerBuilder $container, $file); public function testRolesHierarchy() @@ -182,6 +184,9 @@ public function testCustomAclProvider() protected function getContainer($file) { + if (isset(self::$containerCache[$file])) { + return self::$containerCache[$file]; + } $container = new ContainerBuilder(); $security = new SecurityExtension(); $container->registerExtension($security); @@ -194,6 +199,6 @@ protected function getContainer($file) $container->getCompilerPassConfig()->setRemovingPasses(array()); $container->compile(); - return $container; + return self::$containerCache[$file] = $container; } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/twig.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/twig.yml index 861b1e709fd13..61c1a54d99ba5 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/twig.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/twig.yml @@ -3,5 +3,5 @@ framework: # Twig Configuration twig: - debug: %kernel.debug% - strict_variables: %kernel.debug% + debug: '%kernel.debug%' + strict_variables: '%kernel.debug%' diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 98f4fd0fff00c..2c18a26bc54cf 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=5.3.3", - "symfony/security": "~2.2", + "symfony/security": "~2.3.37|~2.6.13|~2.7.9|~2.8", "symfony/security-acl": "~2.2", "symfony/http-kernel": "~2.2" }, diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index 9b6f806f04913..f29d8a87427fd 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -75,7 +75,7 @@ public function load(array $configs, ContainerBuilder $container) } $reflection = new \ReflectionClass($class); - if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/views')) { + if (is_dir($dir = dirname($reflection->getFileName()).'/Resources/views')) { $this->addTwigPath($twigFilesystemLoaderDefinition, $dir, $bundle); } } diff --git a/src/Symfony/Bundle/TwigBundle/Resources/meta/LICENSE b/src/Symfony/Bundle/TwigBundle/LICENSE similarity index 100% rename from src/Symfony/Bundle/TwigBundle/Resources/meta/LICENSE rename to src/Symfony/Bundle/TwigBundle/LICENSE diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/meta/LICENSE b/src/Symfony/Bundle/WebProfilerBundle/LICENSE similarity index 100% rename from src/Symfony/Bundle/WebProfilerBundle/Resources/meta/LICENSE rename to src/Symfony/Bundle/WebProfilerBundle/LICENSE diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.css.twig index 1224081bd600a..7730f55f09416 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.css.twig @@ -7,7 +7,6 @@ padding: 5px 4px; list-style-type: decimal; margin-left: 20px; - white-space: break-word; } .sf-reset #logs .traces li.error { font-style: normal; diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/body.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/body.css.twig index fa4d076917434..8373e44d0ac8d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/body.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/body.css.twig @@ -116,7 +116,7 @@ build: 56 background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAR1JREFUeNpiPHnyZCMDA8MNID5gZmb2nAEJMH7//v3N169fX969e/cYkL8WqGAHXPLv37//QYzfv39/fvPmzbUnT56sAXInmJub/2H5/x8sx8DCwsIrISFhDmQyPX78+CmQXs70798/BmQsKipqBNTgdvz4cWkmkE5kDATMioqKZkCFdiwg1eiAi4tLGqhQF24nMmBmZuYEigth1QkEbEBxTlySYPvJkwSJ00AnjYylgU6gxB8g/oFVEphkvgLF32KNMmCCewYUv4qhEyj47+HDhyeBzIMYOoEp8CxQw56wsLAncJ1//vz5/P79+2svX74EJc2V4BT58+fPd8CE/QKYHMGJOiIiAp6oWW7evDkNSF8DZYfIyEiU7AAQYACJ2vxVdJW4eQAAAABJRU5ErkJggg==) right top no-repeat; } .sf-button .btn-bg { - padding: 0px 14px; + padding: 0 14px; color: #636363; line-height: 28px; background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAcCAYAAACgXdXMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAClJREFUeNpiPnny5EKGf//+/Wf6//8/A4QAcrGzKCZwGc9sa2urBBBgAIbDUoYVp9lmAAAAAElFTkSuQmCC) repeat-x top left; diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig index e8c0900952539..6335bcd5e6cc5 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig @@ -66,7 +66,7 @@ var leftIconPath = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAhCAYAAADOHBvaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4tJREFUeNrkl19IU1Ecx7fZJN2arhq2JUWJlEZL1MAm1B582GBErMJqtabzRRAqFAYa9OfFFx+KQEG3MkYRZkkEJUUwctVSKCJWJojL1ZiydJvLtNXW98AW1znv7t0CHzrw5Xe3nXM/O/f8zvf8LjcajXJWo/E4q9T+P/CaNMZw29rahBMTE3LyoaKi4m1zc/M865swSS6bzZbT09NzfG5urjYUCikikYiQ+ntWVlZQKBQ+F4lE/Var9Ta+CmcK5hsMhpNer/fiwsLCFiYzycnJGZfJZOctFss9uj+wInhwcDDfbDb3+Hy+I+msoVQqNZtMpnNlZWUhxuChoaENHR0djwOBwN5MEkgsFtsGBgY0uPzOJKtzu7q6rmcKJW12dlaJpbqGy7WpwPyWlpZGj8dzkMX9B+l+dLlcda2trbrEHbQEPDY2Jh0dHTWxgF5AxqsRz9J1cjqdlxDWrwTO7u3tNWK7SFhAL8e221WE7pU6Ytk2t7e311JnTQWLJycntWyhpCmVShXCKboBMJyjCKJlzgVzKJiamtrBAKoH1JoAvU+2MN2g6enp3QgboRnqjHl2u70kHA7zU0APpQMlze/357vd7gKyhang7GAwKEsx1gLoAwp0E8JdJtB4w1LK4sw4OAtWl51inBGwAxT/9iLUQb+ZgsHgJ4I5hYWFAQZjbYBrKPB+hGNM4DweL1pUVBRMzOpweXm5WyAQ/GIAfwj4GbZwiUTyIy8vby7eLw4mQH9paamX4VO7kgTeTTeguLjYg0AOjAgVTD58UygUb1i41l84ogGhka4z+rwi9p3MQHwajeYRjrNFlvBbiDfoOmFtQzU1NU/J5JKBA3w+/71er3/J8hA6kSKpOPX19c9w+YH4VDIwqRbG1Wr1HZVK5eX8o6bVaj9XV1cTk3HFcinpsUjs7AWKNwvWO5gpFI93pqmpyYxLB0neVBUIcaI90OHOzs7TfX19ErZA8niNRuNXnU53M2apTmiBSc0lgEoh9cjIiBYV5i6c1YxKYblc/rOhoeEdIin2nkCfoHk2VSYpV7ZCVdB+h8OxDyocHh4WoEJZskRwvUhVVVUIcldWVtrx1XPoNfQFWkynvCWzzIe2QSXQTmg7Od5QT+WinuagliaFnI8kJvQxJpJIATo34zJ8WyR/YF2sfBFDpKCPHyqLMUeajSVniJq9mYKXjUtwPdY34a7W+/EfAQYAZM5kh2zoNWsAAAAASUVORK5CYII=", rightIconPath = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAhCAYAAADOHBvaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4tJREFUeNrsl11IU2EYx91ytrnpmmy4TYNkqGhEJGiiabuQ2EAiZ1kZW9NtF4pgoBB40weJeCHVjReygVmuIhP6gLoJJNQGadhiJcLa2sb8KN2nrprbel7YYh7WzjnOsIsO/Hnes533/Z33PB/nOZRIJJK2GwflP/ifBg8MDGTOzs4eQeOCggJjb2+vH4aRvwGmyeXyZq/Xe9rv99eGQqHs+D+pVKqfxWJNZ2VlPdRoNPfFYnEgVTBNpVI1Op3OG4FAQETkDul0uo3P518dHh6+B6dB0uC5uTlWf3//zcXFRfV2fMjlcsfUarVGIpG4yYCZDQ0Nz10ulziVAGKz2W+7u7ulNTU1q0TAdKVSOWi1Wlt2InqFQuFTvV5/HoYbW+ICc116T0/PBQLQl0TBEB8nYddtKF6SgXNMJtM1nLUuTUxMSMFeIQqfn5+/vLCwIPgTOL2vr++sx+PJS7LGEEBvowHY60ThkII8iHIVDDMSgbMtFssZnDXkkKOS2AkZuM1mk4HhJAJzV1ZWDuHMZ4DGE8AVeODl5eVin8+XiwVT7HZ7rtvt3kfg5hPB74I5lWxSMBikTU5OlsSYMTAVHoWQRJYg+COA8+PgT8Dokk2CkiuM+fk3mMFg0EiAQ6AWgC3FfoCbOA5GlfRuGQwE3bPFxyKRyAvFPkIQeg6gY3HQerRpvIn5+fkerI9DUN58PB4vsA1oJ5hneFAmk7lZVlZmj704YuAwSrfCwkInzvyhBNBbRHxTWlqK3IJeGJvYdHLBQm9w5rfBNUqyUHRUVVW9A7Ma3eSWlwRK7np4/w6azWYWzjp6UDNRqEAg+DEyMtJJo9Eew+k37I59oI+tra2vIMjw1momkQFpCoViGqAfYOhJVLnQs7dWV1ePy2SyLzvV1EEjsCSVSh/A0BzfkWC3hpxv6Ojo0NbV1a2lCgW/eru6ulBRmQKt4TYCoIMg2ejo6EWdTpcXDodJQ5uamr62t7ffgSHy63tQgEjrkwkqBp0wGo2NWq32MNgMIsCioqJN6DRN5eXl43D6AsUNaJ1Ml7kXFRvQUVDtzMzMMYPBsB/EcjgcVEx7E66oqFivrKx0gFBKvkYuA6FY+b6d9hbVVTboAKgkKtTmcqHgM6G/TuNwOBvRFPmMmg3QJ5Alvlik0tCng1Bu50TznRV9Iuj4iaoeKkDRAPIlA6b67UTBlFvSi+zaR9svAQYA6+V18DvfH/8AAAAASUVORK5CYII=", menu = document.getElementById('navigation'), savedState = Sfjs.getPreference('menu/displayState'), - displayState, elem, className; + displayState; if (null === savedState) { savedState = 'block'; diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig index 7f10150c72bfe..7a83c0e10399d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig @@ -128,7 +128,7 @@ abbr { } #menu-profiler li a span.label { display: block; - padding: 20px 0px 16px 65px; + padding: 20px 0 16px 65px; min-height: 16px; overflow: hidden; } @@ -199,7 +199,7 @@ li { #resume { background-color: #f6f6f6; border-bottom: 1px solid #dfdfdf; - padding: 18px 10px 0px; + padding: 18px 10px 0; margin-left: 250px; height: 34px; color: #313131; @@ -266,7 +266,6 @@ ul.alt li.warning { margin-bottom: 1px; } ul.sf-call-stack li { - text-size: small; padding: 0 0 0 20px; } td.main, td.menu { @@ -366,13 +365,12 @@ td.main, td.menu { line-height: 1.5em; } .sf-profiler-timeline .legends span { - border-left-width: 10px; - border-left-style: solid; + border-left: 10px solid; padding: 0 10px 0 5px; } .sf-profiler-timeline canvas { - border: 1px solid #999; - border-width: 1px 0; + border: 1px #999; + border-style: solid none; } .collapsed-menu-parents #resume, .collapsed-menu-parents #collector-content { diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig index 129fd82d27f2a..5cc31d56b2e53 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig @@ -93,9 +93,9 @@ } .sf-toolbar-block .sf-toolbar-info-piece .sf-toolbar-status { - padding: 0px 5px; + padding: 0 5px; border-radius: 5px; - margin-bottom: 0px; + margin-bottom: 0; vertical-align: top; } @@ -129,13 +129,11 @@ display: none; position: absolute; background-color: #fff; - border: 1px solid #bbb; padding: 9px 0; margin-left: -1px; bottom: 38px; - border-bottom-width: 0; - border-bottom: 1px solid #bbb; + border: 1px solid #bbb; border-radius: 4px 4px 0 0; } @@ -198,7 +196,7 @@ } .sf-toolbar-block .sf-toolbar-icon > a, -.sf-toolbar-block .sf-toolbar-icon > a:link +.sf-toolbar-block .sf-toolbar-icon > a:link, .sf-toolbar-block .sf-toolbar-icon > a:hover { color: black !important; } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_item.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_item.html.twig index 42bbfea5769b7..974fe4b29d297 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_item.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_item.html.twig @@ -1,4 +1,4 @@ -{% if link %} +{% if link|default(true) %} {% set icon %} {{ icon }} {% endset %} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php index 1a29c75b43e0e..73625d13e147a 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php @@ -62,8 +62,6 @@ public function testReturns404onTokenNotFound() if ('found' == $token) { return new Profile($token); } - - return; })) ; diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index 22c889ecd7608..3fe681434c6b6 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -110,7 +110,6 @@ public function insulate($insulated = true) public function setServerParameters(array $server) { $this->server = array_merge(array( - 'HTTP_HOST' => 'localhost', 'HTTP_USER_AGENT' => 'Symfony2 BrowserKit', ), $server); } @@ -273,21 +272,20 @@ public function request($method, $uri, array $parameters = array(), array $files $uri = $this->getAbsoluteUri($uri); - if (!empty($server['HTTP_HOST'])) { - $uri = preg_replace('{^(https?\://)'.preg_quote($this->extractHost($uri)).'}', '${1}'.$server['HTTP_HOST'], $uri); - } + $server = array_merge($this->server, $server); if (isset($server['HTTPS'])) { $uri = preg_replace('{^'.parse_url($uri, PHP_URL_SCHEME).'}', $server['HTTPS'] ? 'https' : 'http', $uri); } - $server = array_merge($this->server, $server); - if (!$this->history->isEmpty()) { $server['HTTP_REFERER'] = $this->history->current()->getUri(); } - $server['HTTP_HOST'] = $this->extractHost($uri); + if (empty($server['HTTP_HOST'])) { + $server['HTTP_HOST'] = $this->extractHost($uri); + } + $server['HTTPS'] = 'https' == parse_url($uri, PHP_URL_SCHEME); $this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content); diff --git a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php index fe0037638547a..993e64a9e426c 100644 --- a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php @@ -93,12 +93,14 @@ public function testGetRequest() $this->assertEquals('http://example.com/', $client->getRequest()->getUri(), '->getCrawler() returns the Request of the last request'); } - public function testGetRequestWithIpAsHost() + public function testGetRequestWithIpAsHttpHost() { $client = new TestClient(); $client->request('GET', 'https://example.com/foo', array(), array(), array('HTTP_HOST' => '127.0.0.1')); - $this->assertEquals('https://127.0.0.1/foo', $client->getRequest()->getUri()); + $this->assertEquals('https://example.com/foo', $client->getRequest()->getUri()); + $headers = $client->getRequest()->getServer(); + $this->assertEquals('127.0.0.1', $headers['HTTP_HOST']); } public function testGetResponse() @@ -212,24 +214,6 @@ public function testRequestURIConversion() $this->assertEquals('http://www.example.com/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); } - public function testRequestURIConversionByServerHost() - { - $client = new TestClient(); - - $server = array('HTTP_HOST' => 'www.exampl+e.com:8000'); - $parameters = array(); - $files = array(); - - $client->request('GET', 'http://exampl+e.com', $parameters, $files, $server); - $this->assertEquals('http://www.exampl+e.com:8000', $client->getRequest()->getUri(), '->request() uses HTTP_HOST to add port'); - - $client->request('GET', 'http://exampl+e.com:8888', $parameters, $files, $server); - $this->assertEquals('http://www.exampl+e.com:8000', $client->getRequest()->getUri(), '->request() uses HTTP_HOST to modify existing port'); - - $client->request('GET', 'http://exampl+e.com:8000', $parameters, $files, $server); - $this->assertEquals('http://www.exampl+e.com:8000', $client->getRequest()->getUri(), '->request() uses HTTP_HOST respects correct set port'); - } - public function testRequestReferer() { $client = new TestClient(); @@ -572,7 +556,7 @@ public function testInsulatedRequests() public function testGetServerParameter() { $client = new TestClient(); - $this->assertEquals('localhost', $client->getServerParameter('HTTP_HOST')); + $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony2 BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); $this->assertEquals('testvalue', $client->getServerParameter('testkey', 'testvalue')); } @@ -581,7 +565,7 @@ public function testSetServerParameter() { $client = new TestClient(); - $this->assertEquals('localhost', $client->getServerParameter('HTTP_HOST')); + $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony2 BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); $client->setServerParameter('HTTP_HOST', 'testhost'); @@ -595,7 +579,7 @@ public function testSetServerParameterInRequest() { $client = new TestClient(); - $this->assertEquals('localhost', $client->getServerParameter('HTTP_HOST')); + $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony2 BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); $client->request('GET', 'https://www.example.com/https/www.example.com', array(), array(), array( @@ -605,10 +589,10 @@ public function testSetServerParameterInRequest() 'NEW_SERVER_KEY' => 'new-server-key-value', )); - $this->assertEquals('localhost', $client->getServerParameter('HTTP_HOST')); + $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony2 BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); - $this->assertEquals('http://testhost/https/www.example.com', $client->getRequest()->getUri()); + $this->assertEquals('http://www.example.com/https/www.example.com', $client->getRequest()->getUri()); $server = $client->getRequest()->getServer(); diff --git a/src/Symfony/Component/ClassLoader/ApcClassLoader.php b/src/Symfony/Component/ClassLoader/ApcClassLoader.php index 9170929a1014b..4f71ea173d50b 100644 --- a/src/Symfony/Component/ClassLoader/ApcClassLoader.php +++ b/src/Symfony/Component/ClassLoader/ApcClassLoader.php @@ -67,8 +67,8 @@ class ApcClassLoader */ public function __construct($prefix, $decorated) { - if (!extension_loaded('apc')) { - throw new \RuntimeException('Unable to use ApcClassLoader as APC is not enabled.'); + if (!function_exists('apcu_fetch')) { + throw new \RuntimeException('Unable to use ApcClassLoader as APC is not installed.'); } if (!method_exists($decorated, 'findFile')) { @@ -122,8 +122,8 @@ public function loadClass($class) */ public function findFile($class) { - if (false === $file = apc_fetch($this->prefix.$class)) { - apc_store($this->prefix.$class, $file = $this->decorated->findFile($class)); + if (false === $file = apcu_fetch($this->prefix.$class)) { + apcu_store($this->prefix.$class, $file = $this->decorated->findFile($class)); } return $file; diff --git a/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php b/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php index 3a3a8a4a44712..bedb30f8955ee 100644 --- a/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php +++ b/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php @@ -71,7 +71,7 @@ class ApcUniversalClassLoader extends UniversalClassLoader */ public function __construct($prefix) { - if (!extension_loaded('apc')) { + if (!function_exists('apcu_fetch')) { throw new \RuntimeException('Unable to use ApcUniversalClassLoader as APC is not enabled.'); } @@ -87,8 +87,8 @@ public function __construct($prefix) */ public function findFile($class) { - if (false === $file = apc_fetch($this->prefix.$class)) { - apc_store($this->prefix.$class, $file = parent::findFile($class)); + if (false === $file = apcu_fetch($this->prefix.$class)) { + apcu_store($this->prefix.$class, $file = parent::findFile($class)); } return $file; diff --git a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php index f811cd0a71fa0..ba0b2e032a78a 100644 --- a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php +++ b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php @@ -149,8 +149,9 @@ public static function fixNamespaceDeclarations($source) $inNamespace = false; $tokens = token_get_all($source); - for (reset($tokens); false !== $token = current($tokens); next($tokens)) { - if (is_string($token)) { + for ($i = 0; isset($tokens[$i]); ++$i) { + $token = $tokens[$i]; + if (!isset($token[1]) || 'b"' === $token) { $rawChunk .= $token; } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { // strip comments @@ -162,12 +163,12 @@ public static function fixNamespaceDeclarations($source) $rawChunk .= $token[1]; // namespace name and whitespaces - while (($t = next($tokens)) && is_array($t) && in_array($t[0], array(T_WHITESPACE, T_NS_SEPARATOR, T_STRING))) { - $rawChunk .= $t[1]; + while (isset($tokens[++$i][1]) && in_array($tokens[$i][0], array(T_WHITESPACE, T_NS_SEPARATOR, T_STRING))) { + $rawChunk .= $tokens[$i][1]; } - if ('{' === $t) { + if ('{' === $tokens[$i]) { $inNamespace = false; - prev($tokens); + --$i; } else { $rawChunk = rtrim($rawChunk)."\n{"; $inNamespace = true; @@ -175,8 +176,8 @@ public static function fixNamespaceDeclarations($source) } elseif (T_START_HEREDOC === $token[0]) { $output .= self::compressCode($rawChunk).$token[1]; do { - $token = next($tokens); - $output .= is_string($token) ? $token : $token[1]; + $token = $tokens[++$i]; + $output .= isset($token[1]) && 'b"' !== $token ? $token[1] : $token; } while ($token[0] !== T_END_HEREDOC); $output .= "\n"; $rawChunk = ''; @@ -192,7 +193,15 @@ public static function fixNamespaceDeclarations($source) $rawChunk .= "}\n"; } - return $output.self::compressCode($rawChunk); + $output .= self::compressCode($rawChunk); + + if (PHP_VERSION_ID >= 70000) { + // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 + unset($tokens, $rawChunk); + gc_mem_caches(); + } + + return $output; } /** diff --git a/src/Symfony/Component/ClassLoader/ClassMapGenerator.php b/src/Symfony/Component/ClassLoader/ClassMapGenerator.php index a4ddce5115fa7..07c974f4283dd 100644 --- a/src/Symfony/Component/ClassLoader/ClassMapGenerator.php +++ b/src/Symfony/Component/ClassLoader/ClassMapGenerator.php @@ -72,6 +72,11 @@ public static function createMap($dir) $classes = self::findClasses($path); + if (PHP_VERSION_ID >= 70000) { + // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 + gc_mem_caches(); + } + foreach ($classes as $class) { $map[$class] = $path; } @@ -95,10 +100,10 @@ private static function findClasses($path) $classes = array(); $namespace = ''; - for ($i = 0, $max = count($tokens); $i < $max; ++$i) { + for ($i = 0; isset($tokens[$i]); ++$i) { $token = $tokens[$i]; - if (is_string($token)) { + if (!isset($token[1])) { continue; } @@ -108,9 +113,9 @@ private static function findClasses($path) case T_NAMESPACE: $namespace = ''; // If there is a namespace, extract it - while (($t = $tokens[++$i]) && is_array($t)) { - if (in_array($t[0], array(T_STRING, T_NS_SEPARATOR))) { - $namespace .= $t[1]; + while (isset($tokens[++$i][1])) { + if (in_array($tokens[$i][0], array(T_STRING, T_NS_SEPARATOR))) { + $namespace .= $tokens[$i][1]; } } $namespace .= '\\'; @@ -121,7 +126,7 @@ private static function findClasses($path) // Skip usage of ::class constant $isClassConstant = false; for ($j = $i - 1; $j > 0; --$j) { - if (is_string($tokens[$j])) { + if (!isset($tokens[$j][1])) { break; } @@ -138,10 +143,11 @@ private static function findClasses($path) } // Find the classname - while (($t = $tokens[++$i]) && is_array($t)) { + while (isset($tokens[++$i][1])) { + $t = $tokens[$i]; if (T_STRING === $t[0]) { $class .= $t[1]; - } elseif ($class !== '' && T_WHITESPACE == $t[0]) { + } elseif ('' !== $class && T_WHITESPACE === $t[0]) { break; } } diff --git a/src/Symfony/Component/ClassLoader/Tests/ApcUniversalClassLoaderTest.php b/src/Symfony/Component/ClassLoader/Tests/ApcUniversalClassLoaderTest.php index 40046f5530112..e1a55a1cdac93 100644 --- a/src/Symfony/Component/ClassLoader/Tests/ApcUniversalClassLoaderTest.php +++ b/src/Symfony/Component/ClassLoader/Tests/ApcUniversalClassLoaderTest.php @@ -13,15 +13,12 @@ use Symfony\Component\ClassLoader\ApcUniversalClassLoader; -/** - * @requires extension apc - */ class ApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase { protected function setUp() { if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) { - apc_clear_cache('user'); + apcu_clear_cache(); } else { $this->markTestSkipped('APC is not enabled.'); } @@ -30,7 +27,7 @@ protected function setUp() protected function tearDown() { if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) { - apc_clear_cache('user'); + apcu_clear_cache(); } } @@ -39,7 +36,7 @@ public function testConstructor() $loader = new ApcUniversalClassLoader('test.prefix.'); $loader->registerNamespace('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures'); - $this->assertEquals($loader->findFile('\Apc\Namespaced\FooBar'), apc_fetch('test.prefix.\Apc\Namespaced\FooBar'), '__construct() takes a prefix as its first argument'); + $this->assertEquals($loader->findFile('\Apc\Namespaced\FooBar'), apcu_fetch('test.prefix.\Apc\Namespaced\FooBar'), '__construct() takes a prefix as its first argument'); } /** diff --git a/src/Symfony/Component/ClassLoader/composer.json b/src/Symfony/Component/ClassLoader/composer.json index 1796ab0b51f5b..ee9a834b82b13 100644 --- a/src/Symfony/Component/ClassLoader/composer.json +++ b/src/Symfony/Component/ClassLoader/composer.json @@ -17,7 +17,8 @@ ], "minimum-stability": "dev", "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "symfony/polyfill-apcu": "~1.1" }, "require-dev": { "symfony/finder": "~2.0,>=2.0.5" diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php index 00e27c630a1dc..a146e89c32ae8 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php @@ -120,7 +120,7 @@ public function testDefinitionExampleGetsTransferredToNode() $tree = $builder->buildTree(); $children = $tree->getChildren(); - $this->assertTrue(is_array($tree->getExample())); + $this->assertInternalType('array', $tree->getExample()); $this->assertEquals('example', $children['child']->getExample()); } } diff --git a/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php index 2bbaadc3a721e..0e64b4ce80917 100644 --- a/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php @@ -19,7 +19,7 @@ class DirectoryResourceTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->directory = sys_get_temp_dir().'/symfonyDirectoryIterator'; + $this->directory = sys_get_temp_dir().DIRECTORY_SEPARATOR.'symfonyDirectoryIterator'; if (!file_exists($this->directory)) { mkdir($this->directory); } diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 78051c37ecf83..7a5b87ffbe45d 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -436,7 +436,7 @@ public function has($name) public function getNamespaces() { $namespaces = array(); - foreach ($this->commands as $command) { + foreach ($this->all() as $command) { $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName())); foreach ($command->getAliases() as $alias) { @@ -530,7 +530,7 @@ public function find($name) // name $commands = array(); - foreach ($this->commands as $command) { + foreach ($this->all() as $command) { $extractedNamespace = $this->extractNamespace($command->getName()); if ($extractedNamespace === $namespace || !empty($namespace) && 0 === strpos($extractedNamespace, $namespace) @@ -556,7 +556,7 @@ public function find($name) // aliases $aliases = array(); - foreach ($this->commands as $command) { + foreach ($this->all() as $command) { foreach ($command->getAliases() as $alias) { $extractedNamespace = $this->extractNamespace($alias); if ($extractedNamespace === $namespace @@ -1028,7 +1028,7 @@ private function findAlternativeCommands($name, $abbrevs) return $item->getName(); }; - return $this->findAlternatives($name, $this->commands, $abbrevs, $callback); + return $this->findAlternatives($name, $this->all(), $abbrevs, $callback); } /** diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index bd899158c4e68..3d3f2c14d78a5 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -370,7 +370,7 @@ public function addArgument($name, $mode = null, $description = '', $default = n * @param string $shortcut The shortcut (can be null) * @param int $mode The option mode: One of the InputOption::VALUE_* constants * @param string $description A description text - * @param mixed $default The default value (must be null for InputOption::VALUE_REQUIRED or InputOption::VALUE_NONE) + * @param mixed $default The default value (must be null for InputOption::VALUE_NONE) * * @return Command The current instance */ diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php index 7a78eb2f80b6c..154a041dae013 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php @@ -31,7 +31,15 @@ class OutputFormatter implements OutputFormatterInterface */ public static function escape($text) { - return preg_replace('/([^\\\\]?)#ix", $message, $matches, PREG_OFFSET_CAPTURE); foreach ($matches[0] as $i => $match) { $pos = $match[1]; @@ -164,6 +172,10 @@ public function format($message) $output .= $this->applyCurrentStyle(substr($message, $offset)); + if (false !== strpos($output, '<<')) { + return strtr($output, array('\\<' => '<', '<<' => '\\')); + } + return str_replace('\\<', '<', $output); } diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php index 167f19901a8fc..26773ca599a39 100644 --- a/src/Symfony/Component/Console/Input/InputOption.php +++ b/src/Symfony/Component/Console/Input/InputOption.php @@ -36,7 +36,7 @@ class InputOption * @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts * @param int $mode The option mode: One of the VALUE_* constants * @param string $description A description text - * @param mixed $default The default value (must be null for self::VALUE_REQUIRED or self::VALUE_NONE) + * @param mixed $default The default value (must be null for self::VALUE_NONE) * * @throws \InvalidArgumentException If option mode is invalid or incompatible */ diff --git a/src/Symfony/Component/Console/Tests/Descriptor/AbstractDescriptorTest.php b/src/Symfony/Component/Console/Tests/Descriptor/AbstractDescriptorTest.php index aab1cf376171f..9cd979271e87c 100644 --- a/src/Symfony/Component/Console/Tests/Descriptor/AbstractDescriptorTest.php +++ b/src/Symfony/Component/Console/Tests/Descriptor/AbstractDescriptorTest.php @@ -82,6 +82,7 @@ public function getDescribeApplicationTestData() } abstract protected function getDescriptor(); + abstract protected function getFormat(); private function getDescriptionTestData(array $objects) diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index eff23c17b49c8..dc77b4d1fd9d2 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -98,8 +98,8 @@ public function testStyleEscaping() $formatter = new OutputFormatter(true); $this->assertEquals( - "(\033[32mz>=2.0,format('('.$formatter->escape('z>=2.0,)') + "(\033[32mz>=2.0,<<format('('.$formatter->escape('z>=2.0,<\\<)') ); $this->assertEquals( diff --git a/src/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php b/src/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php index 16a3a34d6497d..932e8030dd896 100644 --- a/src/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php +++ b/src/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php @@ -28,5 +28,6 @@ public function testSpecificityValue(NodeInterface $node, $value) } abstract public function getToStringConversionTestData(); + abstract public function getSpecificityValueTestData(); } diff --git a/src/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php b/src/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php index a06dca013bae7..57afa5a2422b0 100644 --- a/src/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php +++ b/src/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php @@ -43,7 +43,9 @@ public function testDontHandleValue($value) } abstract public function getHandleValueTestData(); + abstract public function getDontHandleValueTestData(); + abstract protected function generateHandler(); protected function assertStreamEmpty(TokenStream $stream) diff --git a/src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php b/src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php index 143328f412774..407458f48f2cc 100644 --- a/src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php +++ b/src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php @@ -74,7 +74,7 @@ public function testHtmlShakespear($css, $count) $document = simplexml_import_dom($document); $bodies = $document->xpath('//body'); $elements = $bodies[0]->xpath($translator->cssToXPath($css)); - $this->assertEquals($count, count($elements)); + $this->assertCount($count, $elements); } public function getXpathLiteralTestData() diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php index 8308937d4a512..e1c6f2ec63b43 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php @@ -95,6 +95,8 @@ private function updateReferences($container, $currentId, $newId) $definition->setProperties( $this->updateArgumentReferences($definition->getProperties(), $currentId, $newId) ); + + $definition->setFactoryService($this->updateFactoryServiceReference($definition->getFactoryService(), $currentId, $newId)); } } @@ -122,4 +124,13 @@ private function updateArgumentReferences(array $arguments, $currentId, $newId) return $arguments; } + + private function updateFactoryServiceReference($factoryService, $currentId, $newId) + { + if (null === $factoryService) { + return; + } + + return $currentId === $factoryService ? $newId : $factoryService; + } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php index c90d76f48adf5..016778652314f 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -42,6 +43,7 @@ public function process(ContainerBuilder $container) $definition->setArguments($this->processArguments($definition->getArguments())); $definition->setMethodCalls($this->processArguments($definition->getMethodCalls())); $definition->setProperties($this->processArguments($definition->getProperties())); + $definition->setFactoryService($this->processFactoryService($definition->getFactoryService())); } foreach ($container->getAliases() as $id => $alias) { @@ -76,6 +78,15 @@ private function processArguments(array $arguments) return $arguments; } + private function processFactoryService($factoryService) + { + if (null === $factoryService) { + return; + } + + return $this->getDefinitionId($factoryService); + } + /** * Resolves an alias into a definition id. * diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 75de9c4fde03e..effa128eaaf10 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -200,6 +200,10 @@ public function set($id, $service, $scope = self::SCOPE_CONTAINER) $this->scopedServices[$scope][$id] = $service; } + if (isset($this->aliases[$id])) { + unset($this->aliases[$id]); + } + $this->services[$id] = $service; if (method_exists($this, $method = 'synchronize'.strtr($id, $this->underscoreMap).'Service')) { diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 6c52c47b651a9..ad2f89ae77d0d 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -19,6 +19,8 @@ use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Config\Resource\ResourceInterface; @@ -243,7 +245,9 @@ public function addClassResource(\ReflectionClass $class) } do { - $this->addResource(new FileResource($class->getFileName())); + if (is_file($class->getFileName())) { + $this->addResource(new FileResource($class->getFileName())); + } } while ($class = $class->getParentClass()); return $this; @@ -413,9 +417,9 @@ public function has($id) * * @return object The associated service * - * @throws InvalidArgumentException when no definitions are available - * @throws InactiveScopeException when the current scope is not active - * @throws LogicException when a circular dependency is detected + * @throws InvalidArgumentException when no definitions are available + * @throws ServiceCircularReferenceException When a circular reference is detected + * @throws ServiceNotFoundException When the service is not defined * @throws \Exception * * @see Reference @@ -438,7 +442,7 @@ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INV try { $definition = $this->getDefinition($id); - } catch (InvalidArgumentException $e) { + } catch (ServiceNotFoundException $e) { if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) { return; } @@ -788,14 +792,14 @@ public function hasDefinition($id) * * @return Definition A Definition instance * - * @throws InvalidArgumentException if the service definition does not exist + * @throws ServiceNotFoundException if the service definition does not exist */ public function getDefinition($id) { $id = strtolower($id); if (!array_key_exists($id, $this->definitions)) { - throw new InvalidArgumentException(sprintf('The service definition "%s" does not exist.', $id)); + throw new ServiceNotFoundException($id); } return $this->definitions[$id]; @@ -810,7 +814,7 @@ public function getDefinition($id) * * @return Definition A Definition instance * - * @throws InvalidArgumentException if the service definition does not exist + * @throws ServiceNotFoundException if the service definition does not exist */ public function findDefinition($id) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index eca056dea16a5..480857ee64625 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -64,7 +64,7 @@ private function addService($id, $definition) $class = substr($class, 1); } - $code .= sprintf(" class: %s\n", $class); + $code .= sprintf(" class: %s\n", $this->dumper->dump($class)); } if (!$definition->isPublic()) { @@ -88,7 +88,7 @@ private function addService($id, $definition) } if ($definition->getFile()) { - $code .= sprintf(" file: %s\n", $definition->getFile()); + $code .= sprintf(" file: %s\n", $this->dumper->dump($definition->getFile())); } if ($definition->isSynthetic()) { @@ -100,7 +100,7 @@ private function addService($id, $definition) } if ($definition->getFactoryClass()) { - $code .= sprintf(" factory_class: %s\n", $definition->getFactoryClass()); + $code .= sprintf(" factory_class: %s\n", $this->dumper->dump($definition->getFactoryClass())); } if ($definition->isLazy()) { @@ -108,11 +108,11 @@ private function addService($id, $definition) } if ($definition->getFactoryMethod()) { - $code .= sprintf(" factory_method: %s\n", $definition->getFactoryMethod()); + $code .= sprintf(" factory_method: %s\n", $this->dumper->dump($definition->getFactoryMethod())); } if ($definition->getFactoryService()) { - $code .= sprintf(" factory_service: %s\n", $definition->getFactoryService()); + $code .= sprintf(" factory_service: %s\n", $this->dumper->dump($definition->getFactoryService())); } if ($definition->getArguments()) { @@ -128,7 +128,7 @@ private function addService($id, $definition) } if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) { - $code .= sprintf(" scope: %s\n", $scope); + $code .= sprintf(" scope: %s\n", $this->dumper->dump($scope)); } if ($callable = $definition->getConfigurator()) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index b268cb99045d4..0314ba6809586 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -186,6 +186,10 @@ private function parseDefinition($id, $service, $file) $parameters[$name] = SimpleXMLElement::phpize($value); } + if ('' === (string) $tag['name']) { + throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', $id, $file)); + } + $definition->addTag((string) $tag['name'], $parameters); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 91adf2b78d83d..4acdb702a11ed 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -245,6 +245,10 @@ private function parseDefinition($id, $service, $file) throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file)); } + if (!is_string($tag['name']) || '' === $tag['name']) { + throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', $id, $file)); + } + $name = $tag['name']; unset($tag['name']); diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd index e62b475ba36d6..8ad313f8cf3bf 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd +++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd @@ -97,7 +97,7 @@ - + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php index e4d22401d3cdd..1381369ce59bc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php @@ -15,13 +15,17 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +require_once __DIR__.'/../Fixtures/includes/foo.php'; + class ReplaceAliasByActualDefinitionPassTest extends \PHPUnit_Framework_TestCase { public function testProcess() { $container = new ContainerBuilder(); - $container->register('a', '\stdClass'); + $aDefinition = $container->register('a', '\stdClass'); + $aDefinition->setFactoryService('b'); + $aDefinition->setFactoryMethod('createA'); $bDefinition = new Definition('\stdClass'); $bDefinition->setPublic(false); @@ -39,6 +43,27 @@ public function testProcess() $container->has('b_alias') && !$container->hasAlias('b_alias'), '->process() replaces alias to actual.' ); + $this->assertSame('b_alias', $aDefinition->getFactoryService()); + } + + /** + * @group legacy + */ + public function testPrivateAliasesInFactory() + { + $container = new ContainerBuilder(); + + $container->register('a', 'FooClass'); + $container->register('b', 'FooClass') + ->setFactoryService('a') + ->setFactoryMethod('getInstance'); + + $container->register('c', 'stdClass')->setPublic(false); + $container->setAlias('c_alias', 'c'); + + $this->process($container); + + $this->assertInstanceOf('FooClass', $container->get('b')); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveReferencesToAliasesPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveReferencesToAliasesPassTest.php index 6fdc233941e64..c441548fc4ade 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveReferencesToAliasesPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveReferencesToAliasesPassTest.php @@ -11,6 +11,8 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler; +use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Compiler\ResolveReferencesToAliasesPass; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -59,6 +61,21 @@ public function testAliasCircularReference() $this->process($container); } + public function testResolveFactory() + { + $container = new ContainerBuilder(); + $container->register('factory', 'Factory'); + $container->setAlias('factory_alias', new Alias('factory')); + $foo = new Definition(); + $foo->setFactoryService('factory_alias'); + $foo->setFactoryMethod('createFoo'); + $container->setDefinition('foo', $foo); + + $this->process($container); + + $this->assertSame('factory', $foo->getFactoryService()); + } + protected function process(ContainerBuilder $container) { $pass = new ResolveReferencesToAliasesPass(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 3a369d9d2ed18..5719dc68ea2a4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -21,6 +21,8 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\InactiveScopeException; +use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; @@ -50,9 +52,9 @@ public function testDefinitions() try { $builder->getDefinition('baz'); - $this->fail('->getDefinition() throws an InvalidArgumentException if the service definition does not exist'); - } catch (\InvalidArgumentException $e) { - $this->assertEquals('The service definition "baz" does not exist.', $e->getMessage(), '->getDefinition() throws an InvalidArgumentException if the service definition does not exist'); + $this->fail('->getDefinition() throws a ServiceNotFoundException if the service definition does not exist'); + } catch (ServiceNotFoundException $e) { + $this->assertEquals('You have requested a non-existent service "baz".', $e->getMessage(), '->getDefinition() throws a ServiceNotFoundException if the service definition does not exist'); } } @@ -79,9 +81,9 @@ public function testGet() $builder = new ContainerBuilder(); try { $builder->get('foo'); - $this->fail('->get() throws an InvalidArgumentException if the service does not exist'); - } catch (\InvalidArgumentException $e) { - $this->assertEquals('The service definition "foo" does not exist.', $e->getMessage(), '->get() throws an InvalidArgumentException if the service does not exist'); + $this->fail('->get() throws a ServiceNotFoundException if the service does not exist'); + } catch (ServiceNotFoundException $e) { + $this->assertEquals('You have requested a non-existent service "foo".', $e->getMessage(), '->get() throws a ServiceNotFoundException if the service does not exist'); } $this->assertNull($builder->get('foo', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service does not exist and NULL_ON_INVALID_REFERENCE is passed as a second argument'); @@ -217,6 +219,16 @@ public function testAddAliases() $this->assertTrue(isset($aliases['foobar'])); } + public function testSetReplacesAlias() + { + $builder = new ContainerBuilder(); + $builder->setAlias('alias', 'aliased'); + $builder->set('aliased', new \stdClass()); + + $builder->set('alias', $foo = new \stdClass()); + $this->assertSame($foo, $builder->get('alias'), '->set() replaces an existing alias'); + } + public function testAddGetCompilerPass() { $builder = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php index 5acc3c3b842e2..e5cce945ec71f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php @@ -152,6 +152,14 @@ public function testSetAlsoSetsScopedService() $this->assertSame($foo, $services['foo']['foo']); } + public function testSetReplacesAlias() + { + $c = new ProjectServiceContainer(); + + $c->set('alias', $foo = new \stdClass()); + $this->assertSame($foo, $c->get('alias'), '->set() replaces an existing alias'); + } + public function testGet() { $sc = new ProjectServiceContainer(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php index f9747a7c2fae9..5c61e4be2e73d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php @@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Dumper\YamlDumper; +use Symfony\Component\Yaml\Yaml; class YamlDumperTest extends \PHPUnit_Framework_TestCase { @@ -27,24 +28,21 @@ public function testDump() { $dumper = new YamlDumper($container = new ContainerBuilder()); - $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services1.yml', $dumper->dump(), '->dump() dumps an empty container as an empty YAML file'); - - $container = new ContainerBuilder(); - $dumper = new YamlDumper($container); + $this->assertEqualYamlStructure(file_get_contents(self::$fixturesPath.'/yaml/services1.yml'), $dumper->dump(), '->dump() dumps an empty container as an empty YAML file'); } public function testAddParameters() { $container = include self::$fixturesPath.'/containers/container8.php'; $dumper = new YamlDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services8.yml', $dumper->dump(), '->dump() dumps parameters'); + $this->assertEqualYamlStructure(file_get_contents(self::$fixturesPath.'/yaml/services8.yml'), $dumper->dump(), '->dump() dumps parameters'); } public function testAddService() { $container = include self::$fixturesPath.'/containers/container9.php'; $dumper = new YamlDumper($container); - $this->assertEquals(str_replace('%path%', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR, file_get_contents(self::$fixturesPath.'/yaml/services9.yml')), $dumper->dump(), '->dump() dumps services'); + $this->assertEqualYamlStructure(str_replace('%path%', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR, file_get_contents(self::$fixturesPath.'/yaml/services9.yml')), $dumper->dump(), '->dump() dumps services'); $dumper = new YamlDumper($container = new ContainerBuilder()); $container->register('foo', 'FooClass')->addArgument(new \stdClass()); @@ -56,4 +54,9 @@ public function testAddService() $this->assertEquals('Unable to dump a service container if a parameter is an object or a resource.', $e->getMessage(), '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); } } + + private function assertEqualYamlStructure($yaml, $expected, $message = '') + { + $this->assertEquals(Yaml::parse($expected), Yaml::parse($yaml), $message); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/interfaces1.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/interfaces1.php index 27503a351c674..4c93e32017914 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/interfaces1.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/interfaces1.php @@ -11,15 +11,3 @@ $container->setDefinition('foo', $definition); return $container; - -if (!class_exists('FooClass')) { - class FooClass - { - public $bar; - - public function setBar($bar) - { - $this->bar = $bar; - } - } -} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/tag_with_empty_name.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/tag_with_empty_name.xml new file mode 100644 index 0000000000000..1646292462475 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/tag_with_empty_name.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/tag_without_name.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/tag_without_name.xml new file mode 100644 index 0000000000000..bc7373df73cf0 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/tag_without_name.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services10.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services10.yml index f2f8d953d57a3..c66084cdbe8e6 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services10.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services10.yml @@ -6,4 +6,4 @@ services: class: BAR project: - test: %project.parameter.foo% + test: '%project.parameter.foo%' diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml index b79697b6e9399..4531cc57eecc9 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml @@ -5,7 +5,7 @@ services: scope.custom: { class: FooClass, scope: custom } scope.prototype: { class: FooClass, scope: prototype } constructor: { class: FooClass, factory_method: getInstance } - file: { class: FooClass, file: %path%/foo.php } + file: { class: FooClass, file: '%path%/foo.php' } arguments: { class: FooClass, arguments: [foo, '@foo', [true, false]] } configurator1: { class: FooClass, configurator: sc_configure } configurator2: { class: FooClass, configurator: ['@baz', configure] } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml index c6181ed549a61..ae673c17271ea 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml @@ -23,16 +23,16 @@ services: arguments: [foo, '@foo.baz', '%foo_bar%'] configurator: ['@foo.baz', configure] foo.baz: - class: %baz_class% - factory_class: %baz_class% + class: '%baz_class%' + factory_class: '%baz_class%' factory_method: getInstance configurator: ['%baz_class%', configureStatic1] foo_bar: - class: %foo_class% + class: '%foo_class%' scope: prototype method_call1: class: FooClass - file: %path%foo.php + file: '%path%foo.php' calls: - [setBar, ['@foo']] - [setBar, ['@?foo2']] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/tag_name_empty_string.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/tag_name_empty_string.yml new file mode 100644 index 0000000000000..0ea5f53da8cd9 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/tag_name_empty_string.yml @@ -0,0 +1,6 @@ +services: + foo_service: + class: FooClass + tags: + # tag name is an empty string + - { name: '', foo: bar } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/tag_name_no_string.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/tag_name_no_string.yml new file mode 100644 index 0000000000000..f24cafd225b3c --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/tag_name_no_string.yml @@ -0,0 +1,6 @@ +services: + foo_service: + class: FooClass + tags: + # tag name is not a string + - { name: [], foo: bar } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index c0e39ef7ad15c..e5dfa2a13e6bd 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; @@ -207,6 +208,27 @@ public function testParsesTags() } } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + */ + public function testParseTagsWithoutNameThrowsException() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('tag_without_name.xml'); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /The tag name for service ".+" in .* must be a non-empty string/ + */ + public function testParseTagWithEmptyNameThrowsException() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('tag_with_empty_name.xml'); + } + public function testConvertDomElementToArray() { $doc = new \DOMDocument('1.0'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index bd53da0d5f510..2a096695862c1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -233,4 +233,24 @@ public function testTagWithAttributeArrayThrowsException() $this->assertStringStartsWith('A "tags" attribute must be of a scalar-type for service ', $e->getMessage(), '->load() throws an InvalidArgumentException if a tag-attribute is not a scalar'); } } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /The tag name for service ".+" in .+ must be a non-empty string/ + */ + public function testTagWithEmptyNameThrowsException() + { + $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('tag_name_empty_string.yml'); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + * @expectedExceptionMessageREgExp /The tag name for service "\.+" must be a non-empty string/ + */ + public function testTagWithNonStringNameThrowsException() + { + $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('tag_name_no_string.yml'); + } } diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 9dd3daa503bbe..a51463dd0fd84 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -230,7 +230,7 @@ public function addXmlContent($content, $charset = 'UTF-8') if ('' !== trim($content)) { // remove the default namespace to make XPath expressions simpler - @$dom->loadXML(str_replace('xmlns', 'ns', $content), LIBXML_NONET); + @$dom->loadXML(str_replace('xmlns', 'ns', $content), LIBXML_NONET | (defined('LIBXML_PARSEHUGE') ? LIBXML_PARSEHUGE : 0)); } libxml_use_internal_errors($internalErrors); diff --git a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php index b4816eda4e9f1..12194091e0da5 100644 --- a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php +++ b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php @@ -55,6 +55,10 @@ public function hasValue() */ public function isDisabled() { + if (parent::isDisabled() && 'select' === $this->type) { + return true; + } + foreach ($this->options as $option) { if ($option['value'] == $this->value && $option['disabled']) { return true; diff --git a/src/Symfony/Component/DomCrawler/Form.php b/src/Symfony/Component/DomCrawler/Form.php index 4087788540114..3a16242fe9e7c 100644 --- a/src/Symfony/Component/DomCrawler/Form.php +++ b/src/Symfony/Component/DomCrawler/Form.php @@ -157,8 +157,12 @@ public function getPhpValues() * * This method converts fields with the array notation * (like foo[bar] to arrays) like PHP does. + * The returned array is consistent with the array for field values + * (@see getPhpValues), rather than uploaded files found in $_FILES. + * For a compound file field foo[bar] it will create foo[bar][name], + * instead of foo[name][bar] which would be found in $_FILES. * - * @return array An array of field values. + * @return array An array of file field values. */ public function getPhpFiles() { diff --git a/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php b/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php index 954cd9774b843..ce87b15c2ed59 100644 --- a/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php @@ -120,6 +120,14 @@ public function testSelectWithEmptyBooleanAttribute() $this->assertEquals('bar', $field->getValue()); } + public function testSelectIsDisabled() + { + $node = $this->createSelectNode(array('foo' => false, 'bar' => true), array('disabled' => 'disabled')); + $field = new ChoiceFormField($node); + + $this->assertTrue($field->isDisabled(), '->isDisabled() returns true for selects with a disabled attribute'); + } + public function testMultipleSelects() { $node = $this->createSelectNode(array('foo' => false, 'bar' => false), array('multiple' => 'multiple')); diff --git a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php index fb3b4caa26624..1f6b9502d52ce 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php @@ -52,6 +52,18 @@ public function testAddASubscriberService() ->with($event) ; + $service + ->expects($this->once()) + ->method('onEventWithPriority') + ->with($event) + ; + + $service + ->expects($this->once()) + ->method('onEventNested') + ->with($event) + ; + $container = new Container(); $container->set('service.subscriber', $service); @@ -59,6 +71,8 @@ public function testAddASubscriberService() $dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService'); $dispatcher->dispatch('onEvent', $event); + $dispatcher->dispatch('onEventWithPriority', $event); + $dispatcher->dispatch('onEventNested', $event); } public function testPreventDuplicateListenerService() @@ -233,12 +247,20 @@ public static function getSubscribedEvents() { return array( 'onEvent' => 'onEvent', - 'onEvent' => array('onEvent', 10), - 'onEvent' => array('onEvent'), + 'onEventWithPriority' => array('onEventWithPriority', 10), + 'onEventNested' => array(array('onEventNested')), ); } public function onEvent(Event $e) { } + + public function onEventWithPriority(Event $e) + { + } + + public function onEventNested(Event $e) + { + } } diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 4fe9f3485eb37..b1b8052254365 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -100,6 +100,10 @@ public function mkdir($dirs, $mode = 0777) public function exists($files) { foreach ($this->toIterator($files) as $file) { + if ('\\' === DIRECTORY_SEPARATOR && strlen($file) > 258) { + throw new IOException(sprintf('Could not check if file exist because path length exceeds 258 characters for file "%s"', $file)); + } + if (!file_exists($file)) { return false; } @@ -139,7 +143,7 @@ public function remove($files) $files = iterator_to_array($this->toIterator($files)); $files = array_reverse($files); foreach ($files as $file) { - if (!file_exists($file) && !is_link($file)) { + if (!$this->exists($file) && !is_link($file)) { continue; } @@ -157,7 +161,8 @@ public function remove($files) } } else { if (true !== @unlink($file)) { - throw new IOException(sprintf('Failed to remove file %s', $file)); + $error = error_get_last(); + throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, $error['message'])); } } } @@ -253,7 +258,7 @@ public function chgrp($files, $group, $recursive = false) public function rename($origin, $target, $overwrite = false) { // we check that target does not exist - if (!$overwrite && is_readable($target)) { + if (!$overwrite && $this->isReadable($target)) { throw new IOException(sprintf('Cannot rename because the target "%s" already exist.', $target)); } @@ -262,6 +267,22 @@ public function rename($origin, $target, $overwrite = false) } } + /** + * Tells whether a file exists and is readable. + * + * @param string $filename Path to the file. + * + * @throws IOException When windows path is longer than 258 characters + */ + private function isReadable($filename) + { + if ('\\' === DIRECTORY_SEPARATOR && strlen($filename) > 258) { + throw new IOException(sprintf('Could not check if file is readable because path length exceeds 258 characters for file "%s"', $filename)); + } + + return is_readable($filename); + } + /** * Creates a symbolic link or copy a directory. * diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 11f453cc8c419..3eeb1a6199491 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -19,6 +19,7 @@ class FilesystemTest extends \PHPUnit_Framework_TestCase { private $umask; + private $longPathNamesWindows = array(); /** * @var string @@ -56,6 +57,12 @@ protected function setUp() protected function tearDown() { + if (!empty($this->longPathNamesWindows)) { + foreach ($this->longPathNamesWindows as $path) { + exec('DEL '.$path); + } + } + $this->filesystem->remove($this->workspace); umask($this->umask); } @@ -354,6 +361,28 @@ public function testFilesExists() $this->assertTrue($this->filesystem->exists($basePath.'folder')); } + /** + * @expectedException \Symfony\Component\Filesystem\Exception\IOException + */ + public function testFilesExistsFails() + { + if ('\\' !== DIRECTORY_SEPARATOR) { + $this->markTestSkipped('Test covers edge case on Windows only.'); + } + + $basePath = $this->workspace.'\\directory\\'; + + $oldPath = getcwd(); + mkdir($basePath); + chdir($basePath); + $file = str_repeat('T', 259 - strlen($basePath)); + $path = $basePath.$file; + exec('TYPE NUL >>'.$file); // equivalent of touch, we can not use the php touch() here because it suffers from the same limitation + $this->longPathNamesWindows[] = $path; // save this so we can clean up later + chdir($oldPath); + $this->filesystem->exists($path); + } + public function testFilesExistsTraversableObjectOfFilesAndDirectories() { $basePath = $this->workspace.DIRECTORY_SEPARATOR; @@ -884,7 +913,7 @@ public function testMirrorCopiesLinks() public function testMirrorCopiesLinkedDirectoryContents() { - $this->markAsSkippedIfSymlinkIsMissing(); + $this->markAsSkippedIfSymlinkIsMissing(true); $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR; @@ -904,7 +933,7 @@ public function testMirrorCopiesLinkedDirectoryContents() public function testMirrorCopiesRelativeLinkedContents() { - $this->markAsSkippedIfSymlinkIsMissing(); + $this->markAsSkippedIfSymlinkIsMissing(true); $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR; $oldPath = getcwd(); @@ -1028,7 +1057,10 @@ private function getFileGroup($filepath) $this->markTestSkipped('Unable to retrieve file group name'); } - private function markAsSkippedIfSymlinkIsMissing() + /** + * @param bool $relative Whether support for relative symlinks is required + */ + private function markAsSkippedIfSymlinkIsMissing($relative = false) { if (!function_exists('symlink')) { $this->markTestSkipped('symlink is not supported'); @@ -1037,6 +1069,11 @@ private function markAsSkippedIfSymlinkIsMissing() if (false === self::$symlinkOnWindows) { $this->markTestSkipped('symlink requires "Create symbolic links" privilege on Windows'); } + + // https://bugs.php.net/bug.php?id=69473 + if ($relative && '\\' === DIRECTORY_SEPARATOR && 1 === PHP_ZTS) { + $this->markTestSkipped('symlink does not support relative paths on thread safe Windows PHP versions'); + } } private function markAsSkippedIfChmodIsMissing() diff --git a/src/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php b/src/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php index 244301a739e29..da4004d6b525c 100644 --- a/src/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php +++ b/src/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php @@ -94,7 +94,7 @@ public function searchInDirectory($dir) $command->setErrorHandler( $this->ignoreUnreadableDirs // If directory is unreadable and finder is set to ignore it, `stderr` is ignored. - ? function ($stderr) { return; } + ? function ($stderr) { } : function ($stderr) { throw new AccessDeniedException($stderr); } ); diff --git a/src/Symfony/Component/Finder/Glob.php b/src/Symfony/Component/Finder/Glob.php index fedcc5e708ece..837ddddfa77f2 100644 --- a/src/Symfony/Component/Finder/Glob.php +++ b/src/Symfony/Component/Finder/Glob.php @@ -65,7 +65,7 @@ public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardS $firstByte = true; } - if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) { + if ('#' === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) { $regex .= "\\$car"; } elseif ('*' === $car) { $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*'); diff --git a/src/Symfony/Component/Finder/Iterator/FilterIterator.php b/src/Symfony/Component/Finder/Iterator/FilterIterator.php index f4da44c4cdd59..24adeb68f9040 100644 --- a/src/Symfony/Component/Finder/Iterator/FilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/FilterIterator.php @@ -12,9 +12,10 @@ namespace Symfony\Component\Finder\Iterator; /** - * This iterator just overrides the rewind method in order to correct a PHP bug. + * This iterator just overrides the rewind method in order to correct a PHP bug, + * which existed before version 5.5.23/5.6.7. * - * @see https://bugs.php.net/bug.php?id=49104 + * @see https://bugs.php.net/68557 * * @author Alex Bogomazov */ @@ -28,18 +29,19 @@ abstract class FilterIterator extends \FilterIterator */ public function rewind() { + if (PHP_VERSION_ID > 50607 || (PHP_VERSION_ID > 50523 && PHP_VERSION_ID < 50600)) { + parent::rewind(); + + return; + } + $iterator = $this; while ($iterator instanceof \OuterIterator) { $innerIterator = $iterator->getInnerIterator(); - if ($innerIterator instanceof RecursiveDirectoryIterator) { - if ($innerIterator->isRewindable()) { - $innerIterator->next(); - $innerIterator->rewind(); - } - } elseif ($iterator->getInnerIterator() instanceof \FilesystemIterator) { - $iterator->getInnerIterator()->next(); - $iterator->getInnerIterator()->rewind(); + if ($innerIterator instanceof \FilesystemIterator) { + $innerIterator->next(); + $innerIterator->rewind(); } $iterator = $iterator->getInnerIterator(); } diff --git a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php index 3f65d69269756..402033a5c2816 100644 --- a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php +++ b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php @@ -118,8 +118,10 @@ public function rewind() return; } - // @see https://bugs.php.net/bug.php?id=49104 - parent::next(); + // @see https://bugs.php.net/68557 + if (PHP_VERSION_ID < 50523 || PHP_VERSION_ID >= 50600 && PHP_VERSION_ID < 50607) { + parent::next(); + } parent::rewind(); } diff --git a/src/Symfony/Component/Finder/SplFileInfo.php b/src/Symfony/Component/Finder/SplFileInfo.php index c7fbe02191157..31a3f86a674d5 100644 --- a/src/Symfony/Component/Finder/SplFileInfo.php +++ b/src/Symfony/Component/Finder/SplFileInfo.php @@ -38,6 +38,8 @@ public function __construct($file, $relativePath, $relativePathname) /** * Returns the relative path. * + * This path does not contain the file name. + * * @return string the relative path */ public function getRelativePath() @@ -48,6 +50,8 @@ public function getRelativePath() /** * Returns the relative path name. * + * This path contains the file name. + * * @return string the relative path name */ public function getRelativePathname() diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index cee8bd7530767..24e385bdd9faf 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -248,6 +248,7 @@ public function testIn() __DIR__.DIRECTORY_SEPARATOR.'BsdFinderTest.php', __DIR__.DIRECTORY_SEPARATOR.'FinderTest.php', __DIR__.DIRECTORY_SEPARATOR.'GnuFinderTest.php', + __DIR__.DIRECTORY_SEPARATOR.'GlobTest.php', ); $this->assertIterator($expected, $iterator); @@ -458,7 +459,7 @@ public function testNotContainsOnDirectory() * Searching in multiple locations involves AppendIterator which does an unnecessary rewind which leaves FilterIterator * with inner FilesystemIterator in an invalid state. * - * @see https://bugs.php.net/bug.php?id=49104 + * @see https://bugs.php.net/68557 */ public function testMultipleLocations() { @@ -468,8 +469,12 @@ public function testMultipleLocations() ); // it is expected that there are test.py test.php in the tmpDir - $finder = $this->buildFinder(); - $finder->in($locations)->depth('< 1')->name('test.php'); + $finder = new Finder(); + $finder->in($locations) + // the default flag IGNORE_DOT_FILES fixes the problem indirectly + // so we set it to false for better isolation + ->ignoreDotFiles(false) + ->depth('< 1')->name('test.php'); $this->assertCount(1, $finder); } @@ -479,7 +484,7 @@ public function testMultipleLocations() * AppendIterator which does an unnecessary rewind which leaves * FilterIterator with inner FilesystemIterator in an invalid state. * - * @see https://bugs.php.net/bug.php?id=49104 + * @see https://bugs.php.net/68557 */ public function testMultipleLocationsWithSubDirectories() { @@ -517,8 +522,7 @@ public function testRegexSpecialCharsLocationWithPathRestrictionContainingStartF $finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'r+e.gex[c]a(r)s') ->path('/^dir/'); - $expected = array('r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir', - 'r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'bar.dat',); + $expected = array('r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir', 'r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'bar.dat'); $this->assertIterator($this->toAbsoluteFixtures($expected), $finder); } diff --git a/src/Symfony/Component/Finder/Tests/GlobTest.php b/src/Symfony/Component/Finder/Tests/GlobTest.php new file mode 100644 index 0000000000000..cf7d03563b7bd --- /dev/null +++ b/src/Symfony/Component/Finder/Tests/GlobTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Finder\Tests; + +use Symfony\Component\Finder\Glob; + +class GlobTest extends \PHPUnit_Framework_TestCase +{ + public function testGlobToRegexDelimiters() + { + $this->assertEquals('#^(?=[^\.])\#$#', Glob::toRegex('#')); + $this->assertEquals('#^\.[^/]*$#', Glob::toRegex('.*')); + } +} diff --git a/src/Symfony/Component/Finder/Tests/Iterator/FilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/FilterIteratorTest.php index 41e05a0a7b390..4f12d142e7f27 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/FilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/FilterIteratorTest.php @@ -43,8 +43,9 @@ public function testFilterFilesystemIterators() ++$c; } - // This would fail with \FilterIterator but works with Symfony\Component\Finder\Iterator\FilterIterator - // see https://bugs.php.net/bug.php?id=49104 + // This would fail in php older than 5.5.23/5.6.7 with \FilterIterator + // but works with Symfony\Component\Finder\Iterator\FilterIterator + // see https://bugs.php.net/68557 $this->assertEquals(1, $c); } } diff --git a/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php b/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php index e9145127eaba1..0c19ab47a88c1 100644 --- a/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php +++ b/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php @@ -146,7 +146,7 @@ public function testExecute() $cmd->add('--version'); $result = $cmd->execute(); - $this->assertTrue(is_array($result)); + $this->assertInternalType('array', $result); $this->assertNotEmpty($result); $this->assertRegexp('/PHP|HipHop/', $result[0]); } diff --git a/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php b/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php index 01c3c1b0b202e..31bb7797e51e3 100644 --- a/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php +++ b/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php @@ -96,10 +96,6 @@ public function preSubmit(FormEvent $event) $form = $event->getForm(); $data = $event->getData(); - if (null === $data || '' === $data) { - $data = array(); - } - if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) { $data = array(); } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index bde4ba723f3f8..2fe81e1b8eab7 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -71,10 +71,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) if ($options['multiple']) { $builder->addViewTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list'])); - $builder->addEventSubscriber(new FixCheckboxInputListener($options['choice_list']), 10); + $builder->addEventSubscriber(new FixCheckboxInputListener($options['choice_list'])); } else { $builder->addViewTransformer(new ChoiceToBooleanArrayTransformer($options['choice_list'], $builder->has('placeholder'))); - $builder->addEventSubscriber(new FixRadioInputListener($options['choice_list'], $builder->has('placeholder')), 10); + $builder->addEventSubscriber(new FixRadioInputListener($options['choice_list'], $builder->has('placeholder'))); } } else { if ($options['multiple']) { diff --git a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php index a800fc48d92c5..91871a828647e 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php +++ b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php @@ -84,9 +84,10 @@ public function __construct($fieldName, CsrfProviderInterface $csrfProvider, $in public function preSubmit(FormEvent $event) { $form = $event->getForm(); - $data = $event->getData(); if ($form->isRoot() && $form->getConfig()->getOption('compound')) { + $data = $event->getData(); + if (!isset($data[$this->fieldName]) || !$this->csrfProvider->isCsrfTokenValid($this->intention, $data[$this->fieldName])) { $errorMessage = $this->errorMessage; @@ -99,10 +100,9 @@ public function preSubmit(FormEvent $event) if (is_array($data)) { unset($data[$this->fieldName]); + $event->setData($data); } } - - $event->setData($data); } /** diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index f862970a7fd81..5792aa40828c7 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -45,7 +45,7 @@ public function validate($form, Constraint $constraint) // Validate the data against the constraints defined // in the form - $constraints = $config->getOption('constraints'); + $constraints = $config->getOption('constraints', array()); foreach ($constraints as $constraint) { foreach ($groups as $group) { if (in_array($group, $constraint->groups)) { diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php index 7686809588d7d..bef225c422d5a 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php @@ -147,12 +147,9 @@ public function mapViolation(ConstraintViolation $violation, FormInterface $form */ private function matchChild(FormInterface $form, PropertyPathIteratorInterface $it) { - // Remember at what property path underneath "data" - // we are looking. Check if there is a child with that - // path, otherwise increase path by one more piece + $target = null; $chunk = ''; - $foundChild = null; - $foundAtIndex = 0; + $foundAtIndex = null; // Construct mapping rules for the given form $rules = array(); @@ -164,17 +161,11 @@ private function matchChild(FormInterface $form, PropertyPathIteratorInterface $ } } - // Skip forms inheriting their parent data when iterating the children - $childIterator = new \RecursiveIteratorIterator( + $children = iterator_to_array(new \RecursiveIteratorIterator( new InheritDataAwareIterator($form) - ); - - // Make the path longer until we find a matching child - while (true) { - if (!$it->valid()) { - return; - } + )); + while ($it->valid()) { if ($it->isIndex()) { $chunk .= '['.$it->current().']'; } else { @@ -196,33 +187,27 @@ private function matchChild(FormInterface $form, PropertyPathIteratorInterface $ } } - // Test children unless we already found one - if (null === $foundChild) { - foreach ($childIterator as $child) { - /* @var FormInterface $child */ - $childPath = (string) $child->getPropertyPath(); - - // Child found, mark as return value - if ($chunk === $childPath) { - $foundChild = $child; - $foundAtIndex = $it->key(); - } + /** @var FormInterface $child */ + foreach ($children as $key => $child) { + $childPath = (string) $child->getPropertyPath(); + if ($childPath === $chunk) { + $target = $child; + $foundAtIndex = $it->key(); + } elseif (0 === strpos($childPath, $chunk)) { + continue; } + + unset($children[$key]); } - // Add element to the chunk $it->next(); + } - // If we reached the end of the path or if there are no - // more matching mapping rules, return the found child - if (null !== $foundChild && (!$it->valid() || count($rules) === 0)) { - // Reset index in case we tried to find mapping - // rules further down the path - $it->seek($foundAtIndex); - - return $foundChild; - } + if (null !== $foundAtIndex) { + $it->seek($foundAtIndex); } + + return $target; } /** diff --git a/src/Symfony/Component/Form/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Form/Resources/translations/validators.no.xlf similarity index 88% rename from src/Symfony/Component/Form/Resources/translations/validators.nb.xlf rename to src/Symfony/Component/Form/Resources/translations/validators.no.xlf index 5e36bd5fec1d3..c64266c99189b 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.nb.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.no.xlf @@ -8,7 +8,7 @@ The uploaded file was too large. Please try to upload a smaller file. - Den opplastede file var for stor. Vennligst last opp en mindre fil. + Den opplastede filen var for stor. Vennligst last opp en mindre fil. The CSRF token is invalid. diff --git a/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php index 4d4ac86fe73af..e71a1fdfd8058 100644 --- a/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php @@ -28,6 +28,7 @@ public function testRequestShouldNotBeNull() { $this->requestHandler->handleRequest($this->getMockForm('name', 'GET')); } + /** * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException */ diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index c440a0470abbe..aa65e50f56ca0 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -123,6 +123,17 @@ public function testDontValidateIfParentWithoutCascadeValidation() $this->assertNoViolation(); } + public function testMissingConstraintIndex() + { + $object = new \stdClass(); + $form = new FormBuilder('name', '\stdClass', $this->dispatcher, $this->factory); + $form = $form->setData($object)->getForm(); + + $this->validator->validate($form, new Form()); + + $this->assertNoViolation(); + } + public function testValidateConstraintsEvenIfNoCascadeValidation() { $object = $this->getMock('\stdClass'); @@ -558,11 +569,6 @@ public function getValidationGroups(FormInterface $form) return array('group1', 'group2'); } - private function getMockExecutionContext() - { - return $this->getMock('Symfony\Component\Validator\ExecutionContextInterface'); - } - /** * @param string $name * @param string $dataClass diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/BaseValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/BaseValidatorExtensionTest.php index e26bf7f1b69dc..6a15bbfa9e6b6 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/BaseValidatorExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/BaseValidatorExtensionTest.php @@ -64,7 +64,7 @@ public function testValidationGroupsCanBeSetToCallback() public function testValidationGroupsCanBeSetToClosure() { $form = $this->createForm(array( - 'validation_groups' => function (FormInterface $form) { return; }, + 'validation_groups' => function (FormInterface $form) { }, )); $this->assertTrue(is_callable($form->getConfig()->getOption('validation_groups'))); diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php index e4e0f9cc480e2..f6ad34eccb6b8 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php @@ -1474,4 +1474,25 @@ public function testErrorMappingForFormInheritingParentData($target, $childName, $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none'); } } + + public function testBacktrackIfSeveralSubFormsWithSamePropertyPath() + { + $violation = $this->getConstraintViolation('data.address[street]'); + $parent = $this->getForm('parent'); + $child1 = $this->getForm('subform1', 'address'); + $child2 = $this->getForm('subform2', 'address'); + $grandChild = $this->getForm('street'); + + $parent->add($child1); + $parent->add($child2); + $child2->add($grandChild); + + $this->mapper->mapViolation($violation, $parent); + + // The error occurred on the child of the second form with the same path + $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one'); + $this->assertCount(0, $child1->getErrors(), $child1->getName().' should not have an error, but has one'); + $this->assertCount(0, $child2->getErrors(), $child2->getName().' should not have an error, but has one'); + $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChild->getName().' should have an error, but has none'); + } } diff --git a/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php new file mode 100644 index 0000000000000..7596b879a18b4 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Resources; + +class TranslationFilesTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideTranslationFiles + */ + public function testTranslationFileIsValid($filePath) + { + \PHPUnit_Util_XML::loadfile($filePath, false, false, true); + } + + public function provideTranslationFiles() + { + return array_map( + function ($filePath) { return (array) $filePath; }, + glob(dirname(dirname(__DIR__)).'/Resources/translations/*.xlf') + ); + } +} diff --git a/src/Symfony/Component/Form/Tests/Util/OrderedHashMapTest.php b/src/Symfony/Component/Form/Tests/Util/OrderedHashMapTest.php index 7adff69a3fa29..dd51fa5d23a36 100644 --- a/src/Symfony/Component/Form/Tests/Util/OrderedHashMapTest.php +++ b/src/Symfony/Component/Form/Tests/Util/OrderedHashMapTest.php @@ -482,6 +482,6 @@ public function testCount() unset($map[0]); $map[] = 3; - $this->assertSame(2, count($map)); + $this->assertCount(2, $map); } } diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index d20880fceb2cd..22f84da4a4758 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -27,6 +27,9 @@ class BinaryFileResponse extends Response { protected static $trustXSendfileTypeHeader = false; + /** + * @var File + */ protected $file; protected $offset; protected $maxlen; @@ -179,7 +182,7 @@ public function prepare(Request $request) $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); } - if ('HTTP/1.0' != $request->server->get('SERVER_PROTOCOL')) { + if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) { $this->setProtocolVersion('1.1'); } @@ -196,17 +199,17 @@ public function prepare(Request $request) if (false === $path) { $path = $this->file->getPathname(); } - if (strtolower($type) == 'x-accel-redirect') { + if (strtolower($type) === 'x-accel-redirect') { // Do X-Accel-Mapping substitutions. // @link http://wiki.nginx.org/X-accel#X-Accel-Redirect foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) { $mapping = explode('=', $mapping, 2); - if (2 == count($mapping)) { + if (2 === count($mapping)) { $pathPrefix = trim($mapping[0]); $location = trim($mapping[1]); - if (substr($path, 0, strlen($pathPrefix)) == $pathPrefix) { + if (substr($path, 0, strlen($pathPrefix)) === $pathPrefix) { $path = $location.substr($path, strlen($pathPrefix)); break; } @@ -217,7 +220,7 @@ public function prepare(Request $request) $this->maxlen = 0; } elseif ($request->headers->has('Range')) { // Process the range headers. - if (!$request->headers->has('If-Range') || $this->getEtag() == $request->headers->get('If-Range')) { + if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) { $range = $request->headers->get('Range'); $fileSize = $this->file->getSize(); @@ -250,19 +253,32 @@ public function prepare(Request $request) return $this; } + private function hasValidIfRangeHeader($header) + { + if ($this->getEtag() === $header) { + return true; + } + + if (null === $lastModified = $this->getLastModified()) { + return false; + } + + return $lastModified->format('D, d M Y H:i:s').' GMT' === $header; + } + /** * Sends the file. + * + * {@inheritdoc} */ public function sendContent() { if (!$this->isSuccessful()) { - parent::sendContent(); - - return; + return parent::sendContent(); } if (0 === $this->maxlen) { - return; + return $this; } $out = fopen('php://output', 'wb'); @@ -272,6 +288,8 @@ public function sendContent() fclose($out); fclose($file); + + return $this; } /** diff --git a/src/Symfony/Component/HttpFoundation/Cookie.php b/src/Symfony/Component/HttpFoundation/Cookie.php index 061703d9ca0e8..13d69f3bd2edd 100644 --- a/src/Symfony/Component/HttpFoundation/Cookie.php +++ b/src/Symfony/Component/HttpFoundation/Cookie.php @@ -29,13 +29,13 @@ class Cookie /** * Constructor. * - * @param string $name The name of the cookie - * @param string $value The value of the cookie - * @param int|string|\DateTime $expire The time the cookie expires - * @param string $path The path on the server in which the cookie will be available on - * @param string $domain The domain that the cookie is available to - * @param bool $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client - * @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol + * @param string $name The name of the cookie + * @param string $value The value of the cookie + * @param int|string|\DateTime|\DateTimeInterface $expire The time the cookie expires + * @param string $path The path on the server in which the cookie will be available on + * @param string $domain The domain that the cookie is available to + * @param bool $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client + * @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol * * @throws \InvalidArgumentException */ @@ -51,7 +51,7 @@ public function __construct($name, $value = null, $expire = 0, $path = '/', $dom } // convert expiration time to a Unix timestamp - if ($expire instanceof \DateTime) { + if ($expire instanceof \DateTime || $expire instanceof \DateTimeInterface) { $expire = $expire->format('U'); } elseif (!is_numeric($expire)) { $expire = strtotime($expire); diff --git a/src/Symfony/Component/HttpFoundation/RedirectResponse.php b/src/Symfony/Component/HttpFoundation/RedirectResponse.php index a21eb5cc516b2..18d5794c0bf34 100644 --- a/src/Symfony/Component/HttpFoundation/RedirectResponse.php +++ b/src/Symfony/Component/HttpFoundation/RedirectResponse.php @@ -23,7 +23,8 @@ class RedirectResponse extends Response /** * Creates a redirect response so that it conforms to the rules defined for a redirect status code. * - * @param string $url The URL to redirect to + * @param string $url The URL to redirect to. The URL should be a full URL, with schema etc., + * but practically every browser redirects on paths only as well * @param int $status The status code (302 by default) * @param array $headers The headers (Location is always set to the given URL) * @@ -33,10 +34,6 @@ class RedirectResponse extends Response */ public function __construct($url, $status = 302, $headers = array()) { - if (empty($url)) { - throw new \InvalidArgumentException('Cannot redirect to an empty URL.'); - } - parent::__construct('', $status, $headers); $this->setTargetUrl($url); diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index d2af44626cdcb..c93dddaf3f337 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -769,8 +769,7 @@ public function getClientIps() $clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP]))); $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from - - $ip = $clientIps[0]; // Fallback to this when the client IP falls into the range of trusted proxies + $firstTrustedIp = null; // Eliminate all IPs from the forwarded IP chain which are trusted proxies foreach ($clientIps as $key => $clientIp) { @@ -779,13 +778,22 @@ public function getClientIps() $clientIps[$key] = $clientIp = $match[1]; } + if (!filter_var($clientIp, FILTER_VALIDATE_IP)) { + unset($clientIps[$key]); + } + if (IpUtils::checkIp($clientIp, self::$trustedProxies)) { unset($clientIps[$key]); + + // Fallback to this when the client IP falls into the range of trusted proxies + if (null === $firstTrustedIp) { + $firstTrustedIp = $clientIp; + } } } // Now the IP chain contains only untrusted proxies and the client IP - return $clientIps ? array_reverse($clientIps) : array($ip); + return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp); } /** @@ -1707,8 +1715,6 @@ protected function preparePathInfo() return '/'; } - $pathInfo = '/'; - // Remove the query string from REQUEST_URI if ($pos = strpos($requestUri, '?')) { $requestUri = substr($requestUri, 0, $pos); diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index a21e6b921cc68..c65ceb716393e 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -109,6 +109,7 @@ class Response 428 => 'Precondition Required', // RFC6585 429 => 'Too Many Requests', // RFC6585 431 => 'Request Header Fields Too Large', // RFC6585 + 451 => 'Unavailable For Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', @@ -976,11 +977,12 @@ public function isNotModified(Request $request) return $notModified; } - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html /** * Is response invalid? * * @return bool + * + * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html */ public function isInvalid() { diff --git a/src/Symfony/Component/HttpFoundation/ServerBag.php b/src/Symfony/Component/HttpFoundation/ServerBag.php index fa1cb2fc9f134..0d38c08ac0544 100644 --- a/src/Symfony/Component/HttpFoundation/ServerBag.php +++ b/src/Symfony/Component/HttpFoundation/ServerBag.php @@ -86,6 +86,10 @@ public function getHeaders() } } + if (isset($headers['AUTHORIZATION'])) { + return $headers; + } + // PHP_AUTH_USER/PHP_AUTH_PW if (isset($headers['PHP_AUTH_USER'])) { $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']); diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index 35dfab5366501..88fb251366c53 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -80,6 +80,37 @@ public function testRequests($requestRange, $offset, $length, $responseRange) $this->assertEquals($responseRange, $response->headers->get('Content-Range')); } + /** + * @dataProvider provideRanges + */ + public function testRequestsWithoutEtag($requestRange, $offset, $length, $responseRange) + { + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream')); + + // do a request to get the LastModified + $request = Request::create('/'); + $response->prepare($request); + $lastModified = $response->headers->get('Last-Modified'); + + // prepare a request for a range of the testing file + $request = Request::create('/'); + $request->headers->set('If-Range', $lastModified); + $request->headers->set('Range', $requestRange); + + $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r'); + fseek($file, $offset); + $data = fread($file, $length); + fclose($file); + + $this->expectOutputString($data); + $response = clone $response; + $response->prepare($request); + $response->sendContent(); + + $this->assertEquals(206, $response->getStatusCode()); + $this->assertEquals($responseRange, $response->headers->get('Content-Range')); + } + public function provideRanges() { return array( @@ -91,6 +122,25 @@ public function provideRanges() ); } + public function testRangeRequestsWithoutLastModifiedDate() + { + // prevent auto last modified + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'), true, null, false, false); + + // prepare a request for a range of the testing file + $request = Request::create('/'); + $request->headers->set('If-Range', date('D, d M Y H:i:s').' GMT'); + $request->headers->set('Range', 'bytes=1-4'); + + $this->expectOutputString(file_get_contents(__DIR__.'/File/Fixtures/test.gif')); + $response = clone $response; + $response->prepare($request); + $response->sendContent(); + + $this->assertEquals(200, $response->getStatusCode()); + $this->assertNull($response->headers->get('Content-Range')); + } + /** * @dataProvider provideFullFileRanges */ diff --git a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php index fd90103e42e3d..222786533ecca 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php @@ -85,6 +85,17 @@ public function testConstructorWithDateTime() $this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); } + /** + * @requires PHP 5.5 + */ + public function testConstructorWithDateTimeImmutable() + { + $expire = new \DateTimeImmutable(); + $cookie = new Cookie('foo', 'bar', $expire); + + $this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); + } + public function testGetExpiresTimeWithStringValue() { $value = '+1 day'; diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php index 90a143367abcb..d9b9b1f7a327a 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php @@ -81,8 +81,8 @@ public function testMove() $movedFile = $file->move($targetDir); $this->assertInstanceOf('Symfony\Component\HttpFoundation\File\File', $movedFile); - $this->assertTrue(file_exists($targetPath)); - $this->assertFalse(file_exists($path)); + $this->assertFileExists($targetPath); + $this->assertFileNotExists($path); $this->assertEquals(realpath($targetPath), $movedFile->getRealPath()); @unlink($targetPath); @@ -100,8 +100,8 @@ public function testMoveWithNewName() $file = new File($path); $movedFile = $file->move($targetDir, 'test.newname.gif'); - $this->assertTrue(file_exists($targetPath)); - $this->assertFalse(file_exists($path)); + $this->assertFileExists($targetPath); + $this->assertFileNotExists($path); $this->assertEquals(realpath($targetPath), $movedFile->getRealPath()); @unlink($targetPath); @@ -135,8 +135,8 @@ public function testMoveWithNonLatinName($filename, $sanitizedFilename) $movedFile = $file->move($targetDir, $filename); $this->assertInstanceOf('Symfony\Component\HttpFoundation\File\File', $movedFile); - $this->assertTrue(file_exists($targetPath)); - $this->assertFalse(file_exists($path)); + $this->assertFileExists($targetPath); + $this->assertFileNotExists($path); $this->assertEquals(realpath($targetPath), $movedFile->getRealPath()); @unlink($targetPath); diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php index f6ea340091ba5..2e2d27409caa4 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php @@ -164,8 +164,8 @@ public function testMoveLocalFileIsAllowedInTestMode() $movedFile = $file->move(__DIR__.'/Fixtures/directory'); - $this->assertTrue(file_exists($targetPath)); - $this->assertFalse(file_exists($path)); + $this->assertFileExists($targetPath); + $this->assertFileNotExists($path); $this->assertEquals(realpath($targetPath), $movedFile->getRealPath()); @unlink($targetPath); diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index cbc1b74fc9faf..4e20366938b63 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -17,11 +17,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase { - public function testConstructor() - { - $this->testInitialize(); - } - public function testInitialize() { $request = new Request(); @@ -868,6 +863,9 @@ public function testGetClientIpsProvider() // client IP with port array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88:12345, 127.0.0.1', array('127.0.0.1')), + + // invalid forwarded IP is ignored + array(array('88.88.88.88'), '127.0.0.1', 'unknown,88.88.88.88', array('127.0.0.1')), ); } @@ -1671,7 +1669,7 @@ public function testVeryLongHosts($host) $request = Request::create('/'); $request->headers->set('host', $host); $this->assertEquals($host, $request->getHost()); - $this->assertLessThan(1, microtime(true) - $start); + $this->assertLessThan(3, microtime(true) - $start); } /** diff --git a/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php index 20773c4d7a3b6..41e44e10056ea 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php @@ -151,4 +151,19 @@ public function testOAuthBearerAuthWithRedirect() 'AUTHORIZATION' => $headerContent, ), $bag->getHeaders()); } + + /** + * @see https://github.com/symfony/symfony/issues/17345 + */ + public function testItDoesNotOverwriteTheAuthorizationHeaderIfItIsAlreadySet() + { + $headerContent = 'Bearer L-yLEOr9zhmUYRkzN1jwwxwQ-PBNiKDc8dgfB4hTfvo'; + $bag = new ServerBag(array('PHP_AUTH_USER' => 'foo', 'HTTP_AUTHORIZATION' => $headerContent)); + + $this->assertEquals(array( + 'AUTHORIZATION' => $headerContent, + 'PHP_AUTH_USER' => 'foo', + 'PHP_AUTH_PW' => '', + ), $bag->getHeaders()); + } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/AttributeBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/AttributeBagTest.php index 8d0e7a5c13e6d..ca6ce8a38670a 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/AttributeBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/AttributeBagTest.php @@ -43,8 +43,9 @@ protected function setUp() 'category' => array( 'fishing' => array( 'first' => 'cod', - 'second' => 'sole',), + 'second' => 'sole', ), + ), ); $this->bag = new AttributeBag('_sf2'); $this->bag->initialize($this->array); diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php index b8261da5d0c18..470038fe55170 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php @@ -43,8 +43,9 @@ protected function setUp() 'category' => array( 'fishing' => array( 'first' => 'cod', - 'second' => 'sole',), + 'second' => 'sole', ), + ), ); $this->bag = new NamespacedAttributeBag('_sf2', '/'); $this->bag->initialize($this->array); diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php index 1936b1c2942f0..1c6b7b9635222 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php @@ -57,7 +57,7 @@ public function testWrongTableOptionsRead() { $storage = new PdoSessionHandler($this->pdo, array('db_table' => 'bad_name')); $this->setExpectedException('RuntimeException'); - $storage->read('foo', 'bar'); + $storage->read('foo'); } public function testWriteRead() diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php index 94e6541c91154..e3a2d9fe11083 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php @@ -45,6 +45,10 @@ protected function varToString($var) return sprintf('Object(%s)', get_class($var)); } + if ($var instanceof \__PHP_Incomplete_Class) { + return sprintf('__PHP_Incomplete_Class(%s)', $this->getClassNameFromIncomplete($var)); + } + if (is_array($var)) { $a = array(); foreach ($var as $k => $v) { @@ -72,4 +76,11 @@ protected function varToString($var) return (string) $var; } + + private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $var) + { + $array = new \ArrayObject($var); + + return $array['__PHP_Incomplete_Class_Name']; + } } diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index 07179faec4873..eebac8e7c2918 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -255,7 +255,7 @@ protected function invalidate(Request $request, $catch = false) // invalidate only when the response is successful if ($response->isSuccessful() || $response->isRedirect()) { try { - $this->store->invalidate($request, $catch); + $this->store->invalidate($request); // As per the RFC, invalidate Location and Content-Location URLs if present foreach (array('Location', 'Content-Location') as $header) { @@ -481,7 +481,7 @@ protected function forward(Request $request, $catch = false, Response $entry = n $this->processResponseBody($request, $response); if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) { - $response->setPrivate(true); + $response->setPrivate(); } elseif ($this->options['default_ttl'] > 0 && null === $response->getTtl() && !$response->headers->getCacheControlDirective('must-revalidate')) { $response->setTtl($this->options['default_ttl']); } @@ -544,7 +544,7 @@ protected function lock(Request $request, Response $entry) $wait += 50000; } - if ($wait < 2000000) { + if ($wait < 5000000) { // replace the current entry with the fresh one $new = $this->lookup($request); $entry->headers = $new->headers; diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index c90dadfbbd1de..ed61828502a37 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,11 +58,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.3.37'; - const VERSION_ID = 20337; + const VERSION = '2.3.38'; + const VERSION_ID = 20338; const MAJOR_VERSION = 2; const MINOR_VERSION = 3; - const RELEASE_VERSION = 37; + const RELEASE_VERSION = 38; const EXTRA_VERSION = ''; /** @@ -699,14 +699,15 @@ public static function stripComments($source) $output = ''; $tokens = token_get_all($source); $ignoreSpace = false; - for (reset($tokens); false !== $token = current($tokens); next($tokens)) { - if (is_string($token)) { + for ($i = 0; isset($tokens[$i]); ++$i) { + $token = $tokens[$i]; + if (!isset($token[1]) || 'b"' === $token) { $rawChunk .= $token; } elseif (T_START_HEREDOC === $token[0]) { $output .= $rawChunk.$token[1]; do { - $token = next($tokens); - $output .= $token[1]; + $token = $tokens[++$i]; + $output .= isset($token[1]) && 'b"' !== $token ? $token[1] : $token; } while ($token[0] !== T_END_HEREDOC); $rawChunk = ''; } elseif (T_WHITESPACE === $token[0]) { @@ -732,6 +733,12 @@ public static function stripComments($source) $output .= $rawChunk; + if (PHP_VERSION_ID >= 70000) { + // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 + unset($tokens, $rawChunk); + gc_mem_caches(); + } + return $output; } diff --git a/src/Symfony/Component/HttpKernel/Profiler/SqliteProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/SqliteProfilerStorage.php index 0c25bc950c3ae..33c11b68cdaf8 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/SqliteProfilerStorage.php +++ b/src/Symfony/Component/HttpKernel/Profiler/SqliteProfilerStorage.php @@ -77,7 +77,7 @@ protected function fetch($db, $query, array $args = array()) $return = array(); if ($db instanceof \SQLite3) { - $stmt = $this->prepareStatement($db, $query, true); + $stmt = $this->prepareStatement($db, $query); foreach ($args as $arg => $val) { $stmt->bindValue($arg, $val, is_int($val) ? \SQLITE3_INTEGER : \SQLITE3_TEXT); } diff --git a/src/Symfony/Component/HttpKernel/Tests/CacheWarmer/CacheWarmerTest.php b/src/Symfony/Component/HttpKernel/Tests/CacheWarmer/CacheWarmerTest.php index f0ab05d62efe2..fe5ecb2ed313a 100644 --- a/src/Symfony/Component/HttpKernel/Tests/CacheWarmer/CacheWarmerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/CacheWarmer/CacheWarmerTest.php @@ -32,7 +32,7 @@ public function testWriteCacheFileCreatesTheFile() $warmer = new TestCacheWarmer(self::$cacheFile); $warmer->warmUp(dirname(self::$cacheFile)); - $this->assertTrue(file_exists(self::$cacheFile)); + $this->assertFileExists(self::$cacheFile); } /** diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php index f0a1cf4084306..0222998ea2750 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php @@ -65,6 +65,7 @@ class Renderer extends RoutableFragmentRenderer public function render($uri, Request $request, array $options = array()) { } + public function getName() { } diff --git a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php index 6bf5c258846d3..fa1294e80654c 100644 --- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php @@ -307,7 +307,7 @@ public function testStripComments() $heredoc = <<scanLocales($sourceDir, '.txt'); + $locales = $this->scanLocales($sourceDir); $aliases = array(); // Delete locales that are no aliases diff --git a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php index 11f8c0f9470cc..c309fc722dcdf 100644 --- a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php +++ b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php @@ -647,8 +647,7 @@ protected function getDefaultPattern() if (self::NONE !== $this->timetype) { $patternParts[] = $this->defaultTimeFormats[$this->timetype]; } - $pattern = implode(', ', $patternParts); - return $pattern; + return implode(', ', $patternParts); } } diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php index 0ee222ee50fd6..7bc7a2ba880fb 100644 --- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php +++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php @@ -709,11 +709,9 @@ private function roundCurrency($value, $currency) private function round($value, $precision) { $precision = $this->getUnitializedPrecision($value, $precision); - $roundingMode = self::$phpRoundingMap[$this->getAttribute(self::ROUNDING_MODE)]; - $value = round($value, $precision, $roundingMode); - return $value; + return round($value, $precision, $roundingMode); } /** diff --git a/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/IntlBundleReaderTest.php b/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/IntlBundleReaderTest.php index d6f4257647169..b2d7c63a93958 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/IntlBundleReaderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/IntlBundleReaderTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Intl\Tests\Data\Bundle\Reader; use Symfony\Component\Intl\Data\Bundle\Reader\IntlBundleReader; -use Symfony\Component\Intl\Intl; /** * @author Bernhard Schussek diff --git a/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/JsonBundleReaderTest.php b/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/JsonBundleReaderTest.php index 2cc4607b1129e..a6183edfe0737 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/JsonBundleReaderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/JsonBundleReaderTest.php @@ -32,7 +32,7 @@ public function testReadReturnsArray() { $data = $this->reader->read(__DIR__.'/Fixtures/json', 'en'); - $this->assertTrue(is_array($data)); + $this->assertInternalType('array', $data); $this->assertSame('Bar', $data['Foo']); $this->assertFalse(isset($data['ExistsNot'])); } diff --git a/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/PhpBundleReaderTest.php b/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/PhpBundleReaderTest.php index 2beaec7ba26b8..3c58ee7c416cf 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/PhpBundleReaderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Bundle/Reader/PhpBundleReaderTest.php @@ -32,7 +32,7 @@ public function testReadReturnsArray() { $data = $this->reader->read(__DIR__.'/Fixtures/php', 'en'); - $this->assertTrue(is_array($data)); + $this->assertInternalType('array', $data); $this->assertSame('Bar', $data['Foo']); $this->assertFalse(isset($data['ExistsNot'])); } diff --git a/src/Symfony/Component/Intl/Tests/Data/Bundle/Writer/JsonBundleWriterTest.php b/src/Symfony/Component/Intl/Tests/Data/Bundle/Writer/JsonBundleWriterTest.php index b9d50976d98cc..5e4c4b225e2b9 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Bundle/Writer/JsonBundleWriterTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Bundle/Writer/JsonBundleWriterTest.php @@ -13,7 +13,6 @@ use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Intl\Data\Bundle\Writer\JsonBundleWriter; -use Symfony\Component\Intl\Intl; /** * @author Bernhard Schussek diff --git a/src/Symfony/Component/Intl/Tests/Data/Bundle/Writer/PhpBundleWriterTest.php b/src/Symfony/Component/Intl/Tests/Data/Bundle/Writer/PhpBundleWriterTest.php index d11d3d204b3df..ee7b12f1ed040 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Bundle/Writer/PhpBundleWriterTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Bundle/Writer/PhpBundleWriterTest.php @@ -13,7 +13,6 @@ use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Intl\Data\Bundle\Writer\PhpBundleWriter; -use Symfony\Component\Intl\Intl; /** * @author Bernhard Schussek diff --git a/src/Symfony/Component/Intl/Tests/Data/Util/LocaleScannerTest.php b/src/Symfony/Component/Intl/Tests/Data/Util/LocaleScannerTest.php index 7c37c80720b1b..fa487ba3b5332 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Util/LocaleScannerTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Util/LocaleScannerTest.php @@ -64,13 +64,13 @@ public function testScanLocales() { $sortedLocales = array('de', 'de_alias', 'en', 'en_alias', 'fr', 'fr_alias'); - $this->assertSame($sortedLocales, $this->scanner->scanLocales($this->directory, '.txt')); + $this->assertSame($sortedLocales, $this->scanner->scanLocales($this->directory)); } public function testScanAliases() { $sortedAliases = array('de_alias' => 'de', 'en_alias' => 'en', 'fr_alias' => 'fr'); - $this->assertSame($sortedAliases, $this->scanner->scanAliases($this->directory, '.txt')); + $this->assertSame($sortedAliases, $this->scanner->scanAliases($this->directory)); } } diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index e0f49a7e3b2e7..30313c0318336 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -201,9 +201,6 @@ public function run($callback = null) * The callback receives the type of output (out or err) and some bytes from * the output in real-time while writing the standard input to the process. * It allows to have feedback from the independent process during execution. - * If there is no callback passed, the wait() method can be called - * with true as a second parameter then the callback will get all data occurred - * in (and since) the start call. * * @param callback|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR @@ -378,7 +375,11 @@ public function getOutput() $this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true); - return $this->stdout; + if (false === $ret = stream_get_contents($this->stdout, -1, 0)) { + return ''; + } + + return $ret; } /** @@ -395,16 +396,13 @@ public function getIncrementalOutput() { $this->requireProcessIsStarted(__FUNCTION__); - $data = $this->getOutput(); - - $latest = substr($data, $this->incrementalOutputOffset); + $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset); + $this->incrementalOutputOffset = ftell($this->stdout); if (false === $latest) { return ''; } - $this->incrementalOutputOffset = strlen($data); - return $latest; } @@ -421,7 +419,11 @@ public function getErrorOutput() $this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true); - return $this->stderr; + if (false === $ret = stream_get_contents($this->stderr, -1, 0)) { + return ''; + } + + return $ret; } /** @@ -439,16 +441,13 @@ public function getIncrementalErrorOutput() { $this->requireProcessIsStarted(__FUNCTION__); - $data = $this->getErrorOutput(); - - $latest = substr($data, $this->incrementalErrorOutputOffset); + $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset); + $this->incrementalErrorOutputOffset = ftell($this->stderr); if (false === $latest) { return ''; } - $this->incrementalErrorOutputOffset = strlen($data); - return $latest; } @@ -666,21 +665,29 @@ public function stop($timeout = 10, $signal = null) /** * Adds a line to the STDOUT stream. * + * @internal + * * @param string $line The line to append */ public function addOutput($line) { - $this->stdout .= $line; + fseek($this->stdout, 0, SEEK_END); + fwrite($this->stdout, $line); + fseek($this->stdout, $this->incrementalOutputOffset); } /** * Adds a line to the STDERR stream. * + * @internal + * * @param string $line The line to append */ public function addErrorOutput($line) { - $this->stderr .= $line; + fseek($this->stderr, 0, SEEK_END); + fwrite($this->stderr, $line); + fseek($this->stderr, $this->incrementalErrorOutputOffset); } /** @@ -1126,8 +1133,8 @@ private function resetProcessData() $this->exitcode = null; $this->fallbackStatus = array(); $this->processInformation = null; - $this->stdout = null; - $this->stderr = null; + $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'wb+'); + $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'wb+'); $this->process = null; $this->latestSignal = null; $this->status = self::STATUS_READY; diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 7fc370bf81f3b..14daf2c286aa4 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -290,56 +290,40 @@ public function testGetErrorOutput() $this->assertEquals(3, preg_match_all('/ERROR/', $p->getErrorOutput(), $matches)); } - public function testGetIncrementalErrorOutput() + /** + * @dataProvider provideIncrementalOutput + */ + public function testIncrementalOutput($getOutput, $getIncrementalOutput, $uri) { - // use a lock file to toggle between writing ("W") and reading ("R") the - // error stream - $lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock'); - file_put_contents($lock, 'W'); + $lock = tempnam(sys_get_temp_dir(), __FUNCTION__); - $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }'))); + $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('file_put_contents($s = \''.$uri.'\', \'foo\'); flock(fopen('.var_export($lock, true).', \'r\'), LOCK_EX); file_put_contents($s, \'bar\');'))); - $p->start(); - while ($p->isRunning()) { - if ('R' === file_get_contents($lock)) { - $this->assertLessThanOrEqual(1, preg_match_all('/ERROR/', $p->getIncrementalErrorOutput(), $matches)); - file_put_contents($lock, 'W'); - } - usleep(100); - } - - unlink($lock); - } - - public function testGetEmptyIncrementalErrorOutput() - { - // use a lock file to toggle between writing ("W") and reading ("R") the - // output stream - $lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock'); - file_put_contents($lock, 'W'); - - $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }'))); + $h = fopen($lock, 'w'); + flock($h, LOCK_EX); $p->start(); - $shouldWrite = false; + foreach (array('foo', 'bar') as $s) { + while (false === strpos($p->$getOutput(), $s)) { + usleep(1000); + } - while ($p->isRunning()) { - if ('R' === file_get_contents($lock)) { - if (!$shouldWrite) { - $this->assertLessThanOrEqual(1, preg_match_all('/ERROR/', $p->getIncrementalOutput(), $matches)); - $shouldWrite = true; - } else { - $this->assertSame('', $p->getIncrementalOutput()); + $this->assertSame($s, $p->$getIncrementalOutput()); + $this->assertSame('', $p->$getIncrementalOutput()); - file_put_contents($lock, 'W'); - $shouldWrite = false; - } - } - usleep(100); + flock($h, LOCK_UN); } - unlink($lock); + fclose($h); + } + + public function provideIncrementalOutput() + { + return array( + array('getOutput', 'getIncrementalOutput', 'php://stdout'), + array('getErrorOutput', 'getIncrementalErrorOutput', 'php://stderr'), + ); } public function testGetOutput() @@ -350,58 +334,6 @@ public function testGetOutput() $this->assertEquals(3, preg_match_all('/foo/', $p->getOutput(), $matches)); } - public function testGetIncrementalOutput() - { - // use a lock file to toggle between writing ("W") and reading ("R") the - // output stream - $lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock'); - file_put_contents($lock, 'W'); - - $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { echo \' foo \'; $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }'))); - - $p->start(); - while ($p->isRunning()) { - if ('R' === file_get_contents($lock)) { - $this->assertLessThanOrEqual(1, preg_match_all('/foo/', $p->getIncrementalOutput(), $matches)); - file_put_contents($lock, 'W'); - } - usleep(100); - } - - unlink($lock); - } - - public function testGetEmptyIncrementalOutput() - { - // use a lock file to toggle between writing ("W") and reading ("R") the - // output stream - $lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock'); - file_put_contents($lock, 'W'); - - $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { echo \' foo \'; $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }'))); - - $p->start(); - - $shouldWrite = false; - - while ($p->isRunning()) { - if ('R' === file_get_contents($lock)) { - if (!$shouldWrite) { - $this->assertLessThanOrEqual(1, preg_match_all('/foo/', $p->getIncrementalOutput(), $matches)); - $shouldWrite = true; - } else { - $this->assertSame('', $p->getIncrementalOutput()); - - file_put_contents($lock, 'W'); - $shouldWrite = false; - } - } - usleep(100); - } - - unlink($lock); - } - public function testZeroAsOutput() { if ('\\' === DIRECTORY_SEPARATOR) { diff --git a/src/Symfony/Component/PropertyAccess/StringUtil.php b/src/Symfony/Component/PropertyAccess/StringUtil.php index 2f31925e73367..248a6483d8b0a 100644 --- a/src/Symfony/Component/PropertyAccess/StringUtil.php +++ b/src/Symfony/Component/PropertyAccess/StringUtil.php @@ -39,6 +39,9 @@ class StringUtil // nebulae (nebula) array('ea', 2, true, true, 'a'), + // services (service) + array('secivres', 8, true, true, 'service'), + // mice (mouse), lice (louse) array('eci', 3, false, true, 'ouse'), @@ -66,6 +69,12 @@ class StringUtil // movies (movie) array('seivom', 6, true, true, 'movie'), + // news (news) + array('swen', 4, true, true, 'news'), + + // series (series) + array('seires', 6, true, true, 'series'), + // babies (baby) array('sei', 3, false, true, 'y'), diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index a38a3ef967869..51bc6eabc2af1 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -337,7 +337,7 @@ public function testGetValueFailsIfMagicCallDisabled() { $value = new MagicianCall(); - $this->propertyAccessor->getValue($value, 'foobar', 'bam'); + $this->propertyAccessor->getValue($value, 'foobar'); } public function testGetValueReadsMagicCall() diff --git a/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php b/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php index c5691ed7bdc5b..0fd6bb69b2956 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php @@ -102,6 +102,7 @@ public function singularifyProvider() array('movies', 'movie'), array('nebulae', 'nebula'), array('neuroses', array('neuros', 'neurose', 'neurosis')), + array('news', 'news'), array('oases', array('oas', 'oase', 'oasis')), array('objectives', 'objective'), array('oxen', 'ox'), @@ -120,6 +121,8 @@ public function singularifyProvider() array('scarves', array('scarf', 'scarve', 'scarff')), array('schemas', 'schema'), //schemata array('selfies', 'selfie'), + array('series', 'series'), + array('services', 'service'), array('sheriffs', 'sheriff'), array('shoes', array('sho', 'shoe')), array('spies', 'spy'), diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php index 11d8f34d5ad41..24505add17b76 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php @@ -120,7 +120,7 @@ public function load($class, $type = null) $class = new \ReflectionClass($class); if ($class->isAbstract()) { - throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class)); + throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class->getName())); } if ($annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass)) { diff --git a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php index abd68ed6c4fab..f6b99a16ae8b2 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php @@ -66,12 +66,16 @@ public function load($path, $type = null) */ public function supports($resource, $type = null) { + if (!is_string($resource)) { + return false; + } + try { $path = $this->locator->locate($resource); } catch (\Exception $e) { return false; } - return is_string($resource) && is_dir($path) && (!$type || 'annotation' === $type); + return is_dir($path) && (!$type || 'annotation' === $type); } } diff --git a/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php index 8ce57ac18ca54..a3a7e0e5ae50e 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php @@ -64,6 +64,10 @@ public function load($file, $type = null) $collection->addResource(new FileResource($path)); $collection->addCollection($this->loader->load($class, $type)); } + if (PHP_VERSION_ID >= 70000) { + // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 + gc_mem_caches(); + } return $collection; } @@ -88,10 +92,10 @@ protected function findClass($file) $class = false; $namespace = false; $tokens = token_get_all(file_get_contents($file)); - for ($i = 0, $count = count($tokens); $i < $count; ++$i) { + for ($i = 0; isset($tokens[$i]); ++$i) { $token = $tokens[$i]; - if (!is_array($token)) { + if (!isset($token[1])) { continue; } @@ -100,11 +104,11 @@ protected function findClass($file) } if (true === $namespace && T_STRING === $token[0]) { - $namespace = ''; - do { - $namespace .= $token[1]; - $token = $tokens[++$i]; - } while ($i < $count && is_array($token) && in_array($token[0], array(T_NS_SEPARATOR, T_STRING))); + $namespace = $token[1]; + while (isset($tokens[++$i][1]) && in_array($tokens[$i][0], array(T_NS_SEPARATOR, T_STRING))) { + $namespace .= $tokens[$i][1]; + } + $token = $tokens[$i]; } if (T_CLASS === $token[0]) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/bar.xml b/src/Symfony/Component/Routing/Tests/Fixtures/bar.xml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index 2807e1011c1b8..d7b74f01e1bb3 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -623,9 +623,8 @@ protected function getGenerator(RouteCollection $routes, array $parameters = arr $method = 'set'.$key; $context->$method($value); } - $generator = new UrlGenerator($routes, $context, $logger); - return $generator; + return new UrlGenerator($routes, $context, $logger); } protected function getRoutes($name, Route $route) diff --git a/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php b/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php index 2b7c17faaac4c..f0a4aa4aed3e0 100644 --- a/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php @@ -38,7 +38,8 @@ public function provideCompileData() array('/foo'), '/foo', '#^/foo$#s', array(), array( array('text', '/foo'), - ),), + ), + ), array( 'Route with a variable', @@ -46,7 +47,8 @@ public function provideCompileData() '/foo', '#^/foo/(?P[^/]++)$#s', array('bar'), array( array('variable', '/', '[^/]++', 'bar'), array('text', '/foo'), - ),), + ), + ), array( 'Route with a variable that has a default value', @@ -54,7 +56,8 @@ public function provideCompileData() '/foo', '#^/foo(?:/(?P[^/]++))?$#s', array('bar'), array( array('variable', '/', '[^/]++', 'bar'), array('text', '/foo'), - ),), + ), + ), array( 'Route with several variables', @@ -63,7 +66,8 @@ public function provideCompileData() array('variable', '/', '[^/]++', 'foobar'), array('variable', '/', '[^/]++', 'bar'), array('text', '/foo'), - ),), + ), + ), array( 'Route with several variables that have default values', @@ -72,7 +76,8 @@ public function provideCompileData() array('variable', '/', '[^/]++', 'foobar'), array('variable', '/', '[^/]++', 'bar'), array('text', '/foo'), - ),), + ), + ), array( 'Route with several variables but some of them have no default values', @@ -81,28 +86,32 @@ public function provideCompileData() array('variable', '/', '[^/]++', 'foobar'), array('variable', '/', '[^/]++', 'bar'), array('text', '/foo'), - ),), + ), + ), array( 'Route with an optional variable as the first segment', array('/{bar}', array('bar' => 'bar')), '', '#^/(?P[^/]++)?$#s', array('bar'), array( array('variable', '/', '[^/]++', 'bar'), - ),), + ), + ), array( 'Route with a requirement of 0', array('/{bar}', array('bar' => null), array('bar' => '0')), '', '#^/(?P0)?$#s', array('bar'), array( array('variable', '/', '0', 'bar'), - ),), + ), + ), array( 'Route with an optional variable as the first segment with requirements', array('/{bar}', array('bar' => 'bar'), array('bar' => '(foo|bar)')), '', '#^/(?P(foo|bar))?$#s', array('bar'), array( array('variable', '/', '(foo|bar)', 'bar'), - ),), + ), + ), array( 'Route with only optional variables', @@ -110,44 +119,49 @@ public function provideCompileData() '', '#^/(?P[^/]++)?(?:/(?P[^/]++))?$#s', array('foo', 'bar'), array( array('variable', '/', '[^/]++', 'bar'), array('variable', '/', '[^/]++', 'foo'), - ),), + ), + ), array( 'Route with a variable in last position', array('/foo-{bar}'), '/foo', '#^/foo\-(?P[^/]++)$#s', array('bar'), array( - array('variable', '-', '[^/]++', 'bar'), - array('text', '/foo'), - ),), + array('variable', '-', '[^/]++', 'bar'), + array('text', '/foo'), + ), + ), array( 'Route with nested placeholders', array('/{static{var}static}'), '/{static', '#^/\{static(?P[^/]+)static\}$#s', array('var'), array( - array('text', 'static}'), - array('variable', '', '[^/]+', 'var'), - array('text', '/{static'), - ),), + array('text', 'static}'), + array('variable', '', '[^/]+', 'var'), + array('text', '/{static'), + ), + ), array( 'Route without separator between variables', array('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '(y|Y)')), '', '#^/(?P[^/\.]+)(?P[^/\.]+)(?P(y|Y))(?:(?P[^/\.]++)(?:\.(?P<_format>[^/]++))?)?$#s', array('w', 'x', 'y', 'z', '_format'), array( - array('variable', '.', '[^/]++', '_format'), - array('variable', '', '[^/\.]++', 'z'), - array('variable', '', '(y|Y)', 'y'), - array('variable', '', '[^/\.]+', 'x'), - array('variable', '/', '[^/\.]+', 'w'), - ),), + array('variable', '.', '[^/]++', '_format'), + array('variable', '', '[^/\.]++', 'z'), + array('variable', '', '(y|Y)', 'y'), + array('variable', '', '[^/\.]+', 'x'), + array('variable', '/', '[^/\.]+', 'w'), + ), + ), array( 'Route with a format', array('/foo/{bar}.{_format}'), '/foo', '#^/foo/(?P[^/\.]++)\.(?P<_format>[^/]++)$#s', array('bar', '_format'), array( - array('variable', '.', '[^/]++', '_format'), - array('variable', '/', '[^/\.]++', 'bar'), - array('text', '/foo'), - ),), + array('variable', '.', '[^/]++', '_format'), + array('variable', '/', '[^/\.]++', 'bar'), + array('text', '/foo'), + ), + ), ); } diff --git a/src/Symfony/Component/Security/Acl/Dbal/MutableAclProvider.php b/src/Symfony/Component/Security/Acl/Dbal/MutableAclProvider.php index 074c4a039d12f..3baaa9914ea41 100644 --- a/src/Symfony/Component/Security/Acl/Dbal/MutableAclProvider.php +++ b/src/Symfony/Component/Security/Acl/Dbal/MutableAclProvider.php @@ -856,7 +856,7 @@ private function updateOldFieldAceProperty($name, array $changes) */ private function updateNewAceProperty($name, array $changes) { - list($old, $new) = $changes; + list(, $new) = $changes; $sids = new \SplObjectStorage(); $classIds = new \SplObjectStorage(); diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php b/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php index d00ff1cfaefae..1032cb200d657 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php @@ -27,7 +27,7 @@ interface VoterInterface /** * Checks if the voter supports the given attribute. * - * @param string $attribute An attribute + * @param mixed $attribute An attribute (usually the attribute name string) * * @return bool true if this Voter supports the attribute, false otherwise */ diff --git a/src/Symfony/Component/Security/Core/User/UserInterface.php b/src/Symfony/Component/Security/Core/User/UserInterface.php index 1b52dab9965fe..747884282dcaa 100644 --- a/src/Symfony/Component/Security/Core/User/UserInterface.php +++ b/src/Symfony/Component/Security/Core/User/UserInterface.php @@ -47,7 +47,7 @@ interface UserInterface * and populated in any number of different ways when the user object * is created. * - * @return Role[] The user roles + * @return (Role|string)[] The user roles */ public function getRoles(); diff --git a/src/Symfony/Component/Security/Resources/translations/security.no.xlf b/src/Symfony/Component/Security/Resources/translations/security.no.xlf index 3369d43b77fd3..3635916971476 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.no.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.no.xlf @@ -4,7 +4,7 @@ An authentication exception occurred. - En autentiserings feil har skjedd. + En autentiseringsfeil har skjedd. Authentication credentials could not be found. @@ -24,7 +24,7 @@ Not privileged to request the resource. - Ingen tilgang til å be om gitt kilde. + Ingen tilgang til å be om gitt ressurs. Invalid CSRF token. diff --git a/src/Symfony/Component/Security/Tests/Core/Encoder/EncoderFactoryTest.php b/src/Symfony/Component/Security/Tests/Core/Encoder/EncoderFactoryTest.php index 85d4e91356dad..4fe60adcd1fc8 100644 --- a/src/Symfony/Component/Security/Tests/Core/Encoder/EncoderFactoryTest.php +++ b/src/Symfony/Component/Security/Tests/Core/Encoder/EncoderFactoryTest.php @@ -85,15 +85,19 @@ class SomeUser implements UserInterface public function getRoles() { } + public function getPassword() { } + public function getSalt() { } + public function getUsername() { } + public function eraseCredentials() { } diff --git a/src/Symfony/Component/Security/Tests/Core/SecurityContextTest.php b/src/Symfony/Component/Security/Tests/Core/SecurityContextTest.php index 66958892d3205..3fba8d958cc49 100644 --- a/src/Symfony/Component/Security/Tests/Core/SecurityContextTest.php +++ b/src/Symfony/Component/Security/Tests/Core/SecurityContextTest.php @@ -92,6 +92,6 @@ public function testGetSetToken() public function testTranslationsAreNotInCore() { - $this->assertFalse(file_exists(__DIR__.'/../../Core/Resources/translations/')); + $this->assertFileNotExists(__DIR__.'/../../Core/Resources/translations/'); } } diff --git a/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php b/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php index ad96243d47905..8316a8c69de5a 100644 --- a/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php +++ b/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php @@ -140,7 +140,7 @@ public function testOnCoreSecurity() public function testSessionStrategy() { - list($listener, $tokenStorage, $service, $manager) = $this->getListener(false, true, true); + list($listener, $tokenStorage, $service, $manager) = $this->getListener(); $tokenStorage ->expects($this->once()) diff --git a/src/Symfony/Component/Security/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php b/src/Symfony/Component/Security/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php index 61c3559abf470..3ba8f9906c271 100644 --- a/src/Symfony/Component/Security/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php +++ b/src/Symfony/Component/Security/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php @@ -24,6 +24,15 @@ class PersistentTokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase { + public static function setUpBeforeClass() + { + try { + random_bytes(1); + } catch (\Exception $e) { + throw new \PHPUnit_Framework_SkippedTestError($e->getMessage()); + } + } + public function testAutoLoginReturnsNullWhenNoCookie() { $service = $this->getService(null, array('name' => 'foo')); diff --git a/src/Symfony/Component/Security/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php b/src/Symfony/Component/Security/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php index b988c7dc0f4a9..d1ec9b248d905 100644 --- a/src/Symfony/Component/Security/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php +++ b/src/Symfony/Component/Security/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php @@ -172,9 +172,8 @@ public function testLoginFail() { $service = $this->getService(null, array('name' => 'foo', 'path' => '/foo', 'domain' => 'foodomain.foo')); $request = new Request(); - $response = new Response(); - $service->loginFail($request, $response); + $service->loginFail($request); $cookie = $request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME); $this->assertTrue($cookie->isCleared()); diff --git a/src/Symfony/Component/Security/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Security/Tests/Resources/TranslationFilesTest.php new file mode 100644 index 0000000000000..341ec87ea4105 --- /dev/null +++ b/src/Symfony/Component/Security/Tests/Resources/TranslationFilesTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Tests\Resources; + +class TranslationFilesTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideTranslationFiles + */ + public function testTranslationFileIsValid($filePath) + { + \PHPUnit_Util_XML::loadfile($filePath, false, false, true); + } + + public function provideTranslationFiles() + { + return array_map( + function ($filePath) { return (array) $filePath; }, + glob(dirname(dirname(__DIR__)).'/Resources/translations/*.xlf') + ); + } +} diff --git a/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php index 83c3c14384622..bc3d432de5a0e 100644 --- a/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php @@ -59,8 +59,10 @@ public function supportsNormalization($data, $format = null) */ public function supportsDenormalization($data, $type, $format = null) { - $class = new \ReflectionClass($type); + if (PHP_VERSION_ID < 50307) { + return class_exists($type) && in_array('Symfony\Component\Serializer\Normalizer\DenormalizableInterface', class_implements($type), true); + } - return $class->isSubclassOf('Symfony\Component\Serializer\Normalizer\DenormalizableInterface'); + return is_subclass_of($type, 'Symfony\Component\Serializer\Normalizer\DenormalizableInterface'); } } diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php index 1819def5f64ed..c3e07e821c023 100644 --- a/src/Symfony/Component/Serializer/Serializer.php +++ b/src/Symfony/Component/Serializer/Serializer.php @@ -237,7 +237,6 @@ private function normalizeObject($object, $format = null, array $context = array foreach ($this->normalizers as $normalizer) { if ($normalizer instanceof NormalizerInterface && $normalizer->supportsNormalization($object, $format)) { - return $normalizer->normalize($object, $format, $context); } } @@ -271,7 +270,6 @@ private function denormalizeObject($data, $class, $format = null, array $context foreach ($this->normalizers as $normalizer) { if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $class, $format)) { - return $normalizer->denormalize($data, $class, $format, $context); } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php index 1c5d699b5dca2..d870c82e0f867 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -208,7 +208,6 @@ public function provideCallbacks() array( array( 'bar' => function ($bar) { - return; }, ), 'baz', diff --git a/src/Symfony/Component/Translation/Dumper/PhpFileDumper.php b/src/Symfony/Component/Translation/Dumper/PhpFileDumper.php index b354c1245c993..60cc2ef65ea7b 100644 --- a/src/Symfony/Component/Translation/Dumper/PhpFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/PhpFileDumper.php @@ -25,9 +25,7 @@ class PhpFileDumper extends FileDumper */ protected function format(MessageCatalogue $messages, $domain) { - $output = "all($domain), true).";\n"; - - return $output; + return "all($domain), true).";\n"; } /** diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index 0952a4514fb16..50ca9cf75dfcf 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -239,6 +239,30 @@ public function testWhenAResourceHasNoRegisteredLoader() $translator->trans('foo'); } + public function testFallbackCatalogueResources() + { + $translator = new Translator('en_GB', new MessageSelector()); + $translator->addLoader('yml', new \Symfony\Component\Translation\Loader\YamlFileLoader()); + $translator->addResource('yml', __DIR__.'/fixtures/empty.yml', 'en_GB'); + $translator->addResource('yml', __DIR__.'/fixtures/resources.yml', 'en'); + + // force catalogue loading + $this->assertEquals('bar', $translator->trans('foo', array())); + + $cataloguesProperty = new \ReflectionProperty($translator, 'catalogues'); + $cataloguesProperty->setAccessible(true); + $catalogues = $cataloguesProperty->getValue($translator); + + $resources = $catalogues['en']->getResources(); + $this->assertCount(1, $resources); + $this->assertContains( __DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources); + + $resources = $catalogues['en_GB']->getResources(); + $this->assertCount(2, $resources); + $this->assertContains( __DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'empty.yml', $resources); + $this->assertContains( __DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources); + } + /** * @dataProvider getTransTests */ diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 96855e8fe08fb..07c3fc54e477a 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -255,6 +255,9 @@ private function loadFallbackCatalogues($locale) } $fallbackCatalogue = new MessageCatalogue($fallback, $this->catalogues[$fallback]->all()); + foreach ($this->catalogues[$fallback]->getResources() as $resource) { + $fallbackCatalogue->addResource($resource); + } $current->addFallbackCatalogue($fallbackCatalogue); $current = $fallbackCatalogue; } diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf deleted file mode 100644 index a8b790c7d8640..0000000000000 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - This value should be false. - Verdien skal være falsk. - - - This value should be true. - Verdien skal være sann. - - - This value should be of type {{ type }}. - Verdien skal være av typen {{ type }}. - - - This value should be blank. - Verdien skal være blank. - - - The value you selected is not a valid choice. - Verdien skal være en av de gitte valg. - - - You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Du skal velge minst {{ limit }} valg. - - - You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Du kan maks velge {{ limit }} valg. - - - One or more of the given values is invalid. - En eller flere av de oppgitte verdier er ugyldige. - - - This field was not expected. - Dette feltet ikke var forventet. - - - This field is missing. - Dette feltet mangler. - - - This value is not a valid date. - Verdien er ikke en gyldig dato. - - - This value is not a valid datetime. - Verdien er ikke en gyldig dato og tid. - - - This value is not a valid email address. - Verdien er ikke en gyldig e-mail adresse. - - - The file could not be found. - Filen kunne ikke finnes. - - - The file is not readable. - Filen kan ikke leses. - - - The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. - Filen er for stor ({{ size }} {{ suffix }}). Tilatte maksimale størrelse {{ limit }} {{ suffix }}. - - - The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - Mimetypen av filen er ugyldig ({{ type }}). Tilatte mimetyper er {{ types }}. - - - This value should be {{ limit }} or less. - Verdien skal være {{ limit }} eller mindre. - - - This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Verdien er for lang. Den skal ha {{ limit }} bokstaver eller mindre. - - - This value should be {{ limit }} or more. - Verdien skal være {{ limit }} eller mer. - - - This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Verdien er for kort. Den skal ha {{ limit }} tegn eller flere. - - - This value should not be blank. - Verdien må ikke være blank. - - - This value should not be null. - Verdien må ikke være tom (null). - - - This value should be null. - Verdien skal være tom (null). - - - This value is not valid. - Verdien er ikke gyldig. - - - This value is not a valid time. - Verdien er ikke en gyldig tid. - - - This value is not a valid URL. - Verdien er ikke en gyldig URL. - - - The two values should be equal. - De to verdier skal være ens. - - - The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. - Filen er for stor. Den maksimale størrelse er {{ limit }} {{ suffix }}. - - - The file is too large. - Filen er for stor. - - - The file could not be uploaded. - Filen kunne ikke lastes opp. - - - This value should be a valid number. - Denne verdi skal være et gyldig tall. - - - This file is not a valid image. - Denne filen er ikke et gyldig bilde. - - - This is not a valid IP address. - Dette er ikke en gyldig IP adresse. - - - This value is not a valid language. - Denne verdi er ikke et gyldig språk. - - - This value is not a valid locale. - Denne verdi er ikke en gyldig lokalitet. - - - This value is not a valid country. - Denne verdi er ikke et gyldig land. - - - - diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf new file mode 100644 index 0000000000000..566b82e947aed --- /dev/null +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf @@ -0,0 +1,227 @@ + + + + + + This value should be false. + Verdien skulle ha vore tom/nei. + + + This value should be true. + Verdien skulla ha vore satt/ja. + + + This value should be of type {{ type }}. + Verdien må vere av typen {{ type }}. + + + This value should be blank. + Verdien skal vere blank. + + + The value you selected is not a valid choice. + Verdien du valgte er ikkje gyldig. + + + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. + Du må velge minst {{ limit }} valg. + + + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. + Du kan maksimalt gjere {{ limit }} valg. + + + One or more of the given values is invalid. + Ein eller fleire av dei opplyste verdiane er ugyldige. + + + This field was not expected. + Dette feltet var ikke forventet. + + + This field is missing. + Dette feltet mangler. + + + This value is not a valid date. + Verdien er ikkje ein gyldig dato. + + + This value is not a valid datetime. + Verdien er ikkje ein gyldig dato og tid. + + + This value is not a valid email address. + Verdien er ikkje ei gyldig e-postadresse. + + + The file could not be found. + Fila kunne ikkje finnes. + + + The file is not readable. + Fila kan ikkje lesast. + + + The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. + Fila er for stor ({{ size }} {{ suffix }}). Tillatt maksimal størrelse er {{ limit }} {{ suffix }}. + + + The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. + Mime-typen av fila er ugyldig ({{ type }}). Tillatte mime-typar er {{ types }}. + + + This value should be {{ limit }} or less. + Verdien må vere {{ limit }} eller mindre. + + + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. + Verdien er for lang. Den må vere {{ limit }} bokstavar eller mindre. + + + This value should be {{ limit }} or more. + Verdien må vere {{ limit }} eller meir. + + + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. + Verdien er for kort. Den må ha {{ limit }} teikn eller fleire. + + + This value should not be blank. + Verdien må ikkje vere blank. + + + This value should not be null. + Verdien må ikkje vere tom (null). + + + This value should be null. + Verdien må vere tom (null). + + + This value is not valid. + Verdien er ikkje gyldig. + + + This value is not a valid time. + Verdien er ikkje gyldig tidseining. + + + This value is not a valid URL. + Verdien er ikkje ein gyldig URL. + + + The two values should be equal. + Dei to verdiane må vere like. + + + The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. + Fila er for stor. Den maksimale storleik er {{ limit }} {{ suffix }}. + + + The file is too large. + Fila er for stor. + + + The file could not be uploaded. + Fila kunne ikkje bli lasta opp. + + + This value should be a valid number. + Verdien må vere eit gyldig tal. + + + This file is not a valid image. + Fila er ikkje eit gyldig bilete. + + + This is not a valid IP address. + Dette er ikkje ei gyldig IP-adresse. + + + This value is not a valid language. + Verdien er ikkje eit gyldig språk. + + + This value is not a valid locale. + Verdien er ikkje ein gyldig lokalitet (språk/region). + + + This value is not a valid country. + Verdien er ikkje eit gyldig land. + + + This value is already used. + Verdien er allereie i bruk. + + + The size of the image could not be detected. + Storleiken på biletet kunne ikkje oppdagast. + + + The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. + Biletbreidda er for stor, ({{ width }} pikslar). Tillatt maksimumsbreidde er {{ max_width }} pikslar. + + + The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. + Biletbreidda er for liten, ({{ width }} pikslar). Forventa minimumsbreidde er {{ min_width }} pikslar. + + + The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. + Bilethøgda er for stor, ({{ height }} pikslar). Tillatt maksimumshøgde er {{ max_height }} pikslar. + + + The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. + Billethøgda er for låg, ({{ height }} pikslar). Forventa minimumshøgde er {{ min_height }} pikslar. + + + This value should be the user current password. + Verdien må vere brukaren sitt noverande passord. + + + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. + Verdien må vere nøyaktig {{ limit }} teikn. + + + The file was only partially uploaded. + Fila vart kun delvis opplasta. + + + No file was uploaded. + Inga fil vart lasta opp. + + + No temporary folder was configured in php.ini. + Førebels mappe (tmp) er ikkje konfigurert i php.ini. + + + Cannot write temporary file to disk. + Kan ikkje skrive førebels fil til disk. + + + A PHP extension caused the upload to fail. + Ei PHP-udviding forårsaka feil under opplasting. + + + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. + Denne samlinga må innehalde {{ limit }} element eller meir.|Denne samlinga må innehalde {{ limit }} element eller meir. + + + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. + Denne samlinga må innehalde {{ limit }} element eller færre.|Denne samlinga må innehalde {{ limit }} element eller færre. + + + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. + Denne samlinga må innehalde nøyaktig {{ limit }} element.|Denne samlinga må innehalde nøyaktig {{ limit }} element. + + + Invalid card number. + Ugyldig kortnummer. + + + Unsupported card type or invalid card number. + Korttypen er ikkje støtta eller ugyldig kortnummer. + + + + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf index 566b82e947aed..5a9347652a911 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf @@ -4,23 +4,23 @@ This value should be false. - Verdien skulle ha vore tom/nei. + Verdien må være usann. This value should be true. - Verdien skulla ha vore satt/ja. + Verdien må være sann. This value should be of type {{ type }}. - Verdien må vere av typen {{ type }}. + Verdien må være av typen {{ type }}. This value should be blank. - Verdien skal vere blank. + Verdien må være blank. The value you selected is not a valid choice. - Verdien du valgte er ikkje gyldig. + Den valgte verdien er ikke gyldig. You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. @@ -28,11 +28,11 @@ You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Du kan maksimalt gjere {{ limit }} valg. + Du kan maks velge {{ limit }} valg. One or more of the given values is invalid. - Ein eller fleire av dei opplyste verdiane er ugyldige. + En eller flere av de oppgitte verdiene er ugyldige. This field was not expected. @@ -44,175 +44,175 @@ This value is not a valid date. - Verdien er ikkje ein gyldig dato. + Verdien er ikke en gyldig dato. This value is not a valid datetime. - Verdien er ikkje ein gyldig dato og tid. + Verdien er ikke en gyldig dato/tid. This value is not a valid email address. - Verdien er ikkje ei gyldig e-postadresse. + Verdien er ikke en gyldig e-postadresse. The file could not be found. - Fila kunne ikkje finnes. + Filen kunne ikke finnes. The file is not readable. - Fila kan ikkje lesast. + Filen er ikke lesbar. The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. - Fila er for stor ({{ size }} {{ suffix }}). Tillatt maksimal størrelse er {{ limit }} {{ suffix }}. + Filen er for stor ({{ size }} {{ suffix }}). Tilatte maksimale størrelse {{ limit }} {{ suffix }}. The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - Mime-typen av fila er ugyldig ({{ type }}). Tillatte mime-typar er {{ types }}. + Mimetypen av filen er ugyldig ({{ type }}). Tilatte mimetyper er {{ types }}. This value should be {{ limit }} or less. - Verdien må vere {{ limit }} eller mindre. + Verdien må være {{ limit }} tegn lang eller mindre. This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Verdien er for lang. Den må vere {{ limit }} bokstavar eller mindre. + Verdien er for lang. Den må ha {{ limit }} tegn eller mindre. This value should be {{ limit }} or more. - Verdien må vere {{ limit }} eller meir. + Verdien må være {{ limit }} eller mer. This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Verdien er for kort. Den må ha {{ limit }} teikn eller fleire. + Verdien er for kort. Den må ha {{ limit }} tegn eller flere. This value should not be blank. - Verdien må ikkje vere blank. + Verdien må ikke være blank. This value should not be null. - Verdien må ikkje vere tom (null). + Verdien må ikke være tom (null). This value should be null. - Verdien må vere tom (null). + Verdien må være tom (null). This value is not valid. - Verdien er ikkje gyldig. + Verdien er ikke gyldig. This value is not a valid time. - Verdien er ikkje gyldig tidseining. + Verdien er ikke en gyldig tid. This value is not a valid URL. - Verdien er ikkje ein gyldig URL. + Verdien er ikke en gyldig URL. The two values should be equal. - Dei to verdiane må vere like. + Verdiene må være identiske. The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. - Fila er for stor. Den maksimale storleik er {{ limit }} {{ suffix }}. + Filen er for stor. Den maksimale størrelsen er {{ limit }} {{ suffix }}. The file is too large. - Fila er for stor. + Filen er for stor. The file could not be uploaded. - Fila kunne ikkje bli lasta opp. + Filen kunne ikke lastes opp. This value should be a valid number. - Verdien må vere eit gyldig tal. + Verdien må være et gyldig tall. This file is not a valid image. - Fila er ikkje eit gyldig bilete. + Denne filen er ikke et gyldig bilde. This is not a valid IP address. - Dette er ikkje ei gyldig IP-adresse. + Dette er ikke en gyldig IP adresse. This value is not a valid language. - Verdien er ikkje eit gyldig språk. + Verdien er ikke et gyldig språk. This value is not a valid locale. - Verdien er ikkje ein gyldig lokalitet (språk/region). + Verdien er ikke en gyldig lokalitet. This value is not a valid country. - Verdien er ikkje eit gyldig land. + Verdien er ikke et gyldig navn på land. This value is already used. - Verdien er allereie i bruk. + Verdien er allerede brukt. The size of the image could not be detected. - Storleiken på biletet kunne ikkje oppdagast. + Bildestørrelsen kunne ikke oppdages. The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - Biletbreidda er for stor, ({{ width }} pikslar). Tillatt maksimumsbreidde er {{ max_width }} pikslar. + Bildebredden er for stor ({{ width }} piksler). Tillatt maksimumsbredde er {{ max_width }} piksler. The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - Biletbreidda er for liten, ({{ width }} pikslar). Forventa minimumsbreidde er {{ min_width }} pikslar. + Bildebredden er for liten ({{ width }} piksler). Forventet minimumsbredde er {{ min_width }} piksler. The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - Bilethøgda er for stor, ({{ height }} pikslar). Tillatt maksimumshøgde er {{ max_height }} pikslar. + Bildehøyden er for stor ({{ height }} piksler). Tillatt maksimumshøyde er {{ max_height }} piksler. The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - Billethøgda er for låg, ({{ height }} pikslar). Forventa minimumshøgde er {{ min_height }} pikslar. + Bildehøyden er for liten ({{ height }} piksler). Forventet minimumshøyde er {{ min_height }} piksler. - This value should be the user current password. - Verdien må vere brukaren sitt noverande passord. + This value should be the user's current password. + Verdien må være brukerens sitt nåværende passord. This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Verdien må vere nøyaktig {{ limit }} teikn. + Verdien må være nøyaktig {{ limit }} tegn. The file was only partially uploaded. - Fila vart kun delvis opplasta. + Filen var kun delvis opplastet. No file was uploaded. - Inga fil vart lasta opp. + Ingen fil var lastet opp. No temporary folder was configured in php.ini. - Førebels mappe (tmp) er ikkje konfigurert i php.ini. + Den midlertidige mappen (tmp) er ikke konfigurert i php.ini. Cannot write temporary file to disk. - Kan ikkje skrive førebels fil til disk. + Kan ikke skrive midlertidig fil til disk. A PHP extension caused the upload to fail. - Ei PHP-udviding forårsaka feil under opplasting. + En PHP-utvidelse forårsaket en feil under opplasting. This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Denne samlinga må innehalde {{ limit }} element eller meir.|Denne samlinga må innehalde {{ limit }} element eller meir. + Denne samlingen må inneholde {{ limit }} element eller flere.|Denne samlingen må inneholde {{ limit }} elementer eller flere. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Denne samlinga må innehalde {{ limit }} element eller færre.|Denne samlinga må innehalde {{ limit }} element eller færre. + Denne samlingen må inneholde {{ limit }} element eller færre.|Denne samlingen må inneholde {{ limit }} elementer eller færre. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Denne samlinga må innehalde nøyaktig {{ limit }} element.|Denne samlinga må innehalde nøyaktig {{ limit }} element. + Denne samlingen må inneholde nøyaktig {{ limit }} element.|Denne samlingen må inneholde nøyaktig {{ limit }} elementer. Invalid card number. @@ -220,7 +220,99 @@ Unsupported card type or invalid card number. - Korttypen er ikkje støtta eller ugyldig kortnummer. + Korttypen er ikke støttet eller ugyldig kortnummer. + + + This is not a valid International Bank Account Number (IBAN). + Dette er ikke en gyldig IBAN. + + + This value is not a valid ISBN-10. + Verdien er ikke en gyldig ISBN-10. + + + This value is not a valid ISBN-13. + Verdien er ikke en gyldig ISBN-13. + + + This value is neither a valid ISBN-10 nor a valid ISBN-13. + Verdien er hverken en gyldig ISBN-10 eller ISBN-13. + + + This value is not a valid ISSN. + Verdien er ikke en gyldig ISSN. + + + This value is not a valid currency. + Verdien er ikke gyldig valuta. + + + This value should be equal to {{ compared_value }}. + Verdien må være lik {{ compared_value }}. + + + This value should be greater than {{ compared_value }}. + Verdien må være større enn {{ compared_value }}. + + + This value should be greater than or equal to {{ compared_value }}. + Verdien må være større enn eller lik {{ compared_value }}. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Verdien må være identisk med {{ compared_value_type }} {{ compared_value }}. + + + This value should be less than {{ compared_value }}. + Verdien må være mindre enn {{ compared_value }}. + + + This value should be less than or equal to {{ compared_value }}. + Verdien må være mindre enn eller lik {{ compared_value }}. + + + This value should not be equal to {{ compared_value }}. + Verdien må ikke være lik {{ compared_value }}. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Verdien må ikke være identisk med {{ compared_value_type }} {{ compared_value }}. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Bildeforholdet er for stort ({{ ratio }}). Tillatt maksimumsbildeforhold er {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Bildeforholdet er for lite ({{ ratio }}). Forventet maksimumsbildeforhold er {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Bildet er en kvadrat ({{ width }}x{{ height }}px). Kvadratiske bilder er ikke tillatt. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Bildet er i liggende retning ({{ width }}x{{ height }}px). Bilder i liggende retning er ikke tillatt. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Bildet er i stående retning ({{ width }}x{{ height }}px). Bilder i stående retning er ikke tillatt. + + + An empty file is not allowed. + Tomme filer er ikke tilatt. + + + The host could not be resolved. + Vertsnavn kunne ikke løses. + + + This value does not match the expected {{ charset }} charset. + Verdien samsvarer ikke med forventet tegnsett {{ charset }}. + + + This is not a valid Business Identifier Code (BIC). + Dette er ikke en gyldig BIC. diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php index 11418ac707dcd..93cd84d4b180e 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php @@ -92,7 +92,6 @@ public function getValidNumbers() array('MAESTRO', '5020507657408074712'), array('MAESTRO', '5612559223580173965'), array('MAESTRO', '6759744069209'), - array('MAESTRO', '6759744069209'), array('MAESTRO', '6594371785970435599'), array('MASTERCARD', '5555555555554444'), array('MASTERCARD', '5105105105105100'), diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Loader/AnnotationLoaderTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Loader/AnnotationLoaderTest.php index 731ab835619f3..89fe9be80f478 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/Loader/AnnotationLoaderTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/Loader/AnnotationLoaderTest.php @@ -87,6 +87,7 @@ public function testLoadParentClassMetadata() $this->assertEquals($expected_parent, $parent_metadata); } + /** * Test MetaData merge with parent annotation. */ diff --git a/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php new file mode 100644 index 0000000000000..8a766611cd4f9 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Resources; + +class TranslationFilesTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideTranslationFiles + */ + public function testTranslationFileIsValid($filePath) + { + \PHPUnit_Util_XML::loadfile($filePath, false, false, true); + } + + public function provideTranslationFiles() + { + return array_map( + function ($filePath) { return (array) $filePath; }, + glob(dirname(dirname(__DIR__)).'/Resources/translations/*.xlf') + ); + } +} diff --git a/src/Symfony/Component/Yaml/Escaper.php b/src/Symfony/Component/Yaml/Escaper.php index ac325a2c2f259..cb676d0059c78 100644 --- a/src/Symfony/Component/Yaml/Escaper.php +++ b/src/Symfony/Component/Yaml/Escaper.php @@ -31,13 +31,13 @@ class Escaper "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f", - "\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9",); + "\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9"); private static $escaped = array('\\\\', '\\"', '\\\\', '\\"', '\\0', '\\x01', '\\x02', '\\x03', '\\x04', '\\x05', '\\x06', '\\a', '\\b', '\\t', '\\n', '\\v', '\\f', '\\r', '\\x0e', '\\x0f', '\\x10', '\\x11', '\\x12', '\\x13', '\\x14', '\\x15', '\\x16', '\\x17', '\\x18', '\\x19', '\\x1a', '\\e', '\\x1c', '\\x1d', '\\x1e', '\\x1f', - '\\N', '\\_', '\\L', '\\P',); + '\\N', '\\_', '\\L', '\\P'); /** * Determines if a PHP value would require double quoting in YAML. diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index ca419e0565088..5f15e3c5b4a9b 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -102,7 +102,7 @@ public static function dump($value, $exceptionOnInvalidType = false, $objectSupp return 'null'; case is_object($value): if ($objectSupport) { - return '!!php/object:'.serialize($value); + return '!php/object:'.serialize($value); } if ($exceptionOnInvalidType) { @@ -434,6 +434,16 @@ private static function evaluateScalar($scalar, $references = array()) return (string) substr($scalar, 5); case 0 === strpos($scalar, '! '): return (int) self::parseScalar(substr($scalar, 2)); + case 0 === strpos($scalar, '!php/object:'): + if (self::$objectSupport) { + return unserialize(substr($scalar, 12)); + } + + if (self::$exceptionOnInvalidType) { + throw new ParseException('Object support when parsing a YAML file has been disabled.'); + } + + return; case 0 === strpos($scalar, '!!php/object:'): if (self::$objectSupport) { return unserialize(substr($scalar, 13)); @@ -465,7 +475,12 @@ private static function evaluateScalar($scalar, $references = array()) case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar): return (float) str_replace(',', '', $scalar); case preg_match(self::getTimestampRegex(), $scalar): - return strtotime($scalar); + $timeZone = date_default_timezone_get(); + date_default_timezone_set('UTC'); + $time = strtotime($scalar); + date_default_timezone_set($timeZone); + + return $time; } default: return (string) $scalar; diff --git a/src/Symfony/Component/Yaml/Tests/DumperTest.php b/src/Symfony/Component/Yaml/Tests/DumperTest.php index 1d81a287ae956..b1c44c44befce 100644 --- a/src/Symfony/Component/Yaml/Tests/DumperTest.php +++ b/src/Symfony/Component/Yaml/Tests/DumperTest.php @@ -181,7 +181,7 @@ public function testObjectSupportEnabled() { $dump = $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, false, true); - $this->assertEquals('{ foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\A":1:{s:1:"a";s:3:"foo";}, bar: 1 }', $dump, '->dump() is able to dump objects'); + $this->assertEquals('{ foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\A":1:{s:1:"a";s:3:"foo";}, bar: 1 }', $dump, '->dump() is able to dump objects'); } public function testObjectSupportDisabledButNoExceptions() diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml index a06df7fb316fa..cbbb257a027e8 100644 --- a/src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml @@ -752,7 +752,7 @@ yaml: | Billsmer @ 338-4338. php: | array( - 'invoice' => 34843, 'date' => mktime(0, 0, 0, 1, 23, 2001), + 'invoice' => 34843, 'date' => gmmktime(0, 0, 0, 1, 23, 2001), 'bill-to' => array( 'given' => 'Chris', 'family' => 'Dumars', 'address' => array( 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak', 'state' => 'MI', 'postal' => 48046 ) ) , 'ship-to' => @@ -877,7 +877,7 @@ yaml: | php: | array( 'invoice' => 34843, - 'date' => mktime(0, 0, 0, 1, 23, 2001), + 'date' => gmmktime(0, 0, 0, 1, 23, 2001), 'total' => 4443.52 ) --- diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index dbb12f2834133..255928d16d2cd 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -202,7 +202,7 @@ protected function getTestsForParse() "'on'" => 'on', "'off'" => 'off', - '2007-10-30' => mktime(0, 0, 0, 10, 30, 2007), + '2007-10-30' => gmmktime(0, 0, 0, 10, 30, 2007), '2007-10-30T02:59:43Z' => gmmktime(2, 59, 43, 10, 30, 2007), '2007-10-30 02:59:43 Z' => gmmktime(2, 59, 43, 10, 30, 2007), '1960-10-30 02:59:43 Z' => gmmktime(2, 59, 43, 10, 30, 1960), @@ -255,7 +255,6 @@ protected function getTestsForDump() '12.30e+02' => 12.30e+02, '1234' => 0x4D2, '1243' => 02333, - '.Inf' => -log(0), '-.Inf' => log(0), "'686e444'" => '686e444', '.Inf' => 646e444, diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 9d6d42befe94c..34cc81b2d353a 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -426,24 +426,46 @@ public function testObjectSupportEnabled() bar: 1 EOF; $this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects'); - } - public function testObjectSupportDisabledButNoExceptions() - { $input = <<assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects'); + } + /** + * @dataProvider invalidDumpedObjectProvider + */ + public function testObjectSupportDisabledButNoExceptions($input) + { $this->assertEquals(array('foo' => null, 'bar' => 1), $this->parser->parse($input), '->parse() does not parse objects'); } /** + * @dataProvider invalidDumpedObjectProvider * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ - public function testObjectsSupportDisabledWithExceptions() + public function testObjectsSupportDisabledWithExceptions($yaml) + { + $this->parser->parse($yaml, true, false); + } + + public function invalidDumpedObjectProvider() { - $this->parser->parse('foo: !!php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";}', true, false); + $yamlTag = << array($yamlTag), + 'local-tag' => array($localTag), + ); } /** diff --git a/src/Symfony/Component/Yaml/Yaml.php b/src/Symfony/Component/Yaml/Yaml.php index cce18a657aa07..2e14a6c08352d 100644 --- a/src/Symfony/Component/Yaml/Yaml.php +++ b/src/Symfony/Component/Yaml/Yaml.php @@ -21,10 +21,7 @@ class Yaml { /** - * Parses YAML into a PHP array. - * - * The parse method, when supplied with a YAML stream (string or file), - * will do its best to convert YAML in a file into a PHP array. + * Parses YAML into a PHP value. * * Usage: * @@ -40,7 +37,7 @@ class Yaml * @param bool $exceptionOnInvalidType True if an exception must be thrown on invalid types false otherwise * @param bool $objectSupport True if object support is enabled, false otherwise * - * @return array The YAML converted to a PHP array + * @return mixed The YAML converted to a PHP value * * @throws ParseException If the YAML is not valid */