diff --git a/.travis.yml b/.travis.yml
index 18d4646a95664..ef1ef5c7987f4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,9 +7,9 @@ addons:
- parallel
- language-pack-fr-base
-cache:
- directories:
- - .phpunit
+env:
+ global:
+ - MIN_PHP=5.3.9
matrix:
include:
@@ -19,43 +19,48 @@ matrix:
- php: 5.5
- php: 5.6
env: deps=high
- - php: 7
+ - php: 7.0
env: deps=low
fast_finish: true
-services: mongodb
+cache:
+ directories:
+ - .phpunit
+ - php-$MIN_PHP
-env:
- global:
- - deps=no
- - SYMFONY_DEPRECATIONS_HELPER=weak
+services: mongodb
before_install:
- - if [[ "$deps" = "no" ]] && [[ "$TRAVIS_PHP_VERSION" =~ 5.[45] ]] && [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then export deps=skip; 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 [ "$deps" != "skip" ]; then composer self-update; fi;
- - if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then phpenv config-rm xdebug.ini; fi;
- - 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.7 && 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.* ]] && [ "$deps" = "no" ]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo "extension = $(pwd)/modules/symfony_debug.so" >> $INI_FILE); fi;
- - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi;
- - if [ "$deps" != "skip" ]; then ./phpunit install; fi;
- - export PHPUNIT="$(readlink -f ./phpunit)"
+ - if [[ ! $deps && ! $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && $TRAVIS_PHP_VERSION != hhvm && $TRAVIS_PULL_REQUEST != false ]]; then deps=skip; fi;
+ - if [[ ! $deps && ! -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.* && ! $deps ]]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo extension = $(pwd)/modules/symfony_debug.so >> $INI_FILE); 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 [[ $deps != skip ]]; then composer self-update; fi;
+ - if [[ $deps != skip ]]; then ./phpunit install; fi;
+ - export PHPUNIT=$(readlink -f ./phpunit)
install:
- - if [ "$TRAVIS_BRANCH" = "master" ]; then export COMPOSER_ROOT_VERSION=dev-master; else export COMPOSER_ROOT_VERSION="$TRAVIS_BRANCH".x-dev; fi;
- - if [ "$deps" = "no" ]; then export SYMFONY_DEPRECATIONS_HELPER=strict; fi;
- - if [ "$deps" = "no" ]; then composer --prefer-source install; fi;
- - if [ "$deps" != "skip" ]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi;
- - if [ "$deps" != "skip" ] && [ "$deps" != "no" ]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $COMPONENTS; fi;
+ - if [[ $deps != skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi;
+ - if [[ $deps != skip && $deps ]]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $COMPONENTS; fi;
+ - 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 && ${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 --prefer-source install; else export SYMFONY_DEPRECATIONS_HELPER=weak; fi;
+ - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi;
script:
- - if [ "$deps" = "no" ]; then echo "$COMPONENTS" | parallel --gnu '$PHPUNIT --exclude-group tty,benchmark,intl-data {}'; fi;
- - if [ "$deps" = "no" ]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty; fi;
- - if [ "$deps" = "high" ]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer --prefer-source update; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi;
- - if [ "$deps" = "low" ]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer --prefer-source --prefer-lowest --prefer-stable update; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi;
- - if [ "$deps" = "skip" ]; then echo 'This matrix line is skipped for pull requests.'; fi;
+ - if [[ ! $deps ]]; then echo "$COMPONENTS" | parallel --gnu '$PHPUNIT --exclude-group tty,benchmark,intl-data {}'; fi;
+ - if [[ ! $deps ]]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty; fi;
+ - if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} ]]; then echo -e "1\\n0" | parallel --gnu 'echo -e "\\nPHP --enable-sigchild enhanced={}" && ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/'; fi;
+ - if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer --prefer-source update; $PHPUNIT --exclude-group tty,benchmark,intl-data'$LEGACY; fi;
+ - if [[ $deps = low ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer --prefer-source --prefer-lowest --prefer-stable update; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi;
+ - if [[ $deps = skip ]]; then echo This matrix line is skipped for pull requests.; fi;
diff --git a/CHANGELOG-2.3.md b/CHANGELOG-2.3.md
index 9c9d593aa08c7..4974aa08b3a2c 100644
--- a/CHANGELOG-2.3.md
+++ b/CHANGELOG-2.3.md
@@ -7,6 +7,25 @@ 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.35 (2015-11-23)
+
+ * security #16631 CVE-2015-8124: Session Fixation in the "Remember Me" Login Feature (xabbuh)
+ * security #16630 CVE-2015-8125: Potential Remote Timing Attack Vulnerability in Security Remember-Me Service (xabbuh)
+ * bug #16588 Sent out a status text for unknown HTTP headers. (dawehner)
+ * bug #16295 [DependencyInjection] Unescape parameters for all types of injection (Nicofuma)
+ * bug #16574 [Process] Fix PhpProcess with phpdbg runtime (nicolas-grekas)
+ * bug #16352 Fix the server variables in the router_*.php files (leofeyer)
+ * bug #16537 [Validator] Allow an empty path with a non empty fragment or a query (jakzal)
+ * bug #16528 [Translation] Add support for Armenian pluralization. (marcosdsanchez)
+ * bug #16510 [Process] fix Proccess run with pts enabled (ewgRa)
+ * bug #16292 fix race condition at mkdir (#16258) (ewgRa)
+ * bug #16462 [PropertyAccess] Fix dynamic property accessing. (dunglas)
+ * bug #16294 [PropertyAccess] Major performance improvement (dunglas)
+ * bug #16331 fixed Twig deprecation notices (fabpot)
+ * bug #16306 [DoctrineBridge] Fix issue which prevent the profiler to explain a query (Baachi)
+ * bug #16359 Use mb_detect_encoding with $strict = true (nicolas-grekas)
+ * bug #16144 [Security] don't allow to install the split Security packages (xabbuh)
+
* 2.3.34 (2015-10-27)
* bug #16288 [Process] Inherit env vars by default in PhpProcess (nicolas-grekas)
diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md
index 19e9036c82bb2..0055a236352aa 100644
--- a/CHANGELOG-2.7.md
+++ b/CHANGELOG-2.7.md
@@ -7,6 +7,50 @@ in 2.7 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.7.0...v2.7.1
+* 2.7.8 (2015-12-26)
+
+ * bug #16864 [Yaml] fix indented line handling in folded blocks (xabbuh)
+ * bug #17052 Fixed flatten exception recursion with errors (GrahamCampbell)
+ * bug #16826 Embedded identifier support (mihai-stancu)
+ * bug #17079 Also transform inline mappings to objects (WouterJ)
+ * 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 #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)
+ * bug #16860 [Yaml] do not remove "comments" in scalar blocks (xabbuh)
+ * bug #17002 [Console][Table] fixed render row that contains multiple cells. (aitboudad)
+ * bug #16971 [HttpFoundation] Added the ability of using BinaryFileResponse with stream wrappers (jakzal, Sander-Toonen)
+ * bug #17048 Fix the logout path when not using the router (stof)
+ * bug #17049 Fix the logout path when not using the router (stof)
+ * bug #17057 [FrameworkBundle][HttpKernel] the finder is required to discover bundle commands (xabbuh)
+ * bug #17006 [Form] Fix casting regression in DoctrineChoiceLoader (bendavies)
+ * bug #16915 [Process] Enhance compatiblity with --enable-sigchild (nicolas-grekas)
+ * bug #16829 [FrameworkBundle] prevent cache:clear creating too long paths (Tobion)
+ * bug #16921 Fix short array syntax for php 5.3 (ewgRa)
+ * bug #16450 [Serializer] Fixed `array_unique` on array of objects in `getAllowedAttributes`. (CornyPhoenix)
+ * bug #16757 [FrameworkBundle] [Translation] Fixed translations not written when no translations directory in update command (jeremyFreeAgent)
+ * bug #16871 [FrameworkBundle] Disable built-in server commands when Process component is missing (gnugat, xabbuh)
+ * bug #16870 [FrameworkBundle] Disable the server:run command when Process component is missing (gnugat, xabbuh)
+ * bug #16742 [Console][ProgressBar] redrawFrequency should never be 0 (dritter)
+ * bug #16799 Improve error message for undefined DIC aliases (mpdude)
+ * bug #16825 [VarDumper] fix .sf-dump z-index (debug bar conflict) (Antoine LA)
+ * bug #16772 Refactoring EntityUserProvider::__construct() to not do work, cause cache warm error (weaverryan)
+ * bug #16753 [Process] Fix signaling/stopping logic on Windows (nicolas-grekas)
+ * bug #16733 [Console] do not encode backslashes in console default description (Tobion)
+ * bug #16312 [HttpKernel] clearstatcache() so the Cache sees when a .lck file has been released (mpdude)
+ * bug #16351 [WIP] [Form] [TwigBridge] Bootstrap horizontal theme missing tests (pieter2627)
+ * bug #16685 [Form] Fixed: Duplicate choice labels are remembered when using "choices_as_values" = false (webmozart)
+ * bug #16705 [Form] Deprecated setting "choices_as_values" to "false" (webmozart)
+ * bug #16695 [SecurityBundle] disable the init:acl command if ACL is not used (Tobion)
+ * bug #16679 [Form] Disabled view data validation if "data_class" is set to null (webmozart)
+ * bug #16676 [HttpFoundation] Workaround HHVM rewriting HTTP response line (nicolas-grekas)
+ * bug #16668 [ClassLoader] Fix parsing namespace when token_get_all() is missing (nicolas-grekas)
+ * bug #16386 Bug #16343 [Router] Too many Routes ? (jelte)
+ * bug #16651 [Debug] Ensure class declarations are loaded only once (nicolas-grekas)
+
* 2.7.7 (2015-11-23)
* security #16631 CVE-2015-8124: Session Fixation in the "Remember Me" Login Feature (xabbuh)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index b78fd1ff5ee94..9b30d35c1a0ae 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -51,19 +51,19 @@ Symfony is the result of the work of many people who made the code better
- Florin Patan (florinpatan)
- Eric Clemmons (ericclemmons)
- Andrej Hudec (pulzarraider)
- - Deni
- Maxime Steinhausser (ogizanagi)
+ - Deni
- Henrik Westphal (snc)
- Dariusz Górecki (canni)
- Gábor Egyed (1ed)
- Christian Raue
- Arnout Boks (aboks)
- - Michel Weimerskirch (mweimerskirch)
- Kevin Bond (kbond)
+ - Michel Weimerskirch (mweimerskirch)
+ - Douglas Greenshields (shieldo)
- Lee McDermott
- Brandon Turner
- Luis Cordova (cordoval)
- - Douglas Greenshields (shieldo)
- Daniel Holmes (dholmes)
- Bart van den Burg (burgov)
- Jordan Alliot (jalliot)
@@ -85,15 +85,17 @@ Symfony is the result of the work of many people who made the code better
- Adrien Brault (adrienbrault)
- excelwebzone
- Jacob Dreesen (jdreesen)
+ - Michal Piotrowski (eventhorizon)
+ - Peter Kokot (maastermedia)
- Fabien Pennequin (fabienpennequin)
- Peter Rehm (rpet)
- - Peter Kokot (maastermedia)
+ - Pierre du Plessis (pierredup)
- Alexander Schwenn (xelaris)
- Gordon Franke (gimler)
- Robert Schönthal (digitalkaoz)
- Jérémy DERUSSÉ (jderusse)
- Dariusz Ruminski
- - Michal Piotrowski (eventhorizon)
+ - Joshua Thijssen
- Stefano Sala (stefano.sala)
- David Buchmann (dbu)
- Issei Murasawa (issei_m)
@@ -103,7 +105,6 @@ Symfony is the result of the work of many people who made the code better
- Sebastian Hörl (blogsh)
- Daniel Gomes (danielcsgomes)
- Hidenori Goto (hidenorigoto)
- - Joshua Thijssen
- Guilherme Blanco (guilhermeblanco)
- Pablo Godel (pgodel)
- Vladimir Reznichenko (kalessil)
@@ -116,6 +117,7 @@ Symfony is the result of the work of many people who made the code better
- Clemens Tolboom
- Helmer Aaviksoo
- Baptiste Clavié (talus)
+ - Tugdual Saunier (tucksaun)
- Hiromi Hishida (77web)
- Matthieu Ouellette-Vachon (maoueh)
- Michał Pipa (michal.pipa)
@@ -124,8 +126,7 @@ Symfony is the result of the work of many people who made the code better
- Artur Kotyrba
- Rouven Weßling (realityking)
- Charles Sarrazin (csarrazi)
- - Pierre du Plessis (pierredup)
- - Tugdual Saunier (tucksaun)
+ - Warnar Boekkooi (boekkooi)
- Andréia Bohner (andreia)
- Dmitrii Chekaliuk (lazyhammer)
- Clément JOBEILI (dator)
@@ -159,15 +160,17 @@ Symfony is the result of the work of many people who made the code better
- Justin Hileman (bobthecow)
- Michele Orselli (orso)
- Sven Paulus (subsven)
- - Warnar Boekkooi (boekkooi)
- Lars Strojny (lstrojny)
+ - Daniel Wehner
- Rui Marinho (ruimarinho)
+ - Evgeniy (ewgraf)
- Julien Brochet (mewt)
- Sergey Linnik (linniksa)
- Jáchym Toušek
- Marcel Beerta (mazen)
- Vincent AUBERT (vincent)
- julien pauli (jpauli)
+ - Florian Lonqueu-Brochard (florianlb)
- Francois Zaninotto
- Alexander Kotynia (olden)
- Daniel Tschinder
@@ -185,6 +188,7 @@ Symfony is the result of the work of many people who made the code better
- Eugene Leonovich (rybakit)
- Joseph Rouff (rouffj)
- Félix Labrecque (woodspire)
+ - Tomáš Votruba (tomas_votruba)
- GordonsLondon
- Jan Sorgalla (jsor)
- Ray
@@ -201,17 +205,19 @@ Symfony is the result of the work of many people who made the code better
- Beau Simensen (simensen)
- Robert Kiss (kepten)
- Ruben Gonzalez (rubenrua)
+ - Marcos Sánchez
- Kim Hemsø Rasmussen (kimhemsoe)
- Diego Saint Esteben (dosten)
- - Florian Lonqueu-Brochard (florianlb)
- 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
@@ -245,7 +251,7 @@ Symfony is the result of the work of many people who made the code better
- Giorgio Premi
- Erin Millard
- Matthew Lewinski (lewinski)
- - Marcos Sánchez
+ - Antonio J. García Lagar (ajgarlag)
- alquerci
- Francesco Levorato
- Vitaliy Zakharov (zakharovvi)
@@ -255,14 +261,11 @@ 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)
- - Daniel Wehner
- Felix Labrecque
- Yaroslav Kiliba
- Stepan Anchugov (kix)
- Terje Bråten
- - Evgeniy (ewgraf)
- Robbert Klarenbeek (robbertkl)
- - Blanchon Vincent (blanchonvincent)
- hossein zolfi (ocean)
- Clément Gautier (clementgautier)
- Eduardo Gulias (egulias)
@@ -285,6 +288,7 @@ Symfony is the result of the work of many people who made the code better
- Shein Alexey
- Joe Lencioni
- Daniel Tschinder
+ - Diego Agulló (aeoris)
- Kai
- Lee Rowlands
- Maximilian Reichel (phramz)
@@ -313,8 +317,9 @@ Symfony is the result of the work of many people who made the code better
- Thomas Lallement (raziel057)
- Jan Schumann
- Niklas Fiekas
+ - Mark Challoner (markchalloner)
+ - Markus Bachmann (baachi)
- lancergr
- - Antonio J. García Lagar (ajgarlag)
- Olivier Dolbeau (odolbeau)
- Roumen Damianoff (roumen)
- vagrant
@@ -365,9 +370,10 @@ Symfony is the result of the work of many people who made the code better
- Daniel Beyer
- Andrew Udvare (audvare)
- alexpods
- - Richard van Laak (rvanlaak)
+ - Tristan Darricau (nicofuma)
- Erik Trapman (eriktrapman)
- De Cock Xavier (xdecock)
+ - Possum
- Scott Arciszewski
- Norbert Orzechowicz (norzechowicz)
- Matthijs van den Bos (matthijs)
@@ -381,6 +387,7 @@ Symfony is the result of the work of many people who made the code better
- Dawid Pakuła (zulusx)
- Florian Rey (nervo)
- Rodrigo Borrego Bernabé (rodrigobb)
+ - Leo Feyer
- MatTheCat
- John Bafford (jbafford)
- Denis Gorbachev (starfall)
@@ -410,7 +417,6 @@ Symfony is the result of the work of many people who made the code better
- Christopher Davis (chrisguitarguy)
- alcaeus
- vitaliytv
- - Markus Bachmann (baachi)
- Sebastian Blum
- aubx
- Ricky Su (ricky)
@@ -475,6 +481,7 @@ 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
@@ -496,7 +503,6 @@ Symfony is the result of the work of many people who made the code better
- avorobiev
- Venu
- Lars Vierbergen
- - Mark Challoner
- Dennis Hotson
- Andrew Tchircoff (andrewtch)
- michaelwilliams
@@ -534,7 +540,6 @@ Symfony is the result of the work of many people who made the code better
- Rafał Wrzeszcz (rafalwrzeszcz)
- Reen Lokum
- Martin Parsiegla (spea)
- - Possum
- Denis Charrier (brucewouaigne)
- Quentin Schuler
- Pierre Vanliefland (pvanliefland)
@@ -558,12 +563,10 @@ Symfony is the result of the work of many people who made the code better
- Patrick Allaert
- Gustavo Falco (gfalco)
- Matt Robinson (inanimatt)
- - Tristan Darricau (nicofuma)
- Aleksey Podskrebyshev
- Steffen Roßkamp
- David Marín Carreño (davefx)
- Jörn Lang (j.lang)
- - Leo Feyer
- mwsaz
- Benoît Bourgeois
- corphi
@@ -589,7 +592,6 @@ Symfony is the result of the work of many people who made the code better
- Balazs Csaba (balazscsaba2006)
- Harry Walter (haswalt)
- Johnson Page (jwpage)
- - Tomáš Votruba (tomas_votruba)
- Michael Roterman (wtfzdotnet)
- Arno Geurts
- Adán Lobato (adanlobato)
@@ -638,6 +640,7 @@ Symfony is the result of the work of many people who made the code better
- Jérôme Vasseur
- Sander Coolen (scoolen)
- Nicolas Le Goff (nlegoff)
+ - Anne-Sophie Bachelard (annesophie)
- Manuele Menozzi
- Anton Babenko (antonbabenko)
- Irmantas Šiupšinskas (irmantas)
@@ -921,7 +924,6 @@ Symfony is the result of the work of many people who made the code better
- Shane Preece (shane)
- wusuopu
- povilas
- - Diego Agulló
- Alessandro Tagliapietra (alex88)
- Biji (biji)
- Gunnar Lium (gunnarlium)
@@ -1082,7 +1084,6 @@ Symfony is the result of the work of many people who made the code better
- grifx
- Robert Campbell
- Matt Lehner
- - Hidde Wieringa
- Hein Zaw Htet™
- Ruben Kruiswijk
- Michael J
@@ -1106,7 +1107,6 @@ Symfony is the result of the work of many people who made the code better
- Alan Chen
- Maerlyn
- Even André Fiskvik
- - Diego Agulló
- Dane Powell
- Gerrit Drost
- Lenar Lõhmus
@@ -1219,6 +1219,7 @@ Symfony is the result of the work of many people who made the code better
- Sam Williams
- Adrian Philipp
- James Michael DuPont
+ - Eugene Wissner
- Kasperki
- Tammy D
- Ondrej Slinták
@@ -1276,6 +1277,7 @@ 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)
diff --git a/appveyor.yml b/appveyor.yml
index ce46c6ffb6f82..8ff51be4edd11 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -26,8 +26,8 @@ install:
- IF %PHP%==1 cd ext
- IF %PHP%==1 appveyor DownloadFile http://nebm.ist.utl.pt/~glopes/misc/intl_win/php_intl-3.0.0-5.3-nts-vc9-x86.zip
- IF %PHP%==1 7z x php_intl-3.0.0-5.3-nts-vc9-x86.zip -y >nul
- - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/apcu/4.0.7/php_apcu-4.0.7-5.3-nts-vc9-x86.zip
- - IF %PHP%==1 7z x php_apcu-4.0.7-5.3-nts-vc9-x86.zip -y >nul
+ - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/apcu/4.0.10/php_apcu-4.0.10-5.3-nts-vc9-x86.zip
+ - IF %PHP%==1 7z x php_apcu-4.0.10-5.3-nts-vc9-x86.zip -y >nul
- IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/memcache/3.0.8/php_memcache-3.0.8-5.3-nts-vc9-x86.zip
- IF %PHP%==1 7z x php_memcache-3.0.8-5.3-nts-vc9-x86.zip -y >nul
- IF %PHP%==1 del /Q *.zip
@@ -55,9 +55,10 @@ 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=1
+ - php phpunit symfony --exclude-group benchmark,intl-data || SET X=!errorlevel!
- copy /Y c:\php\php.ini-max c:\php\php.ini
- - php phpunit symfony --exclude-group benchmark,intl-data || SET X=1
+ - php phpunit symfony --exclude-group benchmark,intl-data || SET X=!errorlevel!
- exit %X%
diff --git a/phpunit b/phpunit
index 2ab4f25e75cc2..146ab9d37610c 100755
--- a/phpunit
+++ b/phpunit
@@ -11,15 +11,15 @@
*/
// Please update when phpunit needs to be reinstalled with fresh deps:
-// Cache-Id-Version: 2015-11-18 14:14 UTC
+// Cache-Id-Version: 2015-11-28 09:05 UTC
use Symfony\Component\Process\ProcessUtils;
error_reporting(-1);
require __DIR__.'/src/Symfony/Component/Process/ProcessUtils.php';
-// PHPUnit 4.8 does not support PHP 7, while 5.0 requires PHP 5.6+
-$PHPUNIT_VERSION = PHP_VERSION_ID >= 70000 ? '5.0' : '4.8';
+// PHPUnit 4.8 does not support PHP 7, while 5.1 requires PHP 5.6+
+$PHPUNIT_VERSION = PHP_VERSION_ID >= 50600 ? '5.1' : '4.8';
$PHPUNIT_DIR = __DIR__.'/.phpunit';
$PHP = defined('PHP_BINARY') ? PHP_BINARY : 'php';
$PHP = ProcessUtils::escapeArgument($PHP);
@@ -64,10 +64,6 @@ Symfony\Bridge\PhpUnit\TextUI\Command::main();
EOPHP
);
chdir('..');
- if (file_exists('../src/Symfony/Bridge/PhpUnit') && `git diff --name-only HEAD^ -- ../src/Symfony/Bridge/PhpUnit`) {
- passthru(sprintf('\\' === DIRECTORY_SEPARATOR ? '(del /S /F /Q %s & rmdir %1$s) >nul': 'rm -rf %s', str_replace('/', DIRECTORY_SEPARATOR, "phpunit-$PHPUNIT_VERSION/vendor/symfony/phpunit-bridge")));
- symlink(realpath('../src/Symfony/Bridge/PhpUnit'), "phpunit-$PHPUNIT_VERSION/vendor/symfony/phpunit-bridge");
- }
file_put_contents(".$PHPUNIT_VERSION.md5", md5_file(__FILE__));
chdir($oldPwd);
@@ -164,8 +160,9 @@ if (isset($argv[1]) && 'symfony' === $argv[1]) {
unlink($file);
}
- if ($procStatus) {
- $exit = 1;
+ // 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)) {
+ $exit = $procStatus;
echo "\033[41mKO\033[0m $component\n\n";
} else {
echo "\033[32mOK\033[0m $component\n\n";
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index b22aede91d94e..0538884cc43f5 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -47,4 +47,14 @@
+
+
+
+
+
+ Symfony\Component\HttpFoundation
+
+
+
+
diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php
index 2335af713128b..1a09609b28556 100644
--- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php
+++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php
@@ -156,7 +156,7 @@ public function loadChoicesForValues(array $values, $value = null)
// "INDEX BY" clause to the Doctrine query in the loader,
// but I'm not sure whether that's doable in a generic fashion.
foreach ($unorderedObjects as $object) {
- $objectsById[$this->idReader->getIdValue($object)] = $object;
+ $objectsById[(string) $this->idReader->getIdValue($object)] = $object;
}
foreach ($values as $i => $id) {
diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php
index fe0ad19367103..dae4bb0919ad3 100644
--- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php
+++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php
@@ -89,9 +89,10 @@ public function getEntities()
*/
public function getEntitiesByIds($identifier, array $values)
{
- $qb = clone ($this->queryBuilder);
+ $qb = clone $this->queryBuilder;
$alias = current($qb->getRootAliases());
$parameter = 'ORMQueryBuilderLoader_getEntitiesByIds_'.$identifier;
+ $parameter = str_replace('.', '_', $parameter);
$where = $qb->expr()->in($alias.'.'.$identifier, ':'.$parameter);
// Guess type
diff --git a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php
index 562a2952daf05..b2216b7ae31df 100644
--- a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php
+++ b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php
@@ -92,12 +92,16 @@ public function updateToken($series, $tokenValue, \DateTime $lastUsed)
{
$sql = 'UPDATE rememberme_token SET value=:value, lastUsed=:lastUsed'
.' WHERE series=:series';
- $paramValues = array('value' => $tokenValue,
- 'lastUsed' => $lastUsed,
- 'series' => $series,);
- $paramTypes = array('value' => \PDO::PARAM_STR,
- 'lastUsed' => DoctrineType::DATETIME,
- 'series' => \PDO::PARAM_STR,);
+ $paramValues = array(
+ 'value' => $tokenValue,
+ 'lastUsed' => $lastUsed,
+ 'series' => $series,
+ );
+ $paramTypes = array(
+ 'value' => \PDO::PARAM_STR,
+ 'lastUsed' => DoctrineType::DATETIME,
+ 'series' => \PDO::PARAM_STR,
+ );
$updated = $this->conn->executeUpdate($sql, $paramValues, $paramTypes);
if ($updated < 1) {
throw new TokenNotFoundException('No token found.');
@@ -112,16 +116,20 @@ public function createNewToken(PersistentTokenInterface $token)
$sql = 'INSERT INTO rememberme_token'
.' (class, username, series, value, lastUsed)'
.' VALUES (:class, :username, :series, :value, :lastUsed)';
- $paramValues = array('class' => $token->getClass(),
- 'username' => $token->getUsername(),
- 'series' => $token->getSeries(),
- 'value' => $token->getTokenValue(),
- 'lastUsed' => $token->getLastUsed(),);
- $paramTypes = array('class' => \PDO::PARAM_STR,
- 'username' => \PDO::PARAM_STR,
- 'series' => \PDO::PARAM_STR,
- 'value' => \PDO::PARAM_STR,
- 'lastUsed' => DoctrineType::DATETIME,);
+ $paramValues = array(
+ 'class' => $token->getClass(),
+ 'username' => $token->getUsername(),
+ 'series' => $token->getSeries(),
+ 'value' => $token->getTokenValue(),
+ 'lastUsed' => $token->getLastUsed(),
+ );
+ $paramTypes = array(
+ 'class' => \PDO::PARAM_STR,
+ 'username' => \PDO::PARAM_STR,
+ 'series' => \PDO::PARAM_STR,
+ 'value' => \PDO::PARAM_STR,
+ 'lastUsed' => DoctrineType::DATETIME,
+ );
$this->conn->executeUpdate($sql, $paramValues, $paramTypes);
}
}
diff --git a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php
index b34b9bdec4a67..cb8a59458324d 100644
--- a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php
+++ b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php
@@ -27,22 +27,17 @@
*/
class EntityUserProvider implements UserProviderInterface
{
+ private $registry;
+ private $managerName;
+ private $classOrAlias;
private $class;
- private $repository;
private $property;
- private $metadata;
- public function __construct(ManagerRegistry $registry, $class, $property = null, $managerName = null)
+ public function __construct(ManagerRegistry $registry, $classOrAlias, $property = null, $managerName = null)
{
- $em = $registry->getManager($managerName);
- $this->class = $class;
- $this->metadata = $em->getClassMetadata($class);
-
- if (false !== strpos($this->class, ':')) {
- $this->class = $this->metadata->getName();
- }
-
- $this->repository = $em->getRepository($class);
+ $this->registry = $registry;
+ $this->managerName = $managerName;
+ $this->classOrAlias = $classOrAlias;
$this->property = $property;
}
@@ -51,14 +46,15 @@ public function __construct(ManagerRegistry $registry, $class, $property = null,
*/
public function loadUserByUsername($username)
{
+ $repository = $this->getRepository();
if (null !== $this->property) {
- $user = $this->repository->findOneBy(array($this->property => $username));
+ $user = $repository->findOneBy(array($this->property => $username));
} else {
- if (!$this->repository instanceof UserProviderInterface) {
- throw new \InvalidArgumentException(sprintf('The Doctrine repository "%s" must implement UserProviderInterface.', get_class($this->repository)));
+ if (!$repository instanceof UserProviderInterface) {
+ throw new \InvalidArgumentException(sprintf('The Doctrine repository "%s" must implement UserProviderInterface.', get_class($repository)));
}
- $user = $this->repository->loadUserByUsername($username);
+ $user = $repository->loadUserByUsername($username);
}
if (null === $user) {
@@ -73,18 +69,20 @@ public function loadUserByUsername($username)
*/
public function refreshUser(UserInterface $user)
{
- if (!$user instanceof $this->class) {
+ $class = $this->getClass();
+ if (!$user instanceof $class) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
- if ($this->repository instanceof UserProviderInterface) {
- $refreshedUser = $this->repository->refreshUser($user);
+ $repository = $this->getRepository();
+ if ($repository instanceof UserProviderInterface) {
+ $refreshedUser = $repository->refreshUser($user);
} else {
// The user must be reloaded via the primary key as all other data
// might have changed without proper persistence in the database.
// That's the case when the user has been changed by a form with
// validation errors.
- if (!$id = $this->metadata->getIdentifierValues($user)) {
+ if (!$id = $this->getClassMetadata()->getIdentifierValues($user)) {
throw new \InvalidArgumentException('You cannot refresh a user '.
'from the EntityUserProvider that does not contain an identifier. '.
'The user object has to be serialized with its own identifier '.
@@ -92,7 +90,7 @@ public function refreshUser(UserInterface $user)
);
}
- $refreshedUser = $this->repository->find($id);
+ $refreshedUser = $repository->find($id);
if (null === $refreshedUser) {
throw new UsernameNotFoundException(sprintf('User with id %s not found', json_encode($id)));
}
@@ -106,6 +104,36 @@ public function refreshUser(UserInterface $user)
*/
public function supportsClass($class)
{
- return $class === $this->class || is_subclass_of($class, $this->class);
+ return $class === $this->getClass() || is_subclass_of($class, $this->getClass());
+ }
+
+ private function getObjectManager()
+ {
+ return $this->registry->getManager($this->managerName);
+ }
+
+ private function getRepository()
+ {
+ return $this->getObjectManager()->getRepository($this->classOrAlias);
+ }
+
+ private function getClass()
+ {
+ if (null === $this->class) {
+ $class = $this->classOrAlias;
+
+ if (false !== strpos($class, ':')) {
+ $class = $this->getClassMetadata()->getName();
+ }
+
+ $this->class = $class;
+ }
+
+ return $this->class;
+ }
+
+ private function getClassMetadata()
+ {
+ return $this->getObjectManager()->getClassMetadata($this->classOrAlias);
}
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Embeddable/Identifier.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Embeddable/Identifier.php
new file mode 100644
index 0000000000000..f8000dbfd9814
--- /dev/null
+++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Embeddable/Identifier.php
@@ -0,0 +1,28 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bridge\Doctrine\Tests\Fixtures\Embeddable;
+
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Embeddable
+ */
+class Identifier
+{
+ /**
+ * @var int
+ *
+ * @ORM\Id
+ * @ORM\Column(type="integer")
+ */
+ protected $value;
+}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/EmbeddedIdentifierEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/EmbeddedIdentifierEntity.php
new file mode 100644
index 0000000000000..6d7b2670962c7
--- /dev/null
+++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/EmbeddedIdentifierEntity.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bridge\Doctrine\Tests\Fixtures;
+
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity
+ */
+class EmbeddedIdentifierEntity
+{
+ /**
+ * @var Embeddable\Identifier
+ *
+ * @ORM\Embedded(class="Symfony\Bridge\Doctrine\Tests\Fixtures\Embeddable\Identifier")
+ */
+ protected $id;
+}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleStringCastableIdEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleStringCastableIdEntity.php
new file mode 100644
index 0000000000000..e457f69dd091b
--- /dev/null
+++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleStringCastableIdEntity.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bridge\Doctrine\Tests\Fixtures;
+
+use Doctrine\ORM\Mapping\Column;
+use Doctrine\ORM\Mapping\Entity;
+use Doctrine\ORM\Mapping\GeneratedValue;
+use Doctrine\ORM\Mapping\Id;
+
+/** @Entity */
+class SingleStringCastableIdEntity
+{
+ /**
+ * @Id
+ * @Column(type="string")
+ * @GeneratedValue(strategy="NONE")
+ */
+ protected $id;
+
+ /** @Column(type="string", nullable=true) */
+ public $name;
+
+ public function __construct($id, $name)
+ {
+ $this->id = new StringCastableObjectIdentity($id);
+ $this->name = $name;
+ }
+
+ public function __toString()
+ {
+ return (string) $this->name;
+ }
+}
+
+class StringCastableObjectIdentity
+{
+ protected $id;
+
+ public function __construct($id)
+ {
+ $this->id = $id;
+ }
+
+ public function __toString()
+ {
+ return (string) $this->id;
+ }
+}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php
index 5af59445e1825..d755af5430bc4 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php
@@ -14,6 +14,7 @@
use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader;
use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper;
use Doctrine\DBAL\Connection;
+use Doctrine\ORM\Version;
class ORMQueryBuilderLoaderTest extends \PHPUnit_Framework_TestCase
{
@@ -104,4 +105,38 @@ public function testFilterNonIntegerValues()
$loader = new ORMQueryBuilderLoader($qb);
$loader->getEntitiesByIds('id', array(1, '', 2, 3, 'foo'));
}
+
+ public function testEmbeddedIdentifierName()
+ {
+ if (Version::compare('2.5.0') > 0) {
+ $this->markTestSkipped('Applicable only for Doctrine >= 2.5.0');
+
+ return;
+ }
+
+ $em = DoctrineTestHelper::createTestEntityManager();
+
+ $query = $this->getMockBuilder('QueryMock')
+ ->setMethods(array('setParameter', 'getResult', 'getSql', '_doExecute'))
+ ->getMock();
+
+ $query->expects($this->once())
+ ->method('setParameter')
+ ->with('ORMQueryBuilderLoader_getEntitiesByIds_id_value', array(1, 2, 3), Connection::PARAM_INT_ARRAY)
+ ->willReturn($query);
+
+ $qb = $this->getMockBuilder('Doctrine\ORM\QueryBuilder')
+ ->setConstructorArgs(array($em))
+ ->setMethods(array('getQuery'))
+ ->getMock();
+ $qb->expects($this->once())
+ ->method('getQuery')
+ ->willReturn($query);
+
+ $qb->select('e')
+ ->from('Symfony\Bridge\Doctrine\Tests\Fixtures\EmbeddedIdentifierEntity', 'e');
+
+ $loader = new ORMQueryBuilderLoader($qb);
+ $loader->getEntitiesByIds('id.value', array(1, '', 2, 3, 'foo'));
+ }
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
index 78f10848bccbf..ce37d261c06e3 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
@@ -24,6 +24,7 @@
use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeStringIdEntity;
use Symfony\Bridge\Doctrine\Tests\Fixtures\GroupableEntity;
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
+use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringCastableIdEntity;
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity;
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
@@ -40,6 +41,7 @@ class EntityTypeTest extends TypeTestCase
const SINGLE_IDENT_NO_TO_STRING_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity';
const SINGLE_STRING_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity';
const SINGLE_ASSOC_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleAssociationToIntIdEntity';
+ const SINGLE_STRING_CASTABLE_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringCastableIdEntity';
const COMPOSITE_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity';
const COMPOSITE_STRING_IDENT_CLASS = 'Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeStringIdEntity';
@@ -67,6 +69,7 @@ protected function setUp()
$this->em->getClassMetadata(self::SINGLE_IDENT_NO_TO_STRING_CLASS),
$this->em->getClassMetadata(self::SINGLE_STRING_IDENT_CLASS),
$this->em->getClassMetadata(self::SINGLE_ASSOC_IDENT_CLASS),
+ $this->em->getClassMetadata(self::SINGLE_STRING_CASTABLE_IDENT_CLASS),
$this->em->getClassMetadata(self::COMPOSITE_IDENT_CLASS),
$this->em->getClassMetadata(self::COMPOSITE_STRING_IDENT_CLASS),
);
@@ -580,6 +583,139 @@ public function testSubmitMultipleExpandedWithNegativeIntegerId()
$this->assertFalse($field['2']->getData());
}
+ public function testSubmitSingleNonExpandedStringCastableIdentifier()
+ {
+ $entity1 = new SingleStringCastableIdEntity(1, 'Foo');
+ $entity2 = new SingleStringCastableIdEntity(2, 'Bar');
+
+ $this->persist(array($entity1, $entity2));
+
+ $field = $this->factory->createNamed('name', 'entity', null, array(
+ 'multiple' => false,
+ 'expanded' => false,
+ 'em' => 'default',
+ 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
+ 'choice_label' => 'name',
+ ));
+
+ $field->submit('2');
+
+ $this->assertTrue($field->isSynchronized());
+ $this->assertSame($entity2, $field->getData());
+ $this->assertSame('2', $field->getViewData());
+ }
+
+ public function testSubmitSingleStringCastableIdentifierExpanded()
+ {
+ $entity1 = new SingleStringCastableIdEntity(1, 'Foo');
+ $entity2 = new SingleStringCastableIdEntity(2, 'Bar');
+
+ $this->persist(array($entity1, $entity2));
+
+ $field = $this->factory->createNamed('name', 'entity', null, array(
+ 'multiple' => false,
+ 'expanded' => true,
+ 'em' => 'default',
+ 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
+ 'choice_label' => 'name',
+ ));
+
+ $field->submit('2');
+
+ $this->assertTrue($field->isSynchronized());
+ $this->assertSame($entity2, $field->getData());
+ $this->assertFalse($field['0']->getData());
+ $this->assertTrue($field['1']->getData());
+ $this->assertNull($field['0']->getViewData());
+ $this->assertSame('2', $field['1']->getViewData());
+ }
+
+ public function testSubmitMultipleNonExpandedStringCastableIdentifierForExistingData()
+ {
+ $entity1 = new SingleStringCastableIdEntity(1, 'Foo');
+ $entity2 = new SingleStringCastableIdEntity(2, 'Bar');
+ $entity3 = new SingleStringCastableIdEntity(3, 'Baz');
+
+ $this->persist(array($entity1, $entity2, $entity3));
+
+ $field = $this->factory->createNamed('name', 'entity', null, array(
+ 'multiple' => true,
+ 'expanded' => false,
+ 'em' => 'default',
+ 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
+ 'choice_label' => 'name',
+ ));
+
+ $existing = new ArrayCollection(array(0 => $entity2));
+
+ $field->setData($existing);
+ $field->submit(array('1', '3'));
+
+ // entry with index 0 ($entity2) was replaced
+ $expected = new ArrayCollection(array(0 => $entity1, 1 => $entity3));
+
+ $this->assertTrue($field->isSynchronized());
+ $this->assertEquals($expected, $field->getData());
+ // same object still, useful if it is a PersistentCollection
+ $this->assertSame($existing, $field->getData());
+ $this->assertSame(array('1', '3'), $field->getViewData());
+ }
+
+ public function testSubmitMultipleNonExpandedStringCastableIdentifier()
+ {
+ $entity1 = new SingleStringCastableIdEntity(1, 'Foo');
+ $entity2 = new SingleStringCastableIdEntity(2, 'Bar');
+ $entity3 = new SingleStringCastableIdEntity(3, 'Baz');
+
+ $this->persist(array($entity1, $entity2, $entity3));
+
+ $field = $this->factory->createNamed('name', 'entity', null, array(
+ 'multiple' => true,
+ 'expanded' => false,
+ 'em' => 'default',
+ 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
+ 'choice_label' => 'name',
+ ));
+
+ $field->submit(array('1', '3'));
+
+ $expected = new ArrayCollection(array($entity1, $entity3));
+
+ $this->assertTrue($field->isSynchronized());
+ $this->assertEquals($expected, $field->getData());
+ $this->assertSame(array('1', '3'), $field->getViewData());
+ }
+
+ public function testSubmitMultipleStringCastableIdentifierExpanded()
+ {
+ $entity1 = new SingleStringCastableIdEntity(1, 'Foo');
+ $entity2 = new SingleStringCastableIdEntity(2, 'Bar');
+ $entity3 = new SingleStringCastableIdEntity(3, 'Bar');
+
+ $this->persist(array($entity1, $entity2, $entity3));
+
+ $field = $this->factory->createNamed('name', 'entity', null, array(
+ 'multiple' => true,
+ 'expanded' => true,
+ 'em' => 'default',
+ 'class' => self::SINGLE_STRING_CASTABLE_IDENT_CLASS,
+ 'choice_label' => 'name',
+ ));
+
+ $field->submit(array('1', '3'));
+
+ $expected = new ArrayCollection(array($entity1, $entity3));
+
+ $this->assertTrue($field->isSynchronized());
+ $this->assertEquals($expected, $field->getData());
+ $this->assertTrue($field['0']->getData());
+ $this->assertFalse($field['1']->getData());
+ $this->assertTrue($field['2']->getData());
+ $this->assertSame('1', $field['0']->getViewData());
+ $this->assertNull($field['1']->getViewData());
+ $this->assertSame('3', $field['2']->getViewData());
+ }
+
public function testOverrideChoices()
{
$entity1 = new SingleIntIdEntity(1, 'Foo');
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php
index 8c179cd31f246..6203b9dfb29a7 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php
@@ -92,7 +92,7 @@ public function testSupportProxy()
private function getManager($em, $name = null)
{
$manager = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
- $manager->expects($this->once())
+ $manager->expects($this->any())
->method('getManager')
->with($this->equalTo($name))
->will($this->returnValue($em));
diff --git a/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php b/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php
new file mode 100644
index 0000000000000..3d3c74cb73dfc
--- /dev/null
+++ b/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php
@@ -0,0 +1,106 @@
+pushHandler($handler);
+
+ $this->assertTrue($logger->emerg('test'));
+ $this->assertTrue($handler->hasEmergency('test'));
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testCrit()
+ {
+ $handler = new TestHandler();
+ $logger = new Logger('test');
+ $logger->pushHandler($handler);
+
+ $this->assertTrue($logger->crit('test'));
+ $this->assertTrue($handler->hasCritical('test'));
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testErr()
+ {
+ $handler = new TestHandler();
+ $logger = new Logger('test');
+ $logger->pushHandler($handler);
+
+ $this->assertTrue($logger->err('test'));
+ $this->assertTrue($handler->hasError('test'));
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testWarn()
+ {
+ $handler = new TestHandler();
+ $logger = new Logger('test');
+ $logger->pushHandler($handler);
+
+ $this->assertTrue($logger->warn('test'));
+ $this->assertTrue($handler->hasWarning('test'));
+ }
+
+ public function testGetLogs()
+ {
+ $logger = new Logger('test');
+ $logger->pushHandler(new DebugHandler());
+
+ $logger->addInfo('test');
+ $this->assertCount(1, $logger->getLogs());
+ list($record) = $logger->getLogs();
+
+ $this->assertEquals('test', $record['message']);
+ $this->assertEquals(Logger::INFO, $record['priority']);
+ }
+
+ public function testGetLogsWithoutDebugHandler()
+ {
+ $logger = new Logger('test');
+ $logger->pushHandler(new TestHandler());
+ $logger->addInfo('test');
+
+ $this->assertSame(array(), $logger->getLogs());
+ }
+
+ public function testCountErrors()
+ {
+ $logger = new Logger('test');
+ $logger->pushHandler(new DebugHandler());
+
+ $logger->addInfo('test');
+ $logger->addError('uh-oh');
+
+ $this->assertEquals(1, $logger->countErrors());
+ }
+
+ public function testCountErrorsWithoutDebugHandler()
+ {
+ $logger = new Logger('test');
+ $logger->pushHandler(new TestHandler());
+
+ $logger->addInfo('test');
+ $logger->addError('uh-oh');
+
+ $this->assertEquals(0, $logger->countErrors());
+ }
+}
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig
index 767e2798f3ee5..e997615d11378 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig
@@ -25,15 +25,13 @@ col-sm-2
{# Rows #}
{% block form_row -%}
-{% spaceless %}
-{% endspaceless %}
+{##}
{%- endblock form_row %}
{% block checkbox_row -%}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php
new file mode 100644
index 0000000000000..c7195ab577820
--- /dev/null
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php
@@ -0,0 +1,153 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bridge\Twig\Tests\Extension;
+
+use Symfony\Bridge\Twig\Extension\FormExtension;
+use Symfony\Bridge\Twig\Form\TwigRenderer;
+use Symfony\Bridge\Twig\Form\TwigRendererEngine;
+use Symfony\Bridge\Twig\Extension\TranslationExtension;
+use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
+use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
+use Symfony\Component\Form\FormView;
+use Symfony\Component\Form\Tests\AbstractBootstrap3HorizontalLayoutTest;
+
+class FormExtensionBootstrap3HorizontalLayoutTest extends AbstractBootstrap3HorizontalLayoutTest
+{
+ /**
+ * @var FormExtension
+ */
+ protected $extension;
+
+ protected $testableFeatures = array(
+ 'choice_attr',
+ );
+
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $rendererEngine = new TwigRendererEngine(array(
+ 'bootstrap_3_horizontal_layout.html.twig',
+ 'custom_widgets.html.twig',
+ ));
+ $renderer = new TwigRenderer($rendererEngine, $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface'));
+
+ $this->extension = new FormExtension($renderer);
+
+ $loader = new StubFilesystemLoader(array(
+ __DIR__.'/../../Resources/views/Form',
+ __DIR__.'/Fixtures/templates/form',
+ ));
+
+ $environment = new \Twig_Environment($loader, array('strict_variables' => true));
+ $environment->addExtension(new TranslationExtension(new StubTranslator()));
+ $environment->addExtension($this->extension);
+
+ $this->extension->initRuntime($environment);
+ }
+
+ protected function tearDown()
+ {
+ parent::tearDown();
+
+ $this->extension = null;
+ }
+
+ protected function renderForm(FormView $view, array $vars = array())
+ {
+ return (string) $this->extension->renderer->renderBlock($view, 'form', $vars);
+ }
+
+ protected function renderEnctype(FormView $view)
+ {
+ return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
+ }
+
+ protected function renderLabel(FormView $view, $label = null, array $vars = array())
+ {
+ if ($label !== null) {
+ $vars += array('label' => $label);
+ }
+
+ return (string) $this->extension->renderer->searchAndRenderBlock($view, 'label', $vars);
+ }
+
+ protected function renderErrors(FormView $view)
+ {
+ return (string) $this->extension->renderer->searchAndRenderBlock($view, 'errors');
+ }
+
+ protected function renderWidget(FormView $view, array $vars = array())
+ {
+ return (string) $this->extension->renderer->searchAndRenderBlock($view, 'widget', $vars);
+ }
+
+ protected function renderRow(FormView $view, array $vars = array())
+ {
+ return (string) $this->extension->renderer->searchAndRenderBlock($view, 'row', $vars);
+ }
+
+ protected function renderRest(FormView $view, array $vars = array())
+ {
+ return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
+ }
+
+ protected function renderStart(FormView $view, array $vars = array())
+ {
+ return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars);
+ }
+
+ protected function renderEnd(FormView $view, array $vars = array())
+ {
+ return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars);
+ }
+
+ protected function setTheme(FormView $view, array $themes)
+ {
+ $this->extension->renderer->setTheme($view, $themes);
+ }
+
+ public function testRange()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testRangeWithMinMaxValues()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testLabelWithoutTranslationOnButton()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testButtonlabelWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testAttributesNotTranslatedWhenTranslationDomainIsFalse()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php
index a9d161b2b909a..406c1cef16bf4 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php
@@ -125,4 +125,29 @@ public function testRangeWithMinMaxValues()
{
// No-op for forward compatibility with AbstractLayoutTest 2.8
}
+
+ public function testLabelWithoutTranslationOnButton()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testButtonlabelWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testAttributesNotTranslatedWhenTranslationDomainIsFalse()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php
index 1bce43b83780c..9e39ac35dc421 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php
@@ -218,4 +218,29 @@ public function testRangeWithMinMaxValues()
{
// No-op for forward compatibility with AbstractLayoutTest 2.8
}
+
+ public function testLabelWithoutTranslationOnButton()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testButtonlabelWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testAttributesNotTranslatedWhenTranslationDomainIsFalse()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php
index 555ea306fca89..7fa88eef00c7e 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php
@@ -126,4 +126,29 @@ public function testRangeWithMinMaxValues()
{
// No-op for forward compatibility with AbstractLayoutTest 2.8
}
+
+ public function testLabelWithoutTranslationOnButton()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testButtonlabelWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testAttributesNotTranslatedWhenTranslationDomainIsFalse()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php
index dc06c73dba03e..f4a6dbf21ffa4 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php
@@ -31,7 +31,7 @@ public function testEscaping()
public function testTrans($template, $expected, array $variables = array())
{
if ($expected != $this->getTemplate($template)->render($variables)) {
- print $template."\n";
+ echo $template."\n";
$loader = new \Twig_Loader_Array(array('index' => $template));
$twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
$twig->addExtension(new TranslationExtension(new Translator('en', new MessageSelector())));
diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json
index 7ce35a9fac00b..2e569d7435fc8 100644
--- a/src/Symfony/Bridge/Twig/composer.json
+++ b/src/Symfony/Bridge/Twig/composer.json
@@ -22,7 +22,7 @@
"require-dev": {
"symfony/asset": "~2.7",
"symfony/finder": "~2.3",
- "symfony/form": "~2.7,>=2.7.6",
+ "symfony/form": "~2.7,>=2.7.8",
"symfony/http-kernel": "~2.3",
"symfony/intl": "~2.3",
"symfony/routing": "~2.2",
diff --git a/src/Symfony/Bundle/FrameworkBundle/Client.php b/src/Symfony/Bundle/FrameworkBundle/Client.php
index 82e627a726a07..d9b064e5ec5a6 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Client.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Client.php
@@ -185,7 +185,7 @@ protected function getScript($request)
$code = <<getContainer()->getParameter('kernel.cache_dir');
- $oldCacheDir = $realCacheDir.'_old';
+ // the old cache dir name must not be longer than the real one to avoid exceeding
+ // the maximum length of a directory or file path within it (esp. Windows MAX_PATH)
+ $oldCacheDir = substr($realCacheDir, 0, -1).('~' === substr($realCacheDir, -1) ? '+' : '~');
$filesystem = $this->getContainer()->get('filesystem');
if (!is_writable($realCacheDir)) {
@@ -75,7 +77,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
// the warmup cache dir name must have the same length than the real one
// to avoid the many problems in serialized resources files
$realCacheDir = realpath($realCacheDir);
- $warmupDir = substr($realCacheDir, 0, -1).'_';
+ $warmupDir = substr($realCacheDir, 0, -1).('_' === substr($realCacheDir, -1) ? '-' : '_');
if ($filesystem->exists($warmupDir)) {
if ($output->isVerbose()) {
@@ -114,8 +116,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
*/
protected function warmup($warmupDir, $realCacheDir, $enableOptionalWarmers = true)
{
- $this->getContainer()->get('filesystem')->remove($warmupDir);
-
// create a temporary kernel
$realKernel = $this->getContainer()->get('kernel');
$realKernelClass = get_class($realKernel);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerCommand.php
index b979a19f0f73d..acf71c666605a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerCommand.php
@@ -27,6 +27,10 @@ public function isEnabled()
return false;
}
+ if (!class_exists('Symfony\Component\Process\Process')) {
+ return false;
+ }
+
return parent::isEnabled();
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php
index 6af52feaaec57..78b0bd4ee290a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php
@@ -25,18 +25,6 @@
*/
class ServerRunCommand extends ServerCommand
{
- /**
- * {@inheritdoc}
- */
- public function isEnabled()
- {
- if (PHP_VERSION_ID < 50400 || defined('HHVM_VERSION')) {
- return false;
- }
-
- return parent::isEnabled();
- }
-
/**
* {@inheritdoc}
*/
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
index 64143f6e21a19..f8bd0159fcf2f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
@@ -188,9 +188,11 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
}
- if ($bundleTransPath) {
- $writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale')));
+ if (!$bundleTransPath) {
+ $bundleTransPath = end($transPaths).'translations';
}
+
+ $writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale')));
}
$output->newLine();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php
index 4af5b929cbb50..217fd5e50e237 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php
@@ -138,4 +138,29 @@ public function testRangeWithMinMaxValues()
{
// No-op for forward compatibility with AbstractLayoutTest 2.8
}
+
+ public function testLabelWithoutTranslationOnButton()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testButtonlabelWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testAttributesNotTranslatedWhenTranslationDomainIsFalse()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php
index 1bf641fe1b93f..99bfba0c4e7cc 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php
@@ -125,4 +125,29 @@ public function testRangeWithMinMaxValues()
{
// No-op for forward compatibility with AbstractLayoutTest 2.8
}
+
+ public function testLabelWithoutTranslationOnButton()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testButtonlabelWithoutTranslation()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
+
+ public function testAttributesNotTranslatedWhenTranslationDomainIsFalse()
+ {
+ // No-op for forward compatibility with AbstractLayoutTest 2.8
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index 29ff39c46fac3..045d19c354e73 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -21,6 +21,7 @@
"symfony/dependency-injection": "~2.6,>=2.6.2",
"symfony/config": "~2.4",
"symfony/event-dispatcher": "~2.5",
+ "symfony/finder": "~2.0,>=2.0.5",
"symfony/http-foundation": "~2.4.9|~2.5,>=2.5.4",
"symfony/http-kernel": "~2.7",
"symfony/filesystem": "~2.3",
@@ -37,7 +38,6 @@
"symfony/console": "~2.7",
"symfony/css-selector": "~2.0,>=2.0.5",
"symfony/dom-crawler": "~2.0,>=2.0.5",
- "symfony/finder": "~2.0,>=2.0.5",
"symfony/intl": "~2.3",
"symfony/security": "~2.6",
"symfony/form": "~2.7,>=2.7.2",
@@ -49,11 +49,11 @@
},
"suggest": {
"symfony/console": "For using the console commands",
- "symfony/finder": "For using the translation loader and cache warmer",
"symfony/form": "For using forms",
"symfony/serializer": "For using the serializer service",
"symfony/validator": "For using validation",
"symfony/yaml": "For using the debug:config and lint:yaml commands",
+ "symfony/process": "For using the server:run, server:start, server:stop, and server:status commands",
"doctrine/cache": "For using alternative cache drivers"
},
"autoload": {
diff --git a/src/Symfony/Bundle/SecurityBundle/Command/InitAclCommand.php b/src/Symfony/Bundle/SecurityBundle/Command/InitAclCommand.php
index fff5b1e929503..14271dc459a08 100644
--- a/src/Symfony/Bundle/SecurityBundle/Command/InitAclCommand.php
+++ b/src/Symfony/Bundle/SecurityBundle/Command/InitAclCommand.php
@@ -23,6 +23,18 @@
*/
class InitAclCommand extends ContainerAwareCommand
{
+ /**
+ * {@inheritdoc}
+ */
+ public function isEnabled()
+ {
+ if (!$this->getContainer()->has('security.acl.dbal.connection')) {
+ return false;
+ }
+
+ return parent::isEnabled();
+ }
+
/**
* {@inheritdoc}
*/
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php
index e94a21e5bae75..6ac0e6a3af772 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php
@@ -16,7 +16,6 @@ class AuthenticationCommencingTest extends WebTestCase
public function testAuthenticationIsCommencingIfAccessDeniedExceptionIsWrapped()
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'config.yml'));
- $client->insulate();
$client->request('GET', '/secure-but-not-covered-by-access-control');
$this->assertRedirect($client->getResponse(), '/login');
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/DependencyInjection/FirewallEntryPointExtension.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/DependencyInjection/FirewallEntryPointExtension.php
index e4d5bc30f39f9..90b6b3e5eb238 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/DependencyInjection/FirewallEntryPointExtension.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/DependencyInjection/FirewallEntryPointExtension.php
@@ -18,7 +18,7 @@
class FirewallEntryPointExtension extends Extension
{
- public function load(array $config, ContainerBuilder $container)
+ public function load(array $configs, ContainerBuilder $container)
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php
index c2299c9a51f11..80211f5251b08 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php
@@ -19,7 +19,6 @@ class CsrfFormLoginTest extends WebTestCase
public function testFormLoginAndLogoutWithCsrfTokens($config)
{
$client = $this->createClient(array('test_case' => 'CsrfFormLogin', 'root_config' => $config));
- $client->insulate();
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['user_login[username]'] = 'johannes';
@@ -50,7 +49,6 @@ public function testFormLoginAndLogoutWithCsrfTokens($config)
public function testFormLoginWithInvalidCsrfToken($config)
{
$client = $this->createClient(array('test_case' => 'CsrfFormLogin', 'root_config' => $config));
- $client->insulate();
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['user_login[_token]'] = '';
@@ -68,7 +66,6 @@ public function testFormLoginWithInvalidCsrfToken($config)
public function testFormLoginWithCustomTargetPath($config)
{
$client = $this->createClient(array('test_case' => 'CsrfFormLogin', 'root_config' => $config));
- $client->insulate();
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['user_login[username]'] = 'johannes';
@@ -89,7 +86,6 @@ public function testFormLoginWithCustomTargetPath($config)
public function testFormLoginRedirectsToProtectedResourceAfterLogin($config)
{
$client = $this->createClient(array('test_case' => 'CsrfFormLogin', 'root_config' => $config));
- $client->insulate();
$client->request('GET', '/protected-resource');
$this->assertRedirect($client->getResponse(), '/login');
@@ -113,17 +109,13 @@ public function getConfigs()
);
}
- protected function setUp()
+ public static function setUpBeforeClass()
{
- parent::setUp();
-
- $this->deleteTmpDir('CsrfFormLogin');
+ parent::deleteTmpDir('CsrfFormLogin');
}
- protected function tearDown()
+ public static function tearDownAfterClass()
{
- parent::tearDown();
-
- $this->deleteTmpDir('CsrfFormLogin');
+ parent::deleteTmpDir('CsrfFormLogin');
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FirewallEntryPointTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FirewallEntryPointTest.php
index aab98f273fa8e..30d0935ffddd7 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FirewallEntryPointTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FirewallEntryPointTest.php
@@ -18,7 +18,6 @@ class FirewallEntryPointTest extends WebTestCase
public function testItUsesTheConfiguredEntryPointWhenUsingUnknownCredentials()
{
$client = $this->createClient(array('test_case' => 'FirewallEntryPoint'));
- $client->insulate();
$client->request('GET', '/secure/resource', array(), array(), array(
'PHP_AUTH_USER' => 'unknown',
@@ -35,7 +34,6 @@ public function testItUsesTheConfiguredEntryPointWhenUsingUnknownCredentials()
public function testItUsesTheConfiguredEntryPointFromTheExceptionListenerWithFormLoginAndNoCredentials()
{
$client = $this->createClient(array('test_case' => 'FirewallEntryPoint', 'root_config' => 'config_form_login.yml'));
- $client->insulate();
$client->request('GET', '/secure/resource');
@@ -46,17 +44,13 @@ public function testItUsesTheConfiguredEntryPointFromTheExceptionListenerWithFor
);
}
- protected function setUp()
+ public static function setUpBeforeClass()
{
- parent::setUp();
-
- $this->deleteTmpDir('FirewallEntryPoint');
+ parent::deleteTmpDir('FirewallEntryPoint');
}
- protected function tearDown()
+ public static function tearDownAfterClass()
{
- parent::tearDown();
-
- $this->deleteTmpDir('FirewallEntryPoint');
+ parent::deleteTmpDir('FirewallEntryPoint');
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php
index 3bb2235d51652..2f19f3f8a1a9a 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php
@@ -19,7 +19,6 @@ class FormLoginTest extends WebTestCase
public function testFormLogin($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
- $client->insulate();
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = 'johannes';
@@ -39,7 +38,6 @@ public function testFormLogin($config)
public function testFormLogout($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
- $client->insulate();
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = 'johannes';
@@ -73,7 +71,6 @@ public function testFormLogout($config)
public function testFormLoginWithCustomTargetPath($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
- $client->insulate();
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = 'johannes';
@@ -94,7 +91,6 @@ public function testFormLoginWithCustomTargetPath($config)
public function testFormLoginRedirectsToProtectedResourceAfterLogin($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
- $client->insulate();
$client->request('GET', '/protected_resource');
$this->assertRedirect($client->getResponse(), '/login');
@@ -118,17 +114,13 @@ public function getConfigs()
);
}
- protected function setUp()
+ public static function setUpBeforeClass()
{
- parent::setUp();
-
- $this->deleteTmpDir('StandardFormLogin');
+ parent::deleteTmpDir('StandardFormLogin');
}
- protected function tearDown()
+ public static function tearDownAfterClass()
{
- parent::tearDown();
-
- $this->deleteTmpDir('StandardFormLogin');
+ parent::deleteTmpDir('StandardFormLogin');
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php
index 84c79055a977c..14c317966e21a 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php
@@ -19,7 +19,6 @@ class LocalizedRoutesAsPathTest extends WebTestCase
public function testLoginLogoutProcedure($locale)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes.yml'));
- $client->insulate();
$crawler = $client->request('GET', '/'.$locale.'/login');
$form = $crawler->selectButton('login')->form();
@@ -41,7 +40,6 @@ public function testLoginLogoutProcedure($locale)
public function testLoginFailureWithLocalizedFailurePath($locale)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_form_failure_handler.yml'));
- $client->insulate();
$crawler = $client->request('GET', '/'.$locale.'/login');
$form = $crawler->selectButton('login')->form();
@@ -58,7 +56,6 @@ public function testLoginFailureWithLocalizedFailurePath($locale)
public function testAccessRestrictedResource($locale)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes.yml'));
- $client->insulate();
$client->request('GET', '/'.$locale.'/secure/');
$this->assertRedirect($client->getResponse(), '/'.$locale.'/login');
@@ -70,7 +67,6 @@ public function testAccessRestrictedResource($locale)
public function testAccessRestrictedResourceWithForward($locale)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes_with_forward.yml'));
- $client->insulate();
$crawler = $client->request('GET', '/'.$locale.'/secure/');
$this->assertCount(1, $crawler->selectButton('login'), (string) $client->getResponse());
@@ -81,17 +77,13 @@ public function getLocales()
return array(array('en'), array('de'));
}
- protected function setUp()
+ public static function setUpBeforeClass()
{
- parent::setUp();
-
- $this->deleteTmpDir('StandardFormLogin');
+ parent::deleteTmpDir('StandardFormLogin');
}
- protected function tearDown()
+ public static function tearDownAfterClass()
{
- parent::tearDown();
-
- $this->deleteTmpDir('StandardFormLogin');
+ parent::deleteTmpDir('StandardFormLogin');
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php
index 4c1f0853bb65c..c7db437819a1c 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php
@@ -19,7 +19,6 @@ class SecurityRoutingIntegrationTest extends WebTestCase
public function testRoutingErrorIsNotExposedForProtectedResourceWhenAnonymous($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
- $client->insulate();
$client->request('GET', '/protected_resource');
$this->assertRedirect($client->getResponse(), '/login');
@@ -31,7 +30,6 @@ public function testRoutingErrorIsNotExposedForProtectedResourceWhenAnonymous($c
public function testRoutingErrorIsExposedWhenNotProtected($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
- $client->insulate();
$client->request('GET', '/unprotected_resource');
$this->assertEquals(404, $client->getResponse()->getStatusCode(), (string) $client->getResponse());
@@ -43,7 +41,6 @@ public function testRoutingErrorIsExposedWhenNotProtected($config)
public function testRoutingErrorIsNotExposedForProtectedResourceWhenLoggedInWithInsufficientRights($config)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config));
- $client->insulate();
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = 'johannes';
@@ -120,17 +117,13 @@ public function getConfigs()
return array(array('config.yml'), array('routes_as_path.yml'));
}
- protected function setUp()
+ public static function setUpBeforeClass()
{
- parent::setUp();
-
- $this->deleteTmpDir('StandardFormLogin');
+ parent::deleteTmpDir('StandardFormLogin');
}
- protected function tearDown()
+ public static function tearDownAfterClass()
{
- parent::tearDown();
-
- $this->deleteTmpDir('StandardFormLogin');
+ parent::deleteTmpDir('StandardFormLogin');
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php
index f4b3d27f21404..e5079c3283aac 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php
@@ -62,7 +62,6 @@ protected function createAuthenticatedClient($username)
{
$client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'switchuser.yml'));
$client->followRedirects(true);
- $client->insulate();
$form = $client->request('GET', '/login')->selectButton('login')->form();
$form['_username'] = $username;
@@ -72,17 +71,13 @@ protected function createAuthenticatedClient($username)
return $client;
}
- protected function setUp()
+ public static function setUpBeforeClass()
{
- parent::setUp();
-
- $this->deleteTmpDir('StandardFormLogin');
+ parent::deleteTmpDir('StandardFormLogin');
}
- protected function tearDown()
+ public static function tearDownAfterClass()
{
- parent::tearDown();
-
- $this->deleteTmpDir('StandardFormLogin');
+ parent::deleteTmpDir('StandardFormLogin');
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php
index 731c32073c949..33da9028a3daf 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php
@@ -23,7 +23,7 @@ public static function assertRedirect($response, $location)
self::assertEquals('http://localhost'.$location, $response->headers->get('Location'));
}
- protected function deleteTmpDir($testCase)
+ protected static function deleteTmpDir($testCase)
{
if (!file_exists($dir = sys_get_temp_dir().'/'.Kernel::VERSION.'/'.$testCase)) {
return;
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php
index 977be9162c636..b828c5acfd91b 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php
@@ -65,6 +65,18 @@ public function __construct($testCase, $rootConfig, $environment, $debug)
parent::__construct($environment, $debug);
}
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ if (null === $this->name) {
+ $this->name = parent::getName().md5($this->rootConfig);
+ }
+
+ return $this->name;
+ }
+
public function registerBundles()
{
if (!is_file($filename = $this->getRootDir().'/'.$this->testCase.'/bundles.php')) {
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Profiler/TemplateManagerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Profiler/TemplateManagerTest.php
index 5c8a3becb8326..29238a21c439b 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Profiler/TemplateManagerTest.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Profiler/TemplateManagerTest.php
@@ -48,9 +48,9 @@ protected function setUp()
$profiler = $this->mockProfiler();
$twigEnvironment = $this->mockTwigEnvironment();
$templates = array(
- 'data_collector.foo' => array('foo','FooBundle:Collector:foo'),
- 'data_collector.bar' => array('bar','FooBundle:Collector:bar'),
- 'data_collector.baz' => array('baz','FooBundle:Collector:baz'),
+ 'data_collector.foo' => array('foo', 'FooBundle:Collector:foo'),
+ 'data_collector.bar' => array('bar', 'FooBundle:Collector:bar'),
+ 'data_collector.baz' => array('baz', 'FooBundle:Collector:baz'),
);
$this->templateManager = new TemplateManager($profiler, $twigEnvironment, $templates);
diff --git a/src/Symfony/Component/Asset/Package.php b/src/Symfony/Component/Asset/Package.php
index 43bdcf21db68a..77b1c934eb172 100644
--- a/src/Symfony/Component/Asset/Package.php
+++ b/src/Symfony/Component/Asset/Package.php
@@ -60,6 +60,9 @@ protected function getContext()
return $this->context;
}
+ /**
+ * @return VersionStrategyInterface
+ */
protected function getVersionStrategy()
{
return $this->versionStrategy;
diff --git a/src/Symfony/Component/Asset/UrlPackage.php b/src/Symfony/Component/Asset/UrlPackage.php
index 6381a9c1cdbdf..3626ec843c48b 100644
--- a/src/Symfony/Component/Asset/UrlPackage.php
+++ b/src/Symfony/Component/Asset/UrlPackage.php
@@ -39,10 +39,11 @@ class UrlPackage extends Package
private $sslPackage;
/**
- * @param string|array $baseUrls Base asset URLs
+ * @param string|string[] $baseUrls Base asset URLs
* @param VersionStrategyInterface $versionStrategy The version strategy
+ * @param ContextInterface|null $context Context
*/
- public function __construct($baseUrls = array(), VersionStrategyInterface $versionStrategy, ContextInterface $context = null)
+ public function __construct($baseUrls, VersionStrategyInterface $versionStrategy, ContextInterface $context = null)
{
parent::__construct($versionStrategy, $context);
diff --git a/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
index 6028eb57fe5dd..857cf9432bfa3 100644
--- a/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
+++ b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
@@ -21,6 +21,10 @@ class StaticVersionStrategy implements VersionStrategyInterface
private $version;
private $format;
+ /**
+ * @param string $version Version number
+ * @param string $format Url format
+ */
public function __construct($version, $format = null)
{
$this->version = $version;
diff --git a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php
index 36a0fbc6ee26b..fe0037638547a 100644
--- a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php
+++ b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php
@@ -624,4 +624,24 @@ public function testSetServerParameterInRequest()
$this->assertArrayHasKey('HTTPS', $server);
$this->assertFalse($server['HTTPS']);
}
+
+ public function testInternalRequest()
+ {
+ $client = new TestClient();
+
+ $client->request('GET', 'https://www.example.com/https/www.example.com', array(), array(), array(
+ 'HTTP_HOST' => 'testhost',
+ 'HTTP_USER_AGENT' => 'testua',
+ 'HTTPS' => false,
+ 'NEW_SERVER_KEY' => 'new-server-key-value',
+ ));
+
+ $this->assertInstanceOf('Symfony\Component\BrowserKit\Request', $client->getInternalRequest());
+ }
+
+ public function testInternalRequestNull()
+ {
+ $client = new TestClient();
+ $this->assertNull($client->getInternalRequest());
+ }
}
diff --git a/src/Symfony/Component/BrowserKit/Tests/CookieJarTest.php b/src/Symfony/Component/BrowserKit/Tests/CookieJarTest.php
index 4da4404e24949..54a84b43a463b 100644
--- a/src/Symfony/Component/BrowserKit/Tests/CookieJarTest.php
+++ b/src/Symfony/Component/BrowserKit/Tests/CookieJarTest.php
@@ -174,6 +174,16 @@ public function testCookieExpireWithNullPaths()
$this->assertEquals(array(), array_keys($cookieJar->allValues('http://example.com/')));
}
+ public function testCookieExpireWithDomain()
+ {
+ $cookieJar = new CookieJar();
+ $cookieJar->set($cookie1 = new Cookie('foo', 'bar1', null, '/foo', 'http://example2.com/'));
+ $cookieJar->expire('foo', '/foo', 'http://example2.com/');
+
+ $this->assertNull($cookieJar->get('foo'), '->get() returns null if the cookie is expired');
+ $this->assertEquals(array(), array_keys($cookieJar->allValues('http://example2.com/')));
+ }
+
public function testCookieWithSameNameButDifferentPaths()
{
$cookieJar = new CookieJar();
@@ -207,6 +217,14 @@ public function testCookieGetWithSubdomain()
$this->assertEquals($cookie2, $cookieJar->get('foo1', '/', 'test.example.com'));
}
+ public function testCookieGetWithWrongSubdomain()
+ {
+ $cookieJar = new CookieJar();
+ $cookieJar->set($cookie1 = new Cookie('foo1', 'bar', null, '/', 'test.example.com'));
+
+ $this->assertNull($cookieJar->get('foo1', '/', 'foo.example.com'));
+ }
+
public function testCookieGetWithSubdirectory()
{
$cookieJar = new CookieJar();
diff --git a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php
index e1dd0df2c1533..61b364e6d1eac 100644
--- a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php
+++ b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php
@@ -176,4 +176,13 @@ public function testIsExpired()
$cookie = new Cookie('foo', 'bar', 0);
$this->assertFalse($cookie->isExpired());
}
+
+ /**
+ * @expectedException UnexpectedValueException
+ * @expectedExceptionMessage The cookie expiration time "string" is not valid.
+ */
+ public function testConstructException()
+ {
+ $cookie = new Cookie('foo', 'bar', 'string');
+ }
}
diff --git a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php
index c7dc3ae12e0f0..e33bcbbbc6274 100644
--- a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php
+++ b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php
@@ -137,8 +137,8 @@ public static function load($classes, $cacheDir, $name, $autoReload, $adaptive =
public static function fixNamespaceDeclarations($source)
{
if (!function_exists('token_get_all') || !self::$useTokenizer) {
- if (preg_match('/namespace(.*?)\s*;/', $source)) {
- $source = preg_replace('/namespace(.*?)\s*;/', "namespace$1\n{", $source)."}\n";
+ if (preg_match('/(^|\s)namespace(.*?)\s*;/', $source)) {
+ $source = preg_replace('/(^|\s)namespace(.*?)\s*;/', "$1namespace$2\n{", $source)."}\n";
}
return $source;
diff --git a/src/Symfony/Component/ClassLoader/ClassLoader.php b/src/Symfony/Component/ClassLoader/ClassLoader.php
index fc0a569485bd4..a506dc0941946 100644
--- a/src/Symfony/Component/ClassLoader/ClassLoader.php
+++ b/src/Symfony/Component/ClassLoader/ClassLoader.php
@@ -97,7 +97,7 @@ public function addPrefix($prefix, $paths)
$paths
));
} elseif (!in_array($paths, $this->prefixes[$prefix])) {
- $this->prefixes[$prefix][] = $paths;
+ $this->prefixes[$prefix][] = $paths;
}
} else {
$this->prefixes[$prefix] = array_unique((array) $paths);
diff --git a/src/Symfony/Component/ClassLoader/Tests/ClassCollectionLoaderTest.php b/src/Symfony/Component/ClassLoader/Tests/ClassCollectionLoaderTest.php
index 2d78941538191..5019f26ee84c8 100644
--- a/src/Symfony/Component/ClassLoader/Tests/ClassCollectionLoaderTest.php
+++ b/src/Symfony/Component/ClassLoader/Tests/ClassCollectionLoaderTest.php
@@ -205,7 +205,7 @@ public function getFixNamespaceDeclarationsDataWithoutTokenizer()
array("namespace Bar ;\nclass Foo {}\n", "namespace Bar\n{\nclass Foo {}\n}\n"),
array("namespace Foo\Bar;\nclass Foo {}\n", "namespace Foo\Bar\n{\nclass Foo {}\n}\n"),
array("namespace Foo\Bar\Bar\n{\nclass Foo {}\n}\n", "namespace Foo\Bar\Bar\n{\nclass Foo {}\n}\n"),
- array("namespace\n{\nclass Foo {}\n}\n", "namespace\n{\nclass Foo {}\n}\n"),
+ array("\nnamespace\n{\nclass Foo {}\n\$namespace=123;}\n", "\nnamespace\n{\nclass Foo {}\n\$namespace=123;}\n"),
);
}
diff --git a/src/Symfony/Component/Config/Definition/ArrayNode.php b/src/Symfony/Component/Config/Definition/ArrayNode.php
index 05ae1fdcd99e1..751aee12278ed 100644
--- a/src/Symfony/Component/Config/Definition/ArrayNode.php
+++ b/src/Symfony/Component/Config/Definition/ArrayNode.php
@@ -55,14 +55,17 @@ protected function preNormalize($value)
return $value;
}
+ $normalized = array();
+
foreach ($value as $k => $v) {
if (false !== strpos($k, '-') && false === strpos($k, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) {
- $value[$normalizedKey] = $v;
- unset($value[$k]);
+ $normalized[$normalizedKey] = $v;
+ } else {
+ $normalized[$k] = $v;
}
}
- return $value;
+ return $normalized;
}
/**
diff --git a/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php b/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php
index 291c2fd2cce06..652a153a3d604 100644
--- a/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php
+++ b/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php
@@ -74,6 +74,10 @@ public function getPreNormalizationTests()
array('foo-bar_moo' => 'foo'),
array('foo-bar_moo' => 'foo'),
),
+ array(
+ array('anything-with-dash-and-no-underscore' => 'first', 'no_dash' => 'second'),
+ array('anything_with_dash_and_no_underscore' => 'first', 'no_dash' => 'second'),
+ ),
array(
array('foo-bar' => null, 'foo_bar' => 'foo'),
array('foo-bar' => null, 'foo_bar' => 'foo'),
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index e011beecac95e..9076fbbbbf91b 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -631,6 +631,8 @@ public function asXml($namespace = null, $asDom = false)
*/
public function renderException($e, $output)
{
+ $output->writeln('');
+
do {
$title = sprintf(' [%s] ', get_class($e));
@@ -653,7 +655,7 @@ public function renderException($e, $output)
}
}
- $messages = array('', '');
+ $messages = array();
$messages[] = $emptyLine = $formatter->format(sprintf('%s', str_repeat(' ', $len)));
$messages[] = $formatter->format(sprintf('%s%s', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title)))));
foreach ($lines as $line) {
@@ -661,7 +663,6 @@ public function renderException($e, $output)
}
$messages[] = $emptyLine;
$messages[] = '';
- $messages[] = '';
$output->writeln($messages, OutputInterface::OUTPUT_RAW);
@@ -688,14 +689,12 @@ public function renderException($e, $output)
}
$output->writeln('');
- $output->writeln('');
}
} while ($e = $e->getPrevious());
if (null !== $this->runningCommand) {
$output->writeln(sprintf('%s', sprintf($this->runningCommand->getSynopsis(), $this->getName())));
$output->writeln('');
- $output->writeln('');
}
}
diff --git a/src/Symfony/Component/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Console/Descriptor/TextDescriptor.php
index 57e09e4d81c36..f2895bd8e4d17 100644
--- a/src/Symfony/Component/Console/Descriptor/TextDescriptor.php
+++ b/src/Symfony/Component/Console/Descriptor/TextDescriptor.php
@@ -236,10 +236,10 @@ private function writeText($content, array $options = array())
private function formatDefaultValue($default)
{
if (PHP_VERSION_ID < 50400) {
- return str_replace('\/', '/', json_encode($default));
+ return str_replace(array('\/', '\\\\'), array('/', '\\'), json_encode($default));
}
- return json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+ return str_replace('\\\\', '\\', json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
}
/**
diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php
index 0b64b18a1db06..016e885f4b288 100644
--- a/src/Symfony/Component/Console/Helper/ProgressBar.php
+++ b/src/Symfony/Component/Console/Helper/ProgressBar.php
@@ -67,10 +67,8 @@ public function __construct(OutputInterface $output, $max = 0)
// disable overwrite when output does not support ANSI codes.
$this->overwrite = false;
- if ($this->max > 10) {
- // set a reasonable redraw frequency so output isn't flooded
- $this->setRedrawFrequency($max / 10);
- }
+ // set a reasonable redraw frequency so output isn't flooded
+ $this->setRedrawFrequency($max / 10);
}
$this->startTime = time();
@@ -316,11 +314,11 @@ public function setFormat($format)
/**
* Sets the redraw frequency.
*
- * @param int $freq The frequency in steps
+ * @param int|float $freq The frequency in steps
*/
public function setRedrawFrequency($freq)
{
- $this->redrawFreq = (int) $freq;
+ $this->redrawFreq = max((int) $freq, 1);
}
/**
diff --git a/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php b/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php
index 77130f9776ac2..dc2141e99f8ee 100644
--- a/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php
+++ b/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php
@@ -32,7 +32,7 @@ public function ask(InputInterface $input, OutputInterface $output, Question $qu
{
$validator = $question->getValidator();
$question->setValidator(function ($value) use ($validator) {
- if (null !== $validator && is_callable($validator)) {
+ if (null !== $validator) {
$value = $validator($value);
}
diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php
index 6f5fbd047cee7..3823e9c4f61ca 100644
--- a/src/Symfony/Component/Console/Helper/Table.php
+++ b/src/Symfony/Component/Console/Helper/Table.php
@@ -332,7 +332,7 @@ private function calculateNumberOfColumns()
$columns[] = $this->getNumberOfColumns($row);
}
- return $this->numberOfColumns = max($columns);
+ $this->numberOfColumns = max($columns);
}
private function buildTableRows($rows)
@@ -343,7 +343,6 @@ private function buildTableRows($rows)
// Remove any new line breaks and replace it with a new line
foreach ($rows[$rowKey] as $column => $cell) {
- $rows[$rowKey] = $this->fillCells($rows[$rowKey], $column);
if (!strstr($cell, "\n")) {
continue;
}
@@ -363,7 +362,7 @@ private function buildTableRows($rows)
$tableRows = array();
foreach ($rows as $rowKey => $row) {
- $tableRows[] = $row;
+ $tableRows[] = $this->fillCells($row);
if (isset($unmergedRows[$rowKey])) {
$tableRows = array_merge($tableRows, $unmergedRows[$rowKey]);
}
@@ -429,21 +428,23 @@ private function fillNextRows($rows, $line)
* fill cells for a row that contains colspan > 1.
*
* @param array $row
- * @param int $column
*
* @return array
*/
- private function fillCells($row, $column)
+ private function fillCells($row)
{
- $cell = $row[$column];
- if ($cell instanceof TableCell && $cell->getColspan() > 1) {
- foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
- // insert empty value into rows at column position
- array_splice($row, $position, 0, '');
+ $newRow = array();
+ foreach ($row as $column => $cell) {
+ $newRow[] = $cell;
+ if ($cell instanceof TableCell && $cell->getColspan() > 1) {
+ foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
+ // insert empty value at column position
+ $newRow[] = '';
+ }
}
}
- return $row;
+ return $newRow ?: $row;
}
/**
@@ -487,7 +488,7 @@ private function getNumberOfColumns(array $row)
*
* @param array $row
*
- * @return array()
+ * @return array
*/
private function getRowColumns($row)
{
@@ -529,8 +530,6 @@ private function getColumnWidth($column)
/**
* Gets column width.
*
- * @param int $column
- *
* @return int
*/
private function getColumnSeparatorWidth()
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception1.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception1.txt
index 4629345c1e13c..c56f4b603341e 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception1.txt
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception1.txt
@@ -1,8 +1,6 @@
-
[InvalidArgumentException]
Command "foo" is not defined.
-
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception2.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception2.txt
index 3d9d363b69897..58cd420f93c16 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception2.txt
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception2.txt
@@ -1,11 +1,8 @@
-
[InvalidArgumentException]
The "--foo" option does not exist.
-
list [--xml] [--raw] [--format FORMAT] [--] []
-
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt
index 72a72867f3fd7..8276137bd886a 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt
@@ -1,27 +1,18 @@
-
[Exception]
Third exception comment
-
-
-
[Exception]
Second exception comment
-
-
-
[Exception]
First exception this is html
-
foo3:bar
-
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3decorated.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3decorated.txt
index b44d50b0ed04f..b4a7b018af377 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3decorated.txt
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3decorated.txt
@@ -1,27 +1,18 @@
-
[37;41m [39;49m
[37;41m [Exception] [39;49m
[37;41m Third exception [39;49m[34;41mcomment[39;49m[37;41m [39;49m
[37;41m [39;49m
-
-
-
[37;41m [39;49m
[37;41m [Exception] [39;49m
[37;41m Second exception [39;49m[33mcomment[39m[37;41m [39;49m
[37;41m [39;49m
-
-
-
[37;41m [39;49m
[37;41m [Exception] [39;49m
[37;41m First exception [39;49m[37;41m[39;49m[37;41mthis is html[39;49m[37;41m
[39;49m[37;41m [39;49m
[37;41m [39;49m
-
[32mfoo3:bar[39m
-
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception4.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception4.txt
index 19f893b0c8528..9d881e7d0fe2b 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception4.txt
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception4.txt
@@ -1,9 +1,7 @@
-
[InvalidArgumentException]
Command "foo" is not define
d.
-
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1.txt
index 6a98660364219..1ba5f8fdd914d 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1.txt
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1.txt
@@ -1,11 +1,8 @@
-
[Exception]
エラーメッセージ
-
foo
-
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1decorated.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1decorated.txt
index 8c8801b13ff2b..20644251c2f9b 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1decorated.txt
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth1decorated.txt
@@ -1,11 +1,8 @@
-
[37;41m [39;49m
[37;41m [Exception] [39;49m
[37;41m エラーメッセージ [39;49m
[37;41m [39;49m
-
[32mfoo[39m
-
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth2.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth2.txt
index 545cd7b0b49f9..e41fcfcf675af 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth2.txt
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_doublewidth2.txt
@@ -1,12 +1,9 @@
-
[Exception]
コマンドの実行中にエラーが
発生しました。
-
foo
-
diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
index e22734a29e8ef..ffe5bed086348 100644
--- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
@@ -296,7 +296,7 @@ public function testRegressProgress()
public function testRedrawFrequency()
{
- $bar = $this->getMock('Symfony\Component\Console\Helper\ProgressBar', array('display'), array($output = $this->getOutputStream(), 6));
+ $bar = $this->getMock('Symfony\Component\Console\Helper\ProgressBar', array('display'), array($this->getOutputStream(), 6));
$bar->expects($this->exactly(4))->method('display');
$bar->setRedrawFrequency(2);
@@ -307,6 +307,26 @@ public function testRedrawFrequency()
$bar->advance(1);
}
+ public function testRedrawFrequencyIsAtLeastOneIfZeroGiven()
+ {
+ $bar = $this->getMock('Symfony\Component\Console\Helper\ProgressBar', array('display'), array($this->getOutputStream()));
+
+ $bar->expects($this->exactly(2))->method('display');
+ $bar->setRedrawFrequency(0);
+ $bar->start();
+ $bar->advance();
+ }
+
+ public function testRedrawFrequencyIsAtLeastOneIfSmallerOneGiven()
+ {
+ $bar = $this->getMock('Symfony\Component\Console\Helper\ProgressBar', array('display'), array($this->getOutputStream()));
+
+ $bar->expects($this->exactly(2))->method('display');
+ $bar->setRedrawFrequency(0.9);
+ $bar->start();
+ $bar->advance();
+ }
+
/**
* @requires extension mbstring
*/
diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php
index 19bdf00e0662d..ab562fdb57708 100644
--- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php
@@ -459,6 +459,24 @@ public function testRenderProvider()
| ISBN | Title | Author |
+------+-------+--------+
+TABLE
+ ),
+ 'Row with multiple cells' => array(
+ array(),
+ array(
+ array(
+ new TableCell('1', array('colspan' => 3)),
+ new TableCell('2', array('colspan' => 2)),
+ new TableCell('3', array('colspan' => 2)),
+ new TableCell('4', array('colspan' => 2)),
+ ),
+ ),
+ 'default',
+<<tokenize() parses quoted arguments'),
array("'quoted'", array('quoted'), '->tokenize() parses quoted arguments'),
array("'a\rb\nc\td'", array("a\rb\nc\td"), '->tokenize() parses whitespace chars in strings'),
- array("'a'\r'b'\n'c'\t'd'", array('a','b','c','d'), '->tokenize() parses whitespace chars between args as spaces'),
+ array("'a'\r'b'\n'c'\t'd'", array('a', 'b', 'c', 'd'), '->tokenize() parses whitespace chars between args as spaces'),
array('\"quoted\"', array('"quoted"'), '->tokenize() parses escaped-quoted arguments'),
array("\'quoted\'", array('\'quoted\''), '->tokenize() parses escaped-quoted arguments'),
array('-a', array('-a'), '->tokenize() parses short options'),
diff --git a/src/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php b/src/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
index 1db6a591a2f5c..6d24789320561 100644
--- a/src/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
+++ b/src/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
@@ -29,7 +29,7 @@ public function getSpecificityValueTestData()
return array(
array(new ElementNode(), 0),
array(new ElementNode(null, 'element'), 1),
- array(new ElementNode('namespace', 'element'),1),
+ array(new ElementNode('namespace', 'element'), 1),
);
}
}
diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php
index 8c797744d7b05..95ccc8798e8c1 100644
--- a/src/Symfony/Component/Debug/DebugClassLoader.php
+++ b/src/Symfony/Component/Debug/DebugClassLoader.php
@@ -147,7 +147,7 @@ public function loadClass($class)
try {
if ($this->isFinder) {
if ($file = $this->classLoader[0]->findFile($class)) {
- require $file;
+ require_once $file;
}
} else {
call_user_func($this->classLoader, $class);
diff --git a/src/Symfony/Component/Debug/Exception/FlattenException.php b/src/Symfony/Component/Debug/Exception/FlattenException.php
index d8d5c5b9214d5..33c9becf35f6f 100644
--- a/src/Symfony/Component/Debug/Exception/FlattenException.php
+++ b/src/Symfony/Component/Debug/Exception/FlattenException.php
@@ -94,8 +94,13 @@ public static function create(\Exception $exception, $statusCode = null, array $
$e->setClass(get_class($exception));
$e->setFile($exception->getFile());
$e->setLine($exception->getLine());
- if ($exception->getPrevious()) {
- $e->setPrevious(static::create($exception->getPrevious()));
+
+ $previous = $exception->getPrevious();
+
+ if ($previous instanceof \Exception) {
+ $e->setPrevious(static::create($previous));
+ } elseif ($previous instanceof \Throwable) {
+ $e->setPrevious(static::create(new FatalThrowableError($previous)));
}
return $e;
diff --git a/src/Symfony/Component/Debug/README.md b/src/Symfony/Component/Debug/README.md
index 67e6d6c2785c6..82c6e30322de4 100644
--- a/src/Symfony/Component/Debug/README.md
+++ b/src/Symfony/Component/Debug/README.md
@@ -15,6 +15,7 @@ Debug::enable();
You can also use the tools individually:
```php
+use Symfony\Component\Debug\DebugClassLoader;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
@@ -25,11 +26,9 @@ if ('cli' !== php_sapi_name()) {
ini_set('display_errors', 1);
}
ErrorHandler::register();
+DebugClassLoader::enable();
```
-Note that the `Debug::enable()` call also registers the debug class loader
-from the Symfony ClassLoader component when available.
-
This component can optionally take advantage of the features of the HttpKernel
and HttpFoundation components.
diff --git a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php
index 99eaf497d5b4d..6c570e235def7 100644
--- a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php
+++ b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php
@@ -131,6 +131,20 @@ public function testPrevious(\Exception $exception, $statusCode)
$this->assertSame(array($flattened2), $flattened->getAllPrevious());
}
+ /**
+ * @requires PHP 7.0
+ */
+ public function testPreviousError()
+ {
+ $exception = new \Exception('test', 123, new \ParseError('Oh noes!', 42));
+
+ $flattened = FlattenException::create($exception)->getPrevious();
+
+ $this->assertEquals($flattened->getMessage(), 'Parse error: Oh noes!', 'The message is copied from the original exception.');
+ $this->assertEquals($flattened->getCode(), 42, 'The code is copied from the original exception.');
+ $this->assertEquals($flattened->getClass(), 'Symfony\Component\Debug\Exception\FatalThrowableError', 'The class is set to the class of the original exception');
+ }
+
/**
* @dataProvider flattenDataProvider
*/
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php
index 972d708c593c9..8308937d4a512 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php
@@ -45,7 +45,7 @@ public function process(ContainerBuilder $container)
try {
$definition = $container->getDefinition($aliasId);
} catch (InvalidArgumentException $e) {
- throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with "%s".', $alias, $id), null, $e);
+ throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $id, $alias), null, $e);
}
if ($definition->isPublic()) {
diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php
index 510d030517948..355ba26f243d9 100644
--- a/src/Symfony/Component/DependencyInjection/Container.php
+++ b/src/Symfony/Component/DependencyInjection/Container.php
@@ -305,10 +305,7 @@ public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE
$service = $this->$method();
} catch (\Exception $e) {
unset($this->loading[$id]);
-
- if (array_key_exists($id, $this->services)) {
- unset($this->services[$id]);
- }
+ unset($this->services[$id]);
if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
return;
diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php
index 777f4a60548a0..74da38203cf75 100644
--- a/src/Symfony/Component/DependencyInjection/Definition.php
+++ b/src/Symfony/Component/DependencyInjection/Definition.php
@@ -495,9 +495,7 @@ public function hasTag($name)
*/
public function clearTag($name)
{
- if (isset($this->tags[$name])) {
- unset($this->tags[$name]);
- }
+ unset($this->tags[$name]);
return $this;
}
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index bb3df8bef1580..d4010f1f1a199 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -759,6 +759,10 @@ private function addNewInstance($id, Definition $definition, $return, $instantia
if (null !== $definition->getFactory()) {
$callable = $definition->getFactory();
if (is_array($callable)) {
+ if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) {
+ throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $callable[1] ?: 'n/a'));
+ }
+
if ($callable[0] instanceof Reference
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '');
@@ -1310,8 +1314,12 @@ private function dumpValue($value, $interpolate = true)
}
if (is_array($factory)) {
+ if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $factory[1])) {
+ throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $factory[1] ?: 'n/a'));
+ }
+
if (is_string($factory[0])) {
- return sprintf('\\%s::%s(%s)', $factory[0], $factory[1], implode(', ', $arguments));
+ return sprintf('%s::%s(%s)', $this->dumpLiteralClass($this->dumpValue($factory[0])), $factory[1], implode(', ', $arguments));
}
if ($factory[0] instanceof Definition) {
@@ -1342,12 +1350,8 @@ private function dumpValue($value, $interpolate = true)
if (null === $class) {
throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
}
- $class = $this->dumpValue($class);
- if (false !== strpos($class, '$')) {
- throw new RuntimeException('Cannot dump definitions which have a variable class name.');
- }
- return sprintf('new \\%s(%s)', substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
+ return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments));
} elseif ($value instanceof Variable) {
return '$'.$value;
} elseif ($value instanceof Reference) {
@@ -1388,9 +1392,18 @@ private function dumpValue($value, $interpolate = true)
* @param string $class
*
* @return string
+ *
+ * @throws RuntimeException
*/
private function dumpLiteralClass($class)
{
+ if (false !== strpos($class, '$')) {
+ throw new RuntimeException('Cannot dump definitions which have a variable class name.');
+ }
+ if (0 !== strpos($class, "'") || !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
+ throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s)', $class ?: 'n/a'));
+ }
+
return '\\'.substr(str_replace('\\\\', '\\', $class), 1, -1);
}
diff --git a/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php b/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php
index 1fd1baa477137..6e926fa7a8adc 100644
--- a/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php
+++ b/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php
@@ -23,12 +23,12 @@ interface ExtensionInterface
/**
* Loads a specific configuration.
*
- * @param array $config An array of configuration values
+ * @param array $configs An array of configuration values
* @param ContainerBuilder $container A ContainerBuilder instance
*
* @throws \InvalidArgumentException When provided tag is not defined in this extension
*/
- public function load(array $config, ContainerBuilder $container);
+ public function load(array $configs, ContainerBuilder $container);
/**
* Returns the namespace to be used for this extension (XML namespace).
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index 063007e5d34e3..7207a143e6f66 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -154,6 +154,31 @@ public function testAddServiceInvalidServiceId()
$dumper->dump();
}
+ /**
+ * @dataProvider provideInvalidFactories
+ * @expectedException Symfony\Component\DependencyInjection\Exception\RuntimeException
+ * @expectedExceptionMessage Cannot dump definition
+ */
+ public function testInvalidFactories($factory)
+ {
+ $container = new ContainerBuilder();
+ $def = new Definition('stdClass');
+ $def->setFactory($factory);
+ $container->setDefinition('bar', $def);
+ $dumper = new PhpDumper($container);
+ $dumper->dump();
+ }
+
+ public function provideInvalidFactories()
+ {
+ return array(
+ array(array('', 'method')),
+ array(array('class', '')),
+ array(array('...', 'method')),
+ array(array('class', '...')),
+ );
+ }
+
public function testAliases()
{
$container = include self::$fixturesPath.'/containers/container9.php';
diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php
index 93a1f0de4c530..a883fcafa60ab 100644
--- a/src/Symfony/Component/Filesystem/Filesystem.php
+++ b/src/Symfony/Component/Filesystem/Filesystem.php
@@ -192,12 +192,12 @@ public function remove($files)
public function chmod($files, $mode, $umask = 0000, $recursive = false)
{
foreach ($this->toIterator($files) as $file) {
- if ($recursive && is_dir($file) && !is_link($file)) {
- $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
- }
if (true !== @chmod($file, $mode & ~$umask)) {
throw new IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
}
+ if ($recursive && is_dir($file) && !is_link($file)) {
+ $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
+ }
}
}
@@ -443,13 +443,13 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o
*/
public function isAbsolutePath($file)
{
- return (strspn($file, '/\\', 0, 1)
+ return strspn($file, '/\\', 0, 1)
|| (strlen($file) > 3 && ctype_alpha($file[0])
&& substr($file, 1, 1) === ':'
&& (strspn($file, '/\\', 2, 1))
)
|| null !== parse_url($file, PHP_URL_SCHEME)
- );
+ ;
}
/**
diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
index 45254c3c712e6..80a17cae35620 100644
--- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
+++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
@@ -483,6 +483,22 @@ public function testChmodChangesModeOfTraversableFileObject()
$this->assertFilePermissions(753, $directory);
}
+ public function testChmodChangesZeroModeOnSubdirectoriesOnRecursive()
+ {
+ $this->markAsSkippedIfChmodIsMissing();
+
+ $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
+ $subdirectory = $directory.DIRECTORY_SEPARATOR.'subdirectory';
+
+ mkdir($directory);
+ mkdir($subdirectory);
+ chmod($subdirectory, 0000);
+
+ $this->filesystem->chmod($directory, 0753, 0000, true);
+
+ $this->assertFilePermissions(753, $subdirectory);
+ }
+
public function testChown()
{
$this->markAsSkippedIfPosixIsMissing();
diff --git a/src/Symfony/Component/Finder/Iterator/SortableIterator.php b/src/Symfony/Component/Finder/Iterator/SortableIterator.php
index b32ac8d6df4bb..fa3458077acf1 100644
--- a/src/Symfony/Component/Finder/Iterator/SortableIterator.php
+++ b/src/Symfony/Component/Finder/Iterator/SortableIterator.php
@@ -55,15 +55,15 @@ public function __construct(\Traversable $iterator, $sort)
};
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
$this->sort = function ($a, $b) {
- return ($a->getATime() - $b->getATime());
+ return $a->getATime() - $b->getATime();
};
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
$this->sort = function ($a, $b) {
- return ($a->getCTime() - $b->getCTime());
+ return $a->getCTime() - $b->getCTime();
};
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
$this->sort = function ($a, $b) {
- return ($a->getMTime() - $b->getMTime());
+ return $a->getMTime() - $b->getMTime();
};
} elseif (is_callable($sort)) {
$this->sort = $sort;
diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php
index 156735b81751e..b1e6b3bf06b5c 100644
--- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php
+++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php
@@ -74,6 +74,12 @@ public function __construct($choices, $value = null)
$choices = iterator_to_array($choices);
}
+ if (null === $value && $this->castableToString($choices)) {
+ $value = function ($choice) {
+ return (string) $choice;
+ };
+ }
+
if (null !== $value) {
// If a deterministic value generator was passed, use it later
$this->valueCallback = $value;
@@ -207,4 +213,35 @@ protected function flatten(array $choices, $value, &$choicesByValues, &$keysByVa
$structuredValues[$key] = $choiceValue;
}
}
+
+ /**
+ * Checks whether the given choices can be cast to strings without
+ * generating duplicates.
+ *
+ * @param array $choices The choices.
+ * @param array|null $cache The cache for previously checked entries. Internal
+ *
+ * @return bool Returns true if the choices can be cast to strings and
+ * false otherwise.
+ */
+ private function castableToString(array $choices, array &$cache = array())
+ {
+ foreach ($choices as $choice) {
+ if (is_array($choice)) {
+ if (!$this->castableToString($choice, $cache)) {
+ return false;
+ }
+
+ continue;
+ } elseif (!is_scalar($choice)) {
+ return false;
+ } elseif (isset($cache[(string) $choice])) {
+ return false;
+ }
+
+ $cache[(string) $choice] = true;
+ }
+
+ return true;
+ }
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
index 528834d1e3cb8..1465551b906a6 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -238,6 +238,7 @@ public function finishView(FormView $view, FormInterface $form, array $options)
*/
public function configureOptions(OptionsResolver $resolver)
{
+ $choiceLabels = (object) array('labels' => array());
$choiceListFactory = $this->choiceListFactory;
$emptyData = function (Options $options) {
@@ -252,6 +253,45 @@ public function configureOptions(OptionsResolver $resolver)
return $options['required'] ? null : '';
};
+ // BC closure, to be removed in 3.0
+ $choicesNormalizer = function (Options $options, $choices) use ($choiceLabels) {
+ // Unset labels from previous invocations
+ $choiceLabels->labels = array();
+
+ // This closure is irrelevant when "choices_as_values" is set to true
+ if ($options['choices_as_values']) {
+ return $choices;
+ }
+
+ ChoiceType::normalizeLegacyChoices($choices, $choiceLabels);
+
+ return $choices;
+ };
+
+ // BC closure, to be removed in 3.0
+ $choiceLabel = function (Options $options) use ($choiceLabels) {
+ // If the choices contain duplicate labels, the normalizer of the
+ // "choices" option stores them in the $choiceLabels variable
+
+ // Trigger the normalizer
+ $options->offsetGet('choices');
+
+ // Pick labels from $choiceLabels if available
+ if ($choiceLabels->labels) {
+ // Don't pass the labels by reference. We do want to create a
+ // copy here so that every form has an own version of that
+ // variable (contrary to the $choiceLabels object shared by all
+ // forms)
+ $labels = $choiceLabels->labels;
+
+ return function ($choice, $key) use ($labels) {
+ return $labels[$key];
+ };
+ }
+
+ return;
+ };
+
$choiceListNormalizer = function (Options $options, $choiceList) use ($choiceListFactory) {
if ($choiceList) {
@trigger_error('The "choice_list" option is deprecated since version 2.7 and will be removed in 3.0. Use "choice_loader" instead.', E_USER_DEPRECATED);
@@ -322,7 +362,7 @@ public function configureOptions(OptionsResolver $resolver)
'choices' => array(),
'choices_as_values' => false,
'choice_loader' => null,
- 'choice_label' => null,
+ 'choice_label' => $choiceLabel,
'choice_name' => null,
'choice_value' => null,
'choice_attr' => null,
@@ -340,6 +380,7 @@ public function configureOptions(OptionsResolver $resolver)
'choice_translation_domain' => true,
));
+ $resolver->setNormalizer('choices', $choicesNormalizer);
$resolver->setNormalizer('choice_list', $choiceListNormalizer);
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
$resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer);
@@ -454,4 +495,34 @@ private function createChoiceListView(ChoiceListInterface $choiceList, array $op
$options['choice_attr']
);
}
+
+ /**
+ * When "choices_as_values" is set to false, the choices are in the keys and
+ * their labels in the values. Labels may occur twice. The form component
+ * flips the choices array in the new implementation, so duplicate labels
+ * are lost. Store them in a utility array that is used from the
+ * "choice_label" closure by default.
+ *
+ * @param array $choices The choice labels indexed by choices.
+ * Labels are replaced by generated keys.
+ * @param object $choiceLabels The object that receives the choice labels
+ * indexed by generated keys.
+ * @param int $nextKey The next generated key.
+ *
+ * @internal Public only to be accessible from closures on PHP 5.3. Don't
+ * use this method as it may be removed without notice and will be in 3.0.
+ */
+ public static function normalizeLegacyChoices(array &$choices, $choiceLabels, &$nextKey = 0)
+ {
+ foreach ($choices as $choice => $choiceLabel) {
+ if (is_array($choiceLabel)) {
+ $choiceLabel = ''; // Dereference $choices[$choice]
+ self::normalizeLegacyChoices($choices[$choice], $choiceLabels, $nextKey);
+ continue;
+ }
+
+ $choiceLabels->labels[$nextKey] = $choiceLabel;
+ $choices[$choice] = $nextKey++;
+ }
+ }
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php b/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php
index 599aa457b7343..8caacb2dc539d 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php
@@ -28,6 +28,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['allow_add'] && $options['prototype']) {
$prototype = $builder->create($options['prototype_name'], $options['type'], array_replace(array(
+ 'required' => $options['required'],
'label' => $options['prototype_name'].'label__',
), $options['options']));
$builder->setAttribute('prototype', $prototype->getForm());
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php
index 30ee0a0f9e89c..19395a82fe5af 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php
@@ -23,7 +23,8 @@ class CountryType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
- 'choices' => Intl::getRegionBundle()->getCountryNames(),
+ 'choices' => array_flip(Intl::getRegionBundle()->getCountryNames()),
+ 'choices_as_values' => true,
'choice_translation_domain' => false,
));
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
index b473d139e6566..71b660f9bed63 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
@@ -23,7 +23,8 @@ class CurrencyType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
- 'choices' => Intl::getCurrencyBundle()->getCurrencyNames(),
+ 'choices' => array_flip(Intl::getCurrencyBundle()->getCurrencyNames()),
+ 'choices_as_values' => true,
'choice_translation_domain' => false,
));
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
index fb3e9a7182fc8..b1eb4382ed3ec 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
@@ -88,10 +88,13 @@ public function buildForm(FormBuilderInterface $builder, array $options)
if ('choice' === $options['widget']) {
// Only pass a subset of the options to children
$yearOptions['choices'] = $this->formatTimestamps($formatter, '/y+/', $this->listYears($options['years']));
+ $yearOptions['choices_as_values'] = true;
$yearOptions['placeholder'] = $options['placeholder']['year'];
$monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months']));
+ $monthOptions['choices_as_values'] = true;
$monthOptions['placeholder'] = $options['placeholder']['month'];
$dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days']));
+ $dayOptions['choices_as_values'] = true;
$dayOptions['placeholder'] = $options['placeholder']['day'];
}
@@ -262,6 +265,7 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
{
$pattern = $formatter->getPattern();
$timezone = $formatter->getTimezoneId();
+ $formattedTimestamps = array();
if ($setTimeZone = PHP_VERSION_ID >= 50500 || method_exists($formatter, 'setTimeZone')) {
$formatter->setTimeZone('UTC');
@@ -272,8 +276,8 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
if (preg_match($regex, $pattern, $matches)) {
$formatter->setPattern($matches[0]);
- foreach ($timestamps as $key => $timestamp) {
- $timestamps[$key] = $formatter->format($timestamp);
+ foreach ($timestamps as $timestamp => $choice) {
+ $formattedTimestamps[$formatter->format($timestamp)] = $choice;
}
// I'd like to clone the formatter above, but then we get a
@@ -287,7 +291,7 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
$formatter->setTimeZoneId($timezone);
}
- return $timestamps;
+ return $formattedTimestamps;
}
private function listYears(array $years)
@@ -296,7 +300,7 @@ private function listYears(array $years)
foreach ($years as $year) {
if (false !== $y = gmmktime(0, 0, 0, 6, 15, $year)) {
- $result[$year] = $y;
+ $result[$y] = $year;
}
}
@@ -308,7 +312,7 @@ private function listMonths(array $months)
$result = array();
foreach ($months as $month) {
- $result[$month] = gmmktime(0, 0, 0, $month, 15);
+ $result[gmmktime(0, 0, 0, $month, 15)] = $month;
}
return $result;
@@ -319,7 +323,7 @@ private function listDays(array $days)
$result = array();
foreach ($days as $day) {
- $result[$day] = gmmktime(0, 0, 0, 5, $day);
+ $result[gmmktime(0, 0, 0, 5, $day)] = $day;
}
return $result;
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
index 9d071eb8b03ee..1fc0ed1b676f7 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
@@ -23,7 +23,8 @@ class LanguageType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
- 'choices' => Intl::getLanguageBundle()->getLanguageNames(),
+ 'choices' => array_flip(Intl::getLanguageBundle()->getLanguageNames()),
+ 'choices_as_values' => true,
'choice_translation_domain' => false,
));
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
index f09f5a62f1e29..1631dc431ad7b 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
@@ -23,7 +23,8 @@ class LocaleType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
- 'choices' => Intl::getLocaleBundle()->getLocaleNames(),
+ 'choices' => array_flip(Intl::getLocaleBundle()->getLocaleNames()),
+ 'choices_as_values' => true,
'choice_translation_domain' => false,
));
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
index 8002f0b4ee7c1..57c9a44c8f7e5 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
@@ -58,19 +58,21 @@ public function buildForm(FormBuilderInterface $builder, array $options)
$hours = $minutes = array();
foreach ($options['hours'] as $hour) {
- $hours[$hour] = str_pad($hour, 2, '0', STR_PAD_LEFT);
+ $hours[str_pad($hour, 2, '0', STR_PAD_LEFT)] = $hour;
}
// Only pass a subset of the options to children
$hourOptions['choices'] = $hours;
+ $hourOptions['choices_as_values'] = true;
$hourOptions['placeholder'] = $options['placeholder']['hour'];
if ($options['with_minutes']) {
foreach ($options['minutes'] as $minute) {
- $minutes[$minute] = str_pad($minute, 2, '0', STR_PAD_LEFT);
+ $minutes[str_pad($minute, 2, '0', STR_PAD_LEFT)] = $minute;
}
$minuteOptions['choices'] = $minutes;
+ $minuteOptions['choices_as_values'] = true;
$minuteOptions['placeholder'] = $options['placeholder']['minute'];
}
@@ -78,10 +80,11 @@ public function buildForm(FormBuilderInterface $builder, array $options)
$seconds = array();
foreach ($options['seconds'] as $second) {
- $seconds[$second] = str_pad($second, 2, '0', STR_PAD_LEFT);
+ $seconds[str_pad($second, 2, '0', STR_PAD_LEFT)] = $second;
}
$secondOptions['choices'] = $seconds;
+ $secondOptions['choices_as_values'] = true;
$secondOptions['placeholder'] = $options['placeholder']['second'];
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
index 82c07e2f121ba..13c27f9da8c7f 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
@@ -23,13 +23,21 @@ class TimezoneType extends AbstractType
*/
private static $timezones;
+ /**
+ * Stores the available timezone choices.
+ *
+ * @var array
+ */
+ private static $flippedTimezones;
+
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
- 'choices' => self::getTimezones(),
+ 'choices' => self::getFlippedTimezones(),
+ 'choices_as_values' => true,
'choice_translation_domain' => false,
));
}
@@ -85,4 +93,40 @@ public static function getTimezones()
return static::$timezones;
}
+
+ /**
+ * Returns the timezone choices.
+ *
+ * The choices are generated from the ICU function
+ * \DateTimeZone::listIdentifiers(). They are cached during a single request,
+ * so multiple timezone fields on the same page don't lead to unnecessary
+ * overhead.
+ *
+ * @return array The timezone choices
+ */
+ private static function getFlippedTimezones()
+ {
+ if (null === self::$timezones) {
+ self::$timezones = array();
+
+ foreach (\DateTimeZone::listIdentifiers() as $timezone) {
+ $parts = explode('/', $timezone);
+
+ if (count($parts) > 2) {
+ $region = $parts[0];
+ $name = $parts[1].' - '.$parts[2];
+ } elseif (count($parts) > 1) {
+ $region = $parts[0];
+ $name = $parts[1];
+ } else {
+ $region = 'Other';
+ $name = $parts[0];
+ }
+
+ self::$timezones[$region][str_replace('_', ' ', $name)] = $timezone;
+ }
+ }
+
+ return self::$timezones;
+ }
}
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
index 4fb08772d7de4..d1375df8894b8 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
@@ -217,7 +217,7 @@ public function getData()
return $this->data;
}
- private function recursiveBuildPreliminaryFormTree(FormInterface $form, &$output = null, array &$outputByHash)
+ private function recursiveBuildPreliminaryFormTree(FormInterface $form, &$output, array &$outputByHash)
{
$hash = spl_object_hash($form);
@@ -236,7 +236,7 @@ private function recursiveBuildPreliminaryFormTree(FormInterface $form, &$output
}
}
- private function recursiveBuildFinalFormTree(FormInterface $form = null, FormView $view, &$output = null, array &$outputByHash)
+ private function recursiveBuildFinalFormTree(FormInterface $form = null, FormView $view, &$output, array &$outputByHash)
{
$viewHash = spl_object_hash($view);
$formHash = null;
diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php
index a277b580c5f2a..0f68dc851a58f 100644
--- a/src/Symfony/Component/Form/Form.php
+++ b/src/Symfony/Component/Form/Form.php
@@ -356,21 +356,11 @@ public function setData($modelData)
if (!FormUtil::isEmpty($viewData)) {
$dataClass = $this->config->getDataClass();
- $actualType = is_object($viewData) ? 'an instance of class '.get_class($viewData) : 'a(n) '.gettype($viewData);
-
- if (null === $dataClass && is_object($viewData) && !$viewData instanceof \ArrayAccess) {
- $expectedType = 'scalar, array or an instance of \ArrayAccess';
-
- throw new LogicException(
- 'The form\'s view data is expected to be of type '.$expectedType.', '.
- 'but is '.$actualType.'. You '.
- 'can avoid this error by setting the "data_class" option to '.
- '"'.get_class($viewData).'" or by adding a view transformer '.
- 'that transforms '.$actualType.' to '.$expectedType.'.'
- );
- }
-
if (null !== $dataClass && !$viewData instanceof $dataClass) {
+ $actualType = is_object($viewData)
+ ? 'an instance of class '.get_class($viewData)
+ : 'a(n) '.gettype($viewData);
+
throw new LogicException(
'The form\'s view data is expected to be an instance of class '.
$dataClass.', but is '.$actualType.'. You can avoid this error '.
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf
index 2e8585a75c0c8..0db5eddbe68a6 100644
--- a/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf
+++ b/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf
@@ -11,8 +11,8 @@
アップロードされたファイルが大きすぎます。小さなファイルで再度アップロードしてください。
- The CSRF token is invalid.
- CSRFトークンが無効です。
+ The CSRF token is invalid. Please try to resubmit the form.
+ CSRFトークンが無効です、再送信してください。