From 9cf90fbcbf234814a97ea28ef179dc9cc1412909 Mon Sep 17 00:00:00 2001 From: Evgeniy Sokolov Date: Tue, 10 Nov 2015 01:31:08 +0100 Subject: [PATCH 001/136] [2.3][Process] fix Proccess run with pts enabled --- src/Symfony/Component/Process/Process.php | 51 ++++++++++++++--------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 1249962bb5a6e..bbafb4327912e 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -119,12 +119,12 @@ class Process /** * Constructor. * - * @param string $commandline The command line to run - * @param string|null $cwd The working directory or null to use the working dir of the current PHP process - * @param array|null $env The environment variables or null to inherit - * @param string|null $stdin The STDIN content - * @param integer|float|null $timeout The timeout in seconds or null to disable - * @param array $options An array of options for proc_open + * @param string $commandline The command line to run + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to inherit + * @param string|null $stdin The STDIN content + * @param int|float|null $timeout The timeout in seconds or null to disable + * @param array $options An array of options for proc_open * * @throws RuntimeException When proc_open is not installed * @@ -184,7 +184,7 @@ public function __clone() * @param callback|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR * - * @return integer The exit status code + * @return int The exit status code * * @throws RuntimeException When process can't be launch or is stopped * @@ -238,8 +238,20 @@ public function start($callback = null) } } + $ptsWorkaround = null; + + if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { + // Workaround for the bug, when PTS functionality is enabled. + // @see : https://bugs.php.net/69442 + $ptsWorkaround = fopen('php://fd/0', 'r'); + } + $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options); + if ($ptsWorkaround) { + fclose($ptsWorkaround); + } + if (!is_resource($this->process)) { throw new RuntimeException('Unable to launch a new process.'); } @@ -287,7 +299,7 @@ public function restart($callback = null) * * @param callback|null $callback A valid PHP callback * - * @return integer The exitcode of the process + * @return int The exitcode of the process * * @throws RuntimeException When process timed out * @throws RuntimeException When process stopped after receiving signal @@ -302,7 +314,7 @@ public function wait($callback = null) do { $this->checkTimeout(); $running = defined('PHP_WINDOWS_VERSION_BUILD') ? $this->isRunning() : $this->processPipes->hasOpenHandles(); - $close = !defined('PHP_WINDOWS_VERSION_BUILD') || !$running;; + $close = !defined('PHP_WINDOWS_VERSION_BUILD') || !$running; $this->readPipes(true, $close); } while ($running); @@ -324,7 +336,7 @@ public function wait($callback = null) /** * Returns the Pid (process identifier), if applicable. * - * @return integer|null The process id if running, null otherwise + * @return int|null The process id if running, null otherwise * * @throws RuntimeException In case --enable-sigchild is activated */ @@ -342,7 +354,8 @@ public function getPid() /** * Sends a posix signal to the process. * - * @param integer $signal A valid posix signal (see http://www.php.net/manual/en/pcntl.constants.php) + * @param int $signal A valid posix signal (see http://www.php.net/manual/en/pcntl.constants.php) + * * @return Process * * @throws LogicException In case the process is not running @@ -434,7 +447,7 @@ public function getIncrementalErrorOutput() /** * Returns the exit code returned by the process. * - * @return integer The exit status code + * @return int The exit status code * * @throws RuntimeException In case --enable-sigchild is activated and the sigchild compatibility mode is disabled * @@ -508,7 +521,7 @@ public function hasBeenSignaled() * * It is only meaningful if hasBeenSignaled() returns true. * - * @return integer + * @return int * * @throws RuntimeException In case --enable-sigchild is activated * @@ -546,7 +559,7 @@ public function hasBeenStopped() * * It is only meaningful if hasBeenStopped() returns true. * - * @return integer + * @return int * * @api */ @@ -612,10 +625,10 @@ public function getStatus() /** * Stops the process. * - * @param integer|float $timeout The timeout in seconds - * @param integer $signal A posix signal to send in case the process has not stop at timeout, default is SIGKILL + * @param int|float $timeout The timeout in seconds + * @param int $signal A posix signal to send in case the process has not stop at timeout, default is SIGKILL * - * @return integer The exit-code of the process + * @return int The exit-code of the process * * @throws RuntimeException if the process got signaled */ @@ -704,7 +717,7 @@ public function getTimeout() * * To disable the timeout, set this value to null. * - * @param integer|float|null $timeout The timeout in seconds + * @param int|float|null $timeout The timeout in seconds * * @return self The current Process instance * @@ -728,7 +741,7 @@ public function setTimeout($timeout) /** * Enables or disables the TTY mode. * - * @param boolean $tty True to enabled and false to disable + * @param bool $tty True to enabled and false to disable * * @return self The current Process instance */ From 5f1980ba5ce72fab682b210103caab78969fc560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20S=C3=A1nchez?= Date: Wed, 11 Nov 2015 16:25:04 -0300 Subject: [PATCH 002/136] The following change adds support for Armenian pluralization. According to http://www.unicode.org/cldr/charts/27/supplemental/language_plural_rules.html#hy Armenian has 2 forms of pluralization. --- src/Symfony/Component/Translation/PluralizationRules.php | 1 + .../Component/Translation/Tests/PluralizationRulesTest.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/PluralizationRules.php b/src/Symfony/Component/Translation/PluralizationRules.php index 6d91da7fc6c78..8b02773b5884a 100644 --- a/src/Symfony/Component/Translation/PluralizationRules.php +++ b/src/Symfony/Component/Translation/PluralizationRules.php @@ -132,6 +132,7 @@ public static function get($number, $locale) case 'fr': case 'gun': case 'hi': + case 'hy': case 'ln': case 'mg': case 'nso': diff --git a/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php b/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php index 066e07f5ab3f2..43c31672c2ce5 100644 --- a/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php +++ b/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php @@ -61,7 +61,7 @@ public function successLangcodes() { return array( array('1', array('ay','bo', 'cgg','dz','id', 'ja', 'jbo', 'ka','kk','km','ko','ky')), - array('2', array('nl', 'fr', 'en', 'de', 'de_GE')), + array('2', array('nl', 'fr', 'en', 'de', 'de_GE', 'hy', 'hy_AM')), array('3', array('be','bs','cs','hr')), array('4', array('cy','mt', 'sl')), array('5', array()), From 2d0af8e719c9615069a13adcdaf5ef38edb519fc Mon Sep 17 00:00:00 2001 From: Jakub Zalas Date: Fri, 13 Nov 2015 07:29:58 +0000 Subject: [PATCH 003/136] [Validator] Allow an empty path with a non empty fragment or a query --- src/Symfony/Component/Validator/Constraints/UrlValidator.php | 2 +- .../Validator/Tests/Constraints/UrlValidatorTest.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 5af71e6d824ee..5127f8b1660f6 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -33,7 +33,7 @@ class UrlValidator extends ConstraintValidator \] # a IPv6 address ) (:[0-9]+)? # a port (optional) - (/?|/\S+|\?|\#) # a /, nothing, a / with something, a query or a fragment + (/?|/\S+|\?\S*|\#\S*) # a /, nothing, a / with something, a query or a fragment $~ixu'; /** diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index c08531339c2a4..93e9e8237ff0e 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -112,7 +112,11 @@ public function getValidUrls() array('http://username:password@symfony.com'), array('http://user-name@symfony.com'), array('http://symfony.com?'), + array('http://symfony.com?query=1'), + array('http://symfony.com/?query=1'), array('http://symfony.com#'), + array('http://symfony.com#fragment'), + array('http://symfony.com/#fragment'), ); } From 4923411062127aa20b038f74766f27515e0e7c41 Mon Sep 17 00:00:00 2001 From: Leo Feyer Date: Tue, 27 Oct 2015 16:04:34 +0100 Subject: [PATCH 004/136] Fix the server variables in the router_*.php files --- .../Bundle/FrameworkBundle/Resources/config/router_dev.php | 4 ++++ .../Bundle/FrameworkBundle/Resources/config/router_prod.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php index ca0cd1ee1cefb..432ccff9204f1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php @@ -33,6 +33,10 @@ $_SERVER = array_merge($_SERVER, $_ENV); $_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'app_dev.php'; +// Since we are rewriting to app_dev.php, adjust SCRIPT_NAME and PHP_SELF accordingly +$_SERVER['SCRIPT_NAME'] = DIRECTORY_SEPARATOR.'app_dev.php'; +$_SERVER['PHP_SELF'] = DIRECTORY_SEPARATOR.'app_dev.php'; + require 'app_dev.php'; error_log(sprintf('%s:%d [%d]: %s', $_SERVER['REMOTE_ADDR'], $_SERVER['REMOTE_PORT'], http_response_code(), $_SERVER['REQUEST_URI']), 4); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_prod.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_prod.php index 1c6b99b866b74..97613a6248f71 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_prod.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_prod.php @@ -33,6 +33,10 @@ $_SERVER = array_merge($_SERVER, $_ENV); $_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'app.php'; +// Since we are rewriting to app.php, adjust SCRIPT_NAME and PHP_SELF accordingly +$_SERVER['SCRIPT_NAME'] = DIRECTORY_SEPARATOR.'app.php'; +$_SERVER['PHP_SELF'] = DIRECTORY_SEPARATOR.'app.php'; + require 'app.php'; error_log(sprintf('%s:%d [%d]: %s', $_SERVER['REMOTE_ADDR'], $_SERVER['REMOTE_PORT'], http_response_code(), $_SERVER['REQUEST_URI']), 4); From dca92f59d8c104230962b7d1cdd2c6ae2ff6146c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 16 Nov 2015 10:07:19 +0100 Subject: [PATCH 005/136] updated CHANGELOG for 2.8.0-BETA1 --- CHANGELOG-2.8.md | 165 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 CHANGELOG-2.8.md diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md new file mode 100644 index 0000000000000..f36da583f128a --- /dev/null +++ b/CHANGELOG-2.8.md @@ -0,0 +1,165 @@ +CHANGELOG for 2.8.x +=================== + +This changelog references the relevant changes (bug and security fixes) done +in 2.8 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.8.0...v2.8.1 + +* 2.8.0-BETA1 (2015-11-16) + + * feature #16156 [Filesystem] Changed dumpFile to allow dumping to streams (markchalloner, pierredup) + * feature #16502 [Bridge\PhpUnit] Add extra clock-mocked namespaces in phpunit.xml.dist (nicolas-grekas) + * feature #16464 [DependencyInjection] Fix some edge cases with autowiring (dunglas) + * feature #16433 [Yaml] deprecate unquoted indicator characters (xabbuh) + * feature #16419 [FrameworkBundle][Form] Better exception message for private form tagged services (ogizanagi) + * feature #15990 added a micro kernel (fabpot) + * feature #16459 [Security\Core] Deprecate passing $salt to BCryptPasswordEncoder::encodePassword() (nicolas-grekas) + * feature #16409 [Console] Add progress indicator helper (kbond) + * feature #16423 [VarDumper] Deprecate VarDumperTestCase in favor of the trait (nicolas-grekas) + * feature #16424 [DI] Deprecate ContainerAware in favor of ContainerAwareTrait (nicolas-grekas) + * feature #16430 [HttpKernel] PostResponseEvent should extend the KernelEvent (jakzal) + * feature #16325 [VarDumper] Casters for Generator, ReflectionGenerator and ReflectionType (nicolas-grekas) + * feature #16395 checkCredentials() force it to be an affirmative yes! (weaverryan) + * feature #16344 [WebProfilerBundle] Filter links in search results (Rvanlaak) + * feature #16285 [Yaml] deprecated usage of @ and ` at the beginning of an unquoted string (fabpot) + * feature #16317 Rely on iconv and symfony/polyfill-* (nicolas-grekas) + * feature #15966 [FrameworkBundle] PropertyInfo support (dunglas) + * feature #16161 [Validator] Add expressionLanguage to ExpressionValidator constructor (enumag) + * feature #16263 [FrameworkBundle] Add a new ClassCache cache warmer (tucksaun) + * feature #16271 [TwigBundle] added a Twig templates warmer when templating is disabled (fabpot) + * feature #16276 Unify URL generator reference type + make linking in php templates consistent with twig (Tobion) + * feature #15947 Added UserLoaderInterface for loading users through Doctrine. (mtrojanowski) + * feature #16194 [PhpUnit] Mock clock on @group time-sensitive annotations (nicolas-grekas) + * feature #16201 [Yaml] deprecated non-escaped \ in double-quoted strings when parsing (fabpot) + * feature #16198 [EventDispatcher] added EventDispatcher::getListenerPriority() (fabpot) + * feature #15025 [2.8] [Form] Rename CollectionType options for entries (WouterJ) + * feature #16189 [PhpUnitBridge] Add SkippedTestsListener to collect and replay skipped tests (nicolas-grekas) + * feature #15879 Deprecate the SecureRandom class (pierredup) + * feature #16001 [DI] Warn when a definition relies on a deprecated class in ContainerBuilder::createService() (nicolas-grekas) + * feature #14044 [Console] [Helper] [Table] Columns styles (MAXakaWIZARD) + * feature #14908 Include working directory in ProcessFailedException (Rvanlaak) + * feature #16102 Simplify AbstractVoter (Koc) + * feature #15613 [DependencyInjection] Add autowiring capabilities (dunglas) + * feature #14721 [Security] Configuring a user checker per firewall (iltar) + * feature #16069 [WebProfilerBundle] Move AjaxCollector to HttpKernel for use with Silex (glaubinix, fabpot) + * feature #16063 [VarDumper] Add $this->getDump($var) when using VarDumperTestTrait (nicolas-grekas) + * feature #16058 Prevent adding non-DOMElement elements in DomCrawler (stof) + * feature #16057 Deprecate loading multiple documents in the same crawler (stof) + * feature #15742 Using a service as a router resource (weaverryan) + * feature #15778 Fluid interface for building routes in PHP (weaverryan) + * feature #16029 [FrameworkBundle][TwigBridge] do not render empty form action attributes (xabbuh) + * feature #15938 [Console] Bind input before executing the COMMAND event (WouterJ) + * feature #15503 UI & CSS improvement to new toolbar (WouterJ) + * feature #15838 [VarDumper] Dump PHP+Twig code excerpts in backtraces (nicolas-grekas) + * feature #16011 [FrameworkBundle] Tag deprecated services (nicolas-grekas) + * feature #15944 Remove profiler storages (javiereguiluz) + * feature #16007 [HttpFoundation] deprecate finding deep items in request parameters (xabbuh) + * feature #15978 Updated the styles of the cache commands (javiereguiluz) + * feature #15972 [Console] Updated the styles of the server commands (javiereguiluz) + * feature #15964 Symfony Console Style tweaks (javiereguiluz) + * feature #15919 [Form] Guess currency field based on validator constraint (enumag) + * feature #15934 Add a non-static API for the CssSelector component (stof) + * feature #14235 [FrameworkBundle] Refactored assets:install command and apply Symfony styles (1ed) + * feature #15963 added logging of unused tags (Marmelatze, fabpot) + * feature #15970 [TwigBundle] removed usage of Templating classes (fabpot) + * feature #14132 Applied the new styles to the router: commands (javiereguiluz) + * feature #15356 [WebProfilerBundle] Profiler View Latest should preserve all the current query parameters (jbafford) + * feature #15953 [TwigBridge] is_granted no longer raise an exception if the token storage is empty (lyrixx) + * feature #14602 [2.8] [Ldap] Added support for LDAP (New Component + integration in the Security Component). (csarrazi, lyrixx) + * feature #15939 Removed the "Delete profiles" action from the web profiler sidebar (javiereguiluz) + * feature #15962 [Finder] simplified code (fabpot) + * feature #15882 Easier Custom Authentication errors (weaverryan) + * feature #15907 [DomCrawler] Deprecate methods inherited from SplObjectStorage (stof) + * feature #15301 [Form][Type Date/Time] added choice_translation_domain option. (aitboudad) + * feature #15697 [BrowserKit] Added isFollowingRedirects and getMaxRedirects methods (Naktibalda) + * feature #15719 Deprecate ResourceInterface::getResource() (mpdude) + * feature #15818 [WebProfilerBundle] Add collapsed sidebar on small screens (hason) + * feature #15858 [PropertyInfo] Import the component (dunglas) + * feature #15892 deprecated the Shell Console class (fabpot) + * feature #15519 [Validator] added BIC (SWIFT-BIC) validation constraint (mvhirsch) + * feature #12587 [TwigBridge] Foundation form layout integration (totophe) + * feature #15151 [Security] Deprecated supportsAttribute and supportsClass methods (WouterJ) + * feature #15491 Add support for deprecated definitions (Taluu) + * feature #14894 [Console] Add domain exceptions to replace generic exceptions (GromNaN) + * feature #15738 Implement service-based Resource (cache) validation (mpdude) + * feature #14673 New Guard Authentication System (e.g. putting the joy back into security) (weaverryan) + * feature #15870 Updating AbstractVoter so that the method receives the TokenInterface (weaverryan) + * feature #15786 [Translation][File dumper] allow get file content without writing in file. (aitboudad) + * feature #15805 [Finder] Deprecate adapters and related classes (nicolas-grekas) + * feature #15837 [VarDumper] Add EnumStub for dumping virtual collections with casters (nicolas-grekas) + * feature #15699 [Translator][FileDumper] deprecated format method in favor of formatCatalogue. (aitboudad) + * feature #15717 [Translator][Loader] added XLIFF 2.0 support. (xphere, aitboudad) + * feature #15743 Validate the extended type for lazy-loaded type extensions (stof) + * feature #13761 Automatically process extensions when they implement CompilerPassInterface (WouterJ) + * feature #15787 [VarDumper] Add caster for OuterIterator objects (nicolas-grekas) + * feature #13616 [HttpKernel] Add entry point to more easily create/configure the DI extension (egeloen) + * feature #14378 [DX] Added a logout link in the security panel of the web debug toolbar (javiereguiluz) + * feature #15620 [WIP] #15502 Make template shortcuts be usable without Templating component (Koc) + * feature #15523 Redesigned the Symfony Profiler (javiereguiluz) + * feature #15773 Make the exception output visible even in quiet mode, fixes #15680 (Seldaek) + * feature #15772 Convert Output::write's type to an options arg where verbosity can be passed in as well (Seldaek) + * feature #15756 [Translation] added option json_options to JsonFileDumper. (gepo) + * feature #15724 [HttpKernel] Move required RequestStack args as first arguments (nicolas-grekas) + * feature #15521 [Debug] Add BufferingLogger for errors that happen before a proper logger is configured (nicolas-grekas) + * feature #15709 [WebProfilerBundle] deprecated import/export commands (fabpot) + * feature #15710 added ExceptionHandler::getHtml() to expose the full HTML of an exception (fabpot) + * feature #15562 [translation] Deprecated DiffOperation (zerustech) + * feature #15635 [Config] Prototypes info (ogizanagi) + * feature #15551 [Translation] added element metadata to XliffFileDumper (aitboudad) + * feature #15555 [VarDumper] Add caster for pgsql resources (nicolas-grekas) + * feature #15452 [Translator] [Xliff] Add support for target attributes. (marcosdsanchez) + * feature #15416 [DependencyInjection] Added a way to define the priority of service decoration (dosten) + * feature #15433 Allow to define Enum nodes with 1 single element (javiereguiluz) + * feature #13990 [Form] Add flexibility for EntityType (raziel057) + * feature #15382 [Console] Use readline for user input when available #DX (michaelperrin) + * feature #15013 [Security] Removed security-acl from the core (iltar) + * feature #15079 [Form] Deprecated FormTypeInterface::getName() and passing of type instances (webmozart) + * feature #15418 [Debug] Deprecate ExceptionHandler::createResponse (nicolas-grekas) + * feature #15123 [2.8][FrameworkBundle] Allow parameter use_cookies in session configuration (derrabus) + * feature #14987 [FrameworkBundle] Configurable Serializer name converter (dunglas) + * feature #15285 [Config] deprecate cannotBeEmpty() for boolean and numeric nodes (xabbuh) + * feature #15372 [FrameworkBundle] Change the default value of cookie_httponly (jderusse) + * feature #15160 Redesigned the web debug toolbar (javiereguiluz) + * feature #15185 Implement resettable containers (stof) + * feature #15131 [Security] Moved Simple{Form,Pre}AuthenticatorInterfaces to Security\Http (WouterJ) + * feature #15290 [DependencyInjection] Forbid container cloning (jakzal) + * feature #14264 [WebProfilerBundle] Add link to show profile of latest request (xelaris) + * feature #15139 [Translation] Add parameters to DataCollectorTranslator (damienalexandre) + * feature #15175 [VarDumper] Ingore PHPUnit and Prophecy object when they are nested (lyrixx) + * feature #15141 [DX] [Security] Renamed Token#getKey() to getSecret() (WouterJ) + * feature #15154 [Validator] Added missing error codes and turned codes into UUIDs (webmozart) + * feature #15096 [DependencyInjection] Allow anonymous DefinitionDecorator resolving (nicolas-grekas) + * feature #14764 [TwigBundle] Warmup twig templates in non-standard paths (kbond) + * feature #15134 [FrameworkBundle] add option to force web server startup (xabbuh) + * feature #14238 [config] added remove option to ignoreExtraKeys (twifty) + * feature #15076 [Debug] Allow throwing from __toString() with `return trigger_error($e, E_USER_ERROR);` (nicolas-grekas) + * feature #14984 [DependencyInjection] Deprecate scope concept (dosten) + * feature #14429 [FrameworkBundle] Add a doctrine cache service definition for validator mapping (jakzal) + * feature #14991 [Console][Table] allow multiple render() calls. (jaytaph) + * feature #14660 [Form] moved data trimming logic of TrimListener into StringUtil (issei-m) + * feature #15019 [Form] Deprecated "cascade_validation" (webmozart) + * feature #12314 [Form] Add "prototype_data" option to collection type (kgilden) + * feature #12067 [Form] Added the 'range' FormType (jaytaph) + * feature #14993 [Profiler][Translation] added filter. (aitboudad) + * feature #14912 [HttpFoundation] Postpone setting the date header on a Response (jakzal) + * feature #14903 [profiler][request toolbar] Removed route name from the toolbar (MJBGO) + * feature #14904 [toolbar] Merged colored icons in toolbar (MJBGO) + * feature #14781 [TwigBundle] Reconfigure twig paths when they are updated (chbruyand) + * feature #14700 [DependencyInjection] [Routing] [Config] Recursive directory loading (lavoiesl, nicolas-grekas) + * feature #14733 [Security] Add setVoters() on AccessDecisionManager (nicolas-grekas) + * feature #14756 [Serializer] Support for array denormalization (derrabus) + * feature #14630 [Translator] Dump translation constants as tree instead of simple list (gepo) + * feature #14403 [Form] deprecate read_only option (Tobion) + * feature #13324 [WebProfilerBundle] Improved page for logs (hason) + * feature #14561 [FrameworkBundle][DX] Add option to specify additional translation loading paths (Seldaek) + * feature #14563 [FrameworkBundle][EventDispatcher] Add priorities to the debug:event-dispatcher command (Seldaek) + * feature #14546 [Translator] deprecate getMessages in favor of getCatalogue. (aitboudad) + * feature #14320 [Translation] added an --all option to the debug:translation command #14237 (sgehrig) + * feature #14473 [DX] Minor improvement for the translation:debug output (nicolasdewez) + * feature #14443 [VarDumper] Allow preserving a subset of cut arrays (nicolas-grekas) + * feature #14431 [Console] Bind the closure (code) to the Command if possible (lyrixx) + * feature #14424 [VarDumper] Added support for SplFileInfo (lyrixx) + * feature #14359 [Translation] added FileLoader. (aitboudad) + * feature #14383 [FrameworkBundle][Server Command] add address port number option. (aitboudad) From 021c08748648f732691783b8809932e4e606c775 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 16 Nov 2015 10:09:15 +0100 Subject: [PATCH 006/136] updated VERSION for 2.8.0-BETA1 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7c55172d395ae..ba96278837ac9 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -60,12 +60,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.0-DEV'; + const VERSION = '2.8.0-BETA1'; const VERSION_ID = 20800; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = 'BETA1'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From 86b4c0536cac411cdbe7cef3c1c68f17c49d49ec Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 16 Nov 2015 13:50:22 +0100 Subject: [PATCH 007/136] bumped Symfony version to 2.8.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index ba96278837ac9..7c55172d395ae 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -60,12 +60,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.0-BETA1'; + const VERSION = '2.8.0-DEV'; const VERSION_ID = 20800; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'BETA1'; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From 9835236a54a8a74a7ddaa637cff65f7d2e3f762d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 16 Nov 2015 15:59:01 +0100 Subject: [PATCH 008/136] bumped Symfony version to 3.0.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 8b9ffde0c1da7..d636ddbd2ca5e 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -60,12 +60,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '3.0.0-BETA1'; + const VERSION = '3.0.0-DEV'; const VERSION_ID = 30000; const MAJOR_VERSION = 3; const MINOR_VERSION = 0; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'BETA1'; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From 9b0850511f74ccbe93a93eb215418c135dc21a62 Mon Sep 17 00:00:00 2001 From: Douglas Greenshields Date: Tue, 17 Nov 2015 00:41:09 +0000 Subject: [PATCH 009/136] [WebProfilerBundle] correct typo in show stack trace link --- .../Resources/views/Collector/logger.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig index 8ba4d7025ac63..361e684fbf938 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig @@ -162,7 +162,7 @@ {% endif %} {% if stack %} - + {% endif %} {% for index, call in stack if index > 1 %} From 39f09893b9abd87068a623b1041443b55253e0c3 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Tue, 17 Nov 2015 02:04:18 +0100 Subject: [PATCH 010/136] [Validator] [sl] BIC (SWIFT-BIC) validation constraint --- .../Validator/Resources/translations/validators.sl.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf index 4f0e7c6364e37..834db4015e8e4 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf @@ -310,6 +310,10 @@ This value does not match the expected {{ charset }} charset. Ta vrednost se ne ujema s pričakovanim naborom znakov {{ charset }}. + + This is not a valid Business Identifier Code (BIC). + To ni veljavna identifikacijska koda podjetja (BIC). + From 02d2148f370d45f846e75e94c1335b667f9c8358 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 16 Nov 2015 20:24:50 +0100 Subject: [PATCH 011/136] [Form] Enhance some FormRegistry deprecation messages --- .../DependencyInjection/Compiler/FormPass.php | 2 +- src/Symfony/Component/Form/FormRegistry.php | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php index 4b36468aa3f0a..c5d639b808e18 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php @@ -67,7 +67,7 @@ public function process(ContainerBuilder $container) @trigger_error('The alias option of the form.type_extension tag is deprecated since version 2.8 and will be removed in 3.0. Use the extended_type option instead.', E_USER_DEPRECATED); $extendedType = $tag[0]['alias']; } else { - @trigger_error('The extended_type option of the form.type_extension tag is required since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); + @trigger_error('The extended_type option of the form.type_extension tag is required since version 2.8.', E_USER_DEPRECATED); $extendedType = $serviceId; } diff --git a/src/Symfony/Component/Form/FormRegistry.php b/src/Symfony/Component/Form/FormRegistry.php index 66d5a1f7c2b38..a8995afe89f01 100644 --- a/src/Symfony/Component/Form/FormRegistry.php +++ b/src/Symfony/Component/Form/FormRegistry.php @@ -120,7 +120,7 @@ private function resolveAndAddType(FormTypeInterface $type) $hasCustomName = $name !== $fqcn; if ($parentType instanceof FormTypeInterface) { - @trigger_error('Returning a FormTypeInterface from FormTypeInterface::getParent() is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); + @trigger_error(sprintf('Returning a FormTypeInterface from %s::getParent() is deprecated since version 2.8 and will be removed in 3.0. Return the fully-qualified type class name instead.', $fqcn), E_USER_DEPRECATED); $this->resolveAndAddType($parentType); $parentType = $parentType->getName(); @@ -128,14 +128,11 @@ private function resolveAndAddType(FormTypeInterface $type) if ($hasCustomName) { foreach ($this->extensions as $extension) { - $typeExtensions = array_merge( - $typeExtensions, - $extension->getTypeExtensions($name) - ); - } + if ($x = $extension->getTypeExtensions($name)) { + @trigger_error(sprintf('Returning a type name from %s::getExtendedType() is deprecated since version 2.8 and will be removed in 3.0. Return the fully-qualified type class name instead.', get_class($x[0])), E_USER_DEPRECATED); - if ($typeExtensions) { - @trigger_error('Returning a type name from FormTypeExtensionInterface::getExtendedType() is deprecated since version 2.8 and will be removed in 3.0. Return the fully-qualified type class name instead.', E_USER_DEPRECATED); + $typeExtensions = array_merge($typeExtensions, $x); + } } } From 1fab27b58cd9589115ce3668c1cc312c7d1280cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sat, 14 Nov 2015 12:27:50 +0100 Subject: [PATCH 012/136] [Serializer] ObjectNormalizer: don't serialize static methods and props --- .../Serializer/Normalizer/ObjectNormalizer.php | 5 ++++- .../Tests/Normalizer/ObjectNormalizerTest.php | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index ba84ac717f075..fe1676fbf36fb 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -68,6 +68,7 @@ public function normalize($object, $format = null, array $context = array()) $reflClass = new \ReflectionClass($object); foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) { if ( + !$reflMethod->isStatic() && !$reflMethod->isConstructor() && !$reflMethod->isDestructor() && 0 === $reflMethod->getNumberOfRequiredParameters() @@ -86,7 +87,9 @@ public function normalize($object, $format = null, array $context = array()) // properties foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) { - $attributes[$reflProperty->getName()] = true; + if (!$reflProperty->isStatic()) { + $attributes[$reflProperty->getName()] = true; + } } $attributes = array_keys($attributes); diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index 1cadee52b196f..80a021d08fa25 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -456,6 +456,11 @@ public function testNoTraversableSupport() { $this->assertFalse($this->normalizer->supportsNormalization(new \ArrayObject())); } + + public function testNormalizeStatic() + { + $this->assertEquals(array('foo' => 'K'), $this->normalizer->normalize(new ObjectWithStaticPropertiesAndMethods())); + } } class ObjectDummy @@ -605,3 +610,14 @@ public function otherMethod() throw new \RuntimeException('Dummy::otherMethod() should not be called'); } } + +class ObjectWithStaticPropertiesAndMethods +{ + public $foo = 'K'; + public static $bar = 'A'; + + public static function getBaz() + { + return 'L'; + } +} From d4880c4785fce19106a93d74e904e9f0f630e015 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 18 Nov 2015 09:19:46 +0100 Subject: [PATCH 013/136] Add missing exclusions from phpunit.xml.dist --- phpunit.xml.dist | 4 ++++ src/Symfony/Bridge/Doctrine/phpunit.xml.dist | 2 ++ src/Symfony/Bridge/Monolog/phpunit.xml.dist | 2 ++ src/Symfony/Bridge/Propel1/phpunit.xml.dist | 2 ++ src/Symfony/Bridge/ProxyManager/phpunit.xml.dist | 1 + src/Symfony/Bridge/Twig/phpunit.xml.dist | 1 + src/Symfony/Bundle/FrameworkBundle/phpunit.xml.dist | 3 ++- src/Symfony/Bundle/SecurityBundle/phpunit.xml.dist | 3 ++- src/Symfony/Bundle/TwigBundle/phpunit.xml.dist | 3 ++- src/Symfony/Bundle/WebProfilerBundle/phpunit.xml.dist | 3 ++- src/Symfony/Component/BrowserKit/phpunit.xml.dist | 1 + src/Symfony/Component/ClassLoader/phpunit.xml.dist | 1 + src/Symfony/Component/Config/phpunit.xml.dist | 1 + src/Symfony/Component/Console/phpunit.xml.dist | 1 + src/Symfony/Component/CssSelector/phpunit.xml.dist | 1 + src/Symfony/Component/Debug/phpunit.xml.dist | 1 + src/Symfony/Component/DependencyInjection/phpunit.xml.dist | 1 + src/Symfony/Component/EventDispatcher/phpunit.xml.dist | 1 + src/Symfony/Component/Filesystem/phpunit.xml.dist | 2 ++ src/Symfony/Component/Finder/phpunit.xml.dist | 1 + src/Symfony/Component/Form/phpunit.xml.dist | 2 ++ src/Symfony/Component/HttpFoundation/phpunit.xml.dist | 1 + src/Symfony/Component/HttpKernel/phpunit.xml.dist | 1 + src/Symfony/Component/Intl/phpunit.xml.dist | 2 ++ src/Symfony/Component/Locale/phpunit.xml.dist | 1 + src/Symfony/Component/OptionsResolver/phpunit.xml.dist | 2 ++ src/Symfony/Component/Process/phpunit.xml.dist | 2 ++ src/Symfony/Component/PropertyAccess/phpunit.xml.dist | 2 ++ src/Symfony/Component/Routing/phpunit.xml.dist | 3 ++- src/Symfony/Component/Security/phpunit.xml.dist | 5 ++++- src/Symfony/Component/Serializer/phpunit.xml.dist | 3 ++- src/Symfony/Component/Stopwatch/phpunit.xml.dist | 1 + src/Symfony/Component/Templating/phpunit.xml.dist | 2 +- src/Symfony/Component/Translation/phpunit.xml.dist | 2 +- src/Symfony/Component/Validator/phpunit.xml.dist | 3 ++- src/Symfony/Component/Yaml/phpunit.xml.dist | 3 ++- 36 files changed, 59 insertions(+), 11 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e9c709d14223a..4e4e411c3cfb4 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -38,6 +38,10 @@ ./src/Symfony/Bundle/*/Resources ./src/Symfony/Component/*/Resources ./src/Symfony/Component/*/*/Resources + ./src/Symfony/Bridge/*/vendor + ./src/Symfony/Bundle/*/vendor + ./src/Symfony/Component/*/vendor + ./src/Symfony/Component/*/*/vendor diff --git a/src/Symfony/Bridge/Doctrine/phpunit.xml.dist b/src/Symfony/Bridge/Doctrine/phpunit.xml.dist index 13409e6f0f6b5..c006d232219a4 100644 --- a/src/Symfony/Bridge/Doctrine/phpunit.xml.dist +++ b/src/Symfony/Bridge/Doctrine/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -21,6 +22,7 @@ ./Resources ./Tests + ./vendor diff --git a/src/Symfony/Bridge/Monolog/phpunit.xml.dist b/src/Symfony/Bridge/Monolog/phpunit.xml.dist index efd48709de90b..8a60f06a7a310 100644 --- a/src/Symfony/Bridge/Monolog/phpunit.xml.dist +++ b/src/Symfony/Bridge/Monolog/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -21,6 +22,7 @@ ./Resources ./Tests + ./vendor diff --git a/src/Symfony/Bridge/Propel1/phpunit.xml.dist b/src/Symfony/Bridge/Propel1/phpunit.xml.dist index 507e12596cbd4..d6d959c7b01c2 100644 --- a/src/Symfony/Bridge/Propel1/phpunit.xml.dist +++ b/src/Symfony/Bridge/Propel1/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -21,6 +22,7 @@ ./Resources ./Tests + ./vendor diff --git a/src/Symfony/Bridge/ProxyManager/phpunit.xml.dist b/src/Symfony/Bridge/ProxyManager/phpunit.xml.dist index 363805fdfa6ae..60980be9e531e 100644 --- a/src/Symfony/Bridge/ProxyManager/phpunit.xml.dist +++ b/src/Symfony/Bridge/ProxyManager/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Bridge/Twig/phpunit.xml.dist b/src/Symfony/Bridge/Twig/phpunit.xml.dist index d291324949f2d..10c0be1142712 100644 --- a/src/Symfony/Bridge/Twig/phpunit.xml.dist +++ b/src/Symfony/Bridge/Twig/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Bundle/FrameworkBundle/phpunit.xml.dist b/src/Symfony/Bundle/FrameworkBundle/phpunit.xml.dist index eb7c0b0a97a2f..1d25eeb3304c5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/phpunit.xml.dist +++ b/src/Symfony/Bundle/FrameworkBundle/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -19,9 +20,9 @@ ./ - ./vendor ./Resources ./Tests + ./vendor diff --git a/src/Symfony/Bundle/SecurityBundle/phpunit.xml.dist b/src/Symfony/Bundle/SecurityBundle/phpunit.xml.dist index 52f420ae5f2fe..a7fdc326c4571 100644 --- a/src/Symfony/Bundle/SecurityBundle/phpunit.xml.dist +++ b/src/Symfony/Bundle/SecurityBundle/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -19,8 +20,8 @@ ./ - ./Tests ./Resources + ./Tests ./vendor diff --git a/src/Symfony/Bundle/TwigBundle/phpunit.xml.dist b/src/Symfony/Bundle/TwigBundle/phpunit.xml.dist index 715b0bfa87f47..9a8c38f26ef33 100644 --- a/src/Symfony/Bundle/TwigBundle/phpunit.xml.dist +++ b/src/Symfony/Bundle/TwigBundle/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -19,8 +20,8 @@ ./ - ./Tests ./Resources + ./Tests ./vendor diff --git a/src/Symfony/Bundle/WebProfilerBundle/phpunit.xml.dist b/src/Symfony/Bundle/WebProfilerBundle/phpunit.xml.dist index 767f3e066b391..2bcccd6667a26 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/phpunit.xml.dist +++ b/src/Symfony/Bundle/WebProfilerBundle/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -19,8 +20,8 @@ ./ - ./Tests ./Resources + ./Tests ./vendor diff --git a/src/Symfony/Component/BrowserKit/phpunit.xml.dist b/src/Symfony/Component/BrowserKit/phpunit.xml.dist index d6ca28bf1c6b5..d76b2b98afd80 100644 --- a/src/Symfony/Component/BrowserKit/phpunit.xml.dist +++ b/src/Symfony/Component/BrowserKit/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/ClassLoader/phpunit.xml.dist b/src/Symfony/Component/ClassLoader/phpunit.xml.dist index a1b6c82c10161..4856db5be65d1 100644 --- a/src/Symfony/Component/ClassLoader/phpunit.xml.dist +++ b/src/Symfony/Component/ClassLoader/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/Config/phpunit.xml.dist b/src/Symfony/Component/Config/phpunit.xml.dist index 2156534e9ce52..3fe6fd87c8499 100644 --- a/src/Symfony/Component/Config/phpunit.xml.dist +++ b/src/Symfony/Component/Config/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/Console/phpunit.xml.dist b/src/Symfony/Component/Console/phpunit.xml.dist index 729c433aa69e8..ae0dcbeaba41c 100644 --- a/src/Symfony/Component/Console/phpunit.xml.dist +++ b/src/Symfony/Component/Console/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/CssSelector/phpunit.xml.dist b/src/Symfony/Component/CssSelector/phpunit.xml.dist index bc57cfcdfa8d8..14a320c873c11 100644 --- a/src/Symfony/Component/CssSelector/phpunit.xml.dist +++ b/src/Symfony/Component/CssSelector/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/Debug/phpunit.xml.dist b/src/Symfony/Component/Debug/phpunit.xml.dist index e91766065749a..20b0313f0cd89 100644 --- a/src/Symfony/Component/Debug/phpunit.xml.dist +++ b/src/Symfony/Component/Debug/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/DependencyInjection/phpunit.xml.dist b/src/Symfony/Component/DependencyInjection/phpunit.xml.dist index 17a217226da3d..86252d0456ba9 100644 --- a/src/Symfony/Component/DependencyInjection/phpunit.xml.dist +++ b/src/Symfony/Component/DependencyInjection/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/EventDispatcher/phpunit.xml.dist b/src/Symfony/Component/EventDispatcher/phpunit.xml.dist index b14fde575007d..ae0586e0b33de 100644 --- a/src/Symfony/Component/EventDispatcher/phpunit.xml.dist +++ b/src/Symfony/Component/EventDispatcher/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/Filesystem/phpunit.xml.dist b/src/Symfony/Component/Filesystem/phpunit.xml.dist index 32444185a1edc..d066ed7969868 100644 --- a/src/Symfony/Component/Filesystem/phpunit.xml.dist +++ b/src/Symfony/Component/Filesystem/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -20,6 +21,7 @@ ./ ./Tests + ./vendor diff --git a/src/Symfony/Component/Finder/phpunit.xml.dist b/src/Symfony/Component/Finder/phpunit.xml.dist index bc38ccaa45d1d..631e570b9479f 100644 --- a/src/Symfony/Component/Finder/phpunit.xml.dist +++ b/src/Symfony/Component/Finder/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/Form/phpunit.xml.dist b/src/Symfony/Component/Form/phpunit.xml.dist index 104aee4b0b52d..1c4acf476238d 100644 --- a/src/Symfony/Component/Form/phpunit.xml.dist +++ b/src/Symfony/Component/Form/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -19,6 +20,7 @@ ./ + ./Resources ./Tests ./vendor diff --git a/src/Symfony/Component/HttpFoundation/phpunit.xml.dist b/src/Symfony/Component/HttpFoundation/phpunit.xml.dist index b5b660a39433e..9ffdb43a2d744 100644 --- a/src/Symfony/Component/HttpFoundation/phpunit.xml.dist +++ b/src/Symfony/Component/HttpFoundation/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/HttpKernel/phpunit.xml.dist b/src/Symfony/Component/HttpKernel/phpunit.xml.dist index 5b17270141acd..17c48935c7158 100644 --- a/src/Symfony/Component/HttpKernel/phpunit.xml.dist +++ b/src/Symfony/Component/HttpKernel/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/Intl/phpunit.xml.dist b/src/Symfony/Component/Intl/phpunit.xml.dist index d40a1582bb889..9e7ce2f0b2642 100644 --- a/src/Symfony/Component/Intl/phpunit.xml.dist +++ b/src/Symfony/Component/Intl/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -25,6 +26,7 @@ ./ + ./Resources ./Tests ./vendor diff --git a/src/Symfony/Component/Locale/phpunit.xml.dist b/src/Symfony/Component/Locale/phpunit.xml.dist index 4633ca6f04375..0d9b637cc78d1 100644 --- a/src/Symfony/Component/Locale/phpunit.xml.dist +++ b/src/Symfony/Component/Locale/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/OptionsResolver/phpunit.xml.dist b/src/Symfony/Component/OptionsResolver/phpunit.xml.dist index 2398388768711..abf84614bcf76 100644 --- a/src/Symfony/Component/OptionsResolver/phpunit.xml.dist +++ b/src/Symfony/Component/OptionsResolver/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -21,6 +22,7 @@ ./Resources ./Tests + ./vendor diff --git a/src/Symfony/Component/Process/phpunit.xml.dist b/src/Symfony/Component/Process/phpunit.xml.dist index 07b617be4b5d2..788500084abf8 100644 --- a/src/Symfony/Component/Process/phpunit.xml.dist +++ b/src/Symfony/Component/Process/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -20,6 +21,7 @@ ./ ./Tests + ./vendor diff --git a/src/Symfony/Component/PropertyAccess/phpunit.xml.dist b/src/Symfony/Component/PropertyAccess/phpunit.xml.dist index 99858f7b95361..b0b20c1bd9460 100644 --- a/src/Symfony/Component/PropertyAccess/phpunit.xml.dist +++ b/src/Symfony/Component/PropertyAccess/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -21,6 +22,7 @@ ./Resources ./Tests + ./vendor diff --git a/src/Symfony/Component/Routing/phpunit.xml.dist b/src/Symfony/Component/Routing/phpunit.xml.dist index fae243c8152b0..b69f066ac1b2f 100644 --- a/src/Symfony/Component/Routing/phpunit.xml.dist +++ b/src/Symfony/Component/Routing/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -19,8 +20,8 @@ ./ - ./vendor ./Tests + ./vendor diff --git a/src/Symfony/Component/Security/phpunit.xml.dist b/src/Symfony/Component/Security/phpunit.xml.dist index 9a20f91498ae9..9d3cf4a02318d 100644 --- a/src/Symfony/Component/Security/phpunit.xml.dist +++ b/src/Symfony/Component/Security/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -19,8 +20,10 @@ ./ - ./vendor + ./Acl/Resources + ./Resources ./Tests + ./vendor diff --git a/src/Symfony/Component/Serializer/phpunit.xml.dist b/src/Symfony/Component/Serializer/phpunit.xml.dist index da0540137b19a..4799e3cf2f1dd 100644 --- a/src/Symfony/Component/Serializer/phpunit.xml.dist +++ b/src/Symfony/Component/Serializer/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -19,8 +20,8 @@ ./ - ./vendor ./Tests + ./vendor diff --git a/src/Symfony/Component/Stopwatch/phpunit.xml.dist b/src/Symfony/Component/Stopwatch/phpunit.xml.dist index 38078d25bb7ee..b16dcaebf9a47 100644 --- a/src/Symfony/Component/Stopwatch/phpunit.xml.dist +++ b/src/Symfony/Component/Stopwatch/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ diff --git a/src/Symfony/Component/Templating/phpunit.xml.dist b/src/Symfony/Component/Templating/phpunit.xml.dist index 3da1f5de1371c..109584e805db2 100644 --- a/src/Symfony/Component/Templating/phpunit.xml.dist +++ b/src/Symfony/Component/Templating/phpunit.xml.dist @@ -20,8 +20,8 @@ ./ - ./vendor ./Tests + ./vendor diff --git a/src/Symfony/Component/Translation/phpunit.xml.dist b/src/Symfony/Component/Translation/phpunit.xml.dist index 16cca4afb7c69..c25ec5eda6940 100644 --- a/src/Symfony/Component/Translation/phpunit.xml.dist +++ b/src/Symfony/Component/Translation/phpunit.xml.dist @@ -20,8 +20,8 @@ ./ - ./vendor ./Tests + ./vendor diff --git a/src/Symfony/Component/Validator/phpunit.xml.dist b/src/Symfony/Component/Validator/phpunit.xml.dist index 1bf4391c3c181..cf8c343863e5d 100644 --- a/src/Symfony/Component/Validator/phpunit.xml.dist +++ b/src/Symfony/Component/Validator/phpunit.xml.dist @@ -20,8 +20,9 @@ ./ - ./vendor + ./Resources ./Tests + ./vendor diff --git a/src/Symfony/Component/Yaml/phpunit.xml.dist b/src/Symfony/Component/Yaml/phpunit.xml.dist index 8f7741fe393e6..6bdbea16e6426 100644 --- a/src/Symfony/Component/Yaml/phpunit.xml.dist +++ b/src/Symfony/Component/Yaml/phpunit.xml.dist @@ -9,6 +9,7 @@ + ./Tests/ @@ -19,8 +20,8 @@ ./ - ./vendor ./Tests + ./vendor From d04984ad0593063a026257d2744e55ad5763c5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vasseur?= Date: Tue, 17 Nov 2015 17:20:32 +0100 Subject: [PATCH 014/136] Fix PropertyInfo extractor namespace in framework bundle --- .../Bundle/FrameworkBundle/Resources/config/property_info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml index d4ce4f5d246f6..33a0a661f8991 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml @@ -13,7 +13,7 @@ - + From 01251455c0858d6beea032f343f542d0e81f25e2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 16 Nov 2015 10:23:46 +0100 Subject: [PATCH 015/136] [ProxyManager] Tmp fix composer reqs issue in ZF --- composer.json | 1 + src/Symfony/Bridge/ProxyManager/composer.json | 1 + 2 files changed, 2 insertions(+) diff --git a/composer.json b/composer.json index 198070a402ee4..73f564c5fac37 100644 --- a/composer.json +++ b/composer.json @@ -70,6 +70,7 @@ "monolog/monolog": "~1.3", "propel/propel1": "~1.6", "ircmaxell/password-compat": "~1.0", + "zendframework/zend-stdlib": "~2.5", "ocramius/proxy-manager": "~0.3.1" }, "autoload": { diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 82b119b164898..7efa4da4156e7 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -18,6 +18,7 @@ "require": { "php": ">=5.3.3", "symfony/dependency-injection": "~2.3", + "zendframework/zend-stdlib": "~2.5", "ocramius/proxy-manager": "~0.3.1" }, "require-dev": { From db5fbe0e236478e0b2cd829c18dc3fe1d6fa05ea Mon Sep 17 00:00:00 2001 From: Daniel Wehner Date: Wed, 18 Nov 2015 10:45:48 +0100 Subject: [PATCH 016/136] add it back --- src/Symfony/Component/HttpFoundation/Response.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index d67584f13974f..96d5055e00570 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -160,6 +160,7 @@ class Response 415 => 'Unsupported Media Type', 416 => 'Range Not Satisfiable', 417 => 'Expectation Failed', + 418 => 'I\'m a teapot', // RFC2324 422 => 'Unprocessable Entity', // RFC4918 423 => 'Locked', // RFC4918 424 => 'Failed Dependency', // RFC4918 From c4068d923da7973011aa48a5ca86812e8d40119a Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Tue, 17 Nov 2015 16:13:39 -0500 Subject: [PATCH 017/136] Fix bug in windows detection --- src/Symfony/Component/Console/Style/SymfonyStyle.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php index 6e9c64fc2e9c3..365c03ae328f9 100644 --- a/src/Symfony/Component/Console/Style/SymfonyStyle.php +++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php @@ -294,7 +294,7 @@ public function createProgressBar($max = 0) { $progressBar = parent::createProgressBar($max); - if ('\\' === DIRECTORY_SEPARATOR) { + if ('\\' !== DIRECTORY_SEPARATOR) { $progressBar->setEmptyBarCharacter('░'); // light shade character \u2591 $progressBar->setProgressCharacter(''); $progressBar->setBarCharacter('▓'); // dark shade character \u2593 From 15f9cf2740f1827cfb7ace60d6fc847f074f6fe8 Mon Sep 17 00:00:00 2001 From: Daniel Wehner Date: Wed, 18 Nov 2015 09:21:04 +0100 Subject: [PATCH 018/136] Fix call to undefined function json_last_error_message --- .../Serializer/Encoder/JsonDecode.php | 2 +- .../Serializer/Encoder/JsonEncode.php | 2 +- .../Tests/Encoder/JsonDecodeTest.php | 44 +++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php diff --git a/src/Symfony/Component/Serializer/Encoder/JsonDecode.php b/src/Symfony/Component/Serializer/Encoder/JsonDecode.php index d4070c23040db..8925ec36f7f99 100644 --- a/src/Symfony/Component/Serializer/Encoder/JsonDecode.php +++ b/src/Symfony/Component/Serializer/Encoder/JsonDecode.php @@ -108,7 +108,7 @@ public function decode($data, $format, array $context = array()) } if (JSON_ERROR_NONE !== $this->lastError = json_last_error()) { - throw new UnexpectedValueException(json_last_error_message()); + throw new UnexpectedValueException(json_last_error_msg()); } return $decodedData; diff --git a/src/Symfony/Component/Serializer/Encoder/JsonEncode.php b/src/Symfony/Component/Serializer/Encoder/JsonEncode.php index aa7d64530e14d..454c0d6a11470 100644 --- a/src/Symfony/Component/Serializer/Encoder/JsonEncode.php +++ b/src/Symfony/Component/Serializer/Encoder/JsonEncode.php @@ -56,7 +56,7 @@ public function encode($data, $format, array $context = array()) $encodedJson = json_encode($data, $context['json_encode_options']); if (JSON_ERROR_NONE !== $this->lastError = json_last_error()) { - throw new UnexpectedValueException(json_last_error_message()); + throw new UnexpectedValueException(json_last_error_msg()); } return $encodedJson; diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php new file mode 100644 index 0000000000000..03f2187b5576f --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Encoder; + +use Symfony\Component\Serializer\Encoder\JsonDecode; + +class JsonDecodeTest extends \PHPUnit_Framework_TestCase +{ + /** @var \Symfony\Component\Serializer\Encoder\JsonDecode */ + private $decoder; + + protected function setUp() + { + $this->decoder = new JsonDecode(true); + } + + public function testDecodeWithValidData() + { + $json = json_encode(array( + 'hello' => 'world', + )); + $result = $this->decoder->decode($json, 'json'); + $this->assertEquals(array( + 'hello' => 'world', + ), $result); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testDecodeWithInvalidData() + { + $result = $this->decoder->decode('kaboom!', 'json'); + } +} From 75aa6f68f820c4776f3172eb9eff137ba7bae704 Mon Sep 17 00:00:00 2001 From: Eugene Wissner Date: Tue, 17 Nov 2015 03:38:36 +0100 Subject: [PATCH 019/136] Fix undefined array $server --- src/Symfony/Component/HttpFoundation/Tests/RequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 2b54ef5f607d1..dcc1c2eb99132 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -570,7 +570,7 @@ public function testGetUserInfo() { $request = new Request(); - $server['PHP_AUTH_USER'] = 'fabien'; + $server = array('PHP_AUTH_USER' => 'fabien'); $request->initialize(array(), array(), array(), array(), array(), $server); $this->assertEquals('fabien', $request->getUserInfo()); From 7418d29ae97ed10a2299099be34cafe4fa04d56b Mon Sep 17 00:00:00 2001 From: FlorianLB Date: Mon, 16 Nov 2015 11:02:30 +0100 Subject: [PATCH 020/136] [Serializer] add missing unit tests related to Encoder --- .../Tests/Encoder/ChainDecoderTest.php | 77 +++++++++++ .../Tests/Encoder/ChainEncoderTest.php | 129 ++++++++++++++++++ .../Tests/Encoder/JsonDecodeTest.php | 56 ++++++-- .../Tests/Encoder/JsonEncodeTest.php | 59 ++++++++ 4 files changed, 308 insertions(+), 13 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Encoder/ChainDecoderTest.php create mode 100644 src/Symfony/Component/Serializer/Tests/Encoder/ChainEncoderTest.php create mode 100644 src/Symfony/Component/Serializer/Tests/Encoder/JsonEncodeTest.php diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/ChainDecoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/ChainDecoderTest.php new file mode 100644 index 0000000000000..7f7392e6a45b1 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Encoder/ChainDecoderTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Encoder; + +use Symfony\Component\Serializer\Encoder\ChainDecoder; + +class ChainDecoderTest extends \PHPUnit_Framework_TestCase +{ + const FORMAT_1 = 'format1'; + const FORMAT_2 = 'format2'; + const FORMAT_3 = 'format3'; + + private $chainDecoder; + private $decoder1; + private $decoder2; + + protected function setUp() + { + $this->decoder1 = $this + ->getMockBuilder('Symfony\Component\Serializer\Encoder\DecoderInterface') + ->getMock(); + + $this->decoder1 + ->method('supportsDecoding') + ->will($this->returnValueMap(array( + array(self::FORMAT_1, true), + array(self::FORMAT_2, false), + array(self::FORMAT_3, false), + ))); + + $this->decoder2 = $this + ->getMockBuilder('Symfony\Component\Serializer\Encoder\DecoderInterface') + ->getMock(); + + $this->decoder2 + ->method('supportsDecoding') + ->will($this->returnValueMap(array( + array(self::FORMAT_1, false), + array(self::FORMAT_2, true), + array(self::FORMAT_3, false), + ))); + + $this->chainDecoder = new ChainDecoder(array($this->decoder1, $this->decoder2)); + } + + public function testSupportsDecoding() + { + $this->assertTrue($this->chainDecoder->supportsDecoding(self::FORMAT_1)); + $this->assertTrue($this->chainDecoder->supportsDecoding(self::FORMAT_2)); + $this->assertFalse($this->chainDecoder->supportsDecoding(self::FORMAT_3)); + } + + public function testDecode() + { + $this->decoder1->expects($this->never())->method('decode'); + $this->decoder2->expects($this->once())->method('decode'); + + $this->chainDecoder->decode('string_to_decode', self::FORMAT_2); + } + + /** + * @expectedException Symfony\Component\Serializer\Exception\RuntimeException + */ + public function testDecodeUnsupportedFormat() + { + $this->chainDecoder->decode('string_to_decode', self::FORMAT_3); + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/ChainEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/ChainEncoderTest.php new file mode 100644 index 0000000000000..6d3436b33d753 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Encoder/ChainEncoderTest.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Encoder; + +use Symfony\Component\Serializer\Encoder\ChainEncoder; +use Symfony\Component\Serializer\Encoder\NormalizationAwareInterface; + +class ChainEncoderTest extends \PHPUnit_Framework_TestCase +{ + const FORMAT_1 = 'format1'; + const FORMAT_2 = 'format2'; + const FORMAT_3 = 'format3'; + + private $chainEncoder; + private $encoder1; + private $encoder2; + + protected function setUp() + { + $this->encoder1 = $this + ->getMockBuilder('Symfony\Component\Serializer\Encoder\EncoderInterface') + ->getMock(); + + $this->encoder1 + ->method('supportsEncoding') + ->will($this->returnValueMap(array( + array(self::FORMAT_1, true), + array(self::FORMAT_2, false), + array(self::FORMAT_3, false), + ))); + + $this->encoder2 = $this + ->getMockBuilder('Symfony\Component\Serializer\Encoder\EncoderInterface') + ->getMock(); + + $this->encoder2 + ->method('supportsEncoding') + ->will($this->returnValueMap(array( + array(self::FORMAT_1, false), + array(self::FORMAT_2, true), + array(self::FORMAT_3, false), + ))); + + $this->chainEncoder = new ChainEncoder(array($this->encoder1, $this->encoder2)); + } + + public function testSupportsEncoding() + { + $this->assertTrue($this->chainEncoder->supportsEncoding(self::FORMAT_1)); + $this->assertTrue($this->chainEncoder->supportsEncoding(self::FORMAT_2)); + $this->assertFalse($this->chainEncoder->supportsEncoding(self::FORMAT_3)); + } + + public function testEncode() + { + $this->encoder1->expects($this->never())->method('encode'); + $this->encoder2->expects($this->once())->method('encode'); + + $this->chainEncoder->encode(array('foo' => 123), self::FORMAT_2); + } + + /** + * @expectedException Symfony\Component\Serializer\Exception\RuntimeException + */ + public function testEncodeUnsupportedFormat() + { + $this->chainEncoder->encode(array('foo' => 123), self::FORMAT_3); + } + + public function testNeedsNormalizationBasic() + { + $this->assertTrue($this->chainEncoder->needsNormalization(self::FORMAT_1)); + $this->assertTrue($this->chainEncoder->needsNormalization(self::FORMAT_2)); + } + + /** + * @dataProvider booleanProvider + */ + public function testNeedsNormalizationChainNormalizationAware($bool) + { + $chainEncoder = $this + ->getMockBuilder('Symfony\Component\Serializer\Tests\Encoder\ChainNormalizationAwareEncoder') + ->getMock(); + + $chainEncoder->method('supportsEncoding')->willReturn(true); + $chainEncoder->method('needsNormalization')->willReturn($bool); + + $sut = new ChainEncoder(array($chainEncoder)); + + $this->assertEquals($bool, $sut->needsNormalization(self::FORMAT_1)); + } + + public function testNeedsNormalizationNormalizationAware() + { + $encoder = new NormalizationAwareEncoder(); + $sut = new ChainEncoder(array($encoder)); + + $this->assertFalse($sut->needsNormalization(self::FORMAT_1)); + } + + public function booleanProvider() + { + return array( + array(true), + array(false), + ); + } +} + +class ChainNormalizationAwareEncoder extends ChainEncoder implements NormalizationAwareInterface +{ +} + +class NormalizationAwareEncoder implements NormalizationAwareInterface +{ + public function supportsEncoding($format) + { + return true; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php index 03f2187b5576f..97930115748d2 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php @@ -12,33 +12,63 @@ namespace Symfony\Component\Serializer\Tests\Encoder; use Symfony\Component\Serializer\Encoder\JsonDecode; +use Symfony\Component\Serializer\Encoder\JsonEncoder; class JsonDecodeTest extends \PHPUnit_Framework_TestCase { /** @var \Symfony\Component\Serializer\Encoder\JsonDecode */ - private $decoder; + private $decode; protected function setUp() { - $this->decoder = new JsonDecode(true); + $this->decode = new JsonDecode(); } - public function testDecodeWithValidData() + public function testSupportsDecoding() { - $json = json_encode(array( - 'hello' => 'world', - )); - $result = $this->decoder->decode($json, 'json'); - $this->assertEquals(array( - 'hello' => 'world', - ), $result); + $this->assertTrue($this->decode->supportsDecoding(JsonEncoder::FORMAT)); + $this->assertFalse($this->decode->supportsDecoding('foobar')); } /** - * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + * @dataProvider decodeProvider */ - public function testDecodeWithInvalidData() + public function testDecode($toDecode, $expected, $context) { - $result = $this->decoder->decode('kaboom!', 'json'); + $this->assertEquals( + $expected, + $this->decode->decode($toDecode, JsonEncoder::FORMAT, $context) + ); + } + + public function decodeProvider() + { + $stdClass = new \stdClass(); + $stdClass->foo = 'bar'; + + $assoc = array('foo' => 'bar'); + + return array( + array('{"foo": "bar"}', $stdClass, array()), + array('{"foo": "bar"}', $assoc, array('json_decode_associative' => true)), + ); + } + + /** + * @requires function json_last_error_msg + * @dataProvider decodeProviderException + * @expectedException Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testDecodeWithException($value) + { + $this->decode->decode($value, JsonEncoder::FORMAT); + } + + public function decodeProviderException() + { + return array( + array("{'foo': 'bar'}"), + array('kaboom!'), + ); } } diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncodeTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncodeTest.php new file mode 100644 index 0000000000000..3e6fb7b6ec34e --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncodeTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Encoder; + +use Symfony\Component\Serializer\Encoder\JsonEncode; +use Symfony\Component\Serializer\Encoder\JsonEncoder; + +class JsonEncodeTest extends \PHPUnit_Framework_TestCase +{ + private $encoder; + + protected function setUp() + { + $this->encode = new JsonEncode(); + } + + public function testSupportsEncoding() + { + $this->assertTrue($this->encode->supportsEncoding(JsonEncoder::FORMAT)); + $this->assertFalse($this->encode->supportsEncoding('foobar')); + } + + /** + * @dataProvider encodeProvider + */ + public function testEncode($toEncode, $expected, $context) + { + $this->assertEquals( + $expected, + $this->encode->encode($toEncode, JsonEncoder::FORMAT, $context) + ); + } + + public function encodeProvider() + { + return array( + array(array(), '[]', array()), + array(array(), '{}', array('json_encode_options' => JSON_FORCE_OBJECT)), + ); + } + + /** + * @requires function json_last_error_msg + * @expectedException Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testEncodeWithError() + { + $this->encode->encode("\xB1\x31", JsonEncoder::FORMAT); + } +} From 9669238af66ce0daf3ec2ecba5918f9ce9767297 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 17 Nov 2015 17:45:51 +0100 Subject: [PATCH 021/136] [Process] Fix PhpProcess with phpdbg runtime --- composer.json | 2 +- phpunit | 10 ++++++---- src/Symfony/Bridge/ProxyManager/composer.json | 2 +- .../Component/Process/PhpExecutableFinder.php | 7 ++++--- src/Symfony/Component/Process/PhpProcess.php | 7 +++++++ src/Symfony/Component/Process/Process.php | 2 +- .../Process/Tests/AbstractProcessTest.php | 20 ++++--------------- .../Process/Tests/PhpExecutableFinderTest.php | 2 ++ .../Process/Tests/PhpProcessTest.php | 4 ++++ 9 files changed, 30 insertions(+), 26 deletions(-) diff --git a/composer.json b/composer.json index 73f564c5fac37..4d0757a371e69 100644 --- a/composer.json +++ b/composer.json @@ -70,7 +70,7 @@ "monolog/monolog": "~1.3", "propel/propel1": "~1.6", "ircmaxell/password-compat": "~1.0", - "zendframework/zend-stdlib": "~2.5", + "zendframework/zend-stdlib": "~2.2", "ocramius/proxy-manager": "~0.3.1" }, "autoload": { diff --git a/phpunit b/phpunit index 0b8e2e3d3c0f6..2ab4f25e75cc2 100755 --- a/phpunit +++ b/phpunit @@ -11,7 +11,7 @@ */ // Please update when phpunit needs to be reinstalled with fresh deps: -// Cache-Id-Version: 2015-11-09 12:13 UTC +// Cache-Id-Version: 2015-11-18 14:14 UTC use Symfony\Component\Process\ProcessUtils; @@ -23,12 +23,15 @@ $PHPUNIT_VERSION = PHP_VERSION_ID >= 70000 ? '5.0' : '4.8'; $PHPUNIT_DIR = __DIR__.'/.phpunit'; $PHP = defined('PHP_BINARY') ? PHP_BINARY : 'php'; $PHP = ProcessUtils::escapeArgument($PHP); +if ('phpdbg' === PHP_SAPI) { + $PHP .= ' -qrr'; +} $COMPOSER = file_exists($COMPOSER = __DIR__.'/composer.phar') || ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? `where.exe composer.phar` : `which composer.phar`)) ? $PHP.' '.ProcessUtils::escapeArgument($COMPOSER) : 'composer'; -if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__FILE__) !== @file_get_contents("$PHPUNIT_DIR/.md5")) { +if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__FILE__) !== @file_get_contents("$PHPUNIT_DIR/.$PHPUNIT_VERSION.md5")) { // Build a standalone phpunit without symfony/yaml $oldPwd = getcwd(); @@ -49,7 +52,6 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ $zip->close(); chdir("phpunit-$PHPUNIT_VERSION"); passthru("$COMPOSER remove --no-update symfony/yaml"); - passthru("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"<=3.0.0\""); passthru("$COMPOSER require --dev --no-update symfony/phpunit-bridge \">=2.8@dev\""); passthru("$COMPOSER install --prefer-source --no-progress --ansi"); file_put_contents('phpunit', <<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('.md5', md5_file(__FILE__)); + file_put_contents(".$PHPUNIT_VERSION.md5", md5_file(__FILE__)); chdir($oldPwd); } diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 7efa4da4156e7..5f9bd8a2afbaa 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=5.3.3", "symfony/dependency-injection": "~2.3", - "zendframework/zend-stdlib": "~2.5", + "zendframework/zend-stdlib": "~2.2", "ocramius/proxy-manager": "~0.3.1" }, "require-dev": { diff --git a/src/Symfony/Component/Process/PhpExecutableFinder.php b/src/Symfony/Component/Process/PhpExecutableFinder.php index f8f57cc536a25..e8b77b73b6c12 100644 --- a/src/Symfony/Component/Process/PhpExecutableFinder.php +++ b/src/Symfony/Component/Process/PhpExecutableFinder.php @@ -41,8 +41,8 @@ public function find($includeArgs = true) } // PHP_BINARY return the current sapi executable - if (defined('PHP_BINARY') && PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server')) && is_file(PHP_BINARY)) { - return PHP_BINARY; + if (defined('PHP_BINARY') && PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server', 'phpdbg')) && is_file(PHP_BINARY)) { + return PHP_BINARY.($includeArgs ? ' '.implode(' ', $this->findArguments()) : ''); } if ($php = getenv('PHP_PATH')) { @@ -76,9 +76,10 @@ public function findArguments() { $arguments = array(); - // HHVM support if (defined('HHVM_VERSION')) { $arguments[] = '--php'; + } elseif ('phpdbg' === PHP_SAPI) { + $arguments[] = '-qrr'; } return $arguments; diff --git a/src/Symfony/Component/Process/PhpProcess.php b/src/Symfony/Component/Process/PhpProcess.php index 1adbd977adf88..4a2a2625ffae0 100644 --- a/src/Symfony/Component/Process/PhpProcess.php +++ b/src/Symfony/Component/Process/PhpProcess.php @@ -39,6 +39,13 @@ public function __construct($script, $cwd = null, array $env = null, $timeout = if (false === $php = $executableFinder->find()) { $php = null; } + if ('phpdbg' === PHP_SAPI) { + $file = tempnam(sys_get_temp_dir(), 'dbg'); + file_put_contents($file, $script); + register_shutdown_function('unlink', $file); + $php .= ' '.ProcessUtils::escapeArgument($file); + $script = null; + } parent::__construct($php, $cwd, $env, $script, $timeout, $options); } diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index ae11f89c10601..1675ad33994aa 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -242,7 +242,7 @@ public function start($callback = null) if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { // Workaround for the bug, when PTS functionality is enabled. // @see : https://bugs.php.net/69442 - $ptsWorkaround = fopen('php://fd/0', 'r'); + $ptsWorkaround = fopen(__FILE__, 'r'); } $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options); diff --git a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php index 62616eed347d4..1874290936d53 100644 --- a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php +++ b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php @@ -27,7 +27,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase public static function setUpBeforeClass() { $phpBin = new PhpExecutableFinder(); - self::$phpBin = $phpBin->find(); + self::$phpBin = 'phpdbg' === PHP_SAPI ? 'php' : $phpBin->find(); } public function testThatProcessDoesNotThrowWarningDuringRun() @@ -80,7 +80,7 @@ public function testStopWithTimeoutIsActuallyWorking() // exec is mandatory here since we send a signal to the process // see https://github.com/symfony/symfony/issues/5030 about prepending // command with exec - $p = $this->getProcess('exec php '.__DIR__.'/NonStopableProcess.php 3'); + $p = $this->getProcess('exec '.self::$phpBin.' '.__DIR__.'/NonStopableProcess.php 3'); $p->start(); usleep(100000); $start = microtime(true); @@ -410,7 +410,7 @@ public function testTTYCommand() $this->markTestSkipped('Windows does have /dev/tty support'); } - $process = $this->getProcess('echo "foo" >> /dev/null && php -r "usleep(100000);"'); + $process = $this->getProcess('echo "foo" >> /dev/null && '.self::$phpBin.' -r "usleep(100000);"'); $process->setTty(true); $process->start(); $this->assertTrue($process->isRunning()); @@ -633,7 +633,7 @@ public function testProcessThrowsExceptionWhenExternallySignaled() $termSignal = defined('SIGKILL') ? SIGKILL : 9; - $process = $this->getProcess('exec php -r "while (true) {}"'); + $process = $this->getProcess('exec '.self::$phpBin.' -r "while (true) {}"'); $process->start(); posix_kill($process->getPid(), $termSignal); @@ -659,18 +659,6 @@ public function testRestart() $this->assertNotEquals($process1->getOutput(), $process2->getOutput()); } - public function testPhpDeadlock() - { - $this->markTestSkipped('Can cause PHP to hang'); - - // Sleep doesn't work as it will allow the process to handle signals and close - // file handles from the other end. - $process = $this->getProcess(self::$phpBin.' -r "while (true) {}"'); - $process->start(); - - // PHP will deadlock when it tries to cleanup $process - } - public function testRunProcessWithTimeout() { $timeout = 0.5; diff --git a/src/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php b/src/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php index cd4abedc9df73..28bafe38ea1c6 100644 --- a/src/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php +++ b/src/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php @@ -68,6 +68,8 @@ public function testFindArguments() if (defined('HHVM_VERSION')) { $this->assertEquals($f->findArguments(), array('--php'), '::findArguments() returns HHVM arguments'); + } elseif ('phpdbg' === PHP_SAPI) { + $this->assertEquals($f->findArguments(), array('-qrr'), '::findArguments() returns phpdbg arguments'); } else { $this->assertEquals($f->findArguments(), array(), '::findArguments() returns no arguments'); } diff --git a/src/Symfony/Component/Process/Tests/PhpProcessTest.php b/src/Symfony/Component/Process/Tests/PhpProcessTest.php index 5dc546cc1ce6e..2cf79aa1a6d15 100644 --- a/src/Symfony/Component/Process/Tests/PhpProcessTest.php +++ b/src/Symfony/Component/Process/Tests/PhpProcessTest.php @@ -30,6 +30,10 @@ public function testNonBlockingWorks() public function testCommandLine() { + if ('phpdbg' === PHP_SAPI) { + $this->markTestSkipped('phpdbg SAPI is not supported by this test.'); + } + $process = new PhpProcess(<< Date: Wed, 18 Nov 2015 19:46:46 +0100 Subject: [PATCH 022/136] [Form] Fix ResolvedFormType deprecation notices --- src/Symfony/Component/Form/ResolvedFormType.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/ResolvedFormType.php b/src/Symfony/Component/Form/ResolvedFormType.php index b334acff3c655..d637d223a4631 100644 --- a/src/Symfony/Component/Form/ResolvedFormType.php +++ b/src/Symfony/Component/Form/ResolvedFormType.php @@ -71,12 +71,12 @@ public function __construct(FormTypeInterface $innerType, array $typeExtensions // Anyone else should only override getBlockPrefix() if they actually // want to have a different block prefix than the default one if ($isOldOverwritten && !$isNewOverwritten) { - @trigger_error(get_class($this->innerType).': The FormTypeInterface::getName() method is deprecated since version 2.8 and will be removed in 3.0. Remove it from your classes. Use getBlockPrefix() if you want to customize the template block prefix. This method will be added to the FormTypeInterface with Symfony 3.0.', E_USER_DEPRECATED); + @trigger_error(get_class($innerType).': The FormTypeInterface::getName() method is deprecated since version 2.8 and will be removed in 3.0. Remove it from your classes. Use getBlockPrefix() if you want to customize the template block prefix. This method will be added to the FormTypeInterface with Symfony 3.0.', E_USER_DEPRECATED); } $blockPrefix = $innerType->getBlockPrefix(); } else { - @trigger_error(get_class($this->innerType).': The FormTypeInterface::getBlockPrefix() method will be added in version 3.0. You should extend AbstractType or add it to your implementation.', E_USER_DEPRECATED); + @trigger_error(get_class($innerType).': The FormTypeInterface::getBlockPrefix() method will be added in version 3.0. You should extend AbstractType or add it to your implementation.', E_USER_DEPRECATED); // Deal with classes that don't extend AbstractType // Calculate block prefix from the FQCN by default From 04599125238d23e0c5388fbbcc6067055c970f62 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 19 Nov 2015 10:04:56 +0100 Subject: [PATCH 023/136] [WebProfilerBundle] Fix minitoolbar height --- .../Resources/views/Profiler/toolbar.css.twig | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig index 2cb44f87335bb..0a269ea3f772f 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig @@ -2,12 +2,20 @@ background-color: #222; bottom: 0; display: none; - height: 36px; - padding: 5px 6px 0; + height: 30px; + padding: 6px 6px 0; position: fixed; right: 0; z-index: 99999; } +.sf-minitoolbar a { + display: block; +} +.sf-minitoolbar svg, +.sf-minitoolbar img { + max-height: 24px; + max-width: 24px; +} .sf-toolbarreset * { -webkit-box-sizing: content-box; @@ -36,7 +44,8 @@ } .sf-toolbarreset svg, .sf-toolbarreset img { - max-height: 20px; + max-height: 24px; + max-width: 24px; } .sf-toolbarreset .hide-button { From 6e015e7e0e18eacf8eec3940f15440a921458783 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 19 Nov 2015 09:34:27 +0100 Subject: [PATCH 024/136] Remove tmp addition of zend-stdlib --- composer.json | 1 - src/Symfony/Bridge/ProxyManager/composer.json | 1 - 2 files changed, 2 deletions(-) diff --git a/composer.json b/composer.json index 4d0757a371e69..198070a402ee4 100644 --- a/composer.json +++ b/composer.json @@ -70,7 +70,6 @@ "monolog/monolog": "~1.3", "propel/propel1": "~1.6", "ircmaxell/password-compat": "~1.0", - "zendframework/zend-stdlib": "~2.2", "ocramius/proxy-manager": "~0.3.1" }, "autoload": { diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 5f9bd8a2afbaa..82b119b164898 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -18,7 +18,6 @@ "require": { "php": ">=5.3.3", "symfony/dependency-injection": "~2.3", - "zendframework/zend-stdlib": "~2.2", "ocramius/proxy-manager": "~0.3.1" }, "require-dev": { From f15e6e0ba924096edd170926ec09a9af6da514f4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 19 Nov 2015 13:33:23 +0100 Subject: [PATCH 025/136] [Process] Fix trailing space in PHP binary finder --- src/Symfony/Component/Process/PhpExecutableFinder.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Process/PhpExecutableFinder.php b/src/Symfony/Component/Process/PhpExecutableFinder.php index e8b77b73b6c12..fb297825fe364 100644 --- a/src/Symfony/Component/Process/PhpExecutableFinder.php +++ b/src/Symfony/Component/Process/PhpExecutableFinder.php @@ -35,14 +35,17 @@ public function __construct() */ public function find($includeArgs = true) { + $args = $this->findArguments(); + $args = $includeArgs && $args ? ' '.implode(' ', $args) : ''; + // HHVM support if (defined('HHVM_VERSION')) { - return (getenv('PHP_BINARY') ?: PHP_BINARY).($includeArgs ? ' '.implode(' ', $this->findArguments()) : ''); + return (getenv('PHP_BINARY') ?: PHP_BINARY).$args; } // PHP_BINARY return the current sapi executable if (defined('PHP_BINARY') && PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server', 'phpdbg')) && is_file(PHP_BINARY)) { - return PHP_BINARY.($includeArgs ? ' '.implode(' ', $this->findArguments()) : ''); + return PHP_BINARY.$args; } if ($php = getenv('PHP_PATH')) { From 331a0469c10af2a229d411828fa316ea408706c8 Mon Sep 17 00:00:00 2001 From: Tristan Darricau Date: Tue, 20 Oct 2015 14:28:37 +0200 Subject: [PATCH 026/136] [DependencyInjection] Unescape parameters for all types of injection --- .../DependencyInjection/ContainerBuilder.php | 4 ++-- .../Tests/ContainerBuilderTest.php | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 2c4460f394a09..6c52c47b651a9 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -895,7 +895,7 @@ public function createService(Definition $definition, $id, $tryProxy = true) $this->callMethod($service, $call); } - $properties = $this->resolveServices($parameterBag->resolveValue($definition->getProperties())); + $properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties()))); foreach ($properties as $name => $value) { $service->$name = $value; } @@ -1054,7 +1054,7 @@ private function callMethod($service, $call) } } - call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->resolveValue($call[1]))); + call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])))); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index e215b9d00a394..3a369d9d2ed18 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -305,6 +305,24 @@ public function testCreateServiceMethodCalls() $this->assertEquals(array('bar', $builder->get('bar')), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments'); } + public function testCreateServiceMethodCallsWithEscapedParam() + { + $builder = new ContainerBuilder(); + $builder->register('bar', 'stdClass'); + $builder->register('foo1', 'FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%'))); + $builder->setParameter('value', 'bar'); + $this->assertEquals(array('%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments'); + } + + public function testCreateServiceProperties() + { + $builder = new ContainerBuilder(); + $builder->register('bar', 'stdClass'); + $builder->register('foo1', 'FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%')); + $builder->setParameter('value', 'bar'); + $this->assertEquals(array('bar', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the properties'); + } + public function testCreateServiceConfigurator() { $builder = new ContainerBuilder(); From eec6fbc768a3c3b5348641f241f1f4a9d90a303b Mon Sep 17 00:00:00 2001 From: Daniel Wehner Date: Wed, 18 Nov 2015 11:39:29 +0100 Subject: [PATCH 027/136] Sent out a status text for unknown HTTP headers. --- src/Symfony/Component/HttpFoundation/Response.php | 2 +- src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index 3c37187cd1e6b..ad55f8772af47 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -412,7 +412,7 @@ public function setStatusCode($code, $text = null) } if (null === $text) { - $this->statusText = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : ''; + $this->statusText = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : 'unknown status'; return $this; } diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php index 72e143f9da438..f0539079c949c 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php @@ -647,7 +647,7 @@ public function getStatusCodeFixtures() array('200', null, 'OK'), array('200', false, ''), array('200', 'foo', 'foo'), - array('199', null, ''), + array('199', null, 'unknown status'), array('199', false, ''), array('199', 'foo', 'foo'), ); From b06b93fd3051a808cc9428dd979b3b02e65c8e66 Mon Sep 17 00:00:00 2001 From: Eugene Wissner Date: Fri, 20 Nov 2015 04:02:44 +0100 Subject: [PATCH 028/136] [HttpFoundation] Remove not existing class member open() and close() SessionHandlerProxy method suse $this->active that was removed from the parent AbstractProxy class after 2.8. --- .../Session/Storage/Proxy/SessionHandlerProxy.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php index 81643c74b4001..c5e97d415bbe2 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php @@ -42,13 +42,7 @@ public function __construct(\SessionHandlerInterface $handler) */ public function open($savePath, $sessionName) { - $return = (bool) $this->handler->open($savePath, $sessionName); - - if (true === $return) { - $this->active = true; - } - - return $return; + return (bool) $this->handler->open($savePath, $sessionName); } /** @@ -56,8 +50,6 @@ public function open($savePath, $sessionName) */ public function close() { - $this->active = false; - return (bool) $this->handler->close(); } From 576f8029177e7454d8e4c851c2ece123b24ad706 Mon Sep 17 00:00:00 2001 From: ogizanagi Date: Thu, 19 Nov 2015 23:03:24 +0100 Subject: [PATCH 029/136] [Process] PhpExecutableFinder: add regression test --- .../Process/Tests/PhpExecutableFinderTest.php | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php b/src/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php index 28bafe38ea1c6..87d0efe9ebf1f 100644 --- a/src/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php +++ b/src/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php @@ -43,7 +43,27 @@ public function testFindWithPhpPath() } /** - * tests find() with the env var PHP_PATH. + * tests find() with the constant PHP_BINARY. + * + * @requires PHP 5.4 + */ + public function testFind() + { + if (defined('HHVM_VERSION')) { + $this->markTestSkipped('Should not be executed in HHVM context.'); + } + + $f = new PhpExecutableFinder(); + + $current = PHP_BINARY; + $args = 'phpdbg' === PHP_SAPI ? ' -qrr' : ''; + + $this->assertEquals($current.$args, $f->find(), '::find() returns the executable PHP'); + $this->assertEquals($current, $f->find(false), '::find() returns the executable PHP'); + } + + /** + * tests find() with the env var / constant PHP_BINARY with HHVM. */ public function testFindWithHHVM() { From a591ba3d8085587c2892fe7716a9966e1119bef5 Mon Sep 17 00:00:00 2001 From: Joshua Thijssen Date: Fri, 20 Nov 2015 11:06:22 +0100 Subject: [PATCH 030/136] Added translation for BIC validator --- .../Validator/Resources/translations/validators.nl.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index fe3346973e8b4..371ad9741e612 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -306,6 +306,10 @@ This value does not match the expected {{ charset }} charset. Deze waarde is niet in de verwachte tekencodering {{ charset }}. + + This is not a valid Business Identifier Code (BIC). + Dit is geen geldige bedrijfsidentificatiecode (BIC/SWIFT). + From baad4da9b72d2d0af14a3be433a453f22d106870 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 20 Nov 2015 13:11:01 +0100 Subject: [PATCH 031/136] [HttpKernel] Don't reset on shutdown but in FrameworkBundle/Test/KernelTestCase --- src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php | 5 +++++ src/Symfony/Component/HttpKernel/Kernel.php | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php index 04f934c4fe525..aa8b66929c7ce 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Test; +use Symfony\Component\DependencyInjection\ResettableContainerInterface; use Symfony\Component\Finder\Finder; use Symfony\Component\HttpKernel\KernelInterface; @@ -171,7 +172,11 @@ protected static function createKernel(array $options = array()) protected static function ensureKernelShutdown() { if (null !== static::$kernel) { + $container = static::$kernel->getContainer(); static::$kernel->shutdown(); + if ($container instanceof ResettableContainerInterface) { + $container->reset(); + } } } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7c55172d395ae..2b573fe860471 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -23,7 +23,6 @@ use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\DependencyInjection\Loader\DirectoryLoader; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; -use Symfony\Component\DependencyInjection\ResettableContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Bundle\BundleInterface; @@ -171,10 +170,6 @@ public function shutdown() $bundle->setContainer(null); } - if ($this->container instanceof ResettableContainerInterface) { - $this->container->reset(); - } - $this->container = null; } From 357dea1ea82fb31d246ca71b404de2e49f2b4bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Fri, 20 Nov 2015 14:32:45 +0100 Subject: [PATCH 032/136] Add Spanish translation for BIC validator --- .../Validator/Resources/translations/validators.es.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index d874573a7afa0..1fa59dda6ad46 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -310,6 +310,10 @@ This value does not match the expected {{ charset }} charset. La codificación de caracteres para este valor debería ser {{ charset }}. + + This is not a valid Business Identifier Code (BIC). + No es un Código de Identificación Bancaria (BIC) válido. + From 4ffe14cab4c2195cd17bc4c6f20282f4f35a0d69 Mon Sep 17 00:00:00 2001 From: Eugene Wissner Date: Mon, 23 Nov 2015 09:57:25 +0100 Subject: [PATCH 033/136] [HttpFoundation] Remove deprecated class method parameter --- .../Component/HttpFoundation/ParameterBag.php | 30 ++++++++----------- .../HttpFoundation/Tests/ParameterBagTest.php | 14 ++++----- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/ParameterBag.php b/src/Symfony/Component/HttpFoundation/ParameterBag.php index 71477432bcec8..6402602956aa7 100644 --- a/src/Symfony/Component/HttpFoundation/ParameterBag.php +++ b/src/Symfony/Component/HttpFoundation/ParameterBag.php @@ -128,13 +128,12 @@ public function remove($key) * * @param string $key The parameter key * @param string $default The default value if the parameter key does not exist - * @param bool $deep If true, a path like foo[bar] will find deeper items * * @return string The filtered value */ - public function getAlpha($key, $default = '', $deep = false) + public function getAlpha($key, $default = '') { - return preg_replace('/[^[:alpha:]]/', '', $this->get($key, $default, $deep)); + return preg_replace('/[^[:alpha:]]/', '', $this->get($key, $default)); } /** @@ -142,13 +141,12 @@ public function getAlpha($key, $default = '', $deep = false) * * @param string $key The parameter key * @param string $default The default value if the parameter key does not exist - * @param bool $deep If true, a path like foo[bar] will find deeper items * * @return string The filtered value */ - public function getAlnum($key, $default = '', $deep = false) + public function getAlnum($key, $default = '') { - return preg_replace('/[^[:alnum:]]/', '', $this->get($key, $default, $deep)); + return preg_replace('/[^[:alnum:]]/', '', $this->get($key, $default)); } /** @@ -156,14 +154,13 @@ public function getAlnum($key, $default = '', $deep = false) * * @param string $key The parameter key * @param string $default The default value if the parameter key does not exist - * @param bool $deep If true, a path like foo[bar] will find deeper items * * @return string The filtered value */ - public function getDigits($key, $default = '', $deep = false) + public function getDigits($key, $default = '') { // we need to remove - and + because they're allowed in the filter - return str_replace(array('-', '+'), '', $this->filter($key, $default, $deep, FILTER_SANITIZE_NUMBER_INT)); + return str_replace(array('-', '+'), '', $this->filter($key, $default, FILTER_SANITIZE_NUMBER_INT)); } /** @@ -171,13 +168,12 @@ public function getDigits($key, $default = '', $deep = false) * * @param string $key The parameter key * @param int $default The default value if the parameter key does not exist - * @param bool $deep If true, a path like foo[bar] will find deeper items * * @return int The filtered value */ - public function getInt($key, $default = 0, $deep = false) + public function getInt($key, $default = 0) { - return (int) $this->get($key, $default, $deep); + return (int) $this->get($key, $default); } /** @@ -185,13 +181,12 @@ public function getInt($key, $default = 0, $deep = false) * * @param string $key The parameter key * @param mixed $default The default value if the parameter key does not exist - * @param bool $deep If true, a path like foo[bar] will find deeper items * * @return bool The filtered value */ - public function getBoolean($key, $default = false, $deep = false) + public function getBoolean($key, $default = false) { - return $this->filter($key, $default, $deep, FILTER_VALIDATE_BOOLEAN); + return $this->filter($key, $default, FILTER_VALIDATE_BOOLEAN); } /** @@ -199,7 +194,6 @@ public function getBoolean($key, $default = false, $deep = false) * * @param string $key Key. * @param mixed $default Default = null. - * @param bool $deep Default = false. * @param int $filter FILTER_* constant. * @param mixed $options Filter options. * @@ -207,9 +201,9 @@ public function getBoolean($key, $default = false, $deep = false) * * @return mixed */ - public function filter($key, $default = null, $deep = false, $filter = FILTER_DEFAULT, $options = array()) + public function filter($key, $default = null, $filter = FILTER_DEFAULT, $options = array()) { - $value = $this->get($key, $default, $deep); + $value = $this->get($key, $default); // Always turn $options into an array - this allows filter_var option shortcuts. if (!is_array($options) && $options) { diff --git a/src/Symfony/Component/HttpFoundation/Tests/ParameterBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ParameterBagTest.php index 3d1b7f8e1c3a1..1f724d41fa8b2 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ParameterBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ParameterBagTest.php @@ -137,26 +137,26 @@ public function testFilter() $this->assertEmpty($bag->filter('nokey'), '->filter() should return empty by default if no key is found'); - $this->assertEquals('0123', $bag->filter('digits', '', false, FILTER_SANITIZE_NUMBER_INT), '->filter() gets a value of parameter as integer filtering out invalid characters'); + $this->assertEquals('0123', $bag->filter('digits', '', FILTER_SANITIZE_NUMBER_INT), '->filter() gets a value of parameter as integer filtering out invalid characters'); - $this->assertEquals('example@example.com', $bag->filter('email', '', false, FILTER_VALIDATE_EMAIL), '->filter() gets a value of parameter as email'); + $this->assertEquals('example@example.com', $bag->filter('email', '', FILTER_VALIDATE_EMAIL), '->filter() gets a value of parameter as email'); - $this->assertEquals('http://example.com/foo', $bag->filter('url', '', false, FILTER_VALIDATE_URL, array('flags' => FILTER_FLAG_PATH_REQUIRED)), '->filter() gets a value of parameter as URL with a path'); + $this->assertEquals('http://example.com/foo', $bag->filter('url', '', FILTER_VALIDATE_URL, array('flags' => FILTER_FLAG_PATH_REQUIRED)), '->filter() gets a value of parameter as URL with a path'); // This test is repeated for code-coverage - $this->assertEquals('http://example.com/foo', $bag->filter('url', '', false, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED), '->filter() gets a value of parameter as URL with a path'); + $this->assertEquals('http://example.com/foo', $bag->filter('url', '', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED), '->filter() gets a value of parameter as URL with a path'); - $this->assertFalse($bag->filter('dec', '', false, FILTER_VALIDATE_INT, array( + $this->assertFalse($bag->filter('dec', '', FILTER_VALIDATE_INT, array( 'flags' => FILTER_FLAG_ALLOW_HEX, 'options' => array('min_range' => 1, 'max_range' => 0xff), )), '->filter() gets a value of parameter as integer between boundaries'); - $this->assertFalse($bag->filter('hex', '', false, FILTER_VALIDATE_INT, array( + $this->assertFalse($bag->filter('hex', '', FILTER_VALIDATE_INT, array( 'flags' => FILTER_FLAG_ALLOW_HEX, 'options' => array('min_range' => 1, 'max_range' => 0xff), )), '->filter() gets a value of parameter as integer between boundaries'); - $this->assertEquals(array('bang'), $bag->filter('array', '', false), '->filter() gets a value of parameter as an array'); + $this->assertEquals(array('bang'), $bag->filter('array', ''), '->filter() gets a value of parameter as an array'); } public function testGetIterator() From 8feb9ef080b6c04bd40cdec4d0af030002be4cc0 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 5 Nov 2015 15:58:36 -0500 Subject: [PATCH 034/136] [Routing] Changing RouteCollectionBuilder::import() behavior to add to the builder --- .../Component/Routing/RouteCollectionBuilder.php | 12 ++++++++---- .../Routing/Tests/RouteCollectionBuilderTest.php | 7 +++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Routing/RouteCollectionBuilder.php b/src/Symfony/Component/Routing/RouteCollectionBuilder.php index 700ee37234963..a54a049d27d12 100644 --- a/src/Symfony/Component/Routing/RouteCollectionBuilder.php +++ b/src/Symfony/Component/Routing/RouteCollectionBuilder.php @@ -49,16 +49,17 @@ public function __construct(LoaderInterface $loader = null) /** * Import an external routing resource and returns the RouteCollectionBuilder. * - * $routes->mount('/blog', $routes->import('blog.yml')); + * $routes->import('blog.yml', '/blog'); * - * @param mixed $resource - * @param string $type + * @param mixed $resource + * @param string|null $prefix + * @param string $type * * @return RouteCollectionBuilder * * @throws FileLoaderLoadException */ - public function import($resource, $type = null) + public function import($resource, $prefix = '/', $type = null) { /** @var RouteCollection $collection */ $collection = $this->load($resource, $type); @@ -73,6 +74,9 @@ public function import($resource, $type = null) $builder->addResource($resource); } + // mount into this builder + $this->mount($prefix, $builder); + return $builder; } diff --git a/src/Symfony/Component/Routing/Tests/RouteCollectionBuilderTest.php b/src/Symfony/Component/Routing/Tests/RouteCollectionBuilderTest.php index c19fdcbf9ff69..e3a98e3b72698 100644 --- a/src/Symfony/Component/Routing/Tests/RouteCollectionBuilderTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteCollectionBuilderTest.php @@ -45,7 +45,7 @@ public function testImport() // import the file! $routes = new RouteCollectionBuilder($loader); - $importedRoutes = $routes->import('admin_routing.yml', 'yaml'); + $importedRoutes = $routes->import('admin_routing.yml', '/', 'yaml'); // we should get back a RouteCollectionBuilder $this->assertInstanceOf('Symfony\Component\Routing\RouteCollectionBuilder', $importedRoutes); @@ -56,6 +56,9 @@ public function testImport() $this->assertSame($originalRoute, $route); // should return file_resource.yml, which is in the original collection $this->assertCount(1, $addedCollection->getResources()); + + // make sure the routes were imported into the top-level builder + $this->assertCount(1, $routes->build()); } /** @@ -285,7 +288,7 @@ public function testFlushSetsPrefixedWithMultipleLevels() ->method('load') ->will($this->returnValue($importedCollection)); // import this from the /admin route builder - $adminRoutes->mount('/imported', $adminRoutes->import('admin.yml')); + $adminRoutes->import('admin.yml', '/imported'); $collection = $routes->build(); $this->assertEquals('/admin/dashboard', $collection->get('admin_dashboard')->getPath(), 'Routes before mounting have the prefix'); From ca9f446f035ed62976185187306cf1ca7ffa0573 Mon Sep 17 00:00:00 2001 From: Jelle Kapitein Date: Mon, 23 Nov 2015 09:33:29 +0100 Subject: [PATCH 035/136] =?UTF-8?q?[WebProfilerBundle]=20Added=20a=20top?= =?UTF-8?q?=20left=20border=20radius=20to=20the=20minified=20to=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Resources/views/Profiler/toolbar.css.twig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig index 0a269ea3f772f..c0456f61310fb 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig @@ -1,5 +1,6 @@ .sf-minitoolbar { background-color: #222; + border-top-left-radius: 4px; bottom: 0; display: none; height: 30px; @@ -8,6 +9,7 @@ right: 0; z-index: 99999; } + .sf-minitoolbar a { display: block; } @@ -357,6 +359,8 @@ /* Override the setting when the toolbar is on the top */ {% if position == 'top' %} .sf-minitoolbar { + border-bottom-left-radius: 4px; + border-top-left-radius: 0; bottom: auto; right: 0; top: 0; From f1fd7686c5fdc191a599d1e77d9748365f8a19cf Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 10 Nov 2015 16:18:07 +0100 Subject: [PATCH 036/136] fix potential timing attack issue --- ...PersistentTokenBasedRememberMeServices.php | 3 +- .../TokenBasedRememberMeServices.php | 28 ++----------------- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php index f800668a5e2b7..0fffbfe4f992d 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php @@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Util\SecureRandomInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\Security\Core\Util\StringUtils; /** * Concrete implementation of the RememberMeServicesInterface which needs @@ -90,7 +91,7 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request) list($series, $tokenValue) = $cookieParts; $persistentToken = $this->tokenProvider->loadTokenBySeries($series); - if ($persistentToken->getTokenValue() !== $tokenValue) { + if (!StringUtils::equals($persistentToken->getTokenValue(), $tokenValue)) { throw new CookieTheftException('This token was already used. The account is possibly compromised.'); } diff --git a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php index de662fb3d8b90..1aea5fd76d78d 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php @@ -17,6 +17,7 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Core\Util\StringUtils; /** * Concrete implementation of the RememberMeServicesInterface providing @@ -53,7 +54,7 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request) throw new \RuntimeException(sprintf('The UserProviderInterface implementation must return an instance of UserInterface, but returned "%s".', get_class($user))); } - if (true !== $this->compareHashes($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) { + if (!StringUtils::equals($this->generateCookieHash($class, $username, $expires, $user->getPassword()), $hash)) { throw new AuthenticationException('The cookie\'s hash is invalid.'); } @@ -64,31 +65,6 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request) return $user; } - /** - * Compares two hashes using a constant-time algorithm to avoid (remote) - * timing attacks. - * - * This is the same implementation as used in the BasePasswordEncoder. - * - * @param string $hash1 The first hash - * @param string $hash2 The second hash - * - * @return bool true if the two hashes are the same, false otherwise - */ - private function compareHashes($hash1, $hash2) - { - if (strlen($hash1) !== $c = strlen($hash2)) { - return false; - } - - $result = 0; - for ($i = 0; $i < $c; ++$i) { - $result |= ord($hash1[$i]) ^ ord($hash2[$i]); - } - - return 0 === $result; - } - /** * {@inheritdoc} */ From 557ea17eeb21817f3c18147b56c86172794a75df Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 10 Nov 2015 16:41:37 +0100 Subject: [PATCH 037/136] mitigate CSRF timing attack vulnerability --- .../Csrf/CsrfProvider/DefaultCsrfProvider.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php index 31ea45f3d5261..ab62df9a04b6c 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php +++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider; +use Symfony\Component\Security\Core\Util\StringUtils; + /** * Default implementation of CsrfProviderInterface. * @@ -54,6 +56,16 @@ public function generateCsrfToken($intention) */ public function isCsrfTokenValid($intention, $token) { + $expectedToken = $this->generateCsrfToken($intention); + + if (function_exists('hash_equals')) { + return hash_equals($expectedToken, $token); + } + + if (class_exists('Symfony\Component\Security\Core\Util\StringUtils')) { + return StringUtils::equals($expectedToken, $token); + } + return $token === $this->generateCsrfToken($intention); } From 819aa54fe489a403c0a3fe00fd0840ed53a15609 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 10 Nov 2015 16:51:36 +0100 Subject: [PATCH 038/136] prevent timing attacks in digest auth listener --- .../Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php | 2 +- .../Security/Http/Firewall/DigestAuthenticationListener.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php index ab62df9a04b6c..f323de0fd2d40 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php +++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php @@ -66,7 +66,7 @@ public function isCsrfTokenValid($intention, $token) return StringUtils::equals($expectedToken, $token); } - return $token === $this->generateCsrfToken($intention); + return $token === $expectedToken; } /** diff --git a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php index a88250bff386c..5e1159f733105 100644 --- a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php @@ -13,6 +13,7 @@ use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; +use Symfony\Component\Security\Core\Util\StringUtils; use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; @@ -99,7 +100,7 @@ public function handle(GetResponseEvent $event) return; } - if ($serverDigestMd5 !== $digestAuth->getResponse()) { + if (!StringUtils::equals($serverDigestMd5, $digestAuth->getResponse())) { if (null !== $this->logger) { $this->logger->debug(sprintf('Expected response: "%s" but received: "%s"; is AuthenticationDao returning clear text passwords?', $serverDigestMd5, $digestAuth->getResponse())); } From f88e600833b6822db5873e25deaefd14948e4878 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 5 Nov 2015 23:29:27 +0100 Subject: [PATCH 039/136] migrate session after remember me authentication --- .../Http/Firewall/RememberMeListener.php | 8 +++ .../Http/Firewall/RememberMeListenerTest.php | 63 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php index 942e53787a1bc..52a231c70e104 100644 --- a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php @@ -20,6 +20,7 @@ use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; /** * RememberMeListener implements authentication capabilities via a cookie. @@ -33,6 +34,7 @@ class RememberMeListener implements ListenerInterface private $authenticationManager; private $logger; private $dispatcher; + private $sessionStrategy; /** * Constructor. @@ -50,6 +52,7 @@ public function __construct(SecurityContextInterface $securityContext, RememberM $this->authenticationManager = $authenticationManager; $this->logger = $logger; $this->dispatcher = $dispatcher; + $this->sessionStrategy = new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE); } /** @@ -70,6 +73,11 @@ public function handle(GetResponseEvent $event) try { $token = $this->authenticationManager->authenticate($token); + + if ($request->hasSession() && $request->getSession()->isStarted()) { + $this->sessionStrategy->onAuthentication($request, $token); + } + $this->securityContext->setToken($token); if (null !== $this->dispatcher) { diff --git a/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php b/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php index 067cacb6cbdad..ad96243d47905 100644 --- a/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php +++ b/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php @@ -138,6 +138,69 @@ public function testOnCoreSecurity() $listener->handle($event); } + public function testSessionStrategy() + { + list($listener, $tokenStorage, $service, $manager) = $this->getListener(false, true, true); + + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + $service + ->expects($this->once()) + ->method('autoLogin') + ->will($this->returnValue($token)) + ; + + $tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($this->equalTo($token)) + ; + + $manager + ->expects($this->once()) + ->method('authenticate') + ->will($this->returnValue($token)) + ; + + $session = $this->getMock('\Symfony\Component\HttpFoundation\Session\SessionInterface'); + $session + ->expects($this->once()) + ->method('isStarted') + ->will($this->returnValue(true)) + ; + $session + ->expects($this->once()) + ->method('migrate') + ; + + $request = $this->getMock('\Symfony\Component\HttpFoundation\Request'); + $request + ->expects($this->any()) + ->method('hasSession') + ->will($this->returnValue(true)) + ; + + $request + ->expects($this->any()) + ->method('getSession') + ->will($this->returnValue($session)) + ; + + $event = $this->getGetResponseEvent(); + $event + ->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue($request)) + ; + + $listener->handle($event); + } + protected function getGetResponseEvent() { return $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false); From d12cf1904c92ef2525b55da79ae09c800e875171 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 23 Nov 2015 11:17:36 +0100 Subject: [PATCH 040/136] fixed tests --- .../DependencyInjection/Tests/ContainerBuilderTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 86d9103d998df..d470ed386ff80 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -324,7 +324,7 @@ public function testCreateServiceMethodCallsWithEscapedParam() { $builder = new ContainerBuilder(); $builder->register('bar', 'stdClass'); - $builder->register('foo1', 'FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%'))); + $builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%'))); $builder->setParameter('value', 'bar'); $this->assertEquals(array('%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments'); } @@ -333,7 +333,7 @@ public function testCreateServiceProperties() { $builder = new ContainerBuilder(); $builder->register('bar', 'stdClass'); - $builder->register('foo1', 'FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%')); + $builder->register('foo1', 'Bar\FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%')); $builder->setParameter('value', 'bar'); $this->assertEquals(array('bar', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the properties'); } From 3aee6b93e2072dd1c22a922eb30ad30dd8ade737 Mon Sep 17 00:00:00 2001 From: toretto460 Date: Mon, 23 Nov 2015 10:52:19 +0100 Subject: [PATCH 041/136] Fix: Resolve tempdir symlink, not working on OSX --- src/Symfony/Component/Filesystem/Tests/FilesystemTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index ea38e17df567e..d8d3cf33e94e4 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -1042,8 +1042,8 @@ public function testTempnamOnUnwritableFallsBackToSysTmp() $dirname = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'does_not_exist'; $filename = $this->filesystem->tempnam($dirname, 'bar'); - - $this->assertStringStartsWith(rtrim($scheme.sys_get_temp_dir(), DIRECTORY_SEPARATOR), $filename); + $realTempDir = realpath(sys_get_temp_dir()); + $this->assertStringStartsWith(rtrim($scheme.$realTempDir, DIRECTORY_SEPARATOR), $filename); $this->assertFileExists($filename); // Tear down From 2dbb75aef49c39ac680a31f44514f94c29de681d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 23 Nov 2015 11:39:33 +0100 Subject: [PATCH 042/136] removed usage of the deprecated StringUtils::equals() method --- .../Csrf/CsrfProvider/DefaultCsrfProvider.php | 12 +----------- .../Http/Firewall/DigestAuthenticationListener.php | 3 +-- .../PersistentTokenBasedRememberMeServices.php | 3 +-- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php index 7e25a122c6f74..def181d217ae6 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php +++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php @@ -11,8 +11,6 @@ namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider; -use Symfony\Component\Security\Core\Util\StringUtils; - @trigger_error('The '.__NAMESPACE__.'\DefaultCsrfProvider is deprecated since version 2.4 and will be removed in version 3.0. Use the \Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage class instead.', E_USER_DEPRECATED); /** @@ -65,15 +63,7 @@ public function isCsrfTokenValid($intention, $token) { $expectedToken = $this->generateCsrfToken($intention); - if (function_exists('hash_equals')) { - return hash_equals($expectedToken, $token); - } - - if (class_exists('Symfony\Component\Security\Core\Util\StringUtils')) { - return StringUtils::equals($expectedToken, $token); - } - - return $token === $expectedToken; + return hash_equals($expectedToken, $token); } /** diff --git a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php index f2048fdbe41a9..41e5d6d759533 100644 --- a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\User\UserProviderInterface; -use Symfony\Component\Security\Core\Util\StringUtils; use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; @@ -100,7 +99,7 @@ public function handle(GetResponseEvent $event) return; } - if (!StringUtils::equals($serverDigestMd5, $digestAuth->getResponse())) { + if (!hash_equals($serverDigestMd5, $digestAuth->getResponse())) { if (null !== $this->logger) { $this->logger->debug('Unexpected response from the DigestAuth received; is the header returning a clear text passwords?', array('expected' => $serverDigestMd5, 'received' => $digestAuth->getResponse())); } diff --git a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php index cf92a8c2f3f0e..807a4a72a69f4 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php @@ -21,7 +21,6 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Util\SecureRandomInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\Security\Core\Util\StringUtils; /** * Concrete implementation of the RememberMeServicesInterface which needs @@ -94,7 +93,7 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request) list($series, $tokenValue) = $cookieParts; $persistentToken = $this->tokenProvider->loadTokenBySeries($series); - if (!StringUtils::equals($persistentToken->getTokenValue(), $tokenValue)) { + if (!hash_equals($persistentToken->getTokenValue(), $tokenValue)) { throw new CookieTheftException('This token was already used. The account is possibly compromised.'); } From 4e44295288affd971a553241a2a66a4cf431d2d6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 23 Nov 2015 11:42:57 +0100 Subject: [PATCH 043/136] updated CHANGELOG for 2.3.35 --- CHANGELOG-2.3.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) 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) From 6836bc34b7e60da66014c8842718b5566abe36fa Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 23 Nov 2015 11:44:00 +0100 Subject: [PATCH 044/136] update CONTRIBUTORS for 2.3.35 --- CONTRIBUTORS.md | 52 +++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 25 deletions(-) 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) From 3b790dd0da995bd2c3da495e5ed2ee0a8f723d29 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 23 Nov 2015 11:44:06 +0100 Subject: [PATCH 045/136] updated VERSION for 2.3.35 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index d0defb1c9cfc7..be3ea8d1ee900 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.3.35-DEV'; + const VERSION = '2.3.35'; const VERSION_ID = 20335; const MAJOR_VERSION = 2; const MINOR_VERSION = 3; const RELEASE_VERSION = 35; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; /** * Constructor. From 03eb2e909d1e1f86f1785c308cdc2eadb8c86930 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 23 Nov 2015 12:27:40 +0100 Subject: [PATCH 046/136] bumped Symfony version to 2.3.36 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index be3ea8d1ee900..ff5b5906b3a80 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.3.35'; - const VERSION_ID = 20335; + const VERSION = '2.3.36-DEV'; + const VERSION_ID = 20336; const MAJOR_VERSION = 2; const MINOR_VERSION = 3; - const RELEASE_VERSION = 35; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 36; + const EXTRA_VERSION = 'DEV'; /** * Constructor. From 42c9a489c5723a86e7abe5d9d7ce1a0fdb259d04 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 23 Nov 2015 11:56:03 +0000 Subject: [PATCH 047/136] Removed unneeded polyfill from the master --- composer.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/composer.json b/composer.json index 7b0692cfd4e82..da34246718a27 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,6 @@ "psr/log": "~1.0", "symfony/polyfill-intl-icu": "~1.0", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php54": "~1.0", - "symfony/polyfill-php55": "~1.0", "symfony/polyfill-php56": "~1.0", "symfony/polyfill-php70": "~1.0", "symfony/polyfill-util": "~1.0" From d386f9c302ae876d0e733655383656bca996cc47 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 23 Nov 2015 12:57:09 +0100 Subject: [PATCH 048/136] updated CHANGELOG for 2.7.7 --- CHANGELOG-2.7.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md index 05bf4d856d835..19e9036c82bb2 100644 --- a/CHANGELOG-2.7.md +++ b/CHANGELOG-2.7.md @@ -7,6 +7,34 @@ 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.7 (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 #16578 [Console] Fix bug in windows detection (kbond) + * bug #16546 [Serializer] ObjectNormalizer: don't serialize static methods and props (dunglas) + * 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 #15945 [Form] trigger deprecation warning when using empty_value (xabbuh) + * bug #16384 [FrameworkBundle] JsonDescriptor - encode container params only once (xabbuh) + * bug #16480 [VarDumper] Fix PHP7 type-hints compat (nicolas-grekas) + * bug #16463 [PropertyAccess] Port of the performance optimization from 2.3 (dunglas) + * bug #16462 [PropertyAccess] Fix dynamic property accessing. (dunglas) + * bug #16454 [Serializer] GetSetNormalizer shouldn't set/get static methods (boekkooi) + * bug #16453 [Serializer] PropertyNormalizer shouldn't set static properties (boekkooi) + * bug #16471 [VarDumper] Fix casting for ReflectionParameter (nicolas-grekas) + * 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.7.6 (2015-10-27) * bug #16338 [VarDumper] Fix anonymous class dumping (nicolas-grekas) From d99f2410b34f670c7e572b0e8a10028c37848dab Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 23 Nov 2015 12:57:49 +0100 Subject: [PATCH 049/136] updated VERSION for 2.7.7 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 2e7666d83d4e2..c29f9ac93d8fd 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.7-DEV'; + const VERSION = '2.7.7'; const VERSION_ID = 20707; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; const RELEASE_VERSION = 7; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From fc0ee0efd5d0369feeae7ff5a9cc5eebb586ba50 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 23 Nov 2015 13:27:27 +0100 Subject: [PATCH 050/136] bumped Symfony version to 2.7.8 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index c29f9ac93d8fd..18425bee1b641 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.7'; - const VERSION_ID = 20707; + const VERSION = '2.7.8-DEV'; + const VERSION_ID = 20708; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; - const RELEASE_VERSION = 7; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 8; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From 07d627de0f9f9838d8896ab0243f80e4d3d6f966 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Mon, 23 Nov 2015 12:07:13 -0500 Subject: [PATCH 051/136] Tweaking deprecation message to include class name --- .../Component/Config/Resource/BCResourceInterfaceChecker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Config/Resource/BCResourceInterfaceChecker.php b/src/Symfony/Component/Config/Resource/BCResourceInterfaceChecker.php index 631755e8fe926..565ff8bb50e8b 100644 --- a/src/Symfony/Component/Config/Resource/BCResourceInterfaceChecker.php +++ b/src/Symfony/Component/Config/Resource/BCResourceInterfaceChecker.php @@ -29,7 +29,7 @@ public function supports(ResourceInterface $metadata) public function isFresh(ResourceInterface $resource, $timestamp) { - @trigger_error('Resource checking through ResourceInterface::isFresh() is deprecated since 2.8 and will be removed in 3.0', E_USER_DEPRECATED); + @trigger_error(sprintf('The class "%s" is performing resource checking through ResourceInterface::isFresh(), which is deprecated since 2.8 and will be removed in 3.0', get_class($resource)), E_USER_DEPRECATED); return parent::isFresh($resource, $timestamp); // For now, $metadata features the isFresh() method, so off we go (quack quack) } From dfda5ced7c83004d62ac50f2557e1b39aa5395e6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 24 Nov 2015 08:24:59 +0100 Subject: [PATCH 052/136] [travis] Disable xdebug on PHP7 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 62754a68af3a8..c347943fb48a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,7 @@ before_install: - 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" != "hhvm" ]]; 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; From a21a0166c692d1cbb71a9aa0c68f68b6a20215f1 Mon Sep 17 00:00:00 2001 From: Abdellatif Ait boudad Date: Mon, 23 Nov 2015 22:18:49 +0000 Subject: [PATCH 053/136] [DI][autowiring] throw exception when many services use the same class. --- .../Compiler/AutowirePass.php | 2 +- .../Tests/Compiler/AutowirePassTest.php | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 81470a8398eed..ec7880be89b95 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -227,7 +227,7 @@ private function set($type, $id) */ private function createAutowiredDefinition(\ReflectionClass $typeHint, $id) { - if (!$typeHint->isInstantiable()) { + if (isset($this->notGuessableTypes[$typeHint->name]) || !$typeHint->isInstantiable()) { throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s".', $typeHint->name, $id)); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index cc29ea93e02f2..f1ed72e94a4cd 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -117,6 +117,56 @@ public function testTypeCollision() $pass->process($container); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "a". + */ + public function testTypeNotGuessable() + { + $container = new ContainerBuilder(); + + $container->register('a1', __NAMESPACE__.'\Foo'); + $container->register('a2', __NAMESPACE__.'\Foo'); + $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgument'); + $aDefinition->setAutowired(true); + + $pass = new AutowirePass(); + $pass->process($container); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\A" for the service "a". + */ + public function testTypeNotGuessableWithSubclass() + { + $container = new ContainerBuilder(); + + $container->register('a1', __NAMESPACE__.'\B'); + $container->register('a2', __NAMESPACE__.'\B'); + $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgumentForSubclass'); + $aDefinition->setAutowired(true); + + $pass = new AutowirePass(); + $pass->process($container); + } + + public function testTypeNotGuessableWithTypeSet() + { + $container = new ContainerBuilder(); + + $container->register('a1', __NAMESPACE__.'\Foo'); + $container->register('a2', __NAMESPACE__.'\Foo')->addAutowiringType(__NAMESPACE__.'\Foo'); + $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgument'); + $aDefinition->setAutowired(true); + + $pass = new AutowirePass(); + $pass->process($container); + + $this->assertCount(1, $container->getDefinition('a')->getArguments()); + $this->assertEquals('a2', (string) $container->getDefinition('a')->getArgument(0)); + } + public function testWithTypeSet() { $container = new ContainerBuilder(); @@ -335,3 +385,15 @@ public function __construct(Dunglas $k, NotARealClass $r) { } } +class NotGuessableArgument +{ + public function __construct(Foo $k) + { + } +} +class NotGuessableArgumentForSubclass +{ + public function __construct(A $k) + { + } +} From fdfa1767b916bf48bcbc162b25af7d3d8ad29edc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 24 Nov 2015 10:07:02 +0100 Subject: [PATCH 054/136] Minor design tweaks for the Logs and Doctrine profiler panels --- .../Resources/views/Profiler/profiler.css.twig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig index 2f057958ca473..0e0ffe52ddf59 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig @@ -808,6 +808,16 @@ table.logs .metadata strong { color: #222; } +table.logs .sf-call-stack { + margin: 1em 0 1em 1.5em; +} +table.logs .sf-call-stack li { + margin-bottom: 5px; +} +table.logs .sf-call-stack abbr { + border: none; +} + {# Doctrine panel ========================================================================= #} .sql-runnable { @@ -815,6 +825,11 @@ table.logs .metadata strong { margin: .5em 0; padding: 1em; } +.queries-table pre { + {{ mixins.break_long_words|raw }} + margin: 0; + white-space: pre-wrap; +} {# Dump panel ========================================================================= #} From 01c08fccf4853fe204b620266f8551de18b31c50 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 24 Nov 2015 12:55:28 +0100 Subject: [PATCH 055/136] [Debug] Ensure class declarations are loaded only once --- src/Symfony/Component/Debug/DebugClassLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From d3c6d93dff9761cacc811976656574985fb37009 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 24 Nov 2015 14:06:05 +0100 Subject: [PATCH 056/136] [Security] Revert changes made between 2.7 and 2.8-beta --- UPGRADE-2.8.md | 34 +------ .../Authorization/Voter/AbstractVoter.php | 89 +++---------------- .../Authorization/Voter/AbstractVoterTest.php | 74 +-------------- .../Authorization/Voter/Fixtures/MyVoter.php | 27 ++++++ 4 files changed, 43 insertions(+), 181 deletions(-) create mode 100644 src/Symfony/Component/Security/Core/Tests/Authorization/Voter/Fixtures/MyVoter.php diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index ae8bb7fa4ac98..ec4c4ba44719f 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -442,38 +442,8 @@ FrameworkBundle Security -------- - * The AbstractToken::isGranted() method was deprecated. Instead, - override the voteOnAttribute() method. This method has one small - difference: it's passed the TokenInterface instead of the user: - - Before: - - ```php - class MyCustomVoter extends AbstractVoter - { - // ... - - protected function isGranted($attribute, $object, $user = null) - { - // ... - } - } - ``` - - After: - - ```php - class MyCustomVoter extends AbstractVoter - { - // ... - - protected function voteOnAttribute($attribute, $object, TokenInterface $token) - { - $user = $token->getUser(); - // ... - } - } - ``` + * The `VoterInterface::supportsClass` and `supportsAttribute` methods were + deprecated and will be removed from the interface in 3.0. Config ------ diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php index 7b04222eae921..5dcf787c9968c 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/AbstractVoter.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Security\Core\Authorization\Voter; +@trigger_error('The '.__NAMESPACE__.'\AbstractVoter class is deprecated since version 2.8, to be removed in 3.0. Upgrade to Symfony\Component\Security\Core\Authorization\Voter\Voter instead.', E_USER_DEPRECATED); + use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -18,6 +20,8 @@ * Abstract Voter implementation that reduces boilerplate code required to create a custom Voter. * * @author Roman Marintšenko + * + * @deprecated since version 2.8, to be removed in 3.0. Upgrade to Symfony\Component\Security\Core\Authorization\Voter\Voter instead. */ abstract class AbstractVoter implements VoterInterface { @@ -26,8 +30,6 @@ abstract class AbstractVoter implements VoterInterface */ public function supportsAttribute($attribute) { - @trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.', E_USER_DEPRECATED); - return in_array($attribute, $this->getSupportedAttributes()); } @@ -36,8 +38,6 @@ public function supportsAttribute($attribute) */ public function supportsClass($class) { - @trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.', E_USER_DEPRECATED); - foreach ($this->getSupportedClasses() as $supportedClass) { if ($supportedClass === $class || is_subclass_of($class, $supportedClass)) { return true; @@ -62,7 +62,7 @@ public function supportsClass($class) */ public function vote(TokenInterface $token, $object, array $attributes) { - if (!$object) { + if (!$object || !$this->supportsClass(get_class($object))) { return self::ACCESS_ABSTAIN; } @@ -70,14 +70,14 @@ public function vote(TokenInterface $token, $object, array $attributes) $vote = self::ACCESS_ABSTAIN; foreach ($attributes as $attribute) { - if (!$this->supports($attribute, $object)) { + if (!$this->supportsAttribute($attribute)) { continue; } // as soon as at least one attribute is supported, default is to deny access $vote = self::ACCESS_DENIED; - if ($this->voteOnAttribute($attribute, $object, $token)) { + if ($this->isGranted($attribute, $object, $token->getUser())) { // grant access as soon as at least one voter returns a positive response return self::ACCESS_GRANTED; } @@ -86,62 +86,19 @@ public function vote(TokenInterface $token, $object, array $attributes) return $vote; } - /** - * Determines if the attribute and object are supported by this voter. - * - * This method will become abstract in 3.0. - * - * @param string $attribute An attribute - * @param string $object The object to secure - * - * @return bool True if the attribute and object is supported, false otherwise - */ - protected function supports($attribute, $object) - { - @trigger_error('The getSupportedClasses and getSupportedAttributes methods are deprecated since version 2.8 and will be removed in version 3.0. Overwrite supports instead.', E_USER_DEPRECATED); - - $classIsSupported = false; - foreach ($this->getSupportedClasses() as $supportedClass) { - if ($object instanceof $supportedClass) { - $classIsSupported = true; - break; - } - } - - if (!$classIsSupported) { - return false; - } - - if (!in_array($attribute, $this->getSupportedAttributes())) { - return false; - } - - return true; - } - /** * Return an array of supported classes. This will be called by supportsClass. * * @return array an array of supported classes, i.e. array('Acme\DemoBundle\Model\Product') - * - * @deprecated since version 2.8, to be removed in 3.0. Use supports() instead. */ - protected function getSupportedClasses() - { - @trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.', E_USER_DEPRECATED); - } + abstract protected function getSupportedClasses(); /** * Return an array of supported attributes. This will be called by supportsAttribute. * * @return array an array of supported attributes, i.e. array('CREATE', 'READ') - * - * @deprecated since version 2.8, to be removed in 3.0. Use supports() instead. */ - protected function getSupportedAttributes() - { - @trigger_error('The '.__METHOD__.' is deprecated since version 2.8 and will be removed in version 3.0.', E_USER_DEPRECATED); - } + abstract protected function getSupportedAttributes(); /** * Perform a single access check operation on a given attribute, object and (optionally) user @@ -154,33 +111,7 @@ protected function getSupportedAttributes() * @param object $object * @param UserInterface|string $user * - * @deprecated This method will be removed in 3.0 - override voteOnAttribute instead. - * - * @return bool - */ - protected function isGranted($attribute, $object, $user = null) - { - // forces isGranted() or voteOnAttribute() to be overridden - throw new \BadMethodCallException(sprintf('You must override the voteOnAttribute() method in "%s".', get_class($this))); - } - - /** - * Perform a single access check operation on a given attribute, object and token. - * It is safe to assume that $attribute and $object's class pass supports method call. - * - * This method will become abstract in 3.0. - * - * @param string $attribute - * @param object $object - * @param TokenInterface $token - * * @return bool */ - protected function voteOnAttribute($attribute, $object, TokenInterface $token) - { - // the user should override this method, and not rely on the deprecated isGranted() - @trigger_error(sprintf("The AbstractVoter::isGranted() method is deprecated since 2.8 and won't be called anymore in 3.0. Override voteOnAttribute() in %s instead.", get_class($this)), E_USER_DEPRECATED); - - return $this->isGranted($attribute, $object, $token->getUser()); - } + abstract protected function isGranted($attribute, $object, $user = null); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/AbstractVoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/AbstractVoterTest.php index 5ea77320cf610..b537c1b2effc9 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/AbstractVoterTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/AbstractVoterTest.php @@ -11,10 +11,11 @@ namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; +/** + * @group legacy + */ class AbstractVoterTest extends \PHPUnit_Framework_TestCase { protected $token; @@ -50,75 +51,8 @@ public function getTests() */ public function testVote(array $attributes, $expectedVote, $object, $message) { - $voter = new AbstractVoterTest_Voter(); + $voter = new Fixtures\MyVoter(); $this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message); } - - /** - * @dataProvider getTests - * @group legacy - */ - public function testVoteLegacy(array $attributes, $expectedVote, $object, $message) - { - $voter = new AbstractVoterTest_LegacyVoter(); - - $this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message); - } - - /** - * @group legacy - * @expectedException \BadMethodCallException - */ - public function testNoOverriddenMethodsThrowsException() - { - $voter = new AbstractVoterTest_NothingImplementedVoter(); - $voter->vote($this->token, new \stdClass(), array('EDIT')); - } -} - -class AbstractVoterTest_Voter extends AbstractVoter -{ - protected function voteOnAttribute($attribute, $object, TokenInterface $token) - { - return 'EDIT' === $attribute; - } - - protected function supports($attribute, $object) - { - return $object instanceof \stdClass && in_array($attribute, array('EDIT', 'CREATE')); - } -} - -class AbstractVoterTest_LegacyVoter extends AbstractVoter -{ - protected function getSupportedClasses() - { - return array('stdClass'); - } - - protected function getSupportedAttributes() - { - return array('EDIT', 'CREATE'); - } - - protected function isGranted($attribute, $object, $user = null) - { - return 'EDIT' === $attribute; - } -} - -class AbstractVoterTest_NothingImplementedVoter extends AbstractVoter -{ - protected function getSupportedClasses() - { - return array('stdClass'); - } - - protected function getSupportedAttributes() - { - return array('EDIT', 'CREATE'); - } - - // this is a bad voter that hasn't overridden isGranted or voteOnAttribute } diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/Fixtures/MyVoter.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/Fixtures/MyVoter.php new file mode 100644 index 0000000000000..b75f79851be99 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/Fixtures/MyVoter.php @@ -0,0 +1,27 @@ + Date: Thu, 19 Nov 2015 15:20:40 +0100 Subject: [PATCH 057/136] [Security] Deprecate "AbstractVoter" in favor of "Voter" --- UPGRADE-2.8.md | 4 + .../Core/Authorization/Voter/Voter.php | 85 +++++++++++++++++++ .../Tests/Authorization/Voter/VoterTest.php | 70 +++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php create mode 100644 src/Symfony/Component/Security/Core/Tests/Authorization/Voter/VoterTest.php diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index ec4c4ba44719f..ba7a13617af3f 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -442,6 +442,10 @@ FrameworkBundle Security -------- + * The `AbstractVoter` class was deprecated. Instead, extend the `Voter` class and + move your voting logic in the `supports($attribute, $subject)` and + `voteOnAttribute($attribute, $object, TokenInterface $token)` methods. + * The `VoterInterface::supportsClass` and `supportsAttribute` methods were deprecated and will be removed from the interface in 3.0. diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php new file mode 100644 index 0000000000000..8d36fd8f8c919 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Authorization\Voter; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + +/** + * Voter is an abstract default implementation of a voter. + * + * @author Roman Marintšenko + * @author Grégoire Pineau + */ +abstract class Voter implements VoterInterface +{ + /** + * {@inheritdoc} + */ + public function supportsAttribute($attribute) + { + throw new \BadMethodCallException('supportsAttribute method is deprecated since version 2.8, to be removed in 3.0'); + } + + /** + * {@inheritdoc} + */ + public function supportsClass($class) + { + throw new \BadMethodCallException('supportsClass method is deprecated since version 2.8, to be removed in 3.0'); + } + + /** + * {@inheritdoc} + */ + public function vote(TokenInterface $token, $object, array $attributes) + { + // abstain vote by default in case none of the attributes are supported + $vote = self::ACCESS_ABSTAIN; + + foreach ($attributes as $attribute) { + if (!$this->supports($attribute, $object)) { + continue; + } + + // as soon as at least one attribute is supported, default is to deny access + $vote = self::ACCESS_DENIED; + + if ($this->voteOnAttribute($attribute, $object, $token)) { + // grant access as soon as at least one attribute returns a positive response + return self::ACCESS_GRANTED; + } + } + + return $vote; + } + + /** + * Determines if the attribute and subject are supported by this voter. + * + * @param string $attribute An attribute + * @param mixed $subject The subject to secure, e.g. an object the user wants to access or any other PHP type + * + * @return bool True if the attribute and subject are supported, false otherwise + */ + abstract protected function supports($attribute, $subject); + + /** + * Perform a single access check operation on a given attribute, subject and token. + * + * @param string $attribute + * @param mixed $subject + * @param TokenInterface $token + * + * @return bool + */ + abstract protected function voteOnAttribute($attribute, $subject, TokenInterface $token); +} diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/VoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/VoterTest.php new file mode 100644 index 0000000000000..4bac44d981893 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/VoterTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; +use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; + +class VoterTest extends \PHPUnit_Framework_TestCase +{ + protected $token; + + protected function setUp() + { + $this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + } + + public function getTests() + { + return array( + array(array('EDIT'), VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access'), + array(array('CREATE'), VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if attribute and class are supported and attribute does not grant access'), + + array(array('DELETE', 'EDIT'), VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute is supported and grants access'), + array(array('DELETE', 'CREATE'), VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if one attribute is supported and denies access'), + + array(array('CREATE', 'EDIT'), VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute grants access'), + + array(array('DELETE'), VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attribute is supported'), + + array(array('EDIT'), VoterInterface::ACCESS_ABSTAIN, $this, 'ACCESS_ABSTAIN if class is not supported'), + + array(array('EDIT'), VoterInterface::ACCESS_ABSTAIN, null, 'ACCESS_ABSTAIN if object is null'), + + array(array(), VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attributes were provided'), + ); + } + + /** + * @dataProvider getTests + */ + public function testVote(array $attributes, $expectedVote, $object, $message) + { + $voter = new VoterTest_Voter(); + + $this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message); + } +} + +class VoterTest_Voter extends Voter +{ + protected function voteOnAttribute($attribute, $object, TokenInterface $token) + { + return 'EDIT' === $attribute; + } + + protected function supports($attribute, $object) + { + return $object instanceof \stdClass && in_array($attribute, array('EDIT', 'CREATE')); + } +} From 062d707820de675378fa887640b1840f0b298ea8 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 24 Nov 2015 21:31:58 +0100 Subject: [PATCH 058/136] [Yaml] sync changelog and upgrade files --- UPGRADE-2.8.md | 8 ++++++++ UPGRADE-3.0.md | 5 +++++ src/Symfony/Component/Yaml/CHANGELOG.md | 3 ++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index ae8bb7fa4ac98..67e1c0e66f18a 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -505,3 +505,11 @@ Config Additionally, if you have implemented cache validation strategies *using* `isFresh()` yourself, you should have a look at the new cache validation system based on `ResourceChecker`s. + +Yaml +---- + + * Deprecated usage of a colon in an unquoted mapping value + * Deprecated usage of `@`, `` ` ``, `|`, and `>` at the beginning of an unquoted string + * Deprecated non-escaped \ in double-quoted strings when parsing Yaml + ("Foo\Var" is not valid whereas "Foo\\Var" is) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 65386359a5adf..5b86950fc694d 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -1228,6 +1228,11 @@ UPGRADE FROM 2.x to 3.0 ### Yaml + * Using a colon in an unquoted mapping value leads to a `ParseException`. + * Starting an unquoted string with `@`, `` ` ``, `|`, or `>` leads to a `ParseException`. + * Deprecated non-escaped \ in double-quoted strings when parsing Yaml + ("Foo\Var" is not valid whereas "Foo\\Var" is) + * The ability to pass file names to `Yaml::parse()` has been removed. Before: diff --git a/src/Symfony/Component/Yaml/CHANGELOG.md b/src/Symfony/Component/Yaml/CHANGELOG.md index a6a8612f3776a..ccfdb1a792c61 100644 --- a/src/Symfony/Component/Yaml/CHANGELOG.md +++ b/src/Symfony/Component/Yaml/CHANGELOG.md @@ -4,7 +4,8 @@ CHANGELOG 2.8.0 ----- - * Deprecated usage of @ and \` at the beginning of an unquoted string + * Deprecated usage of a colon in an unquoted mapping value + * Deprecated usage of @, \`, | and > at the beginning of an unquoted string * Deprecated non-escaped \ in double-quoted strings when parsing Yaml ("Foo\Var" is not valid whereas "Foo\\Var" is) From 2edebbf2aebc98649183e171e8042b93f6dedc8a Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Tue, 24 Nov 2015 23:11:35 +0100 Subject: [PATCH 059/136] add composer exclude-from-classmap for new 2.8 components --- src/Symfony/Component/Ldap/composer.json | 5 ++++- src/Symfony/Component/PropertyInfo/composer.json | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Ldap/composer.json b/src/Symfony/Component/Ldap/composer.json index 21e4adea9618b..bdbba744b3647 100644 --- a/src/Symfony/Component/Ldap/composer.json +++ b/src/Symfony/Component/Ldap/composer.json @@ -21,7 +21,10 @@ "ext-ldap": "*" }, "autoload": { - "psr-4": { "Symfony\\Component\\Ldap\\": "" } + "psr-4": { "Symfony\\Component\\Ldap\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "minimum-stability": "dev", "extra": { diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index ee34325b7663e..d7861d5b03d88 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -39,7 +39,10 @@ "symfony/serializer": "To use Serializer metadata" }, "autoload": { - "psr-4": { "Symfony\\Component\\PropertyInfo\\": "" } + "psr-4": { "Symfony\\Component\\PropertyInfo\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "minimum-stability": "dev", "extra": { From 0e0b904ff201d35c5275df32c81f70027d408dd6 Mon Sep 17 00:00:00 2001 From: Restless-ET Date: Wed, 30 Sep 2015 18:42:26 +0100 Subject: [PATCH 060/136] [Translation][Form] Do not translate form labels and placeholders when 'translation_domain' is false --- .../views/Form/form_div_layout.html.twig | 12 +-- .../views/Form/foundation_5_layout.html.twig | 4 +- .../views/Form/button_attributes.html.php | 2 +- .../views/Form/button_widget.html.php | 2 +- .../Form/choice_widget_collapsed.html.php | 2 +- .../views/Form/widget_attributes.html.php | 2 +- .../Form/widget_container_attributes.html.php | 2 +- .../Tests/AbstractBootstrap3LayoutTest.php | 83 ++++++++++++++++ .../Form/Tests/AbstractLayoutTest.php | 97 +++++++++++++++++++ 9 files changed, 193 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 89f9910890879..81b6dcee9135d 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -57,7 +57,7 @@ {%- endif -%} {% if placeholder is not none -%} - + {%- endif %} {%- if preferred_choices|length > 0 -%} {% set options = preferred_choices %} @@ -253,7 +253,7 @@ {% endif %} {{ widget|raw }} - {{ label|trans({}, translation_domain) }} + {{ translation_domain is same as(false) ? label : label|trans({}, translation_domain) }} {%- endblock checkbox_radio_label %} diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_attributes.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_attributes.html.php index ac1077a205ae3..2be960d0e179c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_attributes.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_attributes.html.php @@ -1,7 +1,7 @@ id="escape($id) ?>" name="escape($full_name) ?>" disabled="disabled" $v): ?> -escape($k), $view->escape($view['translator']->trans($v, array(), $translation_domain))) ?> +escape($k), $view->escape(false !== $translation_domain ? $view['translator']->trans($v, array(), $translation_domain) : $v)) ?> escape($k), $view->escape($k)) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php index 9dac32fc994c0..4b63876984506 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php @@ -1,4 +1,4 @@ $name, '%id%' => $id)) : $view['form']->humanize($name); } ?> - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_widget_collapsed.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_widget_collapsed.html.php index fe4fbdb348a32..29ea388010758 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_widget_collapsed.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_widget_collapsed.html.php @@ -7,7 +7,7 @@ )) ?> multiple="multiple" > - + 0): ?> block($form, 'choice_widget_options', array('choices' => $preferred_choices)) ?> 0 && null !== $separator): ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php index ac5a481d0b55e..3fefa47c15c99 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php @@ -2,7 +2,7 @@ required="required" $v): ?> -escape($k), $view->escape($view['translator']->trans($v, array(), $translation_domain))) ?> +escape($k), $view->escape(false !== $translation_domain ? $view['translator']->trans($v, array(), $translation_domain) : $v)) ?> escape($k), $view->escape($k)) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_container_attributes.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_container_attributes.html.php index 327925a537196..dc2e5ebea84e6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_container_attributes.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_container_attributes.html.php @@ -1,7 +1,7 @@ id="escape($id) ?>" $v): ?> -escape($k), $view->escape($view['translator']->trans($v, array(), $translation_domain))) ?> +escape($k), $view->escape(false !== $translation_domain ? $view['translator']->trans($v, array(), $translation_domain) : $v)) ?> escape($k), $view->escape($k)) ?> diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php index 13da0c486071a..d952b58412c68 100644 --- a/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php @@ -254,6 +254,32 @@ public function testSingleChoiceWithoutTranslation() ); } + public function testSingleChoiceWithPlaceholderWithoutTranslation() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( + 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'multiple' => false, + 'expanded' => false, + 'required' => false, + 'translation_domain' => false, + 'placeholder' => 'Placeholder&Not&Translated', + )); + + $this->assertWidgetMatchesXpath($form->createView(), array('attr' => array('class' => 'my&class')), +'/select + [@name="name"] + [@class="my&class form-control"] + [not(@required)] + [ + ./option[@value=""][not(@selected)][not(@disabled)][.="Placeholder&Not&Translated"] + /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"] + /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"] + ] + [count(./option)=3] +' + ); + } + public function testSingleChoiceAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( @@ -771,6 +797,52 @@ public function testSingleChoiceExpandedWithPlaceholder() ); } + public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( + 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'multiple' => false, + 'expanded' => true, + 'translation_domain' => false, + 'placeholder' => 'Placeholder&Not&Translated', + )); + + $this->assertWidgetMatchesXpath($form->createView(), array(), +'/div + [ + ./div + [@class="radio"] + [ + ./label + [.=" Placeholder&Not&Translated"] + [ + ./input[@type="radio"][@name="name"][@id="name_placeholder"][not(@checked)] + ] + ] + /following-sibling::div + [@class="radio"] + [ + ./label + [.=" Choice&A"] + [ + ./input[@type="radio"][@name="name"][@id="name_0"][@checked] + ] + ] + /following-sibling::div + [@class="radio"] + [ + ./label + [.=" Choice&B"] + [ + ./input[@type="radio"][@name="name"][@id="name_1"][not(@checked)] + ] + ] + /following-sibling::input[@type="hidden"][@id="name__token"][@class="form-control"] + ] +' + ); + } + public function testSingleChoiceExpandedWithBooleanValue() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', true, array( @@ -2023,6 +2095,17 @@ public function testButton() ); } + public function testButtonlabelWithoutTranslation() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', null, array( + 'translation_domain' => false, + )); + + $this->assertWidgetMatchesXpath($form->createView(), array('attr' => array('class' => 'my&class')), + '/button[@type="button"][@name="name"][.="Name"][@class="my&class btn"]' + ); + } + public function testSubmit() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\SubmitType'); diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 8d5d9ea8a2065..f44aed122b3cf 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -381,6 +381,25 @@ public function testLabelFormatOverriddenOption() ); } + public function testLabelWithoutTranslationOnButton() + { + $form = $this->factory->createNamedBuilder('myform', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + 'translation_domain' => false, + )) + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType') + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view); + + $this->assertMatchesXpath($html, +'/button + [@type="button"] + [@name="myform[mybutton]"] + [.="Mybutton"] +' + ); + } + public function testLabelFormatOnButton() { $form = $this->factory->createNamedBuilder('myform') @@ -549,6 +568,31 @@ public function testSingleChoiceWithoutTranslation() ); } + public function testSingleChoiceWithPlaceholderWithoutTranslation() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( + 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'multiple' => false, + 'expanded' => false, + 'required' => false, + 'translation_domain' => false, + 'placeholder' => 'Placeholder&Not&Translated', + )); + + $this->assertWidgetMatchesXpath($form->createView(), array(), +'/select + [@name="name"] + [not(@required)] + [ + ./option[@value=""][not(@selected)][not(@disabled)][.="Placeholder&Not&Translated"] + /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"] + /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"] + ] + [count(./option)=3] +' + ); + } + public function testSingleChoiceAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( @@ -998,6 +1042,32 @@ public function testSingleChoiceExpandedWithPlaceholder() ); } + public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( + 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'multiple' => false, + 'expanded' => true, + 'translation_domain' => false, + 'placeholder' => 'Placeholder&Not&Translated', + )); + + $this->assertWidgetMatchesXpath($form->createView(), array(), +'/div + [ + ./input[@type="radio"][@name="name"][@id="name_placeholder"][not(@checked)] + /following-sibling::label[@for="name_placeholder"][.="Placeholder&Not&Translated"] + /following-sibling::input[@type="radio"][@name="name"][@id="name_0"][@checked] + /following-sibling::label[@for="name_0"][.="Choice&A"] + /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)] + /following-sibling::label[@for="name_1"][.="Choice&B"] + /following-sibling::input[@type="hidden"][@id="name__token"] + ] + [count(./input)=4] +' + ); + } + public function testSingleChoiceExpandedWithBooleanValue() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', true, array( @@ -2141,6 +2211,17 @@ public function testButtonLabelIsEmpty() $this->assertSame('', $this->renderLabel($form->createView())); } + public function testButtonlabelWithoutTranslation() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', null, array( + 'translation_domain' => false, + )); + + $this->assertWidgetMatchesXpath($form->createView(), array(), + '/button[@type="button"][@name="name"][.="Name"]' + ); + } + public function testSubmit() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\SubmitType'); @@ -2349,4 +2430,20 @@ public function testTranslatedAttributes() $this->assertMatchesXpath($html, '/form//input[@title="[trans]Foo[/trans]"]'); $this->assertMatchesXpath($html, '/form//input[@placeholder="[trans]Bar[/trans]"]'); } + + public function testAttributesNotTranslatedWhenTranslationDomainIsFalse() + { + $view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + 'translation_domain' => false, + )) + ->add('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', array('attr' => array('title' => 'Foo'))) + ->add('lastName', 'Symfony\Component\Form\Extension\Core\Type\TextType', array('attr' => array('placeholder' => 'Bar'))) + ->getForm() + ->createView(); + + $html = $this->renderForm($view); + + $this->assertMatchesXpath($html, '/form//input[@title="Foo"]'); + $this->assertMatchesXpath($html, '/form//input[@placeholder="Bar"]'); + } } From cf284742ff0b6fc5f06ebc36250650f64853a625 Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Sun, 8 Nov 2015 16:53:13 +0100 Subject: [PATCH 061/136] fix unused variable warning --- src/Symfony/Bridge/PhpUnit/ClockMock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/ClockMock.php b/src/Symfony/Bridge/PhpUnit/ClockMock.php index 4b745e38e87fc..b81fee965880a 100644 --- a/src/Symfony/Bridge/PhpUnit/ClockMock.php +++ b/src/Symfony/Bridge/PhpUnit/ClockMock.php @@ -66,7 +66,7 @@ public static function microtime($asFloat = false) return self::$now; } - return sprintf("%0.6f %d\n", $now - (int) $now, (int) self::$now); + return sprintf("%0.6f %d\n", self::$now - (int) self::$now, (int) self::$now); } public static function register($class) From 09f489530ba67312b0d7a2a5d4926838ea4d9f0a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 25 Nov 2015 09:53:09 +0100 Subject: [PATCH 062/136] Fixes the stack traces of the deprecation logs --- .../Resources/views/Collector/logger.html.twig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig index 361e684fbf938..3fb596b0960d2 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig @@ -169,6 +169,7 @@ {% if index == 2 %}
    {% endif %} + {% if call.class is defined %} {% set from = call.class|abbr_class ~ '::' ~ call.function|abbr_method() %} {% elseif call.function is defined %} @@ -179,7 +180,14 @@ {% set from = '-' %} {% endif %} -
  • Called from {{ call.file is defined and call.line is defined ? call.file|format_file(call.line, from) : from|raw }}
  • + {% set file_name = (call.file is defined and call.line is defined) ? call.file|replace({'\\': '/'})|split('/')|last %} + +
  • + {{ from|raw }} + {% if file_name %} + (called from {{ call.file|format_file(call.line, file_name)|raw }}) + {% endif %} +
  • {% if index == stack|length - 1 %}
From 0113ac3ce23825781b782570cccaa5905d0846ea Mon Sep 17 00:00:00 2001 From: Jelte Steijaert Date: Fri, 30 Oct 2015 10:20:47 +0100 Subject: [PATCH 063/136] Bug #16343 [Router] Too many Routes ? --- .../Generator/Dumper/PhpGeneratorDumper.php | 5 ++- .../Dumper/PhpGeneratorDumperTest.php | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php b/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php index 9f26cad837d87..1cd0f19197ca4 100644 --- a/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php +++ b/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php @@ -53,7 +53,7 @@ public function dump(array $options = array()) */ class {$options['class']} extends {$options['base_class']} { - private static \$declaredRoutes = {$this->generateDeclaredRoutes()}; + private static \$declaredRoutes; /** * Constructor. @@ -62,6 +62,9 @@ public function __construct(RequestContext \$context, LoggerInterface \$logger = { \$this->context = \$context; \$this->logger = \$logger; + if (null === self::\$declaredRoutes) { + self::\$declaredRoutes = {$this->generateDeclaredRoutes()}; + } } {$this->generateGenerateMethod()} diff --git a/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php b/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php index 43ef624ddf896..393aa066f597e 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php @@ -34,6 +34,11 @@ class PhpGeneratorDumperTest extends \PHPUnit_Framework_TestCase */ private $testTmpFilepath; + /** + * @var string + */ + private $largeTestTmpFilepath; + protected function setUp() { parent::setUp(); @@ -41,7 +46,9 @@ protected function setUp() $this->routeCollection = new RouteCollection(); $this->generatorDumper = new PhpGeneratorDumper($this->routeCollection); $this->testTmpFilepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_generator.'.$this->getName().'.php'; + $this->largeTestTmpFilepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_generator.'.$this->getName().'.large.php'; @unlink($this->testTmpFilepath); + @unlink($this->largeTestTmpFilepath); } protected function tearDown() @@ -76,6 +83,33 @@ public function testDumpWithRoutes() $this->assertEquals($relativeUrlWithoutParameter, '/app.php/testing2'); } + public function testDumpWithTooManyRoutes() + { + $this->routeCollection->add('Test', new Route('/testing/{foo}')); + for ( $i = 0; $i < 32769; ++$i ) { + $this->routeCollection->add('route_'.$i, new Route('/route_'.$i)); + } + $this->routeCollection->add('Test2', new Route('/testing2')); + + $data = $this->generatorDumper->dump(array( + 'class' => 'ProjectLargeUrlGenerator', + )); + file_put_contents($this->largeTestTmpFilepath, $data); + include $this->largeTestTmpFilepath; + + $projectUrlGenerator = new \ProjectLargeUrlGenerator(new RequestContext('/app.php')); + + $absoluteUrlWithParameter = $projectUrlGenerator->generate('Test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL); + $absoluteUrlWithoutParameter = $projectUrlGenerator->generate('Test2', array(), UrlGeneratorInterface::ABSOLUTE_URL); + $relativeUrlWithParameter = $projectUrlGenerator->generate('Test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_PATH); + $relativeUrlWithoutParameter = $projectUrlGenerator->generate('Test2', array(), UrlGeneratorInterface::ABSOLUTE_PATH); + + $this->assertEquals($absoluteUrlWithParameter, 'http://localhost/app.php/testing/bar'); + $this->assertEquals($absoluteUrlWithoutParameter, 'http://localhost/app.php/testing2'); + $this->assertEquals($relativeUrlWithParameter, '/app.php/testing/bar'); + $this->assertEquals($relativeUrlWithoutParameter, '/app.php/testing2'); + } + /** * @expectedException \InvalidArgumentException */ From a862e5ef8f8af5ed873878a3e4f5bd434c42c7f9 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Wed, 25 Nov 2015 13:51:17 +0100 Subject: [PATCH 064/136] [Debug] remove unused use statement --- src/Symfony/Component/Debug/ExceptionHandler.php | 1 - src/Symfony/Component/Debug/README.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php index 73f5bb08394e8..19cdb1fdb1ed6 100644 --- a/src/Symfony/Component/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/Debug/ExceptionHandler.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Debug; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Debug\Exception\FlattenException; use Symfony\Component\Debug\Exception\OutOfMemoryException; diff --git a/src/Symfony/Component/Debug/README.md b/src/Symfony/Component/Debug/README.md index 67e6d6c2785c6..b3ba95b5aa36b 100644 --- a/src/Symfony/Component/Debug/README.md +++ b/src/Symfony/Component/Debug/README.md @@ -31,7 +31,7 @@ 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. +component. Resources --------- From cc2645404a5767f45c504e2ef151e008f3e56ac3 Mon Sep 17 00:00:00 2001 From: Thomas Rabaix Date: Fri, 20 Nov 2015 23:53:40 +0100 Subject: [PATCH 065/136] fix type assignement --- src/Symfony/Component/Form/FormRegistry.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Form/FormRegistry.php b/src/Symfony/Component/Form/FormRegistry.php index 49db05ba5fd15..b449f20315d03 100644 --- a/src/Symfony/Component/Form/FormRegistry.php +++ b/src/Symfony/Component/Form/FormRegistry.php @@ -88,7 +88,7 @@ public function getType($name) } } - $this->resolveAndAddType($type); + $this->types[$name] = $this->resolveType($type); } return $this->types[$name]; @@ -102,7 +102,7 @@ public function getType($name) * * @return ResolvedFormTypeInterface The resolved type. */ - private function resolveAndAddType(FormTypeInterface $type) + private function resolveType(FormTypeInterface $type) { $typeExtensions = array(); $parentType = $type->getParent(); @@ -115,13 +115,11 @@ private function resolveAndAddType(FormTypeInterface $type) ); } - $resolvedType = $this->resolvedTypeFactory->createResolvedType( + return $this->resolvedTypeFactory->createResolvedType( $type, $typeExtensions, $parentType ? $this->getType($parentType) : null ); - - $this->types[$fqcn] = $resolvedType; } /** From 4a17c9e6afcc83982dfb5af79f4adb82bf806643 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 25 Nov 2015 18:16:22 +0100 Subject: [PATCH 066/136] [ClassLoader] Fix parsing namespace when token_get_all() is missing --- src/Symfony/Component/ClassLoader/ClassCollectionLoader.php | 4 ++-- .../Component/ClassLoader/Tests/ClassCollectionLoaderTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php index 88bd500f1d2c8..6fdd0a4b6b5b9 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/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"), ); } From 171208627dee9c657f1fa6f4bee560a9519bf178 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 25 Nov 2015 19:15:39 +0100 Subject: [PATCH 067/136] Always enable clock-mock for HttpFoundation --- phpunit.xml.dist | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4e4e411c3cfb4..010114e0b9f35 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -45,4 +45,14 @@ + + + + + + Symfony\Component\HttpFoundation + + + + From 5013f9895f621b72798b0dd0d951e2a319e78df9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 26 Nov 2015 07:58:58 +0100 Subject: [PATCH 068/136] [HttpFoundation] Workaround HHVM rewriting HTTP response line --- src/Symfony/Component/HttpFoundation/Response.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index ad55f8772af47..914e54fbb3dd7 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -268,9 +268,6 @@ public function sendHeaders() return $this; } - // status - header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)); - // headers foreach ($this->headers->allPreserveCase() as $name => $values) { foreach ($values as $value) { @@ -278,6 +275,9 @@ public function sendHeaders() } } + // status + header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode); + // cookies foreach ($this->headers->getCookies() as $cookie) { setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly()); From 7aac273701f2aca450703fd37233a86de3730d5e Mon Sep 17 00:00:00 2001 From: Peter Rehm Date: Wed, 25 Nov 2015 10:54:34 +0100 Subject: [PATCH 069/136] Added the renamed options of the collection type to the upgrade information --- UPGRADE-2.8.md | 8 ++++++++ UPGRADE-3.0.md | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index 67e1c0e66f18a..1271097a88c4d 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -213,6 +213,14 @@ Form } } ``` + + * The option "options" of the CollectionType has been renamed to "entry_options". + The usage of the option "options" is deprecated and will be removed in Symfony 3.0. + + * The option "type" of the CollectionType has been renamed to "entry_type". + The usage of the option "type" is deprecated and will be removed in Symfony 3.0. + As a value for the option you should provide the fully-qualified class name (FQCN) + now as well. * Passing type instances to `Form::add()`, `FormBuilder::add()` and the `FormFactory::create*()` methods is deprecated and will not be supported diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 5b86950fc694d..d5533f2b4b813 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -264,6 +264,12 @@ UPGRADE FROM 2.x to 3.0 // ... } ``` + + * The option "options" of the CollectionType has been renamed to "entry_options". + + * The option "type" of the CollectionType has been renamed to "entry_type". + As a value for the option you must provide the fully-qualified class name (FQCN) + now as well. * The `FormIntegrationTestCase` and `FormPerformanceTestCase` classes were moved form the `Symfony\Component\Form\Tests` namespace to the `Symfony\Component\Form\Test` namespace. From f495410d25e0ce7c2bf503be91b1776b4e2359ff Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Thu, 26 Nov 2015 10:11:54 +0100 Subject: [PATCH 070/136] [Form] Disabled view data validation if "data_class" is set to null --- src/Symfony/Component/Form/Form.php | 18 ++++-------------- .../Component/Form/Tests/SimpleFormTest.php | 10 +++++----- 2 files changed, 9 insertions(+), 19 deletions(-) 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/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index 6fb24a8cdc9c7..ae174f045d773 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -840,19 +840,19 @@ public function testGetPropertyPathDefaultsToIndexedNameIfDataClassOfFirstParent $this->assertEquals(new PropertyPath('[name]'), $form->getPropertyPath()); } - /** - * @expectedException \Symfony\Component\Form\Exception\LogicException - */ - public function testViewDataMustNotBeObjectIfDataClassIsNull() + public function testViewDataMayBeObjectIfDataClassIsNull() { + $object = new \stdClass(); $config = new FormConfigBuilder('name', null, $this->dispatcher); $config->addViewTransformer(new FixedDataTransformer(array( '' => '', - 'foo' => new \stdClass(), + 'foo' => $object, ))); $form = new Form($config); $form->setData('foo'); + + $this->assertSame($object, $form->getViewData()); } public function testViewDataMayBeArrayAccessIfDataClassIsNull() From 12a152b6664f2143eddab218bcf22fa39e998261 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 26 Nov 2015 10:39:31 +0100 Subject: [PATCH 071/136] [appveyor] Workaround transient segfault when APCu is enabled --- .travis.yml | 2 +- appveyor.yml | 4 ++-- phpunit | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index c347943fb48a0..c2933ed76e9d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,7 @@ before_install: - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; 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 (echo yes | pecl install -f apcu-4.0.8 && 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" != "hhvm" ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi; - if [ "$deps" != "skip" ]; then ./phpunit install; fi; diff --git a/appveyor.yml b/appveyor.yml index 5237ef69e4e63..45a9e7e9908d7 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.8/php_apcu-4.0.8-5.3-nts-vc9-x86.zip + - IF %PHP%==1 7z x php_apcu-4.0.8-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 diff --git a/phpunit b/phpunit index 2ab4f25e75cc2..3a3b3dd881ef4 100755 --- a/phpunit +++ b/phpunit @@ -164,7 +164,8 @@ if (isset($argv[1]) && 'symfony' === $argv[1]) { unlink($file); } - if ($procStatus) { + // 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 = 1; echo "\033[41mKO\033[0m $component\n\n"; } else { From 1ab73166a724f5323a415575d34d44f284f91ada Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 26 Nov 2015 17:15:31 +0100 Subject: [PATCH 072/136] [DI] use try-finally for container --- .../Component/DependencyInjection/Container.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 388e3e2ddf2e3..3edf12445c8e7 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -272,17 +272,13 @@ public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE try { $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]); throw $e; + } finally { + unset($this->loading[$id]); } - unset($this->loading[$id]); - return $service; } } From 91496229ab2cc518ae8467105eb91e0bb03b738f Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Thu, 26 Nov 2015 09:12:29 +0100 Subject: [PATCH 073/136] [Form] Fixed wrong usages of the "text" type --- src/Symfony/Component/Form/Form.php | 2 +- src/Symfony/Component/Form/Tests/CompoundFormTest.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index a277b580c5f2a..1d177d96b2ab1 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -910,7 +910,7 @@ public function add($child, $type = null, array $options = array()) $options['auto_initialize'] = false; if (null === $type && null === $this->config->getDataClass()) { - $type = 'text'; + $type = 'Symfony\Component\Form\Extension\Core\Type\TextType'; } if (null === $type) { diff --git a/src/Symfony/Component/Form/Tests/CompoundFormTest.php b/src/Symfony/Component/Form/Tests/CompoundFormTest.php index a306647234dd9..0a9ed8e67078f 100644 --- a/src/Symfony/Component/Form/Tests/CompoundFormTest.php +++ b/src/Symfony/Component/Form/Tests/CompoundFormTest.php @@ -172,13 +172,13 @@ public function testAddUsingNameAndType() $this->factory->expects($this->once()) ->method('createNamed') - ->with('foo', 'text', null, array( + ->with('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, array( 'bar' => 'baz', 'auto_initialize' => false, )) ->will($this->returnValue($child)); - $this->form->add('foo', 'text', array('bar' => 'baz')); + $this->form->add('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType', array('bar' => 'baz')); $this->assertTrue($this->form->has('foo')); $this->assertSame($this->form, $child->getParent()); @@ -191,14 +191,14 @@ public function testAddUsingIntegerNameAndType() $this->factory->expects($this->once()) ->method('createNamed') - ->with('0', 'text', null, array( + ->with('0', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, array( 'bar' => 'baz', 'auto_initialize' => false, )) ->will($this->returnValue($child)); // in order to make casting unnecessary - $this->form->add(0, 'text', array('bar' => 'baz')); + $this->form->add(0, 'Symfony\Component\Form\Extension\Core\Type\TextType', array('bar' => 'baz')); $this->assertTrue($this->form->has(0)); $this->assertSame($this->form, $child->getParent()); @@ -211,7 +211,7 @@ public function testAddWithoutType() $this->factory->expects($this->once()) ->method('createNamed') - ->with('foo', 'text') + ->with('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType') ->will($this->returnValue($child)); $this->form->add('foo'); From 5764a00a763efcc18f7230c21e87d5cf137b3a8a Mon Sep 17 00:00:00 2001 From: Wouter J Date: Sat, 21 Nov 2015 17:49:57 +0100 Subject: [PATCH 074/136] [Console] Fix bug with overloading --- .../Bundle/FrameworkBundle/Command/ServerStartCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php index 309ede6d068d3..f743cfbe3312e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php @@ -74,7 +74,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $output = new SymfonyStyle($input, $output); + $output = new SymfonyStyle($input, $cliOutput = $output); if (!extension_loaded('pcntl')) { $output->error(array( @@ -85,7 +85,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($output->ask('Do you want to execute server:run immediately? [Yn] ', true)) { $command = $this->getApplication()->find('server:run'); - return $command->run($input, $output); + return $command->run($input, $cliOutput); } return 1; From 41df3fce32a8bd489fba2e562645deed1f4e5860 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Thu, 26 Nov 2015 18:08:26 +0100 Subject: [PATCH 075/136] [Form] Deprecated TimezoneType::getTimezones() --- UPGRADE-2.8.md | 3 +++ UPGRADE-3.0.md | 3 +++ .../Component/Form/Extension/Core/Type/TimezoneType.php | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index 67e1c0e66f18a..216f1844e78b0 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -251,6 +251,9 @@ Form
``` + + * The `TimezoneType::getTimezones()` method was deprecated and will be removed + in Symfony 3.0. You should not use this method. Translator ---------- diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 5b86950fc694d..d422af0a58563 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -311,6 +311,9 @@ UPGRADE FROM 2.x to 3.0 * The `Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList` class has been removed in favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`. + + * The `TimezoneType::getTimezones()` method was removed. You should not use + this method. ### FrameworkBundle diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php index 3277a1838636c..5e3f4a385aa21 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php @@ -67,9 +67,13 @@ public function getBlockPrefix() * overhead. * * @return array The timezone choices + * + * @deprecated Deprecated since version 2.8 */ public static function getTimezones() { + @trigger_error('The TimezoneType::getTimezones() method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); + if (null === static::$timezones) { static::$timezones = array(); From 5386752bf9cf9fe4fc7ba8aff8f8466b60d2fa04 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Thu, 26 Nov 2015 18:36:46 +0100 Subject: [PATCH 076/136] [Form] Deprecated ArrayKeyChoiceList --- UPGRADE-2.8.md | 3 +++ UPGRADE-3.0.md | 3 +++ src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php | 2 ++ .../Component/Form/Tests/ChoiceList/ArrayKeyChoiceListTest.php | 2 ++ 4 files changed, 10 insertions(+) diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index 67e1c0e66f18a..95a3c6b77fb91 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -251,6 +251,9 @@ Form
``` + + * The class `ArrayKeyChoiceList` was deprecated and will be removed in Symfony + 3.0. Use `ArrayChoiceList` instead. Translator ---------- diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 5b86950fc694d..d6a056a634336 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -312,6 +312,9 @@ UPGRADE FROM 2.x to 3.0 * The `Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList` class has been removed in favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`. + * The `Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList` class has been removed in + favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`. + ### FrameworkBundle * The `config:debug`, `container:debug`, `router:debug`, `translation:debug` diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php index 7c3c107d0f720..fa2e3973f5867 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Form\ChoiceList; +@trigger_error('The '.__NAMESPACE__.'\ArrayKeyChoiceList class is deprecated since version 2.8 and will be removed in 3.0. Use '.__NAMESPACE__.'\ArrayChoiceList instead.', E_USER_DEPRECATED); + use Symfony\Component\Form\Exception\InvalidArgumentException; /** diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/ArrayKeyChoiceListTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/ArrayKeyChoiceListTest.php index 5cbadf6e0fe7b..1f1643158d48d 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/ArrayKeyChoiceListTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/ArrayKeyChoiceListTest.php @@ -15,6 +15,8 @@ /** * @author Bernhard Schussek + * + * @group legacy */ class ArrayKeyChoiceListTest extends AbstractChoiceListTest { From 478375d66424edfe8c9b40cd7f36ed784fba3b62 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 26 Nov 2015 18:53:25 +0100 Subject: [PATCH 077/136] [DI] remove useless condition around unset --- src/Symfony/Component/DependencyInjection/Container.php | 5 +---- src/Symfony/Component/DependencyInjection/Definition.php | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 443a65fb4183a..fb0e31911b8cb 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -312,10 +312,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 e2b40ff4b9703..690daa9c6ab02 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -409,9 +409,7 @@ public function hasTag($name) */ public function clearTag($name) { - if (isset($this->tags[$name])) { - unset($this->tags[$name]); - } + unset($this->tags[$name]); return $this; } From fc66283c7b446a0ba69ce9a4e2b187f6677efad9 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 26 Nov 2015 19:59:37 +0100 Subject: [PATCH 078/136] [SecurityBundle] make ACL an optional dependency --- .../SecurityBundle/DependencyInjection/SecurityExtension.php | 4 ++++ src/Symfony/Bundle/SecurityBundle/composer.json | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index bd0d2959b287a..323fcfe6b385a 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -116,6 +116,10 @@ public function load(array $configs, ContainerBuilder $container) private function aclLoad($config, ContainerBuilder $container) { + if (!interface_exists('Symfony\Component\Security\Acl\Model\AclInterface')) { + throw new \LogicException('You must install symfony/security-acl in order to use the ACL functionality.'); + } + $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('security_acl.xml'); diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 7803025b2b9c7..b185aac3832c9 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -18,7 +18,6 @@ "require": { "php": ">=5.5.9", "symfony/security": "~2.8|~3.0", - "symfony/security-acl": "~2.8|~3.0", "symfony/http-kernel": "~2.8|~3.0", "symfony/polyfill-php70": "~1.0" }, @@ -30,6 +29,7 @@ "symfony/form": "~2.8|~3.0", "symfony/framework-bundle": "~2.8|~3.0", "symfony/http-foundation": "~2.8|~3.0", + "symfony/security-acl": "~2.8|~3.0", "symfony/twig-bundle": "~2.8|~3.0", "symfony/twig-bridge": "~2.8|~3.0", "symfony/process": "~2.8|~3.0", @@ -39,6 +39,9 @@ "doctrine/doctrine-bundle": "~1.4", "twig/twig": "~1.23|~2.0" }, + "suggest": { + "symfony/security-acl": "For using the ACL functionality of this bundle" + }, "autoload": { "psr-4": { "Symfony\\Bundle\\SecurityBundle\\": "" }, "exclude-from-classmap": [ From 55f84a3369091e4fcf718472952a6bcb689c491c Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 26 Nov 2015 20:19:29 +0100 Subject: [PATCH 079/136] [SecurityBundle] disable the init:acl command if ACL is not used --- .../Bundle/SecurityBundle/Command/InitAclCommand.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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} */ From 123a300ad72d77f9d8e34a3ab44449b47be0eb49 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Wed, 25 Nov 2015 14:52:03 +0100 Subject: [PATCH 080/136] [Debug] fix readme: DebugClassLoader moved to debug itself --- src/Symfony/Component/Debug/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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. From acef3a3b340797ff24bafe2b8aa189bb9571b010 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Thu, 26 Nov 2015 22:00:12 +0100 Subject: [PATCH 081/136] CS: remove impossible default argument value --- src/Symfony/Component/Asset/UrlPackage.php | 5 +++-- .../Form/Extension/DataCollector/FormDataCollector.php | 4 ++-- .../HttpKernel/Tests/Controller/ControllerResolverTest.php | 2 +- src/Symfony/Component/Security/Acl/Domain/Acl.php | 2 +- .../RememberMe/PersistentTokenBasedRememberMeServices.php | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) 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/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/HttpKernel/Tests/Controller/ControllerResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php index 32db4e47adc5a..c298c84ec0059 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php @@ -224,7 +224,7 @@ protected function controllerMethod2($foo, $bar = null) { } - protected function controllerMethod3($foo, $bar = null, $foobar) + protected function controllerMethod3($foo, $bar, $foobar) { } diff --git a/src/Symfony/Component/Security/Acl/Domain/Acl.php b/src/Symfony/Component/Security/Acl/Domain/Acl.php index f417c8fda0475..fb70738ae7f65 100644 --- a/src/Symfony/Component/Security/Acl/Domain/Acl.php +++ b/src/Symfony/Component/Security/Acl/Domain/Acl.php @@ -56,7 +56,7 @@ class Acl implements AuditableAclInterface, NotifyPropertyChanged * @param array $loadedSids * @param bool $entriesInheriting */ - public function __construct($id, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSids = array(), $entriesInheriting) + public function __construct($id, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSids, $entriesInheriting) { $this->id = $id; $this->objectIdentity = $objectIdentity; diff --git a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php index 4fb7e09c147ff..eac17d4df2590 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php @@ -44,7 +44,7 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices * @param LoggerInterface $logger * @param SecureRandomInterface $secureRandom */ - public function __construct(array $userProviders, $key, $providerKey, array $options = array(), LoggerInterface $logger = null, SecureRandomInterface $secureRandom) + public function __construct(array $userProviders, $key, $providerKey, array $options, LoggerInterface $logger = null, SecureRandomInterface $secureRandom) { parent::__construct($userProviders, $key, $providerKey, $options, $logger); From 90f3b941d34d9c868bc21a096f96045207e493df Mon Sep 17 00:00:00 2001 From: hainey Date: Fri, 27 Nov 2015 13:33:49 +0900 Subject: [PATCH 082/136] Fixed the wrong source name and the ja translation --- .../Component/Form/Resources/translations/validators.ja.xlf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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トークンが無効です、再送信してください。 From 8588a4f63b718eff02554e766388f1ca05acc35c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 27 Nov 2015 09:21:43 +0100 Subject: [PATCH 083/136] [Process] Don't catch RuntimeException when it complicates tests debugging --- .../Process/Tests/SimpleProcessTest.php | 47 ++++++++----------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/Symfony/Component/Process/Tests/SimpleProcessTest.php b/src/Symfony/Component/Process/Tests/SimpleProcessTest.php index a52cd437a882b..4419581167a8d 100644 --- a/src/Symfony/Component/Process/Tests/SimpleProcessTest.php +++ b/src/Symfony/Component/Process/Tests/SimpleProcessTest.php @@ -152,46 +152,37 @@ public function testSignalWithWrongNonIntSignal() public function testStopTerminatesProcessCleanly() { - try { - $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); - $process->run(function () use ($process) { - $process->stop(); - }); - } catch (\RuntimeException $e) { - $this->fail('A call to stop() is not expected to cause wait() to throw a RuntimeException'); - } + $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); + $process->run(function () use ($process) { + $process->stop(); + }); + $this->assertTrue(true, 'A call to stop() is not expected to cause wait() to throw a RuntimeException'); } public function testKillSignalTerminatesProcessCleanly() { $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); - try { - $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); - $process->run(function () use ($process) { - if ($process->isRunning()) { - $process->signal(defined('SIGKILL') ? SIGKILL : 9); - } - }); - } catch (\RuntimeException $e) { - $this->fail('A call to signal() is not expected to cause wait() to throw a RuntimeException'); - } + $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); + $process->run(function () use ($process) { + if ($process->isRunning()) { + $process->signal(defined('SIGKILL') ? SIGKILL : 9); + } + }); + $this->assertTrue(true, 'A call to signal() is not expected to cause wait() to throw a RuntimeException'); } public function testTermSignalTerminatesProcessCleanly() { $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); - try { - $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); - $process->run(function () use ($process) { - if ($process->isRunning()) { - $process->signal(defined('SIGTERM') ? SIGTERM : 15); - } - }); - } catch (\RuntimeException $e) { - $this->fail('A call to signal() is not expected to cause wait() to throw a RuntimeException'); - } + $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); + $process->run(function () use ($process) { + if ($process->isRunning()) { + $process->signal(defined('SIGTERM') ? SIGTERM : 15); + } + }); + $this->assertTrue(true, 'A call to signal() is not expected to cause wait() to throw a RuntimeException'); } public function testStopWithTimeoutIsActuallyWorking() From 5d7678e4326a574c3d3fa20eadaa59ad9a245dbf Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Thu, 26 Nov 2015 11:53:06 +0100 Subject: [PATCH 084/136] [Form] Deprecated setting "choices_as_values" to "false" --- .../Form/ChoiceList/ArrayChoiceList.php | 37 ++++ .../Form/Extension/Core/Type/ChoiceType.php | 9 + .../Form/Extension/Core/Type/CountryType.php | 3 +- .../Form/Extension/Core/Type/CurrencyType.php | 3 +- .../Form/Extension/Core/Type/DateType.php | 16 +- .../Form/Extension/Core/Type/LanguageType.php | 3 +- .../Form/Extension/Core/Type/LocaleType.php | 3 +- .../Form/Extension/Core/Type/TimeType.php | 9 +- .../Form/Extension/Core/Type/TimezoneType.php | 46 ++++- .../Tests/ChoiceList/ArrayChoiceListTest.php | 48 ++++- .../ChoiceToValueTransformerTest.php | 6 +- .../ChoicesToValuesTransformerTest.php | 6 +- .../Extension/Core/Type/ChoiceTypeTest.php | 178 +++++++++++++++--- 13 files changed, 314 insertions(+), 53 deletions(-) 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 c325521d36174..de20b174abc03 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -281,6 +281,14 @@ public function configureOptions(OptionsResolver $resolver) return $choiceListFactory->createListFromChoices($choices, $options['choice_value']); }; + $choicesAsValuesNormalizer = function (Options $options, $choicesAsValues) { + if (true !== $choicesAsValues) { + @trigger_error('The value "false" for the "choices_as_values" option is deprecated since version 2.8 and will not be supported anymore in 3.0. Set this option to "true" and flip the contents of the "choices" option instead.', E_USER_DEPRECATED); + } + + return $choicesAsValues; + }; + $placeholderNormalizer = function (Options $options, $placeholder) { if (!is_object($options['empty_value']) || !$options['empty_value'] instanceof \Exception) { @trigger_error('The form option "empty_value" is deprecated since version 2.6 and will be removed in 3.0. Use "placeholder" instead.', E_USER_DEPRECATED); @@ -343,6 +351,7 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setNormalizer('choice_list', $choiceListNormalizer); $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); + $resolver->setNormalizer('choices_as_values', $choicesAsValuesNormalizer); $resolver->setAllowedTypes('choice_list', array('null', 'Symfony\Component\Form\ChoiceList\ChoiceListInterface', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface')); $resolver->setAllowedTypes('choices', array('null', 'array', '\Traversable')); diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php index 45da8d509a56a..2f114d9aa2f6b 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 7a26316e01a47..1608890d4a9ad 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 df5835b8b37f6..921b24ff0fd69 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php @@ -93,12 +93,15 @@ 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']; $yearOptions['choice_translation_domain'] = $options['choice_translation_domain']['year']; $monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months'])); + $monthOptions['choices_as_values'] = true; $monthOptions['placeholder'] = $options['placeholder']['month']; $monthOptions['choice_translation_domain'] = $options['choice_translation_domain']['month']; $dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days'])); + $dayOptions['choices_as_values'] = true; $dayOptions['placeholder'] = $options['placeholder']['day']; $dayOptions['choice_translation_domain'] = $options['choice_translation_domain']['day']; } @@ -297,6 +300,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'); @@ -307,8 +311,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 @@ -322,7 +326,7 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $ $formatter->setTimeZoneId($timezone); } - return $timestamps; + return $formattedTimestamps; } private function listYears(array $years) @@ -331,7 +335,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; } } @@ -343,7 +347,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; @@ -354,7 +358,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 6fc6031af11c2..da5cbc75e435f 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 a6d42f8c917ee..25ae92ded903e 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 ed9132863a0f8..1ab2030b1d174 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php @@ -63,20 +63,22 @@ 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']; $hourOptions['choice_translation_domain'] = $options['choice_translation_domain']['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']; $minuteOptions['choice_translation_domain'] = $options['choice_translation_domain']['minute']; } @@ -85,10 +87,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']; $secondOptions['choice_translation_domain'] = $options['choice_translation_domain']['second']; } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php index 3277a1838636c..a3ec7bf744821 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, )); } @@ -93,4 +101,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/Tests/ChoiceList/ArrayChoiceListTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php index 50d4df8a9b7cb..03cb7fce5705a 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php @@ -65,6 +65,40 @@ public function testCreateChoiceListWithValueCallback() $this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 'baz'))); } + public function testCreateChoiceListWithoutValueCallbackAndDuplicateFreeToStringChoices() + { + $choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => 'bar', 10 => 123)); + + $this->assertSame(array('foo', 'bar', '123'), $choiceList->getValues()); + $this->assertSame(array('foo' => 'foo', 'bar' => 'bar', '123' => 123), $choiceList->getChoices()); + $this->assertSame(array('foo' => 2, 'bar' => 7, '123' => 10), $choiceList->getOriginalKeys()); + $this->assertSame(array(1 => 'foo', 2 => 123), $choiceList->getChoicesForValues(array(1 => 'foo', 2 => '123'))); + $this->assertSame(array(1 => 'foo', 2 => '123'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 123))); + } + + public function testCreateChoiceListWithoutValueCallbackAndToStringDuplicates() + { + $choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => '123', 10 => 123)); + + $this->assertSame(array('0', '1', '2'), $choiceList->getValues()); + $this->assertSame(array('0' => 'foo', '1' => '123', '2' => 123), $choiceList->getChoices()); + $this->assertSame(array('0' => 2, '1' => 7, '2' => 10), $choiceList->getOriginalKeys()); + $this->assertSame(array(1 => 'foo', 2 => 123), $choiceList->getChoicesForValues(array(1 => '0', 2 => '2'))); + $this->assertSame(array(1 => '0', 2 => '2'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 123))); + } + + public function testCreateChoiceListWithoutValueCallbackAndMixedChoices() + { + $object = new \stdClass(); + $choiceList = new ArrayChoiceList(array(2 => 'foo', 5 => array(7 => '123'), 10 => $object)); + + $this->assertSame(array('0', '1', '2'), $choiceList->getValues()); + $this->assertSame(array('0' => 'foo', '1' => '123', '2' => $object), $choiceList->getChoices()); + $this->assertSame(array('0' => 2, '1' => 7, '2' => 10), $choiceList->getOriginalKeys()); + $this->assertSame(array(1 => 'foo', 2 => $object), $choiceList->getChoicesForValues(array(1 => '0', 2 => '2'))); + $this->assertSame(array(1 => '0', 2 => '2'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => $object))); + } + public function testCreateChoiceListWithGroupedChoices() { $choiceList = new ArrayChoiceList(array( @@ -72,15 +106,15 @@ public function testCreateChoiceListWithGroupedChoices() 'Group 2' => array('C' => 'c', 'D' => 'd'), )); - $this->assertSame(array('0', '1', '2', '3'), $choiceList->getValues()); + $this->assertSame(array('a', 'b', 'c', 'd'), $choiceList->getValues()); $this->assertSame(array( - 'Group 1' => array('A' => '0', 'B' => '1'), - 'Group 2' => array('C' => '2', 'D' => '3'), + 'Group 1' => array('A' => 'a', 'B' => 'b'), + 'Group 2' => array('C' => 'c', 'D' => 'd'), ), $choiceList->getStructuredValues()); - $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $choiceList->getChoices()); - $this->assertSame(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'), $choiceList->getOriginalKeys()); - $this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => '0', 2 => '1'))); - $this->assertSame(array(1 => '0', 2 => '1'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b'))); + $this->assertSame(array('a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd'), $choiceList->getChoices()); + $this->assertSame(array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'), $choiceList->getOriginalKeys()); + $this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => 'a', 2 => 'b'))); + $this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b'))); } public function testCompareChoicesByIdentityByDefault() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php index c58d072f47434..f60ef05abc507 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php @@ -20,7 +20,7 @@ class ChoiceToValueTransformerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $list = new ArrayChoiceList(array('', 0, 'X')); + $list = new ArrayChoiceList(array('', false, 'X')); $this->transformer = new ChoiceToValueTransformer($list); } @@ -35,7 +35,7 @@ public function transformProvider() return array( // more extensive test set can be found in FormUtilTest array('', '0'), - array(0, '1'), + array(false, '1'), ); } @@ -53,7 +53,7 @@ public function reverseTransformProvider() // values are expected to be valid choice keys already and stay // the same array('0', ''), - array('1', 0), + array('1', false), array('2', 'X'), ); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php index a7dc40aca225f..f7747aaccd0f1 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php @@ -20,7 +20,7 @@ class ChoicesToValuesTransformerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $list = new ArrayChoiceList(array('A', 'B', 'C')); + $list = new ArrayChoiceList(array('', false, 'X')); $this->transformer = new ChoicesToValuesTransformer($list); } @@ -31,7 +31,7 @@ protected function tearDown() public function testTransform() { - $in = array('A', 'B', 'C'); + $in = array('', false, 'X'); $out = array('0', '1', '2'); $this->assertSame($out, $this->transformer->transform($in)); @@ -54,7 +54,7 @@ public function testReverseTransform() { // values are expected to be valid choices and stay the same $in = array('0', '1', '2'); - $out = array('A', 'B', 'C'); + $out = array('', false, 'X'); $this->assertSame($out, $this->transformer->reverseTransform($in)); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index a8bf8edf12655..732c2e86362a0 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -18,14 +18,14 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase { private $choices = array( - 'a' => 'Bernhard', - 'b' => 'Fabien', - 'c' => 'Kris', - 'd' => 'Jon', - 'e' => 'Roman', + 'Bernhard' => 'a', + 'Fabien' => 'b', + 'Kris' => 'c', + 'Jon' => 'd', + 'Roman' => 'e', ); - private $numericChoices = array( + private $numericChoicesFlipped = array( 0 => 'Bernhard', 1 => 'Fabien', 2 => 'Kris', @@ -36,6 +36,18 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase private $objectChoices; protected $groupedChoices = array( + 'Symfony' => array( + 'Bernhard' => 'a', + 'Fabien' => 'b', + 'Kris' => 'c', + ), + 'Doctrine' => array( + 'Jon' => 'd', + 'Roman' => 'e', + ), + ); + + protected $groupedChoicesFlipped = array( 'Symfony' => array( 'a' => 'Bernhard', 'b' => 'Fabien', @@ -109,7 +121,9 @@ public function testChoiceLoaderOptionExpectsChoiceLoaderInterface() public function testChoiceListAndChoicesCanBeEmpty() { - $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType'); + $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( + 'choices_as_values' => true, + )); } public function testExpandedChoicesOptionsTurnIntoChildren() @@ -117,6 +131,20 @@ public function testExpandedChoicesOptionsTurnIntoChildren() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, + )); + + $this->assertCount(count($this->choices), $form, 'Each choice should become a new field'); + } + + /** + * @group legacy + */ + public function testExpandedFlippedChoicesOptionsTurnIntoChildren() + { + $form = $this->factory->create('choice', null, array( + 'expanded' => true, + 'choices' => array_flip($this->choices), )); $this->assertCount(count($this->choices), $form, 'Each choice should become a new field'); @@ -129,6 +157,7 @@ public function testPlaceholderPresentOnNonRequiredExpandedSingleChoice() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $this->assertTrue(isset($form['placeholder'])); @@ -142,6 +171,7 @@ public function testPlaceholderNotPresentIfRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $this->assertFalse(isset($form['placeholder'])); @@ -155,6 +185,7 @@ public function testPlaceholderNotPresentIfMultiple() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $this->assertFalse(isset($form['placeholder'])); @@ -168,9 +199,10 @@ public function testPlaceholderNotPresentIfEmptyChoice() 'expanded' => true, 'required' => false, 'choices' => array( - '' => 'Empty', - 1 => 'Not empty', + 'Empty' => '', + 'Not empty' => 1, ), + 'choices_as_values' => true, )); $this->assertFalse(isset($form['placeholder'])); @@ -182,6 +214,29 @@ public function testExpandedChoicesOptionsAreFlattened() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'expanded' => true, 'choices' => $this->groupedChoices, + 'choices_as_values' => true, + )); + + $flattened = array(); + foreach ($this->groupedChoices as $choices) { + $flattened = array_merge($flattened, array_keys($choices)); + } + + $this->assertCount($form->count(), $flattened, 'Each nested choice should become a new field, not the groups'); + + foreach ($flattened as $value => $choice) { + $this->assertTrue($form->has($value), 'Flattened choice is named after it\'s value'); + } + } + + /** + * @group legacy + */ + public function testExpandedChoicesFlippedOptionsAreFlattened() + { + $form = $this->factory->create('choice', null, array( + 'expanded' => true, + 'choices' => $this->groupedChoicesFlipped, )); $flattened = array(); @@ -229,6 +284,7 @@ public function testExpandedCheckboxesAreNeverRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); foreach ($form as $child) { @@ -243,6 +299,7 @@ public function testExpandedRadiosAreRequiredIfChoiceChildIsRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); foreach ($form as $child) { @@ -257,6 +314,7 @@ public function testExpandedRadiosAreNotRequiredIfChoiceChildIsNotRequired() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); foreach ($form as $child) { @@ -270,6 +328,7 @@ public function testSubmitSingleNonExpanded() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('b'); @@ -285,6 +344,7 @@ public function testSubmitSingleNonExpandedInvalidChoice() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -300,6 +360,7 @@ public function testSubmitSingleNonExpandedNull() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(null); @@ -318,6 +379,7 @@ public function testSubmitSingleNonExpandedNullNoChoices() 'multiple' => false, 'expanded' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(null); @@ -333,6 +395,7 @@ public function testSubmitSingleNonExpandedEmpty() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(''); @@ -348,8 +411,9 @@ public function testSubmitSingleNonExpandedEmptyExplicitEmptyChoice() 'multiple' => false, 'expanded' => false, 'choices' => array( - 'EMPTY_CHOICE' => 'Empty', + 'Empty' => 'EMPTY_CHOICE', ), + 'choices_as_values' => true, 'choice_value' => function () { return ''; }, @@ -371,6 +435,7 @@ public function testSubmitSingleNonExpandedEmptyNoChoices() 'multiple' => false, 'expanded' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(''); @@ -386,6 +451,7 @@ public function testSubmitSingleNonExpandedFalse() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(false); @@ -404,6 +470,7 @@ public function testSubmitSingleNonExpandedFalseNoChoices() 'multiple' => false, 'expanded' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(false); @@ -465,6 +532,7 @@ public function testSubmitMultipleNonExpanded() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array('a', 'b')); @@ -480,6 +548,7 @@ public function testSubmitMultipleNonExpandedEmpty() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array()); @@ -498,6 +567,7 @@ public function testSubmitMultipleNonExpandedEmptyNoChoices() 'multiple' => true, 'expanded' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(array()); @@ -513,6 +583,7 @@ public function testSubmitMultipleNonExpandedInvalidScalarChoice() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -528,6 +599,7 @@ public function testSubmitMultipleNonExpandedInvalidArrayChoice() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array('a', 'foobar')); @@ -588,6 +660,7 @@ public function testSubmitSingleExpandedRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('b'); @@ -616,6 +689,7 @@ public function testSubmitSingleExpandedRequiredInvalidChoice() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -644,6 +718,7 @@ public function testSubmitSingleExpandedNonRequired() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('b'); @@ -674,6 +749,7 @@ public function testSubmitSingleExpandedNonRequiredInvalidChoice() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -702,6 +778,7 @@ public function testSubmitSingleExpandedRequiredNull() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(null); @@ -733,6 +810,7 @@ public function testSubmitSingleExpandedRequiredNullNoChoices() 'expanded' => true, 'required' => true, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(null); @@ -750,6 +828,7 @@ public function testSubmitSingleExpandedRequiredEmpty() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(''); @@ -781,6 +860,7 @@ public function testSubmitSingleExpandedRequiredEmptyNoChoices() 'expanded' => true, 'required' => true, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(''); @@ -798,6 +878,7 @@ public function testSubmitSingleExpandedRequiredFalse() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(false); @@ -829,6 +910,7 @@ public function testSubmitSingleExpandedRequiredFalseNoChoices() 'expanded' => true, 'required' => true, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(false); @@ -846,6 +928,7 @@ public function testSubmitSingleExpandedNonRequiredNull() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(null); @@ -879,6 +962,7 @@ public function testSubmitSingleExpandedNonRequiredNullNoChoices() 'expanded' => true, 'required' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(null); @@ -896,6 +980,7 @@ public function testSubmitSingleExpandedNonRequiredEmpty() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(''); @@ -929,6 +1014,7 @@ public function testSubmitSingleExpandedNonRequiredEmptyNoChoices() 'expanded' => true, 'required' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(''); @@ -946,6 +1032,7 @@ public function testSubmitSingleExpandedNonRequiredFalse() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(false); @@ -979,6 +1066,7 @@ public function testSubmitSingleExpandedNonRequiredFalseNoChoices() 'expanded' => true, 'required' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(false); @@ -995,9 +1083,10 @@ public function testSubmitSingleExpandedWithEmptyChild() 'multiple' => false, 'expanded' => true, 'choices' => array( - '' => 'Empty', - 1 => 'Not empty', + 'Empty' => '', + 'Not empty' => 1, ), + 'choices_as_values' => true, )); $form->submit(''); @@ -1075,12 +1164,15 @@ public function testLegacySubmitSingleExpandedObjectChoices() $this->assertNull($form[4]->getViewData()); } - public function testSubmitSingleExpandedNumericChoices() + /** + * @group legacy + */ + public function testSubmitSingleExpandedNumericChoicesFlipped() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'multiple' => false, 'expanded' => true, - 'choices' => $this->numericChoices, + 'choices' => $this->numericChoicesFlipped, )); $form->submit('1'); @@ -1106,6 +1198,7 @@ public function testSubmitMultipleExpanded() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array('a', 'c')); @@ -1133,6 +1226,7 @@ public function testSubmitMultipleExpandedInvalidScalarChoice() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -1160,6 +1254,7 @@ public function testSubmitMultipleExpandedInvalidArrayChoice() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array('a', 'foobar')); @@ -1187,6 +1282,7 @@ public function testSubmitMultipleExpandedEmpty() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array()); @@ -1215,6 +1311,7 @@ public function testSubmitMultipleExpandedEmptyNoChoices() 'multiple' => true, 'expanded' => true, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(array()); @@ -1229,10 +1326,11 @@ public function testSubmitMultipleExpandedWithEmptyChild() 'multiple' => true, 'expanded' => true, 'choices' => array( - '' => 'Empty', - 1 => 'Not Empty', - 2 => 'Not Empty 2', + 'Empty' => '', + 'Not Empty' => 1, + 'Not Empty 2' => 2, ), + 'choices_as_values' => true, )); $form->submit(array('', '2')); @@ -1312,12 +1410,15 @@ public function testLegacySubmitMultipleExpandedObjectChoices() $this->assertNull($form[4]->getViewData()); } + /** + * @group legacy + */ public function testSubmitMultipleExpandedNumericChoices() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'multiple' => true, 'expanded' => true, - 'choices' => $this->numericChoices, + 'choices' => $this->numericChoicesFlipped, )); $form->submit(array('1', '2')); @@ -1373,16 +1474,18 @@ public function testMultipleSelectedObjectChoices() $this->assertFalse($selectedChecker($view->vars['choices'][1]->value, $view->vars['value'])); } - /* + /** * We need this functionality to create choice fields for Boolean types, - * e.g. false => 'No', true => 'Yes' + * e.g. false => 'No', true => 'Yes'. + * + * @group legacy */ public function testSetDataSingleNonExpandedAcceptsBoolean() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'multiple' => false, 'expanded' => false, - 'choices' => $this->numericChoices, + 'choices' => $this->numericChoicesFlipped, )); $form->setData(false); @@ -1392,12 +1495,15 @@ public function testSetDataSingleNonExpandedAcceptsBoolean() $this->assertTrue($form->isSynchronized()); } + /** + * @group legacy + */ public function testSetDataMultipleNonExpandedAcceptsBoolean() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'multiple' => true, 'expanded' => false, - 'choices' => $this->numericChoices, + 'choices' => $this->numericChoicesFlipped, )); $form->setData(array(false, true)); @@ -1411,6 +1517,7 @@ public function testPassRequiredToView() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1422,6 +1529,7 @@ public function testPassNonRequiredToView() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1433,6 +1541,7 @@ public function testPassMultipleToView() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'multiple' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1444,6 +1553,7 @@ public function testPassExpandedToView() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1454,6 +1564,7 @@ public function testPassChoiceTranslationDomainToView() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1464,6 +1575,7 @@ public function testChoiceTranslationDomainWithTrueValueToView() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->choices, + 'choices_as_values' => true, 'choice_translation_domain' => true, )); $view = $form->createView(); @@ -1475,6 +1587,7 @@ public function testDefaultChoiceTranslationDomainIsSameAsTranslationDomainToVie { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->choices, + 'choices_as_values' => true, 'translation_domain' => 'foo', )); $view = $form->createView(); @@ -1488,7 +1601,10 @@ public function testInheritChoiceTranslationDomainFromParent() ->createNamedBuilder('parent', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, array( 'translation_domain' => 'domain', )) - ->add('child', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType') + ->add('child', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array( + 'choices' => array(), + 'choices_as_values' => true, + )) ->getForm() ->createView(); @@ -1501,6 +1617,7 @@ public function testPlaceholderIsNullByDefaultIfRequired() 'multiple' => false, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1513,6 +1630,7 @@ public function testPlaceholderIsEmptyStringByDefaultIfNotRequired() 'multiple' => false, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1530,6 +1648,7 @@ public function testPassPlaceholderToView($multiple, $expanded, $required, $plac 'required' => $required, 'placeholder' => $placeholder, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1549,6 +1668,7 @@ public function testPassEmptyValueBC($multiple, $expanded, $required, $placehold 'required' => $required, 'empty_value' => $placeholder, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1568,7 +1688,8 @@ public function testDontPassPlaceholderIfContainedInChoices($multiple, $expanded 'expanded' => $expanded, 'required' => $required, 'placeholder' => $placeholder, - 'choices' => array('a' => 'A', '' => 'Empty'), + 'choices' => array('A' => 'a', 'Empty' => ''), + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1622,9 +1743,10 @@ public function getOptionsWithPlaceholder() public function testPassChoicesToView() { - $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'); + $choices = array('A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1638,9 +1760,10 @@ public function testPassChoicesToView() public function testPassPreferredChoicesToView() { - $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'); + $choices = array('A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $choices, + 'choices_as_values' => true, 'preferred_choices' => array('b', 'd'), )); $view = $form->createView(); @@ -1659,6 +1782,7 @@ public function testPassHierarchicalChoicesToView() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->groupedChoices, + 'choices_as_values' => true, 'preferred_choices' => array('b', 'd'), )); $view = $form->createView(); @@ -1710,6 +1834,7 @@ public function testAdjustFullNameForMultipleNonExpanded() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1721,6 +1846,7 @@ public function testInitializeWithEmptyChoices() { $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => array(), + 'choices_as_values' => true, )); } From 3ab8189080738bbe55227698faf0334f35c64081 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Thu, 26 Nov 2015 11:53:06 +0100 Subject: [PATCH 085/136] [Form] Deprecated setting "choices_as_values" to "false" --- .../Form/ChoiceList/ArrayChoiceList.php | 37 ++++ .../Form/Extension/Core/Type/CountryType.php | 3 +- .../Form/Extension/Core/Type/CurrencyType.php | 3 +- .../Form/Extension/Core/Type/DateType.php | 16 +- .../Form/Extension/Core/Type/LanguageType.php | 3 +- .../Form/Extension/Core/Type/LocaleType.php | 3 +- .../Form/Extension/Core/Type/TimeType.php | 9 +- .../Form/Extension/Core/Type/TimezoneType.php | 46 ++++- .../Tests/ChoiceList/ArrayChoiceListTest.php | 48 ++++- .../ChoiceToValueTransformerTest.php | 6 +- .../ChoicesToValuesTransformerTest.php | 6 +- .../Extension/Core/Type/ChoiceTypeTest.php | 169 +++++++++++++++--- 12 files changed, 298 insertions(+), 51 deletions(-) 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/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/Tests/ChoiceList/ArrayChoiceListTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php index 50d4df8a9b7cb..03cb7fce5705a 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php @@ -65,6 +65,40 @@ public function testCreateChoiceListWithValueCallback() $this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 'baz'))); } + public function testCreateChoiceListWithoutValueCallbackAndDuplicateFreeToStringChoices() + { + $choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => 'bar', 10 => 123)); + + $this->assertSame(array('foo', 'bar', '123'), $choiceList->getValues()); + $this->assertSame(array('foo' => 'foo', 'bar' => 'bar', '123' => 123), $choiceList->getChoices()); + $this->assertSame(array('foo' => 2, 'bar' => 7, '123' => 10), $choiceList->getOriginalKeys()); + $this->assertSame(array(1 => 'foo', 2 => 123), $choiceList->getChoicesForValues(array(1 => 'foo', 2 => '123'))); + $this->assertSame(array(1 => 'foo', 2 => '123'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 123))); + } + + public function testCreateChoiceListWithoutValueCallbackAndToStringDuplicates() + { + $choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => '123', 10 => 123)); + + $this->assertSame(array('0', '1', '2'), $choiceList->getValues()); + $this->assertSame(array('0' => 'foo', '1' => '123', '2' => 123), $choiceList->getChoices()); + $this->assertSame(array('0' => 2, '1' => 7, '2' => 10), $choiceList->getOriginalKeys()); + $this->assertSame(array(1 => 'foo', 2 => 123), $choiceList->getChoicesForValues(array(1 => '0', 2 => '2'))); + $this->assertSame(array(1 => '0', 2 => '2'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 123))); + } + + public function testCreateChoiceListWithoutValueCallbackAndMixedChoices() + { + $object = new \stdClass(); + $choiceList = new ArrayChoiceList(array(2 => 'foo', 5 => array(7 => '123'), 10 => $object)); + + $this->assertSame(array('0', '1', '2'), $choiceList->getValues()); + $this->assertSame(array('0' => 'foo', '1' => '123', '2' => $object), $choiceList->getChoices()); + $this->assertSame(array('0' => 2, '1' => 7, '2' => 10), $choiceList->getOriginalKeys()); + $this->assertSame(array(1 => 'foo', 2 => $object), $choiceList->getChoicesForValues(array(1 => '0', 2 => '2'))); + $this->assertSame(array(1 => '0', 2 => '2'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => $object))); + } + public function testCreateChoiceListWithGroupedChoices() { $choiceList = new ArrayChoiceList(array( @@ -72,15 +106,15 @@ public function testCreateChoiceListWithGroupedChoices() 'Group 2' => array('C' => 'c', 'D' => 'd'), )); - $this->assertSame(array('0', '1', '2', '3'), $choiceList->getValues()); + $this->assertSame(array('a', 'b', 'c', 'd'), $choiceList->getValues()); $this->assertSame(array( - 'Group 1' => array('A' => '0', 'B' => '1'), - 'Group 2' => array('C' => '2', 'D' => '3'), + 'Group 1' => array('A' => 'a', 'B' => 'b'), + 'Group 2' => array('C' => 'c', 'D' => 'd'), ), $choiceList->getStructuredValues()); - $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $choiceList->getChoices()); - $this->assertSame(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'), $choiceList->getOriginalKeys()); - $this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => '0', 2 => '1'))); - $this->assertSame(array(1 => '0', 2 => '1'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b'))); + $this->assertSame(array('a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd'), $choiceList->getChoices()); + $this->assertSame(array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'), $choiceList->getOriginalKeys()); + $this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => 'a', 2 => 'b'))); + $this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b'))); } public function testCompareChoicesByIdentityByDefault() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php index c58d072f47434..f60ef05abc507 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoiceToValueTransformerTest.php @@ -20,7 +20,7 @@ class ChoiceToValueTransformerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $list = new ArrayChoiceList(array('', 0, 'X')); + $list = new ArrayChoiceList(array('', false, 'X')); $this->transformer = new ChoiceToValueTransformer($list); } @@ -35,7 +35,7 @@ public function transformProvider() return array( // more extensive test set can be found in FormUtilTest array('', '0'), - array(0, '1'), + array(false, '1'), ); } @@ -53,7 +53,7 @@ public function reverseTransformProvider() // values are expected to be valid choice keys already and stay // the same array('0', ''), - array('1', 0), + array('1', false), array('2', 'X'), ); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php index a7dc40aca225f..f7747aaccd0f1 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php @@ -20,7 +20,7 @@ class ChoicesToValuesTransformerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $list = new ArrayChoiceList(array('A', 'B', 'C')); + $list = new ArrayChoiceList(array('', false, 'X')); $this->transformer = new ChoicesToValuesTransformer($list); } @@ -31,7 +31,7 @@ protected function tearDown() public function testTransform() { - $in = array('A', 'B', 'C'); + $in = array('', false, 'X'); $out = array('0', '1', '2'); $this->assertSame($out, $this->transformer->transform($in)); @@ -54,7 +54,7 @@ public function testReverseTransform() { // values are expected to be valid choices and stay the same $in = array('0', '1', '2'); - $out = array('A', 'B', 'C'); + $out = array('', false, 'X'); $this->assertSame($out, $this->transformer->reverseTransform($in)); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index 215ddac936a54..f2a1f73e49aa7 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -18,14 +18,14 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase { private $choices = array( - 'a' => 'Bernhard', - 'b' => 'Fabien', - 'c' => 'Kris', - 'd' => 'Jon', - 'e' => 'Roman', + 'Bernhard' => 'a', + 'Fabien' => 'b', + 'Kris' => 'c', + 'Jon' => 'd', + 'Roman' => 'e', ); - private $numericChoices = array( + private $numericChoicesFlipped = array( 0 => 'Bernhard', 1 => 'Fabien', 2 => 'Kris', @@ -36,6 +36,18 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase private $objectChoices; protected $groupedChoices = array( + 'Symfony' => array( + 'Bernhard' => 'a', + 'Fabien' => 'b', + 'Kris' => 'c', + ), + 'Doctrine' => array( + 'Jon' => 'd', + 'Roman' => 'e', + ), + ); + + protected $groupedChoicesFlipped = array( 'Symfony' => array( 'a' => 'Bernhard', 'b' => 'Fabien', @@ -107,6 +119,20 @@ public function testExpandedChoicesOptionsTurnIntoChildren() $form = $this->factory->create('choice', null, array( 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, + )); + + $this->assertCount(count($this->choices), $form, 'Each choice should become a new field'); + } + + /** + * @group legacy + */ + public function testExpandedFlippedChoicesOptionsTurnIntoChildren() + { + $form = $this->factory->create('choice', null, array( + 'expanded' => true, + 'choices' => array_flip($this->choices), )); $this->assertCount(count($this->choices), $form, 'Each choice should become a new field'); @@ -119,6 +145,7 @@ public function testPlaceholderPresentOnNonRequiredExpandedSingleChoice() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $this->assertTrue(isset($form['placeholder'])); @@ -132,6 +159,7 @@ public function testPlaceholderNotPresentIfRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $this->assertFalse(isset($form['placeholder'])); @@ -145,6 +173,7 @@ public function testPlaceholderNotPresentIfMultiple() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $this->assertFalse(isset($form['placeholder'])); @@ -158,9 +187,10 @@ public function testPlaceholderNotPresentIfEmptyChoice() 'expanded' => true, 'required' => false, 'choices' => array( - '' => 'Empty', - 1 => 'Not empty', + 'Empty' => '', + 'Not empty' => 1, ), + 'choices_as_values' => true, )); $this->assertFalse(isset($form['placeholder'])); @@ -172,6 +202,29 @@ public function testExpandedChoicesOptionsAreFlattened() $form = $this->factory->create('choice', null, array( 'expanded' => true, 'choices' => $this->groupedChoices, + 'choices_as_values' => true, + )); + + $flattened = array(); + foreach ($this->groupedChoices as $choices) { + $flattened = array_merge($flattened, array_keys($choices)); + } + + $this->assertCount($form->count(), $flattened, 'Each nested choice should become a new field, not the groups'); + + foreach ($flattened as $value => $choice) { + $this->assertTrue($form->has($value), 'Flattened choice is named after it\'s value'); + } + } + + /** + * @group legacy + */ + public function testExpandedChoicesFlippedOptionsAreFlattened() + { + $form = $this->factory->create('choice', null, array( + 'expanded' => true, + 'choices' => $this->groupedChoicesFlipped, )); $flattened = array(); @@ -219,6 +272,7 @@ public function testExpandedCheckboxesAreNeverRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); foreach ($form as $child) { @@ -233,6 +287,7 @@ public function testExpandedRadiosAreRequiredIfChoiceChildIsRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); foreach ($form as $child) { @@ -247,6 +302,7 @@ public function testExpandedRadiosAreNotRequiredIfChoiceChildIsNotRequired() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); foreach ($form as $child) { @@ -260,6 +316,7 @@ public function testSubmitSingleNonExpanded() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('b'); @@ -275,6 +332,7 @@ public function testSubmitSingleNonExpandedInvalidChoice() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -290,6 +348,7 @@ public function testSubmitSingleNonExpandedNull() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(null); @@ -308,6 +367,7 @@ public function testSubmitSingleNonExpandedNullNoChoices() 'multiple' => false, 'expanded' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(null); @@ -323,6 +383,7 @@ public function testSubmitSingleNonExpandedEmpty() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(''); @@ -338,8 +399,9 @@ public function testSubmitSingleNonExpandedEmptyExplicitEmptyChoice() 'multiple' => false, 'expanded' => false, 'choices' => array( - 'EMPTY_CHOICE' => 'Empty', + 'Empty' => 'EMPTY_CHOICE', ), + 'choices_as_values' => true, 'choice_value' => function () { return ''; }, @@ -361,6 +423,7 @@ public function testSubmitSingleNonExpandedEmptyNoChoices() 'multiple' => false, 'expanded' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(''); @@ -376,6 +439,7 @@ public function testSubmitSingleNonExpandedFalse() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(false); @@ -394,6 +458,7 @@ public function testSubmitSingleNonExpandedFalseNoChoices() 'multiple' => false, 'expanded' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(false); @@ -455,6 +520,7 @@ public function testSubmitMultipleNonExpanded() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array('a', 'b')); @@ -470,6 +536,7 @@ public function testSubmitMultipleNonExpandedEmpty() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array()); @@ -488,6 +555,7 @@ public function testSubmitMultipleNonExpandedEmptyNoChoices() 'multiple' => true, 'expanded' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(array()); @@ -503,6 +571,7 @@ public function testSubmitMultipleNonExpandedInvalidScalarChoice() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -518,6 +587,7 @@ public function testSubmitMultipleNonExpandedInvalidArrayChoice() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array('a', 'foobar')); @@ -578,6 +648,7 @@ public function testSubmitSingleExpandedRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('b'); @@ -606,6 +677,7 @@ public function testSubmitSingleExpandedRequiredInvalidChoice() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -634,6 +706,7 @@ public function testSubmitSingleExpandedNonRequired() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('b'); @@ -664,6 +737,7 @@ public function testSubmitSingleExpandedNonRequiredInvalidChoice() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -692,6 +766,7 @@ public function testSubmitSingleExpandedRequiredNull() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(null); @@ -723,6 +798,7 @@ public function testSubmitSingleExpandedRequiredNullNoChoices() 'expanded' => true, 'required' => true, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(null); @@ -740,6 +816,7 @@ public function testSubmitSingleExpandedRequiredEmpty() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(''); @@ -771,6 +848,7 @@ public function testSubmitSingleExpandedRequiredEmptyNoChoices() 'expanded' => true, 'required' => true, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(''); @@ -788,6 +866,7 @@ public function testSubmitSingleExpandedRequiredFalse() 'expanded' => true, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(false); @@ -819,6 +898,7 @@ public function testSubmitSingleExpandedRequiredFalseNoChoices() 'expanded' => true, 'required' => true, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(false); @@ -836,6 +916,7 @@ public function testSubmitSingleExpandedNonRequiredNull() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(null); @@ -869,6 +950,7 @@ public function testSubmitSingleExpandedNonRequiredNullNoChoices() 'expanded' => true, 'required' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(null); @@ -886,6 +968,7 @@ public function testSubmitSingleExpandedNonRequiredEmpty() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(''); @@ -919,6 +1002,7 @@ public function testSubmitSingleExpandedNonRequiredEmptyNoChoices() 'expanded' => true, 'required' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(''); @@ -936,6 +1020,7 @@ public function testSubmitSingleExpandedNonRequiredFalse() 'expanded' => true, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(false); @@ -969,6 +1054,7 @@ public function testSubmitSingleExpandedNonRequiredFalseNoChoices() 'expanded' => true, 'required' => false, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(false); @@ -985,9 +1071,10 @@ public function testSubmitSingleExpandedWithEmptyChild() 'multiple' => false, 'expanded' => true, 'choices' => array( - '' => 'Empty', - 1 => 'Not empty', + 'Empty' => '', + 'Not empty' => 1, ), + 'choices_as_values' => true, )); $form->submit(''); @@ -1065,12 +1152,15 @@ public function testLegacySubmitSingleExpandedObjectChoices() $this->assertNull($form[4]->getViewData()); } - public function testSubmitSingleExpandedNumericChoices() + /** + * @group legacy + */ + public function testSubmitSingleExpandedNumericChoicesFlipped() { $form = $this->factory->create('choice', null, array( 'multiple' => false, 'expanded' => true, - 'choices' => $this->numericChoices, + 'choices' => $this->numericChoicesFlipped, )); $form->submit('1'); @@ -1096,6 +1186,7 @@ public function testSubmitMultipleExpanded() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array('a', 'c')); @@ -1123,6 +1214,7 @@ public function testSubmitMultipleExpandedInvalidScalarChoice() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit('foobar'); @@ -1150,6 +1242,7 @@ public function testSubmitMultipleExpandedInvalidArrayChoice() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array('a', 'foobar')); @@ -1177,6 +1270,7 @@ public function testSubmitMultipleExpandedEmpty() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $form->submit(array()); @@ -1205,6 +1299,7 @@ public function testSubmitMultipleExpandedEmptyNoChoices() 'multiple' => true, 'expanded' => true, 'choices' => array(), + 'choices_as_values' => true, )); $form->submit(array()); @@ -1219,10 +1314,11 @@ public function testSubmitMultipleExpandedWithEmptyChild() 'multiple' => true, 'expanded' => true, 'choices' => array( - '' => 'Empty', - 1 => 'Not Empty', - 2 => 'Not Empty 2', + 'Empty' => '', + 'Not Empty' => 1, + 'Not Empty 2' => 2, ), + 'choices_as_values' => true, )); $form->submit(array('', '2')); @@ -1302,12 +1398,15 @@ public function testLegacySubmitMultipleExpandedObjectChoices() $this->assertNull($form[4]->getViewData()); } + /** + * @group legacy + */ public function testSubmitMultipleExpandedNumericChoices() { $form = $this->factory->create('choice', null, array( 'multiple' => true, 'expanded' => true, - 'choices' => $this->numericChoices, + 'choices' => $this->numericChoicesFlipped, )); $form->submit(array('1', '2')); @@ -1363,16 +1462,18 @@ public function testMultipleSelectedObjectChoices() $this->assertFalse($selectedChecker($view->vars['choices'][1]->value, $view->vars['value'])); } - /* + /** * We need this functionality to create choice fields for Boolean types, - * e.g. false => 'No', true => 'Yes' + * e.g. false => 'No', true => 'Yes'. + * + * @group legacy */ public function testSetDataSingleNonExpandedAcceptsBoolean() { $form = $this->factory->create('choice', null, array( 'multiple' => false, 'expanded' => false, - 'choices' => $this->numericChoices, + 'choices' => $this->numericChoicesFlipped, )); $form->setData(false); @@ -1382,12 +1483,15 @@ public function testSetDataSingleNonExpandedAcceptsBoolean() $this->assertTrue($form->isSynchronized()); } + /** + * @group legacy + */ public function testSetDataMultipleNonExpandedAcceptsBoolean() { $form = $this->factory->create('choice', null, array( 'multiple' => true, 'expanded' => false, - 'choices' => $this->numericChoices, + 'choices' => $this->numericChoicesFlipped, )); $form->setData(array(false, true)); @@ -1401,6 +1505,7 @@ public function testPassRequiredToView() { $form = $this->factory->create('choice', null, array( 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1412,6 +1517,7 @@ public function testPassNonRequiredToView() $form = $this->factory->create('choice', null, array( 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1423,6 +1529,7 @@ public function testPassMultipleToView() $form = $this->factory->create('choice', null, array( 'multiple' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1434,6 +1541,7 @@ public function testPassExpandedToView() $form = $this->factory->create('choice', null, array( 'expanded' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1444,6 +1552,7 @@ public function testPassChoiceTranslationDomainToView() { $form = $this->factory->create('choice', null, array( 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1454,6 +1563,7 @@ public function testChoiceTranslationDomainWithTrueValueToView() { $form = $this->factory->create('choice', null, array( 'choices' => $this->choices, + 'choices_as_values' => true, 'choice_translation_domain' => true, )); $view = $form->createView(); @@ -1465,6 +1575,7 @@ public function testDefaultChoiceTranslationDomainIsSameAsTranslationDomainToVie { $form = $this->factory->create('choice', null, array( 'choices' => $this->choices, + 'choices_as_values' => true, 'translation_domain' => 'foo', )); $view = $form->createView(); @@ -1491,6 +1602,7 @@ public function testPlaceholderIsNullByDefaultIfRequired() 'multiple' => false, 'required' => true, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1503,6 +1615,7 @@ public function testPlaceholderIsEmptyStringByDefaultIfNotRequired() 'multiple' => false, 'required' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1520,6 +1633,7 @@ public function testPassPlaceholderToView($multiple, $expanded, $required, $plac 'required' => $required, 'placeholder' => $placeholder, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1539,6 +1653,7 @@ public function testPassEmptyValueBC($multiple, $expanded, $required, $placehold 'required' => $required, 'empty_value' => $placeholder, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1558,7 +1673,8 @@ public function testDontPassPlaceholderIfContainedInChoices($multiple, $expanded 'expanded' => $expanded, 'required' => $required, 'placeholder' => $placeholder, - 'choices' => array('a' => 'A', '' => 'Empty'), + 'choices' => array('A' => 'a', 'Empty' => ''), + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1612,9 +1728,10 @@ public function getOptionsWithPlaceholder() public function testPassChoicesToView() { - $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'); + $choices = array('A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd'); $form = $this->factory->create('choice', null, array( 'choices' => $choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1628,9 +1745,10 @@ public function testPassChoicesToView() public function testPassPreferredChoicesToView() { - $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'); + $choices = array('A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd'); $form = $this->factory->create('choice', null, array( 'choices' => $choices, + 'choices_as_values' => true, 'preferred_choices' => array('b', 'd'), )); $view = $form->createView(); @@ -1649,6 +1767,7 @@ public function testPassHierarchicalChoicesToView() { $form = $this->factory->create('choice', null, array( 'choices' => $this->groupedChoices, + 'choices_as_values' => true, 'preferred_choices' => array('b', 'd'), )); $view = $form->createView(); @@ -1700,6 +1819,7 @@ public function testAdjustFullNameForMultipleNonExpanded() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, + 'choices_as_values' => true, )); $view = $form->createView(); @@ -1711,6 +1831,7 @@ public function testInitializeWithEmptyChoices() { $this->factory->createNamed('name', 'choice', null, array( 'choices' => array(), + 'choices_as_values' => true, )); } From f4f082ee6daafe2fcafcc4d4a25af8aeca1a3df4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 27 Nov 2015 11:11:22 +0100 Subject: [PATCH 086/136] [HttpFoundation] Deprecate $deep parameter on ParameterBag --- .../Component/HttpFoundation/ParameterBag.php | 25 +++++++++++++++---- .../Component/HttpFoundation/Request.php | 2 +- .../HttpFoundation/Tests/ParameterBagTest.php | 14 +++++------ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/ParameterBag.php b/src/Symfony/Component/HttpFoundation/ParameterBag.php index 35b4869533e46..4560322671470 100644 --- a/src/Symfony/Component/HttpFoundation/ParameterBag.php +++ b/src/Symfony/Component/HttpFoundation/ParameterBag.php @@ -90,7 +90,7 @@ public function add(array $parameters = array()) */ public function get($key, $default = null, $deep = false) { - if (true === $deep) { + if ($deep) { @trigger_error('Using paths to find deeper items in '.__METHOD__.' is deprecated since version 2.8 and will be removed in 3.0. Filter the returned value in your own code instead.', E_USER_DEPRECATED); } @@ -214,7 +214,7 @@ public function getAlnum($key, $default = '', $deep = false) public function getDigits($key, $default = '', $deep = false) { // we need to remove - and + because they're allowed in the filter - return str_replace(array('-', '+'), '', $this->filter($key, $default, $deep, FILTER_SANITIZE_NUMBER_INT)); + return str_replace(array('-', '+'), '', $this->filter($key, $default, FILTER_SANITIZE_NUMBER_INT, array(), $deep)); } /** @@ -242,7 +242,7 @@ public function getInt($key, $default = 0, $deep = false) */ public function getBoolean($key, $default = false, $deep = false) { - return $this->filter($key, $default, $deep, FILTER_VALIDATE_BOOLEAN); + return $this->filter($key, $default, FILTER_VALIDATE_BOOLEAN, array(), $deep); } /** @@ -250,16 +250,31 @@ public function getBoolean($key, $default = false, $deep = false) * * @param string $key Key. * @param mixed $default Default = null. - * @param bool $deep Default = false. * @param int $filter FILTER_* constant. * @param mixed $options Filter options. + * @param bool $deep Default = false. * * @see http://php.net/manual/en/function.filter-var.php * * @return mixed */ - public function filter($key, $default = null, $deep = false, $filter = FILTER_DEFAULT, $options = array()) + public function filter($key, $default = null, $filter = FILTER_DEFAULT, $options = array(), $deep = false) { + static $filters = null; + + if (null === $filters) { + foreach (filter_list() as $tmp) { + $filters[filter_id($tmp)] = 1; + } + } + if (is_bool($filter) || !isset($filters[$filter]) || is_array($deep)) { + @trigger_error('Passing the $deep boolean as 3rd argument to the '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0. Remove it altogether as the $deep argument will be removed in 3.0.', E_USER_ERROR); + $tmp = $deep; + $deep = $filter; + $filter = $options; + $options = $tmp; + } + $value = $this->get($key, $default, $deep); // Always turn $options into an array - this allows filter_var option shortcuts. diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index edc77df10d6de..de36953cecef5 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -724,7 +724,7 @@ public static function getHttpMethodParameterOverride() */ public function get($key, $default = null, $deep = false) { - if (true === $deep) { + if ($deep) { @trigger_error('Using paths to find deeper items in '.__METHOD__.' is deprecated since version 2.8 and will be removed in 3.0. Filter the returned value in your own code instead.', E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/ParameterBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ParameterBagTest.php index d797fb3bbd27b..06a6cbf413c8f 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ParameterBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ParameterBagTest.php @@ -172,26 +172,26 @@ public function testFilter() $this->assertEmpty($bag->filter('nokey'), '->filter() should return empty by default if no key is found'); - $this->assertEquals('0123', $bag->filter('digits', '', false, FILTER_SANITIZE_NUMBER_INT), '->filter() gets a value of parameter as integer filtering out invalid characters'); + $this->assertEquals('0123', $bag->filter('digits', '', FILTER_SANITIZE_NUMBER_INT), '->filter() gets a value of parameter as integer filtering out invalid characters'); - $this->assertEquals('example@example.com', $bag->filter('email', '', false, FILTER_VALIDATE_EMAIL), '->filter() gets a value of parameter as email'); + $this->assertEquals('example@example.com', $bag->filter('email', '', FILTER_VALIDATE_EMAIL), '->filter() gets a value of parameter as email'); - $this->assertEquals('http://example.com/foo', $bag->filter('url', '', false, FILTER_VALIDATE_URL, array('flags' => FILTER_FLAG_PATH_REQUIRED)), '->filter() gets a value of parameter as URL with a path'); + $this->assertEquals('http://example.com/foo', $bag->filter('url', '', FILTER_VALIDATE_URL, array('flags' => FILTER_FLAG_PATH_REQUIRED)), '->filter() gets a value of parameter as URL with a path'); // This test is repeated for code-coverage - $this->assertEquals('http://example.com/foo', $bag->filter('url', '', false, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED), '->filter() gets a value of parameter as URL with a path'); + $this->assertEquals('http://example.com/foo', $bag->filter('url', '', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED), '->filter() gets a value of parameter as URL with a path'); - $this->assertFalse($bag->filter('dec', '', false, FILTER_VALIDATE_INT, array( + $this->assertFalse($bag->filter('dec', '', FILTER_VALIDATE_INT, array( 'flags' => FILTER_FLAG_ALLOW_HEX, 'options' => array('min_range' => 1, 'max_range' => 0xff), )), '->filter() gets a value of parameter as integer between boundaries'); - $this->assertFalse($bag->filter('hex', '', false, FILTER_VALIDATE_INT, array( + $this->assertFalse($bag->filter('hex', '', FILTER_VALIDATE_INT, array( 'flags' => FILTER_FLAG_ALLOW_HEX, 'options' => array('min_range' => 1, 'max_range' => 0xff), )), '->filter() gets a value of parameter as integer between boundaries'); - $this->assertEquals(array('bang'), $bag->filter('array', '', false), '->filter() gets a value of parameter as an array'); + $this->assertEquals(array('bang'), $bag->filter('array', ''), '->filter() gets a value of parameter as an array'); } public function testGetIterator() From 62eba7c426ac0db6bde810a090410eab4bd2292e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 27 Nov 2015 10:24:30 +0100 Subject: [PATCH 087/136] [Form+SecurityBundle] Trigger deprecation for csrf_provider+intention options --- .../DependencyInjection/MainConfiguration.php | 4 ++++ .../Security/Factory/FormLoginFactory.php | 19 +++++++++++++++-- .../MainConfigurationTest.php | 4 ++-- .../Functional/app/CsrfFormLogin/config.yml | 4 ++-- .../Csrf/Type/FormTypeCsrfExtension.php | 21 +++++++++++++++++-- 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index c07794b6b4727..c85c3df907c38 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -242,6 +242,8 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->beforeNormalization() ->ifTrue(function ($v) { return isset($v['csrf_provider']); }) ->then(function ($v) { + @trigger_error("Setting the 'csrf_provider' configuration key on a security firewall is deprecated since version 2.8 and will be removed in 3.0. Use the 'csrf_token_generator' configuration key instead.", E_USER_DEPRECATED); + $v['csrf_token_generator'] = $v['csrf_provider']; unset($v['csrf_provider']); @@ -251,6 +253,8 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->beforeNormalization() ->ifTrue(function ($v) { return isset($v['intention']); }) ->then(function ($v) { + @trigger_error("Setting the 'intention' configuration key on a security firewall is deprecated since version 2.8 and will be removed in 3.0. Use the 'csrf_token_id' key instead.", E_USER_DEPRECATED); + $v['csrf_token_id'] = $v['intention']; unset($v['intention']); diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php index ac9523c507208..c3a19e3f7edf4 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php @@ -48,8 +48,23 @@ public function addConfiguration(NodeDefinition $node) parent::addConfiguration($node); $node + ->beforeNormalization() + ->ifTrue(function ($v) { return isset($v['csrf_provider']) && isset($v['csrf_token_generator']); }) + ->thenInvalid("You should define a value for only one of 'csrf_provider' and 'csrf_token_generator' on a security firewall. Use 'csrf_token_generator' as this replaces 'csrf_provider'.") + ->end() + ->beforeNormalization() + ->ifTrue(function ($v) { return isset($v['csrf_provider']); }) + ->then(function ($v) { + @trigger_error("Setting the 'csrf_provider' configuration key on a security firewall is deprecated since version 2.8 and will be removed in 3.0. Use the 'csrf_token_generator' configuration key instead.", E_USER_DEPRECATED); + + $v['csrf_token_generator'] = $v['csrf_provider']; + unset($v['csrf_provider']); + + return $v; + }) + ->end() ->children() - ->scalarNode('csrf_provider')->cannotBeEmpty()->end() + ->scalarNode('csrf_token_generator')->cannotBeEmpty()->end() ->end() ; } @@ -78,7 +93,7 @@ protected function createListener($container, $id, $config, $userProvider) $container ->getDefinition($listenerId) - ->addArgument(isset($config['csrf_provider']) ? new Reference($config['csrf_provider']) : null) + ->addArgument(isset($config['csrf_token_generator']) ? new Reference($config['csrf_token_generator']) : null) ; return $listenerId; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php index 9d8009ea8a9e0..990632f2b683d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php @@ -74,8 +74,8 @@ public function testCsrfAliases() 'firewalls' => array( 'stub' => array( 'logout' => array( - 'csrf_provider' => 'a_token_generator', - 'intention' => 'a_token_id', + 'csrf_token_generator' => 'a_token_generator', + 'csrf_token_id' => 'a_token_id', ), ), ), diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CsrfFormLogin/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CsrfFormLogin/config.yml index ffcc9352d8260..5a00ac329895d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CsrfFormLogin/config.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CsrfFormLogin/config.yml @@ -36,12 +36,12 @@ security: username_parameter: "user_login[username]" password_parameter: "user_login[password]" csrf_parameter: "user_login[_token]" - csrf_provider: security.csrf.token_manager + csrf_token_generator: security.csrf.token_manager anonymous: ~ logout: path: /logout_path target: / - csrf_provider: security.csrf.token_manager + csrf_token_generator: security.csrf.token_manager access_control: - { path: .*, roles: IS_AUTHENTICATED_FULLY } diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php index cf5038ae1f6cd..34a0144f4e8a4 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php +++ b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -123,6 +123,10 @@ public function configureOptions(OptionsResolver $resolver) { // BC clause for the "intention" option $csrfTokenId = function (Options $options) { + if (null !== $options['intention']) { + @trigger_error('The form option "intention" is deprecated since version 2.8 and will be removed in 3.0. Use "csrf_token_id" instead.', E_USER_DEPRECATED); + } + return $options['intention']; }; @@ -137,15 +141,28 @@ public function configureOptions(OptionsResolver $resolver) : new CsrfProviderAdapter($options['csrf_provider']); }; + $defaultTokenManager = $this->defaultTokenManager; + $csrfProviderNormalizer = function (Options $options, $csrfProvider) use ($defaultTokenManager) { + if (null !== $csrfProvider) { + @trigger_error('The form option "csrf_provider" is deprecated since version 2.8 and will be removed in 3.0. Use "csrf_token_manager" instead.', E_USER_DEPRECATED); + + return $csrfProvider; + } + + return $defaultTokenManager; + }; + $resolver->setDefaults(array( 'csrf_protection' => $this->defaultEnabled, 'csrf_field_name' => $this->defaultFieldName, 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.', 'csrf_token_manager' => $csrfTokenManager, 'csrf_token_id' => $csrfTokenId, - 'csrf_provider' => $this->defaultTokenManager, - 'intention' => null, + 'csrf_provider' => null, // deprecated + 'intention' => null, // deprecated )); + + $resolver->setNormalizer('csrf_provider', $csrfProviderNormalizer); } /** From 42a75bc224d8ab375534410a85b569402cd2045e Mon Sep 17 00:00:00 2001 From: ogizanagi Date: Fri, 27 Nov 2015 13:30:14 +0100 Subject: [PATCH 088/136] [Process] Remove PHP_BINARY existence check --- src/Symfony/Component/Process/PhpExecutableFinder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Process/PhpExecutableFinder.php b/src/Symfony/Component/Process/PhpExecutableFinder.php index fb297825fe364..db31cc1b3ce8b 100644 --- a/src/Symfony/Component/Process/PhpExecutableFinder.php +++ b/src/Symfony/Component/Process/PhpExecutableFinder.php @@ -44,7 +44,7 @@ public function find($includeArgs = true) } // PHP_BINARY return the current sapi executable - if (defined('PHP_BINARY') && PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server', 'phpdbg')) && is_file(PHP_BINARY)) { + if (PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server', 'phpdbg')) && is_file(PHP_BINARY)) { return PHP_BINARY.$args; } From 2a16e87aecd8482e38235b083a89acf115542bb3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 27 Nov 2015 14:24:26 +0100 Subject: [PATCH 089/136] [Form] Fix missing choices_as_values=true in tests --- .../Tests/AbstractBootstrap3LayoutTest.php | 77 ++++++++++++------- .../Form/Tests/AbstractDivLayoutTest.php | 3 +- .../Form/Tests/AbstractLayoutTest.php | 77 ++++++++++++------- 3 files changed, 104 insertions(+), 53 deletions(-) diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php index 7ee2d5b352723..3bafd0ea24591 100644 --- a/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php @@ -212,7 +212,8 @@ public function testCheckboxWithValue() public function testSingleChoice() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, )); @@ -234,7 +235,8 @@ public function testSingleChoice() public function testSingleChoiceWithoutTranslation() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'choice_translation_domain' => false, @@ -257,7 +259,8 @@ public function testSingleChoiceWithoutTranslation() public function testSingleChoiceAttributes() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => false, 'expanded' => false, @@ -282,7 +285,8 @@ public function testSingleChoiceAttributes() public function testSingleChoiceWithPreferred() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -306,7 +310,8 @@ public function testSingleChoiceWithPreferred() public function testSingleChoiceWithPreferredAndNoSeparator() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -329,7 +334,8 @@ public function testSingleChoiceWithPreferredAndNoSeparator() public function testSingleChoiceWithPreferredAndBlankSeparator() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -353,7 +359,8 @@ public function testSingleChoiceWithPreferredAndBlankSeparator() public function testChoiceWithOnlyPreferred() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'preferred_choices' => array('&a', '&b'), 'multiple' => false, 'expanded' => false, @@ -370,7 +377,8 @@ public function testChoiceWithOnlyPreferred() public function testSingleChoiceNonRequired() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => false, 'multiple' => false, 'expanded' => false, @@ -394,7 +402,8 @@ public function testSingleChoiceNonRequired() public function testSingleChoiceNonRequiredNoneSelected() { $form = $this->factory->createNamed('name', 'choice', null, array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => false, 'multiple' => false, 'expanded' => false, @@ -418,7 +427,8 @@ public function testSingleChoiceNonRequiredNoneSelected() public function testSingleChoiceNonRequiredWithPlaceholder() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'required' => false, @@ -443,7 +453,8 @@ public function testSingleChoiceNonRequiredWithPlaceholder() public function testSingleChoiceRequiredWithPlaceholder() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => true, 'multiple' => false, 'expanded' => false, @@ -468,7 +479,8 @@ public function testSingleChoiceRequiredWithPlaceholder() public function testSingleChoiceRequiredWithPlaceholderViaView() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => true, 'multiple' => false, 'expanded' => false, @@ -493,9 +505,10 @@ public function testSingleChoiceGrouped() { $form = $this->factory->createNamed('name', 'choice', '&a', array( 'choices' => array( - 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), - 'Group&2' => array('&c' => 'Choice&C'), + 'Group&1' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'Group&2' => array('Choice&C' => '&c'), ), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, )); @@ -523,7 +536,8 @@ public function testSingleChoiceGrouped() public function testMultipleChoice() { $form = $this->factory->createNamed('name', 'choice', array('&a'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => true, 'multiple' => true, 'expanded' => false, @@ -547,7 +561,8 @@ public function testMultipleChoice() public function testMultipleChoiceAttributes() { $form = $this->factory->createNamed('name', 'choice', array('&a'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'required' => true, 'multiple' => true, @@ -574,7 +589,8 @@ public function testMultipleChoiceAttributes() public function testMultipleChoiceSkipsPlaceholder() { $form = $this->factory->createNamed('name', 'choice', array('&a'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => true, 'expanded' => false, 'placeholder' => 'Test&Me', @@ -597,7 +613,8 @@ public function testMultipleChoiceSkipsPlaceholder() public function testMultipleChoiceNonRequired() { $form = $this->factory->createNamed('name', 'choice', array('&a'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => false, 'multiple' => true, 'expanded' => false, @@ -620,7 +637,8 @@ public function testMultipleChoiceNonRequired() public function testSingleChoiceExpanded() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, )); @@ -655,7 +673,8 @@ public function testSingleChoiceExpanded() public function testSingleChoiceExpandedWithoutTranslation() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'choice_translation_domain' => false, @@ -691,7 +710,8 @@ public function testSingleChoiceExpandedWithoutTranslation() public function testSingleChoiceExpandedAttributes() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => false, 'expanded' => true, @@ -729,7 +749,8 @@ public function testSingleChoiceExpandedAttributes() public function testSingleChoiceExpandedWithPlaceholder() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'placeholder' => 'Test&Me', @@ -774,7 +795,8 @@ public function testSingleChoiceExpandedWithPlaceholder() public function testSingleChoiceExpandedWithBooleanValue() { $form = $this->factory->createNamed('name', 'choice', true, array( - 'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'), + 'choices' => array('Choice&A' => '1', 'Choice&B' => '0'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, )); @@ -809,7 +831,8 @@ public function testSingleChoiceExpandedWithBooleanValue() public function testMultipleChoiceExpanded() { $form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), + 'choices_as_values' => true, 'multiple' => true, 'expanded' => true, 'required' => true, @@ -854,7 +877,8 @@ public function testMultipleChoiceExpanded() public function testMultipleChoiceExpandedWithoutTranslation() { $form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), + 'choices_as_values' => true, 'multiple' => true, 'expanded' => true, 'required' => true, @@ -900,7 +924,8 @@ public function testMultipleChoiceExpandedWithoutTranslation() public function testMultipleChoiceExpandedAttributes() { $form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), + 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => true, 'expanded' => true, diff --git a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php index 45b2f311c2942..7eeeac0a029cc 100644 --- a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php @@ -692,7 +692,8 @@ public function testCollectionRowWithCustomBlock() public function testChoiceRowWithCustomBlock() { $form = $this->factory->createNamedBuilder('name_c', 'choice', 'a', array( - 'choices' => array('a' => 'ChoiceA', 'b' => 'ChoiceB'), + 'choices' => array('ChoiceA' => 'a', 'ChoiceB' => 'b'), + 'choices_as_values' => true, 'expanded' => true, )) ->getForm(); diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 64ecec9b49dfa..0939a2b003a9c 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -497,7 +497,8 @@ public function testCheckboxWithValue() public function testSingleChoice() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, )); @@ -530,7 +531,8 @@ public function testSingleChoice() public function testSingleChoiceWithoutTranslation() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'choice_translation_domain' => false, @@ -552,7 +554,8 @@ public function testSingleChoiceWithoutTranslation() public function testSingleChoiceAttributes() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => false, 'expanded' => false, @@ -576,7 +579,8 @@ public function testSingleChoiceAttributes() public function testSingleChoiceWithPreferred() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -599,7 +603,8 @@ public function testSingleChoiceWithPreferred() public function testSingleChoiceWithPreferredAndNoSeparator() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -621,7 +626,8 @@ public function testSingleChoiceWithPreferredAndNoSeparator() public function testSingleChoiceWithPreferredAndBlankSeparator() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -644,7 +650,8 @@ public function testSingleChoiceWithPreferredAndBlankSeparator() public function testChoiceWithOnlyPreferred() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'preferred_choices' => array('&a', '&b'), 'multiple' => false, 'expanded' => false, @@ -660,7 +667,8 @@ public function testChoiceWithOnlyPreferred() public function testSingleChoiceNonRequired() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => false, 'multiple' => false, 'expanded' => false, @@ -683,7 +691,8 @@ public function testSingleChoiceNonRequired() public function testSingleChoiceNonRequiredNoneSelected() { $form = $this->factory->createNamed('name', 'choice', null, array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => false, 'multiple' => false, 'expanded' => false, @@ -706,7 +715,8 @@ public function testSingleChoiceNonRequiredNoneSelected() public function testSingleChoiceNonRequiredWithPlaceholder() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'required' => false, @@ -730,7 +740,8 @@ public function testSingleChoiceNonRequiredWithPlaceholder() public function testSingleChoiceRequiredWithPlaceholder() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => true, 'multiple' => false, 'expanded' => false, @@ -757,7 +768,8 @@ public function testSingleChoiceRequiredWithPlaceholder() public function testSingleChoiceRequiredWithPlaceholderViaView() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => true, 'multiple' => false, 'expanded' => false, @@ -784,9 +796,10 @@ public function testSingleChoiceGrouped() { $form = $this->factory->createNamed('name', 'choice', '&a', array( 'choices' => array( - 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), - 'Group&2' => array('&c' => 'Choice&C'), + 'Group&1' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'Group&2' => array('Choice&C' => '&c'), ), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, )); @@ -813,7 +826,8 @@ public function testSingleChoiceGrouped() public function testMultipleChoice() { $form = $this->factory->createNamed('name', 'choice', array('&a'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => true, 'multiple' => true, 'expanded' => false, @@ -836,7 +850,8 @@ public function testMultipleChoice() public function testMultipleChoiceAttributes() { $form = $this->factory->createNamed('name', 'choice', array('&a'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'required' => true, 'multiple' => true, @@ -862,7 +877,8 @@ public function testMultipleChoiceAttributes() public function testMultipleChoiceSkipsPlaceholder() { $form = $this->factory->createNamed('name', 'choice', array('&a'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => true, 'expanded' => false, 'placeholder' => 'Test&Me', @@ -884,7 +900,8 @@ public function testMultipleChoiceSkipsPlaceholder() public function testMultipleChoiceNonRequired() { $form = $this->factory->createNamed('name', 'choice', array('&a'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'required' => false, 'multiple' => true, 'expanded' => false, @@ -906,7 +923,8 @@ public function testMultipleChoiceNonRequired() public function testSingleChoiceExpanded() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, )); @@ -928,7 +946,8 @@ public function testSingleChoiceExpanded() public function testSingleChoiceExpandedWithoutTranslation() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'choice_translation_domain' => false, @@ -951,7 +970,8 @@ public function testSingleChoiceExpandedWithoutTranslation() public function testSingleChoiceExpandedAttributes() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => false, 'expanded' => true, @@ -976,7 +996,8 @@ public function testSingleChoiceExpandedAttributes() public function testSingleChoiceExpandedWithPlaceholder() { $form = $this->factory->createNamed('name', 'choice', '&a', array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'placeholder' => 'Test&Me', @@ -1001,7 +1022,8 @@ public function testSingleChoiceExpandedWithPlaceholder() public function testSingleChoiceExpandedWithBooleanValue() { $form = $this->factory->createNamed('name', 'choice', true, array( - 'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'), + 'choices' => array('Choice&A' => '1', 'Choice&B' => '0'), + 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, )); @@ -1023,7 +1045,8 @@ public function testSingleChoiceExpandedWithBooleanValue() public function testMultipleChoiceExpanded() { $form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), + 'choices_as_values' => true, 'multiple' => true, 'expanded' => true, 'required' => true, @@ -1048,7 +1071,8 @@ public function testMultipleChoiceExpanded() public function testMultipleChoiceExpandedWithoutTranslation() { $form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), + 'choices_as_values' => true, 'multiple' => true, 'expanded' => true, 'required' => true, @@ -1074,7 +1098,8 @@ public function testMultipleChoiceExpandedWithoutTranslation() public function testMultipleChoiceExpandedAttributes() { $form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array( - 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'), + 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), + 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => true, 'expanded' => true, From 1179f0727bfe8425642abda290477098e911b46a Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Thu, 26 Nov 2015 15:25:37 +0100 Subject: [PATCH 090/136] [Form] Fixed: Duplicate choice labels are remembered when using "choices_as_values" = false --- .../Form/Extension/Core/Type/ChoiceType.php | 72 ++++++++++++++++++- .../Extension/Core/Type/ChoiceTypeTest.php | 17 +++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index 528834d1e3cb8..4822bcf68b571 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 = array(); $choiceListFactory = $this->choiceListFactory; $emptyData = function (Options $options) { @@ -252,6 +253,44 @@ 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 = 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 + // Don't invoke count() to avoid creating a copy of the array (yet) + if ($choiceLabels) { + // 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 global reference shared by all + // forms) + return function ($choice, $key) use ($choiceLabels) { + return $choiceLabels[$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 +361,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 +379,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 +494,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 array $choiceLabels The array that receives the choice labels + * indexed by generated keys. + * @param int|null $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. + */ + public static function normalizeLegacyChoices(array &$choices, array &$choiceLabels, &$nextKey = 0) + { + foreach ($choices as $choice => &$choiceLabel) { + if (is_array($choiceLabel)) { + self::normalizeLegacyChoices($choiceLabel, $choiceLabels, $nextKey); + continue; + } + + $choiceLabels[$nextKey] = $choiceLabel; + $choices[$choice] = $nextKey; + ++$nextKey; + } + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index 215ddac936a54..c1c1f9a327cde 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -1694,6 +1694,23 @@ public function testPassChoiceDataToView() ), $view->vars['choices']); } + /** + * @group legacy + */ + public function testDuplicateChoiceLabels() + { + $form = $this->factory->create('choice', null, array( + 'choices' => array('a' => 'A', 'b' => 'B', 'c' => 'A'), + )); + $view = $form->createView(); + + $this->assertEquals(array( + new ChoiceView('a', 'a', 'A'), + new ChoiceView('b', 'b', 'B'), + new ChoiceView('c', 'c', 'A'), + ), $view->vars['choices']); + } + public function testAdjustFullNameForMultipleNonExpanded() { $form = $this->factory->createNamed('name', 'choice', null, array( From 5a88fb619fec8bbe7778f8e8b80c45d1de0984cc Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 27 Nov 2015 14:36:40 +0100 Subject: [PATCH 091/136] [Bridge\PhpUnit] Display the stack trace of a deprecation on-demand --- .../PhpUnit/DeprecationErrorHandler.php | 35 +++++++++++++++---- src/Symfony/Bridge/PhpUnit/README.md | 9 ++++- .../Form/ChoiceList/ArrayKeyChoiceList.php | 2 ++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index 063723d32db29..81f59beeccde2 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -47,16 +47,37 @@ public static function register($mode = false) // No-op } - if (0 !== error_reporting()) { - $group = 'unsilenced'; - $ref = &$deprecations[$group][$msg]['count']; - ++$ref; - } elseif (isset($trace[$i]['object']) || isset($trace[$i]['class'])) { + if (isset($trace[$i]['object']) || isset($trace[$i]['class'])) { $class = isset($trace[$i]['object']) ? get_class($trace[$i]['object']) : $trace[$i]['class']; $method = $trace[$i]['function']; - $group = 0 === strpos($method, 'testLegacy') || 0 === strpos($method, 'provideLegacy') || 0 === strpos($method, 'getLegacy') || strpos($class, '\Legacy') || in_array('legacy', \PHPUnit_Util_Test::getGroups($class, $method), true) ? 'legacy' : 'remaining'; + if (0 !== error_reporting()) { + $group = 'unsilenced'; + } elseif (0 === strpos($method, 'testLegacy') + || 0 === strpos($method, 'provideLegacy') + || 0 === strpos($method, 'getLegacy') + || strpos($class, '\Legacy') + || in_array('legacy', \PHPUnit_Util_Test::getGroups($class, $method), true) + ) { + $group = 'legacy'; + } else { + $group = 'remaining'; + } + + if (isset($mode[0]) && '/' === $mode[0] && preg_match($mode, $class.'::'.$method)) { + $e = new \Exception($msg); + $r = new \ReflectionProperty($e, 'trace'); + $r->setAccessible(true); + $r->setValue($e, array_slice($trace, 1, $i)); + echo "\n".ucfirst($group).' deprecation triggered by '.$class.'::'.$method.':'; + echo "\n".$msg; + echo "\nStack trace:"; + echo "\n".str_replace(' '.getcwd().DIRECTORY_SEPARATOR, ' ', $e->getTraceAsString()); + echo "\n"; + + exit(1); + } if ('legacy' !== $group && 'weak' !== $mode) { $ref = &$deprecations[$group][$msg]['count']; ++$ref; @@ -78,7 +99,7 @@ public static function register($mode = false) restore_error_handler(); self::register($mode); } - } else { + } elseif (!isset($mode[0]) || '/' !== $mode[0]) { self::$isRegistered = true; if (self::hasColorSupport()) { $colorize = function ($str, $red) { diff --git a/src/Symfony/Bridge/PhpUnit/README.md b/src/Symfony/Bridge/PhpUnit/README.md index 7b3a7ef67762c..229e802be43cf 100644 --- a/src/Symfony/Bridge/PhpUnit/README.md +++ b/src/Symfony/Bridge/PhpUnit/README.md @@ -8,7 +8,8 @@ It comes with the following features: * disable the garbage collector; * enforce a consistent `C` locale; * auto-register `class_exists` to load Doctrine annotations; - * print a user deprecation notices summary at the end of the test suite. + * print a user deprecation notices summary at the end of the test suite; + * display the stack trace of a deprecation on-demand. By default any non-legacy-tagged or any non-@-silenced deprecation notices will make tests fail. @@ -51,3 +52,9 @@ You have to decide either to: * update your code to not use deprecated interfaces anymore, thus gaining better forward compatibility; * or move them to the **Legacy** section (by using one of the above way). + +In you need to inspect the stack trace of a particular deprecation triggered by +one of your unit tests, you can set the `SYMFONY_DEPRECATIONS_HELPER` env var to +a regexp that matches this test case's `class::method` name. For example, +`SYMFONY_DEPRECATIONS_HELPER=/^MyTest::testMethod$/ phpunit` will stop your test +suite once a deprecation is triggered by the `MyTest::testMethod` test. diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php index fa2e3973f5867..e2e68f16f2db2 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php @@ -41,6 +41,8 @@ * ``` * * @author Bernhard Schussek + * + * @deprecated since version 2.8, to be removed in 3.0. Use ArrayChoiceList instead. */ class ArrayKeyChoiceList extends ArrayChoiceList { From 273ed2557362b157d303f5d4cb49a440a76c5fe6 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 25 Nov 2015 13:40:04 +0100 Subject: [PATCH 092/136] [Yaml] more fixes to changelog and upgrade files --- UPGRADE-2.8.md | 16 ++++++++++++++-- UPGRADE-3.0.md | 17 +++++++++++++++-- src/Symfony/Component/Yaml/CHANGELOG.md | 16 ++++++++++++++-- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index 67e1c0e66f18a..651c637155972 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -511,5 +511,17 @@ Yaml * Deprecated usage of a colon in an unquoted mapping value * Deprecated usage of `@`, `` ` ``, `|`, and `>` at the beginning of an unquoted string - * Deprecated non-escaped \ in double-quoted strings when parsing Yaml - ("Foo\Var" is not valid whereas "Foo\\Var" is) + * When surrounding strings with double-quotes, you must now escape `\` characters. Not + escaping those characters (when surrounded by double-quotes) is deprecated. + + Before: + + ```yml + class: "Foo\Var" + ``` + + After: + + ```yml + class: "Foo\\Var" + ``` diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 5b86950fc694d..14992c149f427 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -1230,8 +1230,21 @@ UPGRADE FROM 2.x to 3.0 * Using a colon in an unquoted mapping value leads to a `ParseException`. * Starting an unquoted string with `@`, `` ` ``, `|`, or `>` leads to a `ParseException`. - * Deprecated non-escaped \ in double-quoted strings when parsing Yaml - ("Foo\Var" is not valid whereas "Foo\\Var" is) + * When surrounding strings with double-quotes, you must now escape `\` characters. Not + escaping those characters (when surrounded by double-quotes) leads to a `ParseException`. + + Before: + + ```yml + class: "Foo\Var" + ``` + + After: + + ```yml + class: "Foo\\Var" + ``` + * The ability to pass file names to `Yaml::parse()` has been removed. diff --git a/src/Symfony/Component/Yaml/CHANGELOG.md b/src/Symfony/Component/Yaml/CHANGELOG.md index ccfdb1a792c61..f55b57047ebef 100644 --- a/src/Symfony/Component/Yaml/CHANGELOG.md +++ b/src/Symfony/Component/Yaml/CHANGELOG.md @@ -6,8 +6,20 @@ CHANGELOG * Deprecated usage of a colon in an unquoted mapping value * Deprecated usage of @, \`, | and > at the beginning of an unquoted string - * Deprecated non-escaped \ in double-quoted strings when parsing Yaml - ("Foo\Var" is not valid whereas "Foo\\Var" is) + * When surrounding strings with double-quotes, you must now escape `\` characters. Not + escaping those characters (when surrounded by double-quotes) is deprecated. + + Before: + + ```yml + class: "Foo\Var" + ``` + + After: + + ```yml + class: "Foo\\Var" + ``` 2.1.0 ----- From 1cec08b844d818ae2dead2b09ec74bcf47c9608c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 27 Nov 2015 23:51:43 +0100 Subject: [PATCH 093/136] [PhpUnitBridge] fix typo --- src/Symfony/Bridge/PhpUnit/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/README.md b/src/Symfony/Bridge/PhpUnit/README.md index 229e802be43cf..9d7ca89838c6e 100644 --- a/src/Symfony/Bridge/PhpUnit/README.md +++ b/src/Symfony/Bridge/PhpUnit/README.md @@ -53,7 +53,7 @@ You have to decide either to: forward compatibility; * or move them to the **Legacy** section (by using one of the above way). -In you need to inspect the stack trace of a particular deprecation triggered by +In case you need to inspect the stack trace of a particular deprecation triggered by one of your unit tests, you can set the `SYMFONY_DEPRECATIONS_HELPER` env var to a regexp that matches this test case's `class::method` name. For example, `SYMFONY_DEPRECATIONS_HELPER=/^MyTest::testMethod$/ phpunit` will stop your test From 444b6eff0a5a8a80d260324ca9eff146750db407 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 28 Nov 2015 00:24:42 +0100 Subject: [PATCH 094/136] test legacy CSRF configuration options --- .../MainConfigurationTest.php | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php index 990632f2b683d..915c2326ca594 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php @@ -91,6 +91,32 @@ public function testCsrfAliases() $this->assertEquals('a_token_id', $processedConfig['firewalls']['stub']['logout']['csrf_token_id']); } + /** + * @group legacy + */ + public function testLegacyCsrfAliases() + { + $config = array( + 'firewalls' => array( + 'stub' => array( + 'logout' => array( + 'csrf_provider' => 'a_token_generator', + 'intention' => 'a_token_id', + ), + ), + ), + ); + $config = array_merge(static::$minimalConfig, $config); + + $processor = new Processor(); + $configuration = new MainConfiguration(array(), array()); + $processedConfig = $processor->processConfiguration($configuration, array($config)); + $this->assertTrue(isset($processedConfig['firewalls']['stub']['logout']['csrf_token_generator'])); + $this->assertEquals('a_token_generator', $processedConfig['firewalls']['stub']['logout']['csrf_token_generator']); + $this->assertTrue(isset($processedConfig['firewalls']['stub']['logout']['csrf_token_id'])); + $this->assertEquals('a_token_id', $processedConfig['firewalls']['stub']['logout']['csrf_token_id']); + } + /** * @expectedException \InvalidArgumentException */ From 59b782a200e9cd03082a931dd00e45d01cd0e444 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 28 Nov 2015 10:05:13 +0100 Subject: [PATCH 095/136] [ci] Force update of ./phpunit deps --- phpunit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit b/phpunit index 3a3b3dd881ef4..78710c12744ce 100755 --- a/phpunit +++ b/phpunit @@ -11,7 +11,7 @@ */ // 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; From 5bc34d2d51d5803fb92592bae463d4a54d3f9a3d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 26 Nov 2015 19:00:33 +0100 Subject: [PATCH 096/136] [Form] Drop remaing CsrfProviderAdapter/Interface mentions --- .../Bridge/Twig/Extension/FormExtension.php | 10 ++-- .../Templating/Helper/FormHelper.php | 8 ++-- .../Security/Factory/FormLoginFactory.php | 2 +- .../DependencyInjection/SecurityExtension.php | 2 +- .../MainConfigurationTest.php | 48 ------------------- .../Form/UserLoginType.php | 4 +- .../Form/Extension/Csrf/CsrfExtension.php | 11 +---- .../EventListener/CsrfValidationListener.php | 11 +---- .../Csrf/Type/FormTypeCsrfExtension.php | 39 +-------------- .../Templating/TemplatingExtension.php | 11 +---- src/Symfony/Component/Form/FormRenderer.php | 13 +---- .../Security/Http/Firewall/LogoutListener.php | 15 ++---- .../SimpleFormAuthenticationListener.php | 16 ++----- ...namePasswordFormAuthenticationListener.php | 15 ++---- .../Http/Logout/LogoutUrlGenerator.php | 10 +--- .../Tests/Firewall/LogoutListenerTest.php | 2 +- 16 files changed, 28 insertions(+), 189 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/FormExtension.php b/src/Symfony/Bridge/Twig/Extension/FormExtension.php index d6ee8349e15d1..dab1a6a35ad05 100644 --- a/src/Symfony/Bridge/Twig/Extension/FormExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/FormExtension.php @@ -94,15 +94,11 @@ public function getTests() } /** - * Renders a CSRF token. - * - * @param string $intention The intention of the protected action. - * - * @return string A CSRF token. + * {@inheritdoc} */ - public function renderCsrfToken($intention) + public function renderCsrfToken($tokenId) { - return $this->renderer->renderCsrfToken($intention); + return $this->renderer->renderCsrfToken($tokenId); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php index 2bd2336ee5919..067bca3511303 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php @@ -223,7 +223,7 @@ public function block(FormView $view, $blockName, array $variables = array()) * echo $view['form']->csrfToken('rm_user_'.$user->getId()); * * - * Check the token in your action using the same intention. + * Check the token in your action using the same CSRF token id. * * * $csrfProvider = $this->get('security.csrf.token_generator'); @@ -232,15 +232,15 @@ public function block(FormView $view, $blockName, array $variables = array()) * } * * - * @param string $intention The intention of the protected action + * @param string $tokenId The CSRF token id of the protected action * * @return string A CSRF token * * @throws \BadMethodCallException When no CSRF provider was injected in the constructor. */ - public function csrfToken($intention) + public function csrfToken($tokenId) { - return $this->renderer->renderCsrfToken($intention); + return $this->renderer->renderCsrfToken($tokenId); } public function humanize($text) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php index c3a19e3f7edf4..aa81aa8b92f63 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php @@ -29,7 +29,7 @@ public function __construct() $this->addOption('username_parameter', '_username'); $this->addOption('password_parameter', '_password'); $this->addOption('csrf_parameter', '_csrf_token'); - $this->addOption('intention', 'authenticate'); + $this->addOption('csrf_token_id', 'authenticate'); $this->addOption('post_only', true); } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 323fcfe6b385a..964a315428d1c 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -303,7 +303,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.logout_listener')); $listener->replaceArgument(3, array( 'csrf_parameter' => $firewall['logout']['csrf_parameter'], - 'intention' => $firewall['logout']['csrf_token_id'], + 'csrf_token_id' => $firewall['logout']['csrf_token_id'], 'logout_path' => $firewall['logout']['path'], )); $listeners[] = new Reference($listenerId); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php index 915c2326ca594..8a8f5c8329dea 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php @@ -91,54 +91,6 @@ public function testCsrfAliases() $this->assertEquals('a_token_id', $processedConfig['firewalls']['stub']['logout']['csrf_token_id']); } - /** - * @group legacy - */ - public function testLegacyCsrfAliases() - { - $config = array( - 'firewalls' => array( - 'stub' => array( - 'logout' => array( - 'csrf_provider' => 'a_token_generator', - 'intention' => 'a_token_id', - ), - ), - ), - ); - $config = array_merge(static::$minimalConfig, $config); - - $processor = new Processor(); - $configuration = new MainConfiguration(array(), array()); - $processedConfig = $processor->processConfiguration($configuration, array($config)); - $this->assertTrue(isset($processedConfig['firewalls']['stub']['logout']['csrf_token_generator'])); - $this->assertEquals('a_token_generator', $processedConfig['firewalls']['stub']['logout']['csrf_token_generator']); - $this->assertTrue(isset($processedConfig['firewalls']['stub']['logout']['csrf_token_id'])); - $this->assertEquals('a_token_id', $processedConfig['firewalls']['stub']['logout']['csrf_token_id']); - } - - /** - * @expectedException \InvalidArgumentException - */ - public function testCsrfOriginalAndAliasValueCausesException() - { - $config = array( - 'firewalls' => array( - 'stub' => array( - 'logout' => array( - 'csrf_token_id' => 'a_token_id', - 'intention' => 'old_name', - ), - ), - ), - ); - $config = array_merge(static::$minimalConfig, $config); - - $processor = new Processor(); - $configuration = new MainConfiguration(array(), array()); - $processor->processConfiguration($configuration, array($config)); - } - public function testDefaultUserCheckers() { $processor = new Processor(); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/CsrfFormLoginBundle/Form/UserLoginType.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/CsrfFormLoginBundle/Form/UserLoginType.php index aa5305ec528fd..b82e1f827897d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/CsrfFormLoginBundle/Form/UserLoginType.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/CsrfFormLoginBundle/Form/UserLoginType.php @@ -76,12 +76,12 @@ public function buildForm(FormBuilderInterface $builder, array $options) */ public function configureOptions(OptionsResolver $resolver) { - /* Note: the form's intention must correspond to that for the form login + /* Note: the form's csrf_token_id must correspond to that for the form login * listener in order for the CSRF token to validate successfully. */ $resolver->setDefaults(array( - 'intention' => 'authenticate', + 'csrf_token_id' => 'authenticate', )); } } diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php index 0bc8ca7db19d0..7e599ab62b933 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php +++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php @@ -11,9 +11,6 @@ namespace Symfony\Component\Form\Extension\Csrf; -use Symfony\Component\Form\Exception\UnexpectedTypeException; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Form\AbstractExtension; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Translation\TranslatorInterface; @@ -47,14 +44,8 @@ class CsrfExtension extends AbstractExtension * @param TranslatorInterface $translator The translator for translating error messages * @param null|string $translationDomain The translation domain for translating */ - public function __construct($tokenManager, TranslatorInterface $translator = null, $translationDomain = null) + public function __construct(CsrfTokenManagerInterface $tokenManager, TranslatorInterface $translator = null, $translationDomain = null) { - if ($tokenManager instanceof CsrfProviderInterface) { - $tokenManager = new CsrfProviderAdapter($tokenManager); - } elseif (!$tokenManager instanceof CsrfTokenManagerInterface) { - throw new UnexpectedTypeException($tokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface'); - } - $this->tokenManager = $tokenManager; $this->translator = $translator; $this->translationDomain = $translationDomain; diff --git a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php index e96c1c930d5c1..f3c9db0df82b9 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php +++ b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php @@ -12,9 +12,6 @@ namespace Symfony\Component\Form\Extension\Csrf\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Form\Exception\UnexpectedTypeException; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; @@ -75,14 +72,8 @@ public static function getSubscribedEvents() ); } - public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null) + public function __construct($fieldName, CsrfTokenManagerInterface $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null) { - if ($tokenManager instanceof CsrfProviderInterface) { - $tokenManager = new CsrfProviderAdapter($tokenManager); - } elseif (!$tokenManager instanceof CsrfTokenManagerInterface) { - throw new UnexpectedTypeException($tokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface'); - } - $this->fieldName = $fieldName; $this->tokenManager = $tokenManager; $this->tokenId = $tokenId; diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php index 34a0144f4e8a4..a00bae6c6f228 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php +++ b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -12,10 +12,6 @@ namespace Symfony\Component\Form\Extension\Csrf\Type; use Symfony\Component\Form\AbstractTypeExtension; -use Symfony\Component\Form\Exception\UnexpectedTypeException; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfTokenManagerAdapter; use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormView; @@ -55,14 +51,8 @@ class FormTypeCsrfExtension extends AbstractTypeExtension */ private $translationDomain; - public function __construct($defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null) + public function __construct(CsrfTokenManagerInterface $defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null) { - if ($defaultTokenManager instanceof CsrfProviderInterface) { - $defaultTokenManager = new CsrfProviderAdapter($defaultTokenManager); - } elseif (!$defaultTokenManager instanceof CsrfTokenManagerInterface) { - throw new UnexpectedTypeException($defaultTokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface'); - } - $this->defaultTokenManager = $defaultTokenManager; $this->defaultEnabled = $defaultEnabled; $this->defaultFieldName = $defaultFieldName; @@ -130,39 +120,14 @@ public function configureOptions(OptionsResolver $resolver) return $options['intention']; }; - // BC clause for the "csrf_provider" option - $csrfTokenManager = function (Options $options) { - if ($options['csrf_provider'] instanceof CsrfTokenManagerInterface) { - return $options['csrf_provider']; - } - - return $options['csrf_provider'] instanceof CsrfTokenManagerAdapter - ? $options['csrf_provider']->getTokenManager(false) - : new CsrfProviderAdapter($options['csrf_provider']); - }; - - $defaultTokenManager = $this->defaultTokenManager; - $csrfProviderNormalizer = function (Options $options, $csrfProvider) use ($defaultTokenManager) { - if (null !== $csrfProvider) { - @trigger_error('The form option "csrf_provider" is deprecated since version 2.8 and will be removed in 3.0. Use "csrf_token_manager" instead.', E_USER_DEPRECATED); - - return $csrfProvider; - } - - return $defaultTokenManager; - }; - $resolver->setDefaults(array( 'csrf_protection' => $this->defaultEnabled, 'csrf_field_name' => $this->defaultFieldName, 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.', - 'csrf_token_manager' => $csrfTokenManager, + 'csrf_token_manager' => $this->defaultTokenManager, 'csrf_token_id' => $csrfTokenId, - 'csrf_provider' => null, // deprecated 'intention' => null, // deprecated )); - - $resolver->setNormalizer('csrf_provider', $csrfProviderNormalizer); } /** diff --git a/src/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php b/src/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php index 3c29bef5742af..6d47d73167c80 100644 --- a/src/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php +++ b/src/Symfony/Component/Form/Extension/Templating/TemplatingExtension.php @@ -12,9 +12,6 @@ namespace Symfony\Component\Form\Extension\Templating; use Symfony\Component\Form\AbstractExtension; -use Symfony\Component\Form\Exception\UnexpectedTypeException; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Form\FormRenderer; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Templating\PhpEngine; @@ -27,14 +24,8 @@ */ class TemplatingExtension extends AbstractExtension { - public function __construct(PhpEngine $engine, $csrfTokenManager = null, array $defaultThemes = array()) + public function __construct(PhpEngine $engine, CsrfTokenManagerInterface $csrfTokenManager = null, array $defaultThemes = array()) { - if ($csrfTokenManager instanceof CsrfProviderInterface) { - $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); - } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { - throw new UnexpectedTypeException($csrfTokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface'); - } - $engine->addHelpers(array( new FormHelper(new FormRenderer(new TemplatingRendererEngine($engine, $defaultThemes), $csrfTokenManager)), )); diff --git a/src/Symfony/Component/Form/FormRenderer.php b/src/Symfony/Component/Form/FormRenderer.php index b286ffdf41b24..5a32c9d4308d5 100644 --- a/src/Symfony/Component/Form/FormRenderer.php +++ b/src/Symfony/Component/Form/FormRenderer.php @@ -13,9 +13,6 @@ use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\BadMethodCallException; -use Symfony\Component\Form\Exception\UnexpectedTypeException; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; /** @@ -57,17 +54,9 @@ class FormRenderer implements FormRendererInterface * * @param FormRendererEngineInterface $engine * @param CsrfTokenManagerInterface|null $csrfTokenManager - * - * @throws UnexpectedTypeException */ - public function __construct(FormRendererEngineInterface $engine, $csrfTokenManager = null) + public function __construct(FormRendererEngineInterface $engine, CsrfTokenManagerInterface $csrfTokenManager = null) { - if ($csrfTokenManager instanceof CsrfProviderInterface) { - $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); - } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { - throw new UnexpectedTypeException($csrfTokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface or null'); - } - $this->engine = $engine; $this->csrfTokenManager = $csrfTokenManager; } diff --git a/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php b/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php index 6211ee0323c71..47583bebf56e5 100644 --- a/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php @@ -11,13 +11,10 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Security\Core\Exception\InvalidArgumentException; use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; @@ -49,19 +46,13 @@ class LogoutListener implements ListenerInterface * @param array $options An array of options to process a logout attempt * @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance */ - public function __construct(TokenStorageInterface $tokenStorage, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), $csrfTokenManager = null) + public function __construct(TokenStorageInterface $tokenStorage, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), CsrfTokenManagerInterface $csrfTokenManager = null) { - if ($csrfTokenManager instanceof CsrfProviderInterface) { - $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); - } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { - throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); - } - $this->tokenStorage = $tokenStorage; $this->httpUtils = $httpUtils; $this->options = array_merge(array( 'csrf_parameter' => '_csrf_token', - 'intention' => 'logout', + 'csrf_token_id' => 'logout', 'logout_path' => '/logout', ), $options); $this->successHandler = $successHandler; @@ -101,7 +92,7 @@ public function handle(GetResponseEvent $event) if (null !== $this->csrfTokenManager) { $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); - if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { + if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { throw new LogoutException('Invalid CSRF token.'); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php index 36f7bb50578d1..76c66bcf249ae 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php @@ -12,10 +12,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Security\Core\Exception\InvalidArgumentException; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; @@ -56,20 +53,13 @@ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener * @param SimpleFormAuthenticatorInterface $simpleAuthenticator A SimpleFormAuthenticatorInterface instance * * @throws \InvalidArgumentException In case no simple authenticator is provided - * @throws InvalidArgumentException In case an invalid CSRF token manager is passed */ - public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $csrfTokenManager = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null) + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null) { if (!$simpleAuthenticator) { throw new \InvalidArgumentException('Missing simple authenticator'); } - if ($csrfTokenManager instanceof CsrfProviderInterface) { - $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); - } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { - throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); - } - $this->simpleAuthenticator = $simpleAuthenticator; $this->csrfTokenManager = $csrfTokenManager; @@ -77,7 +67,7 @@ public function __construct(TokenStorageInterface $tokenStorage, AuthenticationM 'username_parameter' => '_username', 'password_parameter' => '_password', 'csrf_parameter' => '_csrf_token', - 'intention' => 'authenticate', + 'csrf_token_id' => 'authenticate', 'post_only' => true, ), $options); @@ -104,7 +94,7 @@ protected function attemptAuthentication(Request $request) if (null !== $this->csrfTokenManager) { $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); - if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { + if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index d20ab19f62940..c8195ce583cfd 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -11,8 +11,6 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\Request; use Psr\Log\LoggerInterface; use Symfony\Component\Security\Csrf\CsrfToken; @@ -25,7 +23,6 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; -use Symfony\Component\Security\Core\Exception\InvalidArgumentException; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Core\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -40,19 +37,13 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL { private $csrfTokenManager; - public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $csrfTokenManager = null) + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null) { - if ($csrfTokenManager instanceof CsrfProviderInterface) { - $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); - } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { - throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); - } - parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array( 'username_parameter' => '_username', 'password_parameter' => '_password', 'csrf_parameter' => '_csrf_token', - 'intention' => 'authenticate', + 'csrf_token_id' => 'authenticate', 'post_only' => true, ), $options), $logger, $dispatcher); @@ -79,7 +70,7 @@ protected function attemptAuthentication(Request $request) if (null !== $this->csrfTokenManager) { $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); - if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { + if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); } } diff --git a/src/Symfony/Component/Security/Http/Logout/LogoutUrlGenerator.php b/src/Symfony/Component/Security/Http/Logout/LogoutUrlGenerator.php index ff7ea5b775e91..991b1fcc818e2 100644 --- a/src/Symfony/Component/Security/Http/Logout/LogoutUrlGenerator.php +++ b/src/Symfony/Component/Security/Http/Logout/LogoutUrlGenerator.php @@ -11,8 +11,6 @@ namespace Symfony\Component\Security\Http\Logout; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; -use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; @@ -47,14 +45,8 @@ public function __construct(RequestStack $requestStack = null, UrlGeneratorInter * @param string $csrfParameter The CSRF token parameter name * @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance */ - public function registerListener($key, $logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenManager = null) + public function registerListener($key, $logoutPath, $csrfTokenId, $csrfParameter, CsrfTokenManagerInterface $csrfTokenManager = null) { - if ($csrfTokenManager instanceof CsrfProviderInterface) { - $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); - } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { - throw new \InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); - } - $this->listeners[$key] = array($logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenManager); } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php index 15c996e6261a5..367c810f51f39 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php @@ -213,7 +213,7 @@ private function getListener($successHandler = null, $tokenManager = null) $successHandler ?: $this->getSuccessHandler(), $options = array( 'csrf_parameter' => '_csrf_token', - 'intention' => 'logout', + 'csrf_token_id' => 'logout', 'logout_path' => '/logout', 'target_url' => '/', ), From ed0e26a620978f5173bc83bf3cd7ca8f6829c12c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 27 Nov 2015 17:52:10 +0100 Subject: [PATCH 097/136] [Form] Remove choices_as_values option on ChoiceType --- .../Doctrine/Form/Type/DoctrineType.php | 1 - src/Symfony/Bridge/Doctrine/composer.json | 2 +- .../Form/ChoiceList/ArrayKeyChoiceList.php | 190 --------------- .../Factory/CachingFactoryDecorator.php | 29 --- .../Factory/ChoiceListFactoryInterface.php | 22 -- .../Factory/DefaultChoiceListFactory.php | 16 -- .../Factory/PropertyAccessDecorator.php | 19 -- .../Form/Extension/Core/Type/ChoiceType.php | 18 +- .../Form/Extension/Core/Type/CountryType.php | 1 - .../Form/Extension/Core/Type/CurrencyType.php | 1 - .../Form/Extension/Core/Type/DateType.php | 3 - .../Form/Extension/Core/Type/LanguageType.php | 1 - .../Form/Extension/Core/Type/LocaleType.php | 1 - .../Form/Extension/Core/Type/TimeType.php | 3 - .../Form/Extension/Core/Type/TimezoneType.php | 1 - .../Tests/AbstractBootstrap3LayoutTest.php | 27 --- .../Form/Tests/AbstractDivLayoutTest.php | 1 - .../Form/Tests/AbstractLayoutTest.php | 27 --- .../ChoiceList/ArrayKeyChoiceListTest.php | 183 --------------- .../Extension/Core/Type/ChoiceTypeTest.php | 218 ------------------ 20 files changed, 9 insertions(+), 755 deletions(-) delete mode 100644 src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php delete mode 100644 src/Symfony/Component/Form/Tests/ChoiceList/ArrayKeyChoiceListTest.php diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index c6612246804b2..353c18528710f 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -259,7 +259,6 @@ public function configureOptions(OptionsResolver $resolver) 'em' => null, 'query_builder' => null, 'choices' => null, - 'choices_as_values' => true, 'choice_loader' => $choiceLoader, 'choice_label' => array(__CLASS__, 'createChoiceLabel'), 'choice_name' => $choiceName, diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 0e686e1ccee2e..d1443b369858d 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -22,7 +22,7 @@ "require-dev": { "symfony/stopwatch": "~2.8|~3.0", "symfony/dependency-injection": "~2.8|~3.0", - "symfony/form": "~2.8|~3.0", + "symfony/form": "~3.0,>3.0-BETA1", "symfony/http-kernel": "~2.8|~3.0", "symfony/property-access": "~2.8|~3.0", "symfony/property-info": "~2.8|3.0", diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php deleted file mode 100644 index 183b849fe9a8c..0000000000000 --- a/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php +++ /dev/null @@ -1,190 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form\ChoiceList; - -@trigger_error('The '.__NAMESPACE__.'\ArrayKeyChoiceList class is deprecated since version 2.8 and will be removed in 3.0. Use '.__NAMESPACE__.'\ArrayChoiceList instead.', E_USER_DEPRECATED); - -use Symfony\Component\Form\Exception\InvalidArgumentException; - -/** - * A list of choices that can be stored in the keys of a PHP array. - * - * PHP arrays accept only strings and integers as array keys. Other scalar types - * are cast to integers and strings according to the description of - * {@link toArrayKey()}. This implementation applies the same casting rules for - * the choices passed to the constructor and to {@link getValuesForChoices()}. - * - * By default, the choices are cast to strings and used as values. Optionally, - * you may pass custom values. The keys of the value array must match the keys - * of the choice array. - * - * Example: - * - * ```php - * $choices = array('' => 'Don\'t know', 0 => 'No', 1 => 'Yes'); - * $choiceList = new ArrayKeyChoiceList(array_keys($choices)); - * - * $values = $choiceList->getValues() - * // => array('', '0', '1') - * - * $selectedValues = $choiceList->getValuesForChoices(array(true)); - * // => array('1') - * ``` - * - * @author Bernhard Schussek - * - * @deprecated since version 2.8, to be removed in 3.0. Use ArrayChoiceList instead. - */ -class ArrayKeyChoiceList extends ArrayChoiceList -{ - /** - * Whether the choices are used as values. - * - * @var bool - */ - private $useChoicesAsValues = false; - - /** - * Casts the given choice to an array key. - * - * PHP arrays accept only strings and integers as array keys. Integer - * strings such as "42" are automatically cast to integers. The boolean - * values "true" and "false" are cast to the integers 1 and 0. Every other - * scalar value is cast to a string. - * - * @param mixed $choice The choice - * - * @return int|string The choice as PHP array key - * - * @throws InvalidArgumentException If the choice is not scalar - * - * @internal Must not be used outside this class - */ - public static function toArrayKey($choice) - { - if (!is_scalar($choice) && null !== $choice) { - throw new InvalidArgumentException(sprintf( - 'The value of type "%s" cannot be converted to a valid array key.', - gettype($choice) - )); - } - - if (is_bool($choice) || (string) (int) $choice === (string) $choice) { - return (int) $choice; - } - - return (string) $choice; - } - - /** - * Creates a list with the given choices and values. - * - * The given choice array must have the same array keys as the value array. - * Each choice must be castable to an integer/string according to the - * casting rules described in {@link toArrayKey()}. - * - * If no values are given, the choices are cast to strings and used as - * values. - * - * @param array|\Traversable $choices The selectable choices - * @param callable $value The callable for creating the value - * for a choice. If `null` is passed, the - * choices are cast to strings and used - * as values - * - * @throws InvalidArgumentException If the keys of the choices don't match - * the keys of the values or if any of the - * choices is not scalar - */ - public function __construct($choices, callable $value = null) - { - // If no values are given, use the choices as values - // Since the choices are stored in the collection keys, i.e. they are - // strings or integers, we are guaranteed to be able to convert them - // to strings - if (null === $value) { - $value = function ($choice) { - return (string) $choice; - }; - - $this->useChoicesAsValues = true; - } - - parent::__construct($choices, $value); - } - - /** - * {@inheritdoc} - */ - public function getChoicesForValues(array $values) - { - if ($this->useChoicesAsValues) { - $values = array_map('strval', $values); - - // If the values are identical to the choices, so we can just return - // them to improve performance a little bit - return array_map(array(__CLASS__, 'toArrayKey'), array_intersect($values, array_keys($this->choices))); - } - - return parent::getChoicesForValues($values); - } - - /** - * {@inheritdoc} - */ - public function getValuesForChoices(array $choices) - { - $choices = array_map(array(__CLASS__, 'toArrayKey'), $choices); - - if ($this->useChoicesAsValues) { - // If the choices are identical to the values, we can just return - // them to improve performance a little bit - return array_map('strval', array_intersect($choices, $this->choices)); - } - - return parent::getValuesForChoices($choices); - } - - /** - * Flattens and flips an array into the given output variable. - * - * @param array $choices The array to flatten - * @param callable $value The callable for generating choice values - * @param array $choicesByValues The flattened choices indexed by the - * corresponding values - * @param array $keysByValues The original keys indexed by the - * corresponding values - * - * @internal Must not be used by user-land code - */ - protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues) - { - if (null === $choicesByValues) { - $choicesByValues = array(); - $keysByValues = array(); - $structuredValues = array(); - } - - foreach ($choices as $choice => $key) { - if (is_array($key)) { - $this->flatten($key, $value, $choicesByValues, $keysByValues, $structuredValues[$choice]); - - continue; - } - - $choiceValue = (string) call_user_func($value, $choice); - $choicesByValues[$choiceValue] = $choice; - $keysByValues[$choiceValue] = $key; - $structuredValues[$key] = $choiceValue; - } - } -} diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php b/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php index ae7f2375bb896..6580e661d4d66 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php @@ -135,35 +135,6 @@ public function createListFromChoices($choices, $value = null) return $this->lists[$hash]; } - /** - * {@inheritdoc} - * - * @deprecated Added for backwards compatibility in Symfony 2.7, to be - * removed in Symfony 3.0. - */ - public function createListFromFlippedChoices($choices, $value = null, $triggerDeprecationNotice = true) - { - if ($choices instanceof \Traversable) { - $choices = iterator_to_array($choices); - } - - // The value is not validated on purpose. The decorated factory may - // decide which values to accept and which not. - - // We ignore the choice groups for caching. If two choice lists are - // requested with the same choices, but a different grouping, the same - // choice list is returned. - self::flatten($choices, $flatChoices); - - $hash = self::generateHash(array($flatChoices, $value), 'fromFlippedChoices'); - - if (!isset($this->lists[$hash])) { - $this->lists[$hash] = $this->decoratedFactory->createListFromFlippedChoices($choices, $value, $triggerDeprecationNotice); - } - - return $this->lists[$hash]; - } - /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php b/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php index 7933dd91d48d7..1c6f24d6986f8 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php @@ -39,28 +39,6 @@ interface ChoiceListFactoryInterface */ public function createListFromChoices($choices, $value = null); - /** - * Creates a choice list for the given choices. - * - * The choices should be passed in the keys of the choices array. Since the - * choices array will be flipped, the entries of the array must be strings - * or integers. - * - * Optionally, a callable can be passed for generating the choice values. - * The callable receives the choice as first and the array key as the second - * argument. - * - * @param array|\Traversable $choices The choices - * @param null|callable $value The callable generating the choice - * values - * - * @return ChoiceListInterface The choice list - * - * @deprecated Added for backwards compatibility in Symfony 2.7, to be - * removed in Symfony 3.0. - */ - public function createListFromFlippedChoices($choices, $value = null); - /** * Creates a choice list that is loaded with the given loader. * diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php index f49be10c36392..e632c1238c861 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Form\ChoiceList\Factory; -use Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\LazyChoiceList; @@ -35,21 +34,6 @@ public function createListFromChoices($choices, $value = null) return new ArrayChoiceList($choices, $value); } - /** - * {@inheritdoc} - * - * @deprecated Added for backwards compatibility in Symfony 2.7, to be - * removed in Symfony 3.0. - */ - public function createListFromFlippedChoices($choices, $value = null, $triggerDeprecationNotice = true) - { - if ($triggerDeprecationNotice) { - @trigger_error('The '.__METHOD__.' is deprecated since version 2.7 and will be removed in 3.0.', E_USER_DEPRECATED); - } - - return new ArrayKeyChoiceList($choices, $value); - } - /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php index 1b68fd8924284..130cd49f78bd2 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php @@ -104,25 +104,6 @@ public function createListFromChoices($choices, $value = null) return $this->decoratedFactory->createListFromChoices($choices, $value); } - /** - * {@inheritdoc} - * - * @param array|\Traversable $choices The choices - * @param null|callable|string|PropertyPath $value The callable or path for - * generating the choice values - * - * @return ChoiceListInterface The choice list - * - * @deprecated Added for backwards compatibility in Symfony 2.7, to be - * removed in Symfony 3.0. - */ - public function createListFromFlippedChoices($choices, $value = null, $triggerDeprecationNotice = true) - { - // Property paths are not supported here, because array keys can never - // be objects - return $this->decoratedFactory->createListFromFlippedChoices($choices, $value, $triggerDeprecationNotice); - } - /** * {@inheritdoc} * diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index 4d3ad7719595a..6c4cf9ccaae36 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -260,20 +260,19 @@ public function configureOptions(OptionsResolver $resolver) // Harden against NULL values (like in EntityType and ModelType) $choices = null !== $options['choices'] ? $options['choices'] : array(); - // BC when choices are in the keys, not in the values - if (!$options['choices_as_values']) { - return $choiceListFactory->createListFromFlippedChoices($choices, $options['choice_value'], false); - } - return $choiceListFactory->createListFromChoices($choices, $options['choice_value']); }; $choicesAsValuesNormalizer = function (Options $options, $choicesAsValues) { - if (true !== $choicesAsValues) { - @trigger_error('The value "false" for the "choices_as_values" option is deprecated since version 2.8 and will not be supported anymore in 3.0. Set this option to "true" and flip the contents of the "choices" option instead.', E_USER_DEPRECATED); + if (null !== $choicesAsValues) { + if (true !== $choicesAsValues) { + throw new \RuntimeException('The "choices_as_values" option should not be used. Remove it and flip the contents of the "choices" option instead.'); + } + // To be uncommented in 3.1 + //@trigger_error('The "choices_as_values" option is deprecated since version 3.1 and will be removed in 4.0. You should not use it anymore.', E_USER_DEPRECATED); } - return $choicesAsValues; + return true; }; $placeholderNormalizer = function (Options $options, $placeholder) { @@ -309,7 +308,7 @@ public function configureOptions(OptionsResolver $resolver) 'expanded' => false, 'choice_list' => null, // deprecated 'choices' => array(), - 'choices_as_values' => false, + 'choices_as_values' => null, // to be deprecated in 3.1 'choice_loader' => null, 'choice_label' => null, 'choice_name' => null, @@ -336,7 +335,6 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('choice_list', array('null', 'Symfony\Component\Form\ChoiceList\ChoiceListInterface')); $resolver->setAllowedTypes('choices', array('null', 'array', '\Traversable')); $resolver->setAllowedTypes('choice_translation_domain', array('null', 'bool', 'string')); - $resolver->setAllowedTypes('choices_as_values', 'bool'); $resolver->setAllowedTypes('choice_loader', array('null', 'Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')); $resolver->setAllowedTypes('choice_label', array('null', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath')); $resolver->setAllowedTypes('choice_name', array('null', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath')); diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php index 4e8bb6f6a5113..b4a65f2978b64 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php @@ -24,7 +24,6 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( '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 5086b0d4deb1a..7e0497fcc92fc 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php @@ -24,7 +24,6 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( '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 2dd0ab4c5328c..be96084e21f33 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php @@ -93,15 +93,12 @@ 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']; $yearOptions['choice_translation_domain'] = $options['choice_translation_domain']['year']; $monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months'])); - $monthOptions['choices_as_values'] = true; $monthOptions['placeholder'] = $options['placeholder']['month']; $monthOptions['choice_translation_domain'] = $options['choice_translation_domain']['month']; $dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days'])); - $dayOptions['choices_as_values'] = true; $dayOptions['placeholder'] = $options['placeholder']['day']; $dayOptions['choice_translation_domain'] = $options['choice_translation_domain']['day']; } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php index 08bab70280588..022ab24a8bda3 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php @@ -24,7 +24,6 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( '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 4763ea4bc491b..86ff038b74a74 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php @@ -24,7 +24,6 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( '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 5461071621f4e..8b148b685dcdc 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php @@ -68,7 +68,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) // Only pass a subset of the options to children $hourOptions['choices'] = $hours; - $hourOptions['choices_as_values'] = true; $hourOptions['placeholder'] = $options['placeholder']['hour']; $hourOptions['choice_translation_domain'] = $options['choice_translation_domain']['hour']; @@ -78,7 +77,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) } $minuteOptions['choices'] = $minutes; - $minuteOptions['choices_as_values'] = true; $minuteOptions['placeholder'] = $options['placeholder']['minute']; $minuteOptions['choice_translation_domain'] = $options['choice_translation_domain']['minute']; } @@ -91,7 +89,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) } $secondOptions['choices'] = $seconds; - $secondOptions['choices_as_values'] = true; $secondOptions['placeholder'] = $options['placeholder']['second']; $secondOptions['choice_translation_domain'] = $options['choice_translation_domain']['second']; } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php index 1bb82ac694aee..f0e3ad4443a9a 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php @@ -37,7 +37,6 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'choices' => self::getFlippedTimezones(), - 'choices_as_values' => true, 'choice_translation_domain' => false, )); } diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php index 7f49c5091dae7..32a4af7dde8c6 100644 --- a/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php @@ -213,7 +213,6 @@ public function testSingleChoice() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, )); @@ -236,7 +235,6 @@ public function testSingleChoiceWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'choice_translation_domain' => false, @@ -260,7 +258,6 @@ public function testSingleChoiceWithPlaceholderWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'required' => false, @@ -287,7 +284,6 @@ public function testSingleChoiceAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => false, 'expanded' => false, @@ -311,7 +307,6 @@ public function testSingleChoiceWithPreferred() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -336,7 +331,6 @@ public function testSingleChoiceWithPreferredAndNoSeparator() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -360,7 +354,6 @@ public function testSingleChoiceWithPreferredAndBlankSeparator() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -385,7 +378,6 @@ public function testChoiceWithOnlyPreferred() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'preferred_choices' => array('&a', '&b'), 'multiple' => false, 'expanded' => false, @@ -403,7 +395,6 @@ public function testSingleChoiceNonRequired() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => false, 'multiple' => false, 'expanded' => false, @@ -428,7 +419,6 @@ public function testSingleChoiceNonRequiredNoneSelected() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => false, 'multiple' => false, 'expanded' => false, @@ -453,7 +443,6 @@ public function testSingleChoiceNonRequiredWithPlaceholder() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'required' => false, @@ -479,7 +468,6 @@ public function testSingleChoiceRequiredWithPlaceholder() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => true, 'multiple' => false, 'expanded' => false, @@ -505,7 +493,6 @@ public function testSingleChoiceRequiredWithPlaceholderViaView() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => true, 'multiple' => false, 'expanded' => false, @@ -533,7 +520,6 @@ public function testSingleChoiceGrouped() 'Group&1' => array('Choice&A' => '&a', 'Choice&B' => '&b'), 'Group&2' => array('Choice&C' => '&c'), ), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, )); @@ -562,7 +548,6 @@ public function testMultipleChoice() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => true, 'multiple' => true, 'expanded' => false, @@ -587,7 +572,6 @@ public function testMultipleChoiceAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'required' => true, 'multiple' => true, @@ -613,7 +597,6 @@ public function testMultipleChoiceSkipsPlaceholder() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => true, 'expanded' => false, 'placeholder' => 'Test&Me', @@ -637,7 +620,6 @@ public function testMultipleChoiceNonRequired() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => false, 'multiple' => true, 'expanded' => false, @@ -661,7 +643,6 @@ public function testSingleChoiceExpanded() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, )); @@ -697,7 +678,6 @@ public function testSingleChoiceExpandedWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'choice_translation_domain' => false, @@ -734,7 +714,6 @@ public function testSingleChoiceExpandedAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => false, 'expanded' => true, @@ -771,7 +750,6 @@ public function testSingleChoiceExpandedWithPlaceholder() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'placeholder' => 'Test&Me', @@ -817,7 +795,6 @@ public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'translation_domain' => false, @@ -864,7 +841,6 @@ public function testSingleChoiceExpandedWithBooleanValue() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', true, array( 'choices' => array('Choice&A' => '1', 'Choice&B' => '0'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, )); @@ -900,7 +876,6 @@ public function testMultipleChoiceExpanded() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a', '&c'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), - 'choices_as_values' => true, 'multiple' => true, 'expanded' => true, 'required' => true, @@ -946,7 +921,6 @@ public function testMultipleChoiceExpandedWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a', '&c'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), - 'choices_as_values' => true, 'multiple' => true, 'expanded' => true, 'required' => true, @@ -993,7 +967,6 @@ public function testMultipleChoiceExpandedAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a', '&c'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), - 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => true, 'expanded' => true, diff --git a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php index 461c885795fa6..b5f6017084369 100644 --- a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php @@ -692,7 +692,6 @@ public function testChoiceRowWithCustomBlock() { $form = $this->factory->createNamedBuilder('name_c', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', 'a', array( 'choices' => array('ChoiceA' => 'a', 'ChoiceB' => 'b'), - 'choices_as_values' => true, 'expanded' => true, )) ->getForm(); diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 92f3ea7e24bb9..7bade490f9b2b 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -488,7 +488,6 @@ public function testSingleChoice() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, )); @@ -522,7 +521,6 @@ public function testSingleChoiceWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'choice_translation_domain' => false, @@ -545,7 +543,6 @@ public function testSingleChoiceWithPlaceholderWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'required' => false, @@ -571,7 +568,6 @@ public function testSingleChoiceAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => false, 'expanded' => false, @@ -594,7 +590,6 @@ public function testSingleChoiceWithPreferred() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -618,7 +613,6 @@ public function testSingleChoiceWithPreferredAndNoSeparator() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -641,7 +635,6 @@ public function testSingleChoiceWithPreferredAndBlankSeparator() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'preferred_choices' => array('&b'), 'multiple' => false, 'expanded' => false, @@ -665,7 +658,6 @@ public function testChoiceWithOnlyPreferred() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'preferred_choices' => array('&a', '&b'), 'multiple' => false, 'expanded' => false, @@ -682,7 +674,6 @@ public function testSingleChoiceNonRequired() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => false, 'multiple' => false, 'expanded' => false, @@ -706,7 +697,6 @@ public function testSingleChoiceNonRequiredNoneSelected() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => false, 'multiple' => false, 'expanded' => false, @@ -730,7 +720,6 @@ public function testSingleChoiceNonRequiredWithPlaceholder() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, 'required' => false, @@ -755,7 +744,6 @@ public function testSingleChoiceRequiredWithPlaceholder() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => true, 'multiple' => false, 'expanded' => false, @@ -783,7 +771,6 @@ public function testSingleChoiceRequiredWithPlaceholderViaView() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => true, 'multiple' => false, 'expanded' => false, @@ -813,7 +800,6 @@ public function testSingleChoiceGrouped() 'Group&1' => array('Choice&A' => '&a', 'Choice&B' => '&b'), 'Group&2' => array('Choice&C' => '&c'), ), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, )); @@ -841,7 +827,6 @@ public function testMultipleChoice() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => true, 'multiple' => true, 'expanded' => false, @@ -865,7 +850,6 @@ public function testMultipleChoiceAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'required' => true, 'multiple' => true, @@ -890,7 +874,6 @@ public function testMultipleChoiceSkipsPlaceholder() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => true, 'expanded' => false, 'placeholder' => 'Test&Me', @@ -913,7 +896,6 @@ public function testMultipleChoiceNonRequired() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'required' => false, 'multiple' => true, 'expanded' => false, @@ -936,7 +918,6 @@ public function testSingleChoiceExpanded() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, )); @@ -959,7 +940,6 @@ public function testSingleChoiceExpandedWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'choice_translation_domain' => false, @@ -983,7 +963,6 @@ public function testSingleChoiceExpandedAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => false, 'expanded' => true, @@ -1007,7 +986,6 @@ public function testSingleChoiceExpandedWithPlaceholder() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'placeholder' => 'Test&Me', @@ -1033,7 +1011,6 @@ public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, 'translation_domain' => false, @@ -1060,7 +1037,6 @@ public function testSingleChoiceExpandedWithBooleanValue() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', true, array( 'choices' => array('Choice&A' => '1', 'Choice&B' => '0'), - 'choices_as_values' => true, 'multiple' => false, 'expanded' => true, )); @@ -1083,7 +1059,6 @@ public function testMultipleChoiceExpanded() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a', '&c'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), - 'choices_as_values' => true, 'multiple' => true, 'expanded' => true, 'required' => true, @@ -1109,7 +1084,6 @@ public function testMultipleChoiceExpandedWithoutTranslation() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a', '&c'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), - 'choices_as_values' => true, 'multiple' => true, 'expanded' => true, 'required' => true, @@ -1136,7 +1110,6 @@ public function testMultipleChoiceExpandedAttributes() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array('&a', '&c'), array( 'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'), - 'choices_as_values' => true, 'choice_attr' => array('Choice&B' => array('class' => 'foo&bar')), 'multiple' => true, 'expanded' => true, diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/ArrayKeyChoiceListTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/ArrayKeyChoiceListTest.php deleted file mode 100644 index 1f1643158d48d..0000000000000 --- a/src/Symfony/Component/Form/Tests/ChoiceList/ArrayKeyChoiceListTest.php +++ /dev/null @@ -1,183 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form\Tests\ChoiceList; - -use Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList; - -/** - * @author Bernhard Schussek - * - * @group legacy - */ -class ArrayKeyChoiceListTest extends AbstractChoiceListTest -{ - private $object; - - protected function setUp() - { - parent::setUp(); - - $this->object = new \stdClass(); - } - - protected function createChoiceList() - { - return new ArrayKeyChoiceList(array_flip($this->getChoices())); - } - - protected function getChoices() - { - return array(0, 1, 'a', 'b', ''); - } - - protected function getValues() - { - return array('0', '1', 'a', 'b', ''); - } - - public function testUseChoicesAsValuesByDefault() - { - $list = new ArrayKeyChoiceList(array('' => 'Empty', 0 => 'Zero', 1 => 'One', '1.23' => 'Float')); - - $this->assertSame(array('', '0', '1', '1.23'), $list->getValues()); - $this->assertSame(array('' => '', 0 => 0, 1 => 1, '1.23' => '1.23'), $list->getChoices()); - $this->assertSame(array('' => 'Empty', 0 => 'Zero', 1 => 'One', '1.23' => 'Float'), $list->getOriginalKeys()); - } - - public function testNoChoices() - { - $list = new ArrayKeyChoiceList(array()); - - $this->assertSame(array(), $list->getValues()); - } - - public function testGetChoicesForValuesConvertsValuesToStrings() - { - $this->assertSame(array(0), $this->list->getChoicesForValues(array(0))); - $this->assertSame(array(0), $this->list->getChoicesForValues(array('0'))); - $this->assertSame(array(1), $this->list->getChoicesForValues(array(1))); - $this->assertSame(array(1), $this->list->getChoicesForValues(array('1'))); - $this->assertSame(array('a'), $this->list->getChoicesForValues(array('a'))); - $this->assertSame(array('b'), $this->list->getChoicesForValues(array('b'))); - $this->assertSame(array(''), $this->list->getChoicesForValues(array(''))); - // "1" === (string) true - $this->assertSame(array(1), $this->list->getChoicesForValues(array(true))); - // "" === (string) false - $this->assertSame(array(''), $this->list->getChoicesForValues(array(false))); - // "" === (string) null - $this->assertSame(array(''), $this->list->getChoicesForValues(array(null))); - $this->assertSame(array(), $this->list->getChoicesForValues(array(1.23))); - } - - public function testGetValuesForChoicesConvertsChoicesToArrayKeys() - { - $this->assertSame(array('0'), $this->list->getValuesForChoices(array(0))); - $this->assertSame(array('0'), $this->list->getValuesForChoices(array('0'))); - $this->assertSame(array('1'), $this->list->getValuesForChoices(array(1))); - $this->assertSame(array('1'), $this->list->getValuesForChoices(array('1'))); - $this->assertSame(array('a'), $this->list->getValuesForChoices(array('a'))); - $this->assertSame(array('b'), $this->list->getValuesForChoices(array('b'))); - // Always cast booleans to 0 and 1, because: - // array(true => 'Yes', false => 'No') === array(1 => 'Yes', 0 => 'No') - // see ChoiceTypeTest::testSetDataSingleNonExpandedAcceptsBoolean - $this->assertSame(array('0'), $this->list->getValuesForChoices(array(false))); - $this->assertSame(array('1'), $this->list->getValuesForChoices(array(true))); - } - - /** - * @dataProvider provideConvertibleChoices - */ - public function testConvertChoicesIfNecessary(array $choices, array $converted) - { - $list = new ArrayKeyChoiceList($choices); - - $this->assertSame($converted, $list->getChoices()); - } - - public function provideConvertibleChoices() - { - return array( - array(array(0 => 'Label'), array(0 => 0)), - array(array(1 => 'Label'), array(1 => 1)), - array(array('1.23' => 'Label'), array('1.23' => '1.23')), - array(array('foobar' => 'Label'), array('foobar' => 'foobar')), - // The default value of choice fields is NULL. It should be treated - // like the empty value for this choice list type - array(array(null => 'Label'), array('' => '')), - array(array('1.23' => 'Label'), array('1.23' => '1.23')), - // Always cast booleans to 0 and 1, because: - // array(true => 'Yes', false => 'No') === array(1 => 'Yes', 0 => 'No') - // see ChoiceTypeTest::testSetDataSingleNonExpandedAcceptsBoolean - array(array(true => 'Label'), array(1 => 1)), - array(array(false => 'Label'), array(0 => 0)), - ); - } - - /** - * @dataProvider provideInvalidChoices - * @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException - */ - public function testGetValuesForChoicesFailsIfInvalidChoices(array $choices) - { - $this->list->getValuesForChoices($choices); - } - - public function provideInvalidChoices() - { - return array( - array(array(new \stdClass())), - array(array(array(1, 2))), - ); - } - - /** - * @dataProvider provideConvertibleValues - */ - public function testConvertValuesToStrings($value, $converted) - { - $callback = function () use ($value) { - return $value; - }; - - $list = new ArrayKeyChoiceList(array('choice' => 'Label'), $callback); - - $this->assertSame(array($converted), $list->getValues()); - } - - public function provideConvertibleValues() - { - return array( - array(0, '0'), - array(1, '1'), - array('0', '0'), - array('1', '1'), - array('1.23', '1.23'), - array('foobar', 'foobar'), - array('', ''), - ); - } - - public function testCreateChoiceListWithValueCallback() - { - $callback = function ($choice) { - return ':'.$choice; - }; - - $choiceList = new ArrayKeyChoiceList(array('foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'), $callback); - - $this->assertSame(array(':foo', ':bar', ':baz'), $choiceList->getValues()); - $this->assertSame(array(':foo' => 'foo', ':bar' => 'bar', ':baz' => 'baz'), $choiceList->getChoices()); - $this->assertSame(array(':foo' => 'Foo', ':bar' => 'Bar', ':baz' => 'Baz'), $choiceList->getOriginalKeys()); - $this->assertSame(array(1 => 'foo', 2 => 'baz'), $choiceList->getChoicesForValues(array(1 => ':foo', 2 => ':baz'))); - $this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 'baz'))); - } -} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index 5d989ec6aaca6..fc61e3b044cfe 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -13,7 +13,6 @@ use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView; use Symfony\Component\Form\ChoiceList\View\ChoiceView; -use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList; class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase { @@ -25,14 +24,6 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase 'Roman' => 'e', ); - private $numericChoicesFlipped = array( - 0 => 'Bernhard', - 1 => 'Fabien', - 2 => 'Kris', - 3 => 'Jon', - 4 => 'Roman', - ); - private $objectChoices; protected $groupedChoices = array( @@ -47,18 +38,6 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase ), ); - protected $groupedChoicesFlipped = array( - 'Symfony' => array( - 'a' => 'Bernhard', - 'b' => 'Fabien', - 'c' => 'Kris', - ), - 'Doctrine' => array( - 'd' => 'Jon', - 'e' => 'Roman', - ), - ); - protected function setUp() { parent::setUp(); @@ -112,7 +91,6 @@ public function testChoiceLoaderOptionExpectsChoiceLoaderInterface() public function testChoiceListAndChoicesCanBeEmpty() { $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( - 'choices_as_values' => true, )); } @@ -121,20 +99,6 @@ public function testExpandedChoicesOptionsTurnIntoChildren() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'expanded' => true, 'choices' => $this->choices, - 'choices_as_values' => true, - )); - - $this->assertCount(count($this->choices), $form, 'Each choice should become a new field'); - } - - /** - * @group legacy - */ - public function testExpandedFlippedChoicesOptionsTurnIntoChildren() - { - $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( - 'expanded' => true, - 'choices' => array_flip($this->choices), )); $this->assertCount(count($this->choices), $form, 'Each choice should become a new field'); @@ -147,7 +111,6 @@ public function testPlaceholderPresentOnNonRequiredExpandedSingleChoice() 'expanded' => true, 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $this->assertTrue(isset($form['placeholder'])); @@ -161,7 +124,6 @@ public function testPlaceholderNotPresentIfRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $this->assertFalse(isset($form['placeholder'])); @@ -175,7 +137,6 @@ public function testPlaceholderNotPresentIfMultiple() 'expanded' => true, 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $this->assertFalse(isset($form['placeholder'])); @@ -192,7 +153,6 @@ public function testPlaceholderNotPresentIfEmptyChoice() 'Empty' => '', 'Not empty' => 1, ), - 'choices_as_values' => true, )); $this->assertFalse(isset($form['placeholder'])); @@ -204,29 +164,6 @@ public function testExpandedChoicesOptionsAreFlattened() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'expanded' => true, 'choices' => $this->groupedChoices, - 'choices_as_values' => true, - )); - - $flattened = array(); - foreach ($this->groupedChoices as $choices) { - $flattened = array_merge($flattened, array_keys($choices)); - } - - $this->assertCount($form->count(), $flattened, 'Each nested choice should become a new field, not the groups'); - - foreach ($flattened as $value => $choice) { - $this->assertTrue($form->has($value), 'Flattened choice is named after it\'s value'); - } - } - - /** - * @group legacy - */ - public function testExpandedChoicesFlippedOptionsAreFlattened() - { - $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( - 'expanded' => true, - 'choices' => $this->groupedChoicesFlipped, )); $flattened = array(); @@ -255,7 +192,6 @@ public function testExpandedChoicesOptionsAreFlattenedObjectChoices() 'Symfony' => array($obj1, $obj2, $obj3), 'Doctrine' => array($obj4, $obj5), ), - 'choices_as_values' => true, 'choice_name' => 'id', )); @@ -274,7 +210,6 @@ public function testExpandedCheckboxesAreNeverRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); foreach ($form as $child) { @@ -289,7 +224,6 @@ public function testExpandedRadiosAreRequiredIfChoiceChildIsRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); foreach ($form as $child) { @@ -304,7 +238,6 @@ public function testExpandedRadiosAreNotRequiredIfChoiceChildIsNotRequired() 'expanded' => true, 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); foreach ($form as $child) { @@ -318,7 +251,6 @@ public function testSubmitSingleNonExpanded() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit('b'); @@ -334,7 +266,6 @@ public function testSubmitSingleNonExpandedInvalidChoice() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit('foobar'); @@ -350,7 +281,6 @@ public function testSubmitSingleNonExpandedNull() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(null); @@ -369,7 +299,6 @@ public function testSubmitSingleNonExpandedNullNoChoices() 'multiple' => false, 'expanded' => false, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(null); @@ -385,7 +314,6 @@ public function testSubmitSingleNonExpandedEmpty() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(''); @@ -403,7 +331,6 @@ public function testSubmitSingleNonExpandedEmptyExplicitEmptyChoice() 'choices' => array( 'Empty' => 'EMPTY_CHOICE', ), - 'choices_as_values' => true, 'choice_value' => function () { return ''; }, @@ -425,7 +352,6 @@ public function testSubmitSingleNonExpandedEmptyNoChoices() 'multiple' => false, 'expanded' => false, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(''); @@ -441,7 +367,6 @@ public function testSubmitSingleNonExpandedFalse() 'multiple' => false, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(false); @@ -460,7 +385,6 @@ public function testSubmitSingleNonExpandedFalseNoChoices() 'multiple' => false, 'expanded' => false, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(false); @@ -476,7 +400,6 @@ public function testSubmitSingleNonExpandedObjectChoices() 'multiple' => false, 'expanded' => false, 'choices' => $this->objectChoices, - 'choices_as_values' => true, 'choice_label' => 'name', 'choice_value' => 'id', )); @@ -495,7 +418,6 @@ public function testSubmitMultipleNonExpanded() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(array('a', 'b')); @@ -511,7 +433,6 @@ public function testSubmitMultipleNonExpandedEmpty() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(array()); @@ -530,7 +451,6 @@ public function testSubmitMultipleNonExpandedEmptyNoChoices() 'multiple' => true, 'expanded' => false, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(array()); @@ -546,7 +466,6 @@ public function testSubmitMultipleNonExpandedInvalidScalarChoice() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit('foobar'); @@ -562,7 +481,6 @@ public function testSubmitMultipleNonExpandedInvalidArrayChoice() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(array('a', 'foobar')); @@ -578,7 +496,6 @@ public function testSubmitMultipleNonExpandedObjectChoices() 'multiple' => true, 'expanded' => false, 'choices' => $this->objectChoices, - 'choices_as_values' => true, 'choice_label' => 'name', 'choice_value' => 'id', )); @@ -597,7 +514,6 @@ public function testSubmitSingleExpandedRequired() 'expanded' => true, 'required' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit('b'); @@ -626,7 +542,6 @@ public function testSubmitSingleExpandedRequiredInvalidChoice() 'expanded' => true, 'required' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit('foobar'); @@ -655,7 +570,6 @@ public function testSubmitSingleExpandedNonRequired() 'expanded' => true, 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit('b'); @@ -686,7 +600,6 @@ public function testSubmitSingleExpandedNonRequiredInvalidChoice() 'expanded' => true, 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit('foobar'); @@ -715,7 +628,6 @@ public function testSubmitSingleExpandedRequiredNull() 'expanded' => true, 'required' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(null); @@ -747,7 +659,6 @@ public function testSubmitSingleExpandedRequiredNullNoChoices() 'expanded' => true, 'required' => true, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(null); @@ -765,7 +676,6 @@ public function testSubmitSingleExpandedRequiredEmpty() 'expanded' => true, 'required' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(''); @@ -797,7 +707,6 @@ public function testSubmitSingleExpandedRequiredEmptyNoChoices() 'expanded' => true, 'required' => true, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(''); @@ -815,7 +724,6 @@ public function testSubmitSingleExpandedRequiredFalse() 'expanded' => true, 'required' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(false); @@ -847,7 +755,6 @@ public function testSubmitSingleExpandedRequiredFalseNoChoices() 'expanded' => true, 'required' => true, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(false); @@ -865,7 +772,6 @@ public function testSubmitSingleExpandedNonRequiredNull() 'expanded' => true, 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(null); @@ -899,7 +805,6 @@ public function testSubmitSingleExpandedNonRequiredNullNoChoices() 'expanded' => true, 'required' => false, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(null); @@ -917,7 +822,6 @@ public function testSubmitSingleExpandedNonRequiredEmpty() 'expanded' => true, 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(''); @@ -951,7 +855,6 @@ public function testSubmitSingleExpandedNonRequiredEmptyNoChoices() 'expanded' => true, 'required' => false, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(''); @@ -969,7 +872,6 @@ public function testSubmitSingleExpandedNonRequiredFalse() 'expanded' => true, 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(false); @@ -1003,7 +905,6 @@ public function testSubmitSingleExpandedNonRequiredFalseNoChoices() 'expanded' => true, 'required' => false, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(false); @@ -1023,7 +924,6 @@ public function testSubmitSingleExpandedWithEmptyChild() 'Empty' => '', 'Not empty' => 1, ), - 'choices_as_values' => true, )); $form->submit(''); @@ -1043,7 +943,6 @@ public function testSubmitSingleExpandedObjectChoices() 'multiple' => false, 'expanded' => true, 'choices' => $this->objectChoices, - 'choices_as_values' => true, 'choice_label' => 'name', 'choice_value' => 'id', )); @@ -1065,38 +964,12 @@ public function testSubmitSingleExpandedObjectChoices() $this->assertNull($form[4]->getViewData()); } - public function testSubmitSingleExpandedNumericChoices() - { - $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( - 'multiple' => false, - 'expanded' => true, - 'choices' => $this->numericChoicesFlipped, - )); - - $form->submit('1'); - - $this->assertSame(1, $form->getData()); - $this->assertTrue($form->isSynchronized()); - - $this->assertFalse($form[0]->getData()); - $this->assertTrue($form[1]->getData()); - $this->assertFalse($form[2]->getData()); - $this->assertFalse($form[3]->getData()); - $this->assertFalse($form[4]->getData()); - $this->assertNull($form[0]->getViewData()); - $this->assertSame('1', $form[1]->getViewData()); - $this->assertNull($form[2]->getViewData()); - $this->assertNull($form[3]->getViewData()); - $this->assertNull($form[4]->getViewData()); - } - public function testSubmitMultipleExpanded() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(array('a', 'c')); @@ -1124,7 +997,6 @@ public function testSubmitMultipleExpandedInvalidScalarChoice() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit('foobar'); @@ -1152,7 +1024,6 @@ public function testSubmitMultipleExpandedInvalidArrayChoice() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(array('a', 'foobar')); @@ -1180,7 +1051,6 @@ public function testSubmitMultipleExpandedEmpty() 'multiple' => true, 'expanded' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $form->submit(array()); @@ -1209,7 +1079,6 @@ public function testSubmitMultipleExpandedEmptyNoChoices() 'multiple' => true, 'expanded' => true, 'choices' => array(), - 'choices_as_values' => true, )); $form->submit(array()); @@ -1228,7 +1097,6 @@ public function testSubmitMultipleExpandedWithEmptyChild() 'Not Empty' => 1, 'Not Empty 2' => 2, ), - 'choices_as_values' => true, )); $form->submit(array('', '2')); @@ -1250,7 +1118,6 @@ public function testSubmitMultipleExpandedObjectChoices() 'multiple' => true, 'expanded' => true, 'choices' => $this->objectChoices, - 'choices_as_values' => true, 'choice_label' => 'name', 'choice_value' => 'id', )); @@ -1272,38 +1139,12 @@ public function testSubmitMultipleExpandedObjectChoices() $this->assertNull($form[4]->getViewData()); } - public function testSubmitMultipleExpandedNumericChoices() - { - $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( - 'multiple' => true, - 'expanded' => true, - 'choices' => $this->numericChoicesFlipped, - )); - - $form->submit(array('1', '2')); - - $this->assertSame(array(1, 2), $form->getData()); - $this->assertTrue($form->isSynchronized()); - - $this->assertFalse($form[0]->getData()); - $this->assertTrue($form[1]->getData()); - $this->assertTrue($form[2]->getData()); - $this->assertFalse($form[3]->getData()); - $this->assertFalse($form[4]->getData()); - $this->assertNull($form[0]->getViewData()); - $this->assertSame('1', $form[1]->getViewData()); - $this->assertSame('2', $form[2]->getViewData()); - $this->assertNull($form[3]->getViewData()); - $this->assertNull($form[4]->getViewData()); - } - public function testSingleSelectedObjectChoices() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', $this->objectChoices[3], array( 'multiple' => false, 'expanded' => false, 'choices' => $this->objectChoices, - 'choices_as_values' => true, 'choice_label' => 'name', 'choice_value' => 'id', )); @@ -1321,7 +1162,6 @@ public function testMultipleSelectedObjectChoices() 'multiple' => true, 'expanded' => false, 'choices' => $this->objectChoices, - 'choices_as_values' => true, 'choice_label' => 'name', 'choice_value' => 'id', )); @@ -1333,50 +1173,10 @@ public function testMultipleSelectedObjectChoices() $this->assertFalse($selectedChecker($view->vars['choices'][1]->value, $view->vars['value'])); } - /** - * We need this functionality to create choice fields for Boolean types, - * e.g. false => 'No', true => 'Yes'. - * - * @group legacy - */ - public function testSetDataSingleNonExpandedAcceptsBoolean() - { - $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( - 'multiple' => false, - 'expanded' => false, - 'choices' => $this->numericChoicesFlipped, - )); - - $form->setData(false); - - $this->assertFalse($form->getData()); - $this->assertEquals('0', $form->getViewData()); - $this->assertTrue($form->isSynchronized()); - } - - /** - * @group legacy - */ - public function testSetDataMultipleNonExpandedAcceptsBoolean() - { - $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( - 'multiple' => true, - 'expanded' => false, - 'choices' => $this->numericChoicesFlipped, - )); - - $form->setData(array(false, true)); - - $this->assertEquals(array(false, true), $form->getData()); - $this->assertEquals(array('0', '1'), $form->getViewData()); - $this->assertTrue($form->isSynchronized()); - } - public function testPassRequiredToView() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1388,7 +1188,6 @@ public function testPassNonRequiredToView() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1400,7 +1199,6 @@ public function testPassMultipleToView() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'multiple' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1412,7 +1210,6 @@ public function testPassExpandedToView() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'expanded' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1423,7 +1220,6 @@ public function testPassChoiceTranslationDomainToView() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1434,7 +1230,6 @@ public function testChoiceTranslationDomainWithTrueValueToView() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->choices, - 'choices_as_values' => true, 'choice_translation_domain' => true, )); $view = $form->createView(); @@ -1446,7 +1241,6 @@ public function testDefaultChoiceTranslationDomainIsSameAsTranslationDomainToVie { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->choices, - 'choices_as_values' => true, 'translation_domain' => 'foo', )); $view = $form->createView(); @@ -1462,7 +1256,6 @@ public function testInheritChoiceTranslationDomainFromParent() )) ->add('child', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array( 'choices' => array(), - 'choices_as_values' => true, )) ->getForm() ->createView(); @@ -1476,7 +1269,6 @@ public function testPlaceholderIsNullByDefaultIfRequired() 'multiple' => false, 'required' => true, 'choices' => $this->choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1489,7 +1281,6 @@ public function testPlaceholderIsEmptyStringByDefaultIfNotRequired() 'multiple' => false, 'required' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1507,7 +1298,6 @@ public function testPassPlaceholderToView($multiple, $expanded, $required, $plac 'required' => $required, 'placeholder' => $placeholder, 'choices' => $this->choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1526,7 +1316,6 @@ public function testDontPassPlaceholderIfContainedInChoices($multiple, $expanded 'required' => $required, 'placeholder' => $placeholder, 'choices' => array('A' => 'a', 'Empty' => ''), - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1583,7 +1372,6 @@ public function testPassChoicesToView() $choices = array('A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1600,7 +1388,6 @@ public function testPassPreferredChoicesToView() $choices = array('A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $choices, - 'choices_as_values' => true, 'preferred_choices' => array('b', 'd'), )); $view = $form->createView(); @@ -1619,7 +1406,6 @@ public function testPassHierarchicalChoicesToView() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => $this->groupedChoices, - 'choices_as_values' => true, 'preferred_choices' => array('b', 'd'), )); $view = $form->createView(); @@ -1651,7 +1437,6 @@ public function testPassChoiceDataToView() $obj4 = (object) array('value' => 'd', 'label' => 'D'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => array($obj1, $obj2, $obj3, $obj4), - 'choices_as_values' => true, 'choice_label' => 'label', 'choice_value' => 'value', )); @@ -1671,7 +1456,6 @@ public function testAdjustFullNameForMultipleNonExpanded() 'multiple' => true, 'expanded' => false, 'choices' => $this->choices, - 'choices_as_values' => true, )); $view = $form->createView(); @@ -1683,7 +1467,6 @@ public function testInitializeWithEmptyChoices() { $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => array(), - 'choices_as_values' => true, )); } @@ -1696,7 +1479,6 @@ public function testInitializeWithDefaultObjectChoice() $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( 'choices' => array($obj1, $obj2, $obj3, $obj4), - 'choices_as_values' => true, 'choice_label' => 'label', 'choice_value' => 'value', // Used to break because "data_class" was inferred, which needs to From 812396d6c6b9a64d713b0e343ac874a161903683 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 28 Nov 2015 10:18:46 +0100 Subject: [PATCH 098/136] [Security] remove deprecated HTTP digest auth key --- .../Security/Factory/HttpDigestFactory.php | 16 ---------------- .../DigestAuthenticationEntryPoint.php | 10 ---------- .../Firewall/DigestAuthenticationListener.php | 2 +- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php index 63875f83081bc..ae9322f229c21 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php @@ -58,22 +58,6 @@ public function getKey() public function addConfiguration(NodeDefinition $node) { $node - ->beforeNormalization() - ->ifTrue(function ($v) { return isset($v['key']); }) - ->then(function ($v) { - if (isset($v['secret'])) { - throw new \LogicException('Cannot set both key and secret options for http_digest, use only secret instead.'); - } - - @trigger_error('http_digest.key is deprecated since version 2.8 and will be removed in 3.0. Use http_digest.secret instead.', E_USER_DEPRECATED); - - $v['secret'] = $v['key']; - - unset($v['key']); - - return $v; - }) - ->end() ->children() ->scalarNode('provider')->end() ->scalarNode('realm')->defaultValue('Secured Area')->end() diff --git a/src/Symfony/Component/Security/Http/EntryPoint/DigestAuthenticationEntryPoint.php b/src/Symfony/Component/Security/Http/EntryPoint/DigestAuthenticationEntryPoint.php index cdb98ebb83e7b..9dfd5929459fb 100644 --- a/src/Symfony/Component/Security/Http/EntryPoint/DigestAuthenticationEntryPoint.php +++ b/src/Symfony/Component/Security/Http/EntryPoint/DigestAuthenticationEntryPoint.php @@ -64,16 +64,6 @@ public function start(Request $request, AuthenticationException $authException = return $response; } - /** - * @deprecated Since version 2.8, to be removed in 3.0. Use getSecret() instead. - */ - public function getKey() - { - @trigger_error(__method__.'() is deprecated since version 2.8 and will be removed in 3.0. Use getSecret() instead.', E_USER_DEPRECATED); - - return $this->getSecret(); - } - /** * @return string */ diff --git a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php index 41e5d6d759533..ef723ea070c34 100644 --- a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php @@ -78,7 +78,7 @@ public function handle(GetResponseEvent $event) } try { - $digestAuth->validateAndDecode($this->authenticationEntryPoint->getKey(), $this->authenticationEntryPoint->getRealmName()); + $digestAuth->validateAndDecode($this->authenticationEntryPoint->getSecret(), $this->authenticationEntryPoint->getRealmName()); } catch (BadCredentialsException $e) { $this->fail($event, $request, $e); From 0108cd4c90c4f2361958462209f0128caef8d351 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 28 Nov 2015 11:07:17 +0100 Subject: [PATCH 099/136] remove unused abstract test classes --- ...bstractEntityChoiceListCompositeIdTest.php | 58 ------------ ...bstractEntityChoiceListSingleIntIdTest.php | 58 ------------ ...ractEntityChoiceListSingleStringIdTest.php | 58 ------------ .../AbstractEntityChoiceListTest.php | 88 ------------------- 4 files changed, 262 deletions(-) delete mode 100644 src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListCompositeIdTest.php delete mode 100644 src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleIntIdTest.php delete mode 100644 src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleStringIdTest.php delete mode 100644 src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListCompositeIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListCompositeIdTest.php deleted file mode 100644 index 5980d9c734c54..0000000000000 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListCompositeIdTest.php +++ /dev/null @@ -1,58 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; - -use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity; - -/** - * @author Bernhard Schussek - */ -abstract class AbstractEntityChoiceListCompositeIdTest extends AbstractEntityChoiceListTest -{ - protected function getEntityClass() - { - return 'Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity'; - } - - /** - * @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface - */ - protected function createObjects() - { - return array( - new CompositeIntIdEntity(10, 11, 'A'), - new CompositeIntIdEntity(20, 21, 'B'), - new CompositeIntIdEntity(30, 31, 'C'), - new CompositeIntIdEntity(40, 41, 'D'), - ); - } - - protected function getChoices() - { - return array(0 => $this->obj1, 1 => $this->obj2, 2 => $this->obj3, 3 => $this->obj4); - } - - protected function getLabels() - { - return array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'); - } - - protected function getValues() - { - return array(0 => '0', 1 => '1', 2 => '2', 3 => '3'); - } - - protected function getIndices() - { - return array(0, 1, 2, 3); - } -} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleIntIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleIntIdTest.php deleted file mode 100644 index 74af66db360e2..0000000000000 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleIntIdTest.php +++ /dev/null @@ -1,58 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; - -use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; - -/** - * @author Bernhard Schussek - */ -abstract class AbstractEntityChoiceListSingleIntIdTest extends AbstractEntityChoiceListTest -{ - protected function getEntityClass() - { - return 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity'; - } - - /** - * @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface - */ - protected function createObjects() - { - return array( - new SingleIntIdEntity(-10, 'A'), - new SingleIntIdEntity(10, 'B'), - new SingleIntIdEntity(20, 'C'), - new SingleIntIdEntity(30, 'D'), - ); - } - - protected function getChoices() - { - return array('_10' => $this->obj1, 10 => $this->obj2, 20 => $this->obj3, 30 => $this->obj4); - } - - protected function getLabels() - { - return array('_10' => 'A', 10 => 'B', 20 => 'C', 30 => 'D'); - } - - protected function getValues() - { - return array('_10' => '-10', 10 => '10', 20 => '20', 30 => '30'); - } - - protected function getIndices() - { - return array('_10', 10, 20, 30); - } -} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleStringIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleStringIdTest.php deleted file mode 100644 index 56b4c21319826..0000000000000 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleStringIdTest.php +++ /dev/null @@ -1,58 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; - -use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity; - -/** - * @author Bernhard Schussek - */ -abstract class AbstractEntityChoiceListSingleStringIdTest extends AbstractEntityChoiceListTest -{ - protected function getEntityClass() - { - return 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity'; - } - - /** - * @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface - */ - protected function createObjects() - { - return array( - new SingleStringIdEntity('a', 'A'), - new SingleStringIdEntity('b', 'B'), - new SingleStringIdEntity('c', 'C'), - new SingleStringIdEntity('d', 'D'), - ); - } - - protected function getChoices() - { - return array(0 => $this->obj1, 1 => $this->obj2, 2 => $this->obj3, 3 => $this->obj4); - } - - protected function getLabels() - { - return array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'); - } - - protected function getValues() - { - return array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'); - } - - protected function getIndices() - { - return array(0, 1, 2, 3); - } -} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php deleted file mode 100644 index 4f3d54a30f15f..0000000000000 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; - -use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; -use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList; -use Doctrine\ORM\Tools\SchemaTool; -use Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest; - -/** - * @author Bernhard Schussek - */ -abstract class AbstractEntityChoiceListTest extends AbstractChoiceListTest -{ - /** - * @var \Doctrine\ORM\EntityManager - */ - protected $em; - - protected $obj1; - - protected $obj2; - - protected $obj3; - - protected $obj4; - - protected function setUp() - { - $this->em = DoctrineTestHelper::createTestEntityManager(); - - $schemaTool = new SchemaTool($this->em); - $classes = $this->getClassesMetadata(); - - try { - $schemaTool->dropSchema($classes); - } catch (\Exception $e) { - } - - try { - $schemaTool->createSchema($classes); - } catch (\Exception $e) { - } - - list($this->obj1, $this->obj2, $this->obj3, $this->obj4) = $this->createObjects(); - - $this->em->persist($this->obj1); - $this->em->persist($this->obj2); - $this->em->persist($this->obj3); - $this->em->persist($this->obj4); - $this->em->flush(); - - parent::setUp(); - } - - protected function tearDown() - { - parent::tearDown(); - - $this->em = null; - } - - abstract protected function getEntityClass(); - - abstract protected function createObjects(); - - protected function getClassesMetadata() - { - return array($this->em->getClassMetadata($this->getEntityClass())); - } - - /** - * @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface - */ - protected function createChoiceList() - { - return new EntityChoiceList($this->em, $this->getEntityClass()); - } -} From 62b3cb280557022500a865db8ac39f6c4b8d1064 Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Wed, 25 Nov 2015 23:16:51 +0100 Subject: [PATCH 100/136] AssetBundle - fix docs --- src/Symfony/Component/Asset/Package.php | 3 +++ .../Component/Asset/VersionStrategy/StaticVersionStrategy.php | 4 ++++ 2 files changed, 7 insertions(+) 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/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; From 683f0f7315eca62de4ce270b9eeea4c0f51173f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sat, 14 Nov 2015 13:20:58 +0100 Subject: [PATCH 101/136] [Serializer] Improve ObjectNormalizer performance --- .../Normalizer/ObjectNormalizer.php | 99 ++++++++++++------- .../Tests/Normalizer/ObjectNormalizerTest.php | 14 ++- 2 files changed, 76 insertions(+), 37 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index fe1676fbf36fb..c731dd7a97f17 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -26,6 +26,8 @@ */ class ObjectNormalizer extends AbstractNormalizer { + private static $attributesCache = array(); + /** * @var PropertyAccessorInterface */ @@ -58,42 +60,7 @@ public function normalize($object, $format = null, array $context = array()) } $data = array(); - $attributes = $this->getAllowedAttributes($object, $context, true); - - // If not using groups, detect manually - if (false === $attributes) { - $attributes = array(); - - // methods - $reflClass = new \ReflectionClass($object); - foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) { - if ( - !$reflMethod->isStatic() && - !$reflMethod->isConstructor() && - !$reflMethod->isDestructor() && - 0 === $reflMethod->getNumberOfRequiredParameters() - ) { - $name = $reflMethod->getName(); - - if (strpos($name, 'get') === 0 || strpos($name, 'has') === 0) { - // getters and hassers - $attributes[lcfirst(substr($name, 3))] = true; - } elseif (strpos($name, 'is') === 0) { - // issers - $attributes[lcfirst(substr($name, 2))] = true; - } - } - } - - // properties - foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) { - if (!$reflProperty->isStatic()) { - $attributes[$reflProperty->getName()] = true; - } - } - - $attributes = array_keys($attributes); - } + $attributes = $this->getAttributes($object, $context); foreach ($attributes as $attribute) { if (in_array($attribute, $this->ignoredAttributes)) { @@ -162,4 +129,64 @@ public function denormalize($data, $class, $format = null, array $context = arra return $object; } + + /** + * Gets and caches attributes for this class and context. + * + * @param object $object + * @param array $context + * + * @return array + */ + private function getAttributes($object, array $context) + { + $key = sprintf('%s-%s', get_class($object), serialize($context)); + + if (isset(self::$attributesCache[$key])) { + return self::$attributesCache[$key]; + } + + $allowedAttributes = $this->getAllowedAttributes($object, $context, true); + + if (false !== $allowedAttributes) { + return self::$attributesCache[$key] = $allowedAttributes; + } + + // If not using groups, detect manually + $attributes = array(); + + // methods + $reflClass = new \ReflectionClass($object); + foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) { + if ( + $reflMethod->getNumberOfRequiredParameters() !== 0 || + $reflMethod->isStatic() || + $reflMethod->isConstructor() || + $reflMethod->isDestructor() + ) { + continue; + } + + $name = $reflMethod->getName(); + + if (strpos($name, 'get') === 0 || strpos($name, 'has') === 0) { + // getters and hassers + $attributes[lcfirst(substr($name, 3))] = true; + } elseif (strpos($name, 'is') === 0) { + // issers + $attributes[lcfirst(substr($name, 2))] = true; + } + } + + // properties + foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) { + if ($reflProperty->isStatic()) { + continue; + } + + $attributes[$reflProperty->getName()] = true; + } + + return self::$attributesCache[$key] = array_keys($attributes); + } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index 80a021d08fa25..ec676efe1690e 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -29,7 +29,7 @@ class ObjectNormalizerTest extends \PHPUnit_Framework_TestCase { /** - * @var ObjectNormalizerTest + * @var ObjectNormalizer */ private $normalizer; /** @@ -239,6 +239,18 @@ public function testGroupsDenormalize() $this->assertEquals($obj, $normalized); } + public function testNormalizeNoPropertyInGroup() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFoo('foo'); + + $this->assertEquals(array(), $this->normalizer->normalize($obj, null, array('groups' => array('notExist')))); + } + public function testGroupsNormalizeWithNameConverter() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); From a35d3d44d0426a25683d2875208abb23b411a180 Mon Sep 17 00:00:00 2001 From: Pieter Date: Tue, 27 Oct 2015 13:04:29 +0200 Subject: [PATCH 102/136] [WIP] [Form] [TwigBridge] Bootstrap horizontal theme missing tests --- .../bootstrap_3_horizontal_layout.html.twig | 10 +- ...xtensionBootstrap3HorizontalLayoutTest.php | 118 +++++++++++++ ...AbstractBootstrap3HorizontalLayoutTest.php | 157 ++++++++++++++++++ 3 files changed, 279 insertions(+), 6 deletions(-) create mode 100644 src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php create mode 100644 src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php 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 %}
- {{ form_label(form) }} + {{- form_label(form) -}}
- {{ form_widget(form) }} - {{ form_errors(form) }} + {{- form_widget(form) -}} + {{- form_errors(form) -}}
-
-{% 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..bf26dda05be92 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php @@ -0,0 +1,118 @@ + + * + * 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); + } +} diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php new file mode 100644 index 0000000000000..1273fa505bd2c --- /dev/null +++ b/src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php @@ -0,0 +1,157 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests; + +abstract class AbstractBootstrap3HorizontalLayoutTest extends AbstractBootstrap3LayoutTest +{ + public function testLabelOnForm() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\DateType'); + $view = $form->createView(); + $this->renderWidget($view, array('label' => 'foo')); + $html = $this->renderLabel($view); + + $this->assertMatchesXpath($html, +'/label + [@class="col-sm-2 control-label required"] + [.="[trans]Name[/trans]"] +' + ); + } + + public function testLabelDoesNotRenderFieldAttributes() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), null, array( + 'attr' => array( + 'class' => 'my&class', + ), + )); + + $this->assertMatchesXpath($html, +'/label + [@for="name"] + [@class="col-sm-2 control-label required"] +' + ); + } + + public function testLabelWithCustomAttributesPassedDirectly() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), null, array( + 'label_attr' => array( + 'class' => 'my&class', + ), + )); + + $this->assertMatchesXpath($html, +'/label + [@for="name"] + [@class="my&class col-sm-2 control-label required"] +' + ); + } + + public function testLabelWithCustomTextAndCustomAttributesPassedDirectly() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Custom label', array( + 'label_attr' => array( + 'class' => 'my&class', + ), + )); + + $this->assertMatchesXpath($html, +'/label + [@for="name"] + [@class="my&class col-sm-2 control-label required"] + [.="[trans]Custom label[/trans]"] +' + ); + } + + public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, array( + 'label' => 'Custom label', + )); + $html = $this->renderLabel($form->createView(), null, array( + 'label_attr' => array( + 'class' => 'my&class', + ), + )); + + $this->assertMatchesXpath($html, +'/label + [@for="name"] + [@class="my&class col-sm-2 control-label required"] + [.="[trans]Custom label[/trans]"] +' + ); + } + + public function testStartTag() + { + $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + 'method' => 'get', + 'action' => 'http://example.com/directory', + )); + + $html = $this->renderStart($form->createView()); + + $this->assertSame('
', $html); + } + + public function testStartTagWithOverriddenVars() + { + $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + 'method' => 'put', + 'action' => 'http://example.com/directory', + )); + + $html = $this->renderStart($form->createView(), array( + 'method' => 'post', + 'action' => 'http://foo.com/directory', + )); + + $this->assertSame('', $html); + } + + public function testStartTagForMultipartForm() + { + $form = $this->factory->createBuilder('Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + 'method' => 'get', + 'action' => 'http://example.com/directory', + )) + ->add('file', 'Symfony\Component\Form\Extension\Core\Type\FileType') + ->getForm(); + + $html = $this->renderStart($form->createView()); + + $this->assertSame('', $html); + } + + public function testStartTagWithExtraAttributes() + { + $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + 'method' => 'get', + 'action' => 'http://example.com/directory', + )); + + $html = $this->renderStart($form->createView(), array( + 'attr' => array('class' => 'foobar'), + )); + + $this->assertSame('', $html); + } +} From 982710ff18b9dc592cbdba8900db4a60f9daad98 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 22 Oct 2015 12:12:04 +0200 Subject: [PATCH 103/136] [HttpKernel] clearstatcache() so the Cache sees when a .lck file has been released --- src/Symfony/Component/HttpKernel/HttpCache/Store.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Store.php b/src/Symfony/Component/HttpKernel/HttpCache/Store.php index 4901e2cf297aa..15a956d4d4908 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/Store.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/Store.php @@ -106,7 +106,10 @@ public function unlock(Request $request) public function isLocked(Request $request) { - return is_file($this->getPath($this->getCacheKey($request).'.lck')); + $path = $this->getPath($this->getCacheKey($request).'.lck'); + clearstatcache(true, $path); + + return is_file($path); } /** From d834cd3d680ba937d96235905523f518c584b2d1 Mon Sep 17 00:00:00 2001 From: WouterJ Date: Sat, 28 Nov 2015 12:15:28 +0100 Subject: [PATCH 104/136] Added getBlockPrefix to FormTypeInterface --- src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php | 8 -------- src/Symfony/Component/Form/AbstractType.php | 7 +------ src/Symfony/Component/Form/FormTypeInterface.php | 10 ++++++++++ 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php index 9ee98c73277b9..f0c8a9e785157 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php @@ -56,14 +56,6 @@ public function getLoader(ObjectManager $manager, $queryBuilder, $class) return new ORMQueryBuilderLoader($queryBuilder); } - /** - * {@inheritdoc} - */ - public function getName() - { - return $this->getBlockPrefix(); - } - /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/AbstractType.php b/src/Symfony/Component/Form/AbstractType.php index 9be91dfcede86..e99f1073b1359 100644 --- a/src/Symfony/Component/Form/AbstractType.php +++ b/src/Symfony/Component/Form/AbstractType.php @@ -48,12 +48,7 @@ public function configureOptions(OptionsResolver $resolver) } /** - * Returns the prefix of the template block name for this type. - * - * The block prefixes default to the underscored short class name with - * the "Type" suffix removed (e.g. "UserProfileType" => "user_profile"). - * - * @return string The prefix of the template block name + * {@inheritdoc} */ public function getBlockPrefix() { diff --git a/src/Symfony/Component/Form/FormTypeInterface.php b/src/Symfony/Component/Form/FormTypeInterface.php index 584e650a1d8b2..1e80f477ca6bb 100644 --- a/src/Symfony/Component/Form/FormTypeInterface.php +++ b/src/Symfony/Component/Form/FormTypeInterface.php @@ -75,6 +75,16 @@ public function finishView(FormView $view, FormInterface $form, array $options); */ public function configureOptions(OptionsResolver $resolver); + /** + * Returns the prefix of the template block name for this type. + * + * The block prefix defaults to the underscored short class name with + * the "Type" suffix removed (e.g. "UserProfileType" => "user_profile"). + * + * @return string The prefix of the template block name + */ + public function getBlockPrefix(); + /** * Returns the name of the parent type. * From 8add4053c034341efc5413b2105846b52616d488 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Sat, 28 Nov 2015 12:40:39 +0100 Subject: [PATCH 105/136] [Form] Removed useless code --- .../Tests/Form/Type/EntityTypeTest.php | 36 ++------- .../Form/Extension/Core/Type/ChoiceType.php | 73 ++++++++++--------- .../Extension/Core/Type/ChoiceTypeTest.php | 10 --- 3 files changed, 46 insertions(+), 73 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index 1f0cee39828d4..7acc7d276fc09 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -982,37 +982,13 @@ public function testLoaderCaching() 'property3' => 2, )); - $choiceList1 = $form->get('property1')->getConfig()->getOption('choice_list'); - $choiceList2 = $form->get('property2')->getConfig()->getOption('choice_list'); - $choiceList3 = $form->get('property3')->getConfig()->getOption('choice_list'); + $choiceLoader1 = $form->get('property1')->getConfig()->getOption('choice_loader'); + $choiceLoader2 = $form->get('property2')->getConfig()->getOption('choice_loader'); + $choiceLoader3 = $form->get('property3')->getConfig()->getOption('choice_loader'); - $this->assertInstanceOf('Symfony\Component\Form\ChoiceList\ChoiceListInterface', $choiceList1); - $this->assertSame($choiceList1, $choiceList2); - $this->assertSame($choiceList1, $choiceList3); - } - - public function testCacheChoiceLists() - { - $entity1 = new SingleIntIdEntity(1, 'Foo'); - - $this->persist(array($entity1)); - - $field1 = $this->factory->createNamed('name', 'Symfony\Bridge\Doctrine\Form\Type\EntityType', null, array( - 'em' => 'default', - 'class' => self::SINGLE_IDENT_CLASS, - 'required' => false, - 'choice_label' => 'name', - )); - - $field2 = $this->factory->createNamed('name', 'Symfony\Bridge\Doctrine\Form\Type\EntityType', null, array( - 'em' => 'default', - 'class' => self::SINGLE_IDENT_CLASS, - 'required' => false, - 'choice_label' => 'name', - )); - - $this->assertInstanceOf('Symfony\Component\Form\ChoiceList\ChoiceListInterface', $field1->getConfig()->getOption('choice_list')); - $this->assertSame($field1->getConfig()->getOption('choice_list'), $field2->getConfig()->getOption('choice_list')); + $this->assertInstanceOf('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface', $choiceLoader1); + $this->assertSame($choiceLoader1, $choiceLoader2); + $this->assertSame($choiceLoader1, $choiceLoader3); } protected function createRegistryMock($name, $em) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index 6c4cf9ccaae36..549d46f0ee97e 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -52,10 +52,13 @@ public function __construct(ChoiceListFactoryInterface $choiceListFactory = null */ public function buildForm(FormBuilderInterface $builder, array $options) { + $choiceList = $this->createChoiceList($options); + $builder->setAttribute('choice_list', $choiceList); + if ($options['expanded']) { $builder->setDataMapper($options['multiple'] - ? new CheckboxListMapper($options['choice_list']) - : new RadioListMapper($options['choice_list'])); + ? new CheckboxListMapper($choiceList) + : new RadioListMapper($choiceList)); // Initialize all choices before doing the index check below. // This helps in cases where index checks are optimized for non @@ -64,12 +67,12 @@ public function buildForm(FormBuilderInterface $builder, array $options) // requires another SQL query. When the initialization is done first, // one SQL query is sufficient. - $choiceListView = $this->createChoiceListView($options['choice_list'], $options); + $choiceListView = $this->createChoiceListView($choiceList, $options); $builder->setAttribute('choice_list_view', $choiceListView); // Check if the choices already contain the empty value // Only add the placeholder option if this is not the case - if (null !== $options['placeholder'] && 0 === count($options['choice_list']->getChoicesForValues(array('')))) { + if (null !== $options['placeholder'] && 0 === count($choiceList->getChoicesForValues(array('')))) { $placeholderView = new ChoiceView(null, '', $options['placeholder']); // "placeholder" is a reserved name @@ -139,10 +142,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) } } elseif ($options['multiple']) { // tag without "multiple" option - $builder->addViewTransformer(new ChoiceToValueTransformer($options['choice_list'])); + $builder->addViewTransformer(new ChoiceToValueTransformer($choiceList)); } if ($options['multiple'] && $options['by_reference']) { @@ -162,10 +165,13 @@ public function buildView(FormView $view, FormInterface $form, array $options) $choiceTranslationDomain = $view->vars['translation_domain']; } + /** @var ChoiceListInterface $choiceList */ + $choiceList = $form->getConfig()->getAttribute('choice_list'); + /** @var ChoiceListView $choiceListView */ $choiceListView = $form->getConfig()->hasAttribute('choice_list_view') ? $form->getConfig()->getAttribute('choice_list_view') - : $this->createChoiceListView($options['choice_list'], $options); + : $this->createChoiceListView($choiceList, $options); $view->vars = array_replace($view->vars, array( 'multiple' => $options['multiple'], @@ -192,7 +198,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) } // Check if the choices already contain the empty value - $view->vars['placeholder_in_choices'] = 0 !== count($options['choice_list']->getChoicesForValues(array(''))); + $view->vars['placeholder_in_choices'] = 0 !== count($choiceList->getChoicesForValues(array(''))); // Only add the empty value option if this is not the case if (null !== $options['placeholder'] && !$view->vars['placeholder_in_choices']) { @@ -235,8 +241,6 @@ public function finishView(FormView $view, FormInterface $form, array $options) */ public function configureOptions(OptionsResolver $resolver) { - $choiceListFactory = $this->choiceListFactory; - $emptyData = function (Options $options) { if ($options['multiple'] || $options['expanded']) { return array(); @@ -249,29 +253,20 @@ public function configureOptions(OptionsResolver $resolver) return $options['required'] ? null : ''; }; - $choiceListNormalizer = function (Options $options) use ($choiceListFactory) { - if (null !== $options['choice_loader']) { - return $choiceListFactory->createListFromLoader( - $options['choice_loader'], - $options['choice_value'] - ); + $choicesAsValuesNormalizer = function (Options $options, $choicesAsValues) { + // Not set by the user + if (null === $choicesAsValues) { + return true; } - // Harden against NULL values (like in EntityType and ModelType) - $choices = null !== $options['choices'] ? $options['choices'] : array(); - - return $choiceListFactory->createListFromChoices($choices, $options['choice_value']); - }; - - $choicesAsValuesNormalizer = function (Options $options, $choicesAsValues) { - if (null !== $choicesAsValues) { - if (true !== $choicesAsValues) { - throw new \RuntimeException('The "choices_as_values" option should not be used. Remove it and flip the contents of the "choices" option instead.'); - } - // To be uncommented in 3.1 - //@trigger_error('The "choices_as_values" option is deprecated since version 3.1 and will be removed in 4.0. You should not use it anymore.', E_USER_DEPRECATED); + // Set by the user + if (true !== $choicesAsValues) { + throw new \RuntimeException('The "choices_as_values" option should not be used. Remove it and flip the contents of the "choices" option instead.'); } + // To be uncommented in 3.1 + //@trigger_error('The "choices_as_values" option is deprecated since version 3.1 and will be removed in 4.0. You should not use it anymore.', E_USER_DEPRECATED); + return true; }; @@ -306,9 +301,8 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setDefaults(array( 'multiple' => false, 'expanded' => false, - 'choice_list' => null, // deprecated 'choices' => array(), - 'choices_as_values' => null, // to be deprecated in 3.1 + 'choices_as_values' => null, // to be deprecated in 3.1 'choice_loader' => null, 'choice_label' => null, 'choice_name' => null, @@ -327,12 +321,10 @@ public function configureOptions(OptionsResolver $resolver) 'choice_translation_domain' => true, )); - $resolver->setNormalizer('choice_list', $choiceListNormalizer); $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); $resolver->setNormalizer('choices_as_values', $choicesAsValuesNormalizer); - $resolver->setAllowedTypes('choice_list', array('null', 'Symfony\Component\Form\ChoiceList\ChoiceListInterface')); $resolver->setAllowedTypes('choices', array('null', 'array', '\Traversable')); $resolver->setAllowedTypes('choice_translation_domain', array('null', 'bool', 'string')); $resolver->setAllowedTypes('choice_loader', array('null', 'Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface')); @@ -422,6 +414,21 @@ private function addSubForm(FormBuilderInterface $builder, $name, ChoiceView $ch $builder->add($name, $choiceType, $choiceOpts); } + private function createChoiceList(array $options) + { + if (null !== $options['choice_loader']) { + return $this->choiceListFactory->createListFromLoader( + $options['choice_loader'], + $options['choice_value'] + ); + } + + // Harden against NULL values (like in EntityType and ModelType) + $choices = null !== $options['choices'] ? $options['choices'] : array(); + + return $this->choiceListFactory->createListFromChoices($choices, $options['choice_value']); + } + private function createChoiceListView(ChoiceListInterface $choiceList, array $options) { // If no explicit grouping information is given, use the structural diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index fc61e3b044cfe..f5fff1ea74a5d 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -68,16 +68,6 @@ public function testChoicesOptionExpectsArrayOrTraversable() )); } - /** - * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException - */ - public function testChoiceListOptionExpectsChoiceListInterface() - { - $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( - 'choice_list' => array('foo' => 'foo'), - )); - } - /** * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException */ From f94c6d412646c1ba4ea8ed8fdaac5b49ce84d6e7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 28 Nov 2015 13:49:09 +0100 Subject: [PATCH 106/136] [Bundle\Twig] Fix lowet form dep --- src/Symfony/Bridge/Twig/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 32fcb84a080d9..5b002979a88df 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|~3.0.0", "symfony/finder": "~2.3|~3.0.0", - "symfony/form": "~2.8", + "symfony/form": "~2.8,>2.8-BETA1", "symfony/http-kernel": "~2.8|~3.0.0", "symfony/polyfill-intl-icu": "~1.0", "symfony/routing": "~2.2|~3.0.0", From 4a2aea0bd72b334c1cece36cf73c7b736ba44617 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 28 Nov 2015 13:08:21 +0100 Subject: [PATCH 107/136] [Form] remove deprecated getTimezones() method --- .../Form/Extension/Core/Type/TimezoneType.php | 51 +------------------ 1 file changed, 2 insertions(+), 49 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php index f0e3ad4443a9a..7f2f34f705e87 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php @@ -23,20 +23,13 @@ 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::getFlippedTimezones(), + 'choices' => self::getTimezones(), 'choice_translation_domain' => false, )); } @@ -57,46 +50,6 @@ public function getBlockPrefix() return 'timezone'; } - /** - * 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 - * - * @deprecated Deprecated since version 2.8 - */ - public static function getTimezones() - { - @trigger_error('The TimezoneType::getTimezones() method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - - if (null === static::$timezones) { - static::$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]; - } - - static::$timezones[$region][$timezone] = str_replace('_', ' ', $name); - } - } - - return static::$timezones; - } - /** * Returns the timezone choices. * @@ -107,7 +60,7 @@ public static function getTimezones() * * @return array The timezone choices */ - private static function getFlippedTimezones() + private static function getTimezones() { if (null === self::$timezones) { self::$timezones = array(); From 04508658b52274dfd7a6d7502d565c764e569e5d Mon Sep 17 00:00:00 2001 From: Jakub Zalas Date: Sat, 28 Nov 2015 11:32:42 +0000 Subject: [PATCH 108/136] [Security][SecurityBundle] Use csrf_token_id instead of deprecated intention --- UPGRADE-2.8.md | 9 +++++++++ src/Symfony/Bundle/SecurityBundle/CHANGELOG.md | 1 + .../Security/Factory/FormLoginFactory.php | 2 +- .../DependencyInjection/SecurityExtension.php | 2 +- .../CsrfFormLoginBundle/Form/UserLoginType.php | 4 ++-- src/Symfony/Component/Security/CHANGELOG.md | 2 ++ .../Security/Http/Firewall/LogoutListener.php | 14 ++++++++++++-- .../Firewall/SimpleFormAuthenticationListener.php | 14 ++++++++++++-- .../UsernamePasswordFormAuthenticationListener.php | 14 ++++++++++++-- .../Http/Tests/Firewall/LogoutListenerTest.php | 2 +- 10 files changed, 53 insertions(+), 11 deletions(-) diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index bfd2aacc3ea84..80fef5d8c25f3 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -455,6 +455,15 @@ Security * The `VoterInterface::supportsClass` and `supportsAttribute` methods were deprecated and will be removed from the interface in 3.0. + * The `intention` option is deprecated for all the authentication listeners, + and will be removed in 3.0. Use the `csrf_token_id` option instead. + +SecurityBundle +-------------- + + * The `intention` firewall listener setting is deprecated, and will be removed in 3.0. + Use the `csrf_token_id` option instead. + Config ------ diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index 21083ddbc92c0..11873ee9fae7d 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * deprecated the `key` setting of `anonymous`, `remember_me` and `http_digest` in favor of the `secret` setting. + * deprecated the `intention` firewall listener setting in favor of the `csrf_token_id`. 2.6.0 ----- diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php index c3a19e3f7edf4..aa81aa8b92f63 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php @@ -29,7 +29,7 @@ public function __construct() $this->addOption('username_parameter', '_username'); $this->addOption('password_parameter', '_password'); $this->addOption('csrf_parameter', '_csrf_token'); - $this->addOption('intention', 'authenticate'); + $this->addOption('csrf_token_id', 'authenticate'); $this->addOption('post_only', true); } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 5914e3fe2be33..68bbbc4fd374a 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -299,7 +299,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.logout_listener')); $listener->replaceArgument(3, array( 'csrf_parameter' => $firewall['logout']['csrf_parameter'], - 'intention' => $firewall['logout']['csrf_token_id'], + 'csrf_token_id' => $firewall['logout']['csrf_token_id'], 'logout_path' => $firewall['logout']['path'], )); $listeners[] = new Reference($listenerId); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/CsrfFormLoginBundle/Form/UserLoginType.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/CsrfFormLoginBundle/Form/UserLoginType.php index 48b87fbecbfc1..0f4cd6bb844eb 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/CsrfFormLoginBundle/Form/UserLoginType.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/CsrfFormLoginBundle/Form/UserLoginType.php @@ -79,12 +79,12 @@ public function buildForm(FormBuilderInterface $builder, array $options) */ public function configureOptions(OptionsResolver $resolver) { - /* Note: the form's intention must correspond to that for the form login + /* Note: the form's csrf_token_id must correspond to that for the form login * listener in order for the CSRF token to validate successfully. */ $resolver->setDefaults(array( - 'intention' => 'authenticate', + 'csrf_token_id' => 'authenticate', )); } } diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 84fe742b729cc..b33f053a0b049 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -18,6 +18,8 @@ CHANGELOG `Symfony\Component\Security\Core\Authorization\Voter\VoterInterface`. * deprecated `getSupportedAttributes()` and `getSupportedClasses()` methods of `Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter`, use `supports()` instead. + * deprecated the `intention` option for all the authentication listeners, + use the `csrf_token_id` option instead. 2.7.0 ----- diff --git a/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php b/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php index 6211ee0323c71..e19d39cc2950d 100644 --- a/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php @@ -57,11 +57,21 @@ public function __construct(TokenStorageInterface $tokenStorage, HttpUtils $http throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); } + if (isset($options['intention'])) { + if (isset($options['csrf_token_id'])) { + throw new \InvalidArgumentException(sprintf('You should only define an option for one of "intention" or "csrf_token_id" for the "%s". Use the "csrf_token_id" as it replaces "intention".', __CLASS__)); + } + + @trigger_error('The "intention" option for the '.__CLASS__.' is deprecated since version 2.8 and will be removed in 3.0. Use the "csrf_token_id" option instead.', E_USER_DEPRECATED); + + $options['csrf_token_id'] = $options['intention']; + } + $this->tokenStorage = $tokenStorage; $this->httpUtils = $httpUtils; $this->options = array_merge(array( 'csrf_parameter' => '_csrf_token', - 'intention' => 'logout', + 'csrf_token_id' => 'logout', 'logout_path' => '/logout', ), $options); $this->successHandler = $successHandler; @@ -101,7 +111,7 @@ public function handle(GetResponseEvent $event) if (null !== $this->csrfTokenManager) { $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); - if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { + if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { throw new LogoutException('Invalid CSRF token.'); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php index fedaa4e62f00e..436376360be3a 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php @@ -70,6 +70,16 @@ public function __construct(TokenStorageInterface $tokenStorage, AuthenticationM throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); } + if (isset($options['intention'])) { + if (isset($options['csrf_token_id'])) { + throw new \InvalidArgumentException(sprintf('You should only define an option for one of "intention" or "csrf_token_id" for the "%s". Use the "csrf_token_id" as it replaces "intention".', __CLASS__)); + } + + @trigger_error('The "intention" option for the '.__CLASS__.' is deprecated since version 2.8 and will be removed in 3.0. Use the "csrf_token_id" option instead.', E_USER_DEPRECATED); + + $options['csrf_token_id'] = $options['intention']; + } + $this->simpleAuthenticator = $simpleAuthenticator; $this->csrfTokenManager = $csrfTokenManager; @@ -77,7 +87,7 @@ public function __construct(TokenStorageInterface $tokenStorage, AuthenticationM 'username_parameter' => '_username', 'password_parameter' => '_password', 'csrf_parameter' => '_csrf_token', - 'intention' => 'authenticate', + 'csrf_token_id' => 'authenticate', 'post_only' => true, ), $options); @@ -104,7 +114,7 @@ protected function attemptAuthentication(Request $request) if (null !== $this->csrfTokenManager) { $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); - if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { + if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index d20ab19f62940..24c3ca6509c26 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -48,11 +48,21 @@ public function __construct(TokenStorageInterface $tokenStorage, AuthenticationM throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); } + if (isset($options['intention'])) { + if (isset($options['csrf_token_id'])) { + throw new \InvalidArgumentException(sprintf('You should only define an option for one of "intention" or "csrf_token_id" for the "%s". Use the "csrf_token_id" as it replaces "intention".', __CLASS__)); + } + + @trigger_error('The "intention" option for the '.__CLASS__.' is deprecated since version 2.8 and will be removed in 3.0. Use the "csrf_token_id" option instead.', E_USER_DEPRECATED); + + $options['csrf_token_id'] = $options['intention']; + } + parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array( 'username_parameter' => '_username', 'password_parameter' => '_password', 'csrf_parameter' => '_csrf_token', - 'intention' => 'authenticate', + 'csrf_token_id' => 'authenticate', 'post_only' => true, ), $options), $logger, $dispatcher); @@ -79,7 +89,7 @@ protected function attemptAuthentication(Request $request) if (null !== $this->csrfTokenManager) { $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); - if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { + if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); } } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php index 15c996e6261a5..367c810f51f39 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php @@ -213,7 +213,7 @@ private function getListener($successHandler = null, $tokenManager = null) $successHandler ?: $this->getSuccessHandler(), $options = array( 'csrf_parameter' => '_csrf_token', - 'intention' => 'logout', + 'csrf_token_id' => 'logout', 'logout_path' => '/logout', 'target_url' => '/', ), From 96afff6a058deb9ea9d36fab3b1741ea9502943b Mon Sep 17 00:00:00 2001 From: WouterJ Date: Wed, 4 Nov 2015 14:58:00 +0100 Subject: [PATCH 109/136] [SecurityBundle] Fix disabling of RoleHierarchyVoter when passing empty hierarchy --- .../DependencyInjection/SecurityExtension.php | 2 +- .../SecurityExtensionTest.php | 27 +++++++++++++++++++ .../Voter/RoleHierarchyVoterTest.php | 15 +++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 68bbbc4fd374a..5f45b1f794bdb 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -168,7 +168,7 @@ private function configureDbalAclProvider(array $config, ContainerBuilder $conta */ private function createRoleHierarchy($config, ContainerBuilder $container) { - if (!isset($config['role_hierarchy'])) { + if (!isset($config['role_hierarchy']) || 0 === count($config['role_hierarchy'])) { $container->removeDefinition('security.access.role_hierarchy_voter'); return; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index 4dd33020c572d..859f5b4e2d73f 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -94,6 +94,33 @@ public function testFirewallWithInvalidUserProvider() $container->compile(); } + public function testDisableRoleHierarchyVoter() + { + $container = $this->getRawContainer(); + + $container->loadFromExtension('security', array( + 'providers' => array( + 'default' => array('id' => 'foo'), + ), + + 'role_hierarchy' => null, + + 'firewalls' => array( + 'some_firewall' => array( + 'pattern' => '/.*', + 'http_basic' => null, + ), + ), + )); + + $container->compile(); + + $admDefinition = $container->getDefinition('security.access.decision_manager'); + $registeredVoters = array_map('strval', $admDefinition->getArgument(0)); + + $this->assertNotContains('security.access.role_hierarchy_voter', $registeredVoters); + } + protected function getRawContainer() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php index c50ecf38c587d..4b03bacd784a5 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php @@ -33,4 +33,19 @@ public function getVoteTests() array(array('ROLE_FOO'), array('ROLE_FOOBAR'), VoterInterface::ACCESS_GRANTED), )); } + + /** + * @dataProvider getVoteWithEmptyHierarchyTests + */ + public function testVoteWithEmptyHierarchy($roles, $attributes, $expected) + { + $voter = new RoleHierarchyVoter(new RoleHierarchy(array())); + + $this->assertSame($expected, $voter->vote($this->getToken($roles), null, $attributes)); + } + + public function getVoteWithEmptyHierarchyTests() + { + return parent::getVoteTests(); + } } From d641fc5d7cf576c7341973f270621c15361341a0 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 28 Nov 2015 11:46:08 +0100 Subject: [PATCH 110/136] [Form] remove deprecated CSRF options --- .../DependencyInjection/MainConfiguration.php | 30 ------------------- .../Security/Factory/FormLoginFactory.php | 15 ---------- .../Csrf/Type/FormTypeCsrfExtension.php | 12 +------- 3 files changed, 1 insertion(+), 56 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 547cedd6aa54a..bf828ed22aa0e 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -231,36 +231,6 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->arrayNode('logout') ->treatTrueLike(array()) ->canBeUnset() - ->beforeNormalization() - ->ifTrue(function ($v) { return isset($v['csrf_provider']) && isset($v['csrf_token_generator']); }) - ->thenInvalid("You should define a value for only one of 'csrf_provider' and 'csrf_token_generator' on a security firewall. Use 'csrf_token_generator' as this replaces 'csrf_provider'.") - ->end() - ->beforeNormalization() - ->ifTrue(function ($v) { return isset($v['intention']) && isset($v['csrf_token_id']); }) - ->thenInvalid("You should define a value for only one of 'intention' and 'csrf_token_id' on a security firewall. Use 'csrf_token_id' as this replaces 'intention'.") - ->end() - ->beforeNormalization() - ->ifTrue(function ($v) { return isset($v['csrf_provider']); }) - ->then(function ($v) { - @trigger_error("Setting the 'csrf_provider' configuration key on a security firewall is deprecated since version 2.8 and will be removed in 3.0. Use the 'csrf_token_generator' configuration key instead.", E_USER_DEPRECATED); - - $v['csrf_token_generator'] = $v['csrf_provider']; - unset($v['csrf_provider']); - - return $v; - }) - ->end() - ->beforeNormalization() - ->ifTrue(function ($v) { return isset($v['intention']); }) - ->then(function ($v) { - @trigger_error("Setting the 'intention' configuration key on a security firewall is deprecated since version 2.8 and will be removed in 3.0. Use the 'csrf_token_id' key instead.", E_USER_DEPRECATED); - - $v['csrf_token_id'] = $v['intention']; - unset($v['intention']); - - return $v; - }) - ->end() ->children() ->scalarNode('csrf_parameter')->defaultValue('_csrf_token')->end() ->scalarNode('csrf_token_generator')->cannotBeEmpty()->end() diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php index aa81aa8b92f63..021c050b79247 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php @@ -48,21 +48,6 @@ public function addConfiguration(NodeDefinition $node) parent::addConfiguration($node); $node - ->beforeNormalization() - ->ifTrue(function ($v) { return isset($v['csrf_provider']) && isset($v['csrf_token_generator']); }) - ->thenInvalid("You should define a value for only one of 'csrf_provider' and 'csrf_token_generator' on a security firewall. Use 'csrf_token_generator' as this replaces 'csrf_provider'.") - ->end() - ->beforeNormalization() - ->ifTrue(function ($v) { return isset($v['csrf_provider']); }) - ->then(function ($v) { - @trigger_error("Setting the 'csrf_provider' configuration key on a security firewall is deprecated since version 2.8 and will be removed in 3.0. Use the 'csrf_token_generator' configuration key instead.", E_USER_DEPRECATED); - - $v['csrf_token_generator'] = $v['csrf_provider']; - unset($v['csrf_provider']); - - return $v; - }) - ->end() ->children() ->scalarNode('csrf_token_generator')->cannotBeEmpty()->end() ->end() diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php index a00bae6c6f228..2fca459aa29f0 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php +++ b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -111,22 +111,12 @@ public function finishView(FormView $view, FormInterface $form, array $options) */ public function configureOptions(OptionsResolver $resolver) { - // BC clause for the "intention" option - $csrfTokenId = function (Options $options) { - if (null !== $options['intention']) { - @trigger_error('The form option "intention" is deprecated since version 2.8 and will be removed in 3.0. Use "csrf_token_id" instead.', E_USER_DEPRECATED); - } - - return $options['intention']; - }; - $resolver->setDefaults(array( 'csrf_protection' => $this->defaultEnabled, 'csrf_field_name' => $this->defaultFieldName, 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.', 'csrf_token_manager' => $this->defaultTokenManager, - 'csrf_token_id' => $csrfTokenId, - 'intention' => null, // deprecated + 'csrf_token_id' => null, )); } From fa9fd26016d39543e72ef3b23b2ce838bf1171f3 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 28 Oct 2015 23:34:54 +0100 Subject: [PATCH 111/136] [Form] removed unused base test case --- .../ChoiceList/AbstractChoiceListTest.php | 297 ------------------ 1 file changed, 297 deletions(-) delete mode 100644 src/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/AbstractChoiceListTest.php diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/AbstractChoiceListTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/AbstractChoiceListTest.php deleted file mode 100644 index a17d672f62679..0000000000000 --- a/src/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/AbstractChoiceListTest.php +++ /dev/null @@ -1,297 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form\Tests\Extension\Core\ChoiceList; - -/** - * @author Bernhard Schussek - * - * @group legacy - */ -abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase -{ - /** - * @var \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface - */ - protected $list; - - /** - * @var array - */ - protected $choices; - - /** - * @var array - */ - protected $values; - - /** - * @var array - */ - protected $indices; - - /** - * @var array - */ - protected $labels; - - /** - * @var mixed - */ - protected $choice1; - - /** - * @var mixed - */ - protected $choice2; - - /** - * @var mixed - */ - protected $choice3; - - /** - * @var mixed - */ - protected $choice4; - - /** - * @var string - */ - protected $value1; - - /** - * @var string - */ - protected $value2; - - /** - * @var string - */ - protected $value3; - - /** - * @var string - */ - protected $value4; - - /** - * @var int|string - */ - protected $index1; - - /** - * @var int|string - */ - protected $index2; - - /** - * @var int|string - */ - protected $index3; - - /** - * @var int|string - */ - protected $index4; - - /** - * @var string - */ - protected $label1; - - /** - * @var string - */ - protected $label2; - - /** - * @var string - */ - protected $label3; - - /** - * @var string - */ - protected $label4; - - protected function setUp() - { - parent::setUp(); - - $this->list = $this->createChoiceList(); - - $this->choices = $this->getChoices(); - $this->indices = $this->getIndices(); - $this->values = $this->getValues(); - $this->labels = $this->getLabels(); - - // allow access to the individual entries without relying on their indices - reset($this->choices); - reset($this->indices); - reset($this->values); - reset($this->labels); - - for ($i = 1; $i <= 4; ++$i) { - $this->{'choice'.$i} = current($this->choices); - $this->{'index'.$i} = current($this->indices); - $this->{'value'.$i} = current($this->values); - $this->{'label'.$i} = current($this->labels); - - next($this->choices); - next($this->indices); - next($this->values); - next($this->labels); - } - } - - public function testGetChoices() - { - $this->assertSame($this->choices, $this->list->getChoices()); - } - - public function testGetValues() - { - $this->assertSame($this->values, $this->list->getValues()); - } - - public function testGetIndicesForChoices() - { - $choices = array($this->choice1, $this->choice2); - $this->assertSame(array($this->index1, $this->index2), $this->list->getIndicesForChoices($choices)); - } - - public function testGetIndicesForChoicesPreservesKeys() - { - $choices = array(5 => $this->choice1, 8 => $this->choice2); - $this->assertSame(array(5 => $this->index1, 8 => $this->index2), $this->list->getIndicesForChoices($choices)); - } - - public function testGetIndicesForChoicesPreservesOrder() - { - $choices = array($this->choice2, $this->choice1); - $this->assertSame(array($this->index2, $this->index1), $this->list->getIndicesForChoices($choices)); - } - - public function testGetIndicesForChoicesIgnoresNonExistingChoices() - { - $choices = array($this->choice1, $this->choice2, 'foobar'); - $this->assertSame(array($this->index1, $this->index2), $this->list->getIndicesForChoices($choices)); - } - - public function testGetIndicesForChoicesEmpty() - { - $this->assertSame(array(), $this->list->getIndicesForChoices(array())); - } - - public function testGetIndicesForValues() - { - // values and indices are always the same - $values = array($this->value1, $this->value2); - $this->assertSame(array($this->index1, $this->index2), $this->list->getIndicesForValues($values)); - } - - public function testGetIndicesForValuesPreservesKeys() - { - // values and indices are always the same - $values = array(5 => $this->value1, 8 => $this->value2); - $this->assertSame(array(5 => $this->index1, 8 => $this->index2), $this->list->getIndicesForValues($values)); - } - - public function testGetIndicesForValuesPreservesOrder() - { - $values = array($this->value2, $this->value1); - $this->assertSame(array($this->index2, $this->index1), $this->list->getIndicesForValues($values)); - } - - public function testGetIndicesForValuesIgnoresNonExistingValues() - { - $values = array($this->value1, $this->value2, 'foobar'); - $this->assertSame(array($this->index1, $this->index2), $this->list->getIndicesForValues($values)); - } - - public function testGetIndicesForValuesEmpty() - { - $this->assertSame(array(), $this->list->getIndicesForValues(array())); - } - - public function testGetChoicesForValues() - { - $values = array($this->value1, $this->value2); - $this->assertSame(array($this->choice1, $this->choice2), $this->list->getChoicesForValues($values)); - } - - public function testGetChoicesForValuesPreservesKeys() - { - $values = array(5 => $this->value1, 8 => $this->value2); - $this->assertSame(array(5 => $this->choice1, 8 => $this->choice2), $this->list->getChoicesForValues($values)); - } - - public function testGetChoicesForValuesPreservesOrder() - { - $values = array($this->value2, $this->value1); - $this->assertSame(array($this->choice2, $this->choice1), $this->list->getChoicesForValues($values)); - } - - public function testGetChoicesForValuesIgnoresNonExistingValues() - { - $values = array($this->value1, $this->value2, 'foobar'); - $this->assertSame(array($this->choice1, $this->choice2), $this->list->getChoicesForValues($values)); - } - - // https://github.com/symfony/symfony/issues/3446 - public function testGetChoicesForValuesEmpty() - { - $this->assertSame(array(), $this->list->getChoicesForValues(array())); - } - - public function testGetValuesForChoices() - { - $choices = array($this->choice1, $this->choice2); - $this->assertSame(array($this->value1, $this->value2), $this->list->getValuesForChoices($choices)); - } - - public function testGetValuesForChoicesPreservesKeys() - { - $choices = array(5 => $this->choice1, 8 => $this->choice2); - $this->assertSame(array(5 => $this->value1, 8 => $this->value2), $this->list->getValuesForChoices($choices)); - } - - public function testGetValuesForChoicesPreservesOrder() - { - $choices = array($this->choice2, $this->choice1); - $this->assertSame(array($this->value2, $this->value1), $this->list->getValuesForChoices($choices)); - } - - public function testGetValuesForChoicesIgnoresNonExistingChoices() - { - $choices = array($this->choice1, $this->choice2, 'foobar'); - $this->assertSame(array($this->value1, $this->value2), $this->list->getValuesForChoices($choices)); - } - - public function testGetValuesForChoicesEmpty() - { - $this->assertSame(array(), $this->list->getValuesForChoices(array())); - } - - /** - * @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface - */ - abstract protected function createChoiceList(); - - abstract protected function getChoices(); - - abstract protected function getLabels(); - - abstract protected function getValues(); - - abstract protected function getIndices(); -} From 6001644ffe6faa41c036c49b29213ae1ba99fd70 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 28 Nov 2015 17:51:37 +0100 Subject: [PATCH 112/136] [Form] Fix tests and reference usage --- .../Form/Extension/Core/Type/ChoiceType.php | 43 ++++++++++--------- ...AbstractBootstrap3HorizontalLayoutTest.php | 20 ++++----- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index 4822bcf68b571..1465551b906a6 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -238,7 +238,7 @@ public function finishView(FormView $view, FormInterface $form, array $options) */ public function configureOptions(OptionsResolver $resolver) { - $choiceLabels = array(); + $choiceLabels = (object) array('labels' => array()); $choiceListFactory = $this->choiceListFactory; $emptyData = function (Options $options) { @@ -254,9 +254,9 @@ public function configureOptions(OptionsResolver $resolver) }; // BC closure, to be removed in 3.0 - $choicesNormalizer = function (Options $options, $choices) use (&$choiceLabels) { + $choicesNormalizer = function (Options $options, $choices) use ($choiceLabels) { // Unset labels from previous invocations - $choiceLabels = array(); + $choiceLabels->labels = array(); // This closure is irrelevant when "choices_as_values" is set to true if ($options['choices_as_values']) { @@ -269,7 +269,7 @@ public function configureOptions(OptionsResolver $resolver) }; // BC closure, to be removed in 3.0 - $choiceLabel = function (Options $options) use (&$choiceLabels) { + $choiceLabel = function (Options $options) use ($choiceLabels) { // If the choices contain duplicate labels, the normalizer of the // "choices" option stores them in the $choiceLabels variable @@ -277,14 +277,15 @@ public function configureOptions(OptionsResolver $resolver) $options->offsetGet('choices'); // Pick labels from $choiceLabels if available - // Don't invoke count() to avoid creating a copy of the array (yet) - if ($choiceLabels) { + 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 global reference shared by all + // variable (contrary to the $choiceLabels object shared by all // forms) - return function ($choice, $key) use ($choiceLabels) { - return $choiceLabels[$key]; + $labels = $choiceLabels->labels; + + return function ($choice, $key) use ($labels) { + return $labels[$key]; }; } @@ -502,26 +503,26 @@ private function createChoiceListView(ChoiceListInterface $choiceList, array $op * 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 array $choiceLabels The array that receives the choice labels - * indexed by generated keys. - * @param int|null $nextKey The next generated key. + * @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. + * use this method as it may be removed without notice and will be in 3.0. */ - public static function normalizeLegacyChoices(array &$choices, array &$choiceLabels, &$nextKey = 0) + public static function normalizeLegacyChoices(array &$choices, $choiceLabels, &$nextKey = 0) { - foreach ($choices as $choice => &$choiceLabel) { + foreach ($choices as $choice => $choiceLabel) { if (is_array($choiceLabel)) { - self::normalizeLegacyChoices($choiceLabel, $choiceLabels, $nextKey); + $choiceLabel = ''; // Dereference $choices[$choice] + self::normalizeLegacyChoices($choices[$choice], $choiceLabels, $nextKey); continue; } - $choiceLabels[$nextKey] = $choiceLabel; - $choices[$choice] = $nextKey; - ++$nextKey; + $choiceLabels->labels[$nextKey] = $choiceLabel; + $choices[$choice] = $nextKey++; } } } diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php index 1273fa505bd2c..0fcfd60e47c1c 100644 --- a/src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php @@ -15,7 +15,7 @@ abstract class AbstractBootstrap3HorizontalLayoutTest extends AbstractBootstrap3 { public function testLabelOnForm() { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\DateType'); + $form = $this->factory->createNamed('name', 'date'); $view = $form->createView(); $this->renderWidget($view, array('label' => 'foo')); $html = $this->renderLabel($view); @@ -30,7 +30,7 @@ public function testLabelOnForm() public function testLabelDoesNotRenderFieldAttributes() { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $form = $this->factory->createNamed('name', 'text'); $html = $this->renderLabel($form->createView(), null, array( 'attr' => array( 'class' => 'my&class', @@ -47,7 +47,7 @@ public function testLabelDoesNotRenderFieldAttributes() public function testLabelWithCustomAttributesPassedDirectly() { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $form = $this->factory->createNamed('name', 'text'); $html = $this->renderLabel($form->createView(), null, array( 'label_attr' => array( 'class' => 'my&class', @@ -64,7 +64,7 @@ public function testLabelWithCustomAttributesPassedDirectly() public function testLabelWithCustomTextAndCustomAttributesPassedDirectly() { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $form = $this->factory->createNamed('name', 'text'); $html = $this->renderLabel($form->createView(), 'Custom label', array( 'label_attr' => array( 'class' => 'my&class', @@ -82,7 +82,7 @@ public function testLabelWithCustomTextAndCustomAttributesPassedDirectly() public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly() { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, array( + $form = $this->factory->createNamed('name', 'text', null, array( 'label' => 'Custom label', )); $html = $this->renderLabel($form->createView(), null, array( @@ -102,7 +102,7 @@ public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly public function testStartTag() { - $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + $form = $this->factory->create('form', null, array( 'method' => 'get', 'action' => 'http://example.com/directory', )); @@ -114,7 +114,7 @@ public function testStartTag() public function testStartTagWithOverriddenVars() { - $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + $form = $this->factory->create('form', null, array( 'method' => 'put', 'action' => 'http://example.com/directory', )); @@ -129,11 +129,11 @@ public function testStartTagWithOverriddenVars() public function testStartTagForMultipartForm() { - $form = $this->factory->createBuilder('Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + $form = $this->factory->createBuilder('form', null, array( 'method' => 'get', 'action' => 'http://example.com/directory', )) - ->add('file', 'Symfony\Component\Form\Extension\Core\Type\FileType') + ->add('file', 'file') ->getForm(); $html = $this->renderStart($form->createView()); @@ -143,7 +143,7 @@ public function testStartTagForMultipartForm() public function testStartTagWithExtraAttributes() { - $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array( + $form = $this->factory->create('form', null, array( 'method' => 'get', 'action' => 'http://example.com/directory', )); From a3f48a5879beac7e9f69037cf58d0b3806475208 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 28 Nov 2015 19:08:21 +0100 Subject: [PATCH 113/136] [Bridge/Twig] Fix legacy test --- .../FormExtensionBootstrap3HorizontalLayoutTest.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php index bf26dda05be92..833829fd97178 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php @@ -67,11 +67,6 @@ 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) { From 873a5417a8a440f9d4834f0e160fe7954977c9e2 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Sat, 28 Nov 2015 23:15:59 +0100 Subject: [PATCH 114/136] [Console] do not encode backslashes in console default description --- src/Symfony/Component/Console/Descriptor/TextDescriptor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Console/Descriptor/TextDescriptor.php index fffd0e8486a2b..dce6af9f6d77c 100644 --- a/src/Symfony/Component/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Component/Console/Descriptor/TextDescriptor.php @@ -187,10 +187,10 @@ protected function describeApplication(Application $application, array $options 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)); } /** From 3f89b2c71484be0422568e5283ed95a70010a0bb Mon Sep 17 00:00:00 2001 From: Charles Sarrazin Date: Sat, 28 Nov 2015 23:09:12 +0100 Subject: [PATCH 115/136] Marked the Ldap component as internal and removed Ldap constants polyfill --- .../Component/Ldap/Exception/ConnectionException.php | 2 ++ src/Symfony/Component/Ldap/Exception/LdapException.php | 2 ++ src/Symfony/Component/Ldap/LdapClient.php | 2 ++ src/Symfony/Component/Ldap/LdapClientInterface.php | 5 ++--- src/Symfony/Component/Ldap/README.md | 10 +++++++--- .../Provider/LdapBindAuthenticationProvider.php | 2 +- .../Component/Security/Core/User/LdapUserProvider.php | 2 +- 7 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Ldap/Exception/ConnectionException.php b/src/Symfony/Component/Ldap/Exception/ConnectionException.php index 80d9af51ea911..d5023c5d02d7c 100644 --- a/src/Symfony/Component/Ldap/Exception/ConnectionException.php +++ b/src/Symfony/Component/Ldap/Exception/ConnectionException.php @@ -15,6 +15,8 @@ * ConnectionException is throw if binding to ldap can not be established. * * @author Grégoire Pineau + * + * @internal */ class ConnectionException extends \RuntimeException { diff --git a/src/Symfony/Component/Ldap/Exception/LdapException.php b/src/Symfony/Component/Ldap/Exception/LdapException.php index 213625b021b2b..ef3bd929bb852 100644 --- a/src/Symfony/Component/Ldap/Exception/LdapException.php +++ b/src/Symfony/Component/Ldap/Exception/LdapException.php @@ -15,6 +15,8 @@ * LdapException is throw if php ldap module is not loaded. * * @author Grégoire Pineau + * + * @internal */ class LdapException extends \RuntimeException { diff --git a/src/Symfony/Component/Ldap/LdapClient.php b/src/Symfony/Component/Ldap/LdapClient.php index ebb263d5cf0c5..0a8fa22c16c6f 100644 --- a/src/Symfony/Component/Ldap/LdapClient.php +++ b/src/Symfony/Component/Ldap/LdapClient.php @@ -18,6 +18,8 @@ * @author Grégoire Pineau * @author Francis Besset * @author Charles Sarrazin + * + * @internal */ class LdapClient implements LdapClientInterface { diff --git a/src/Symfony/Component/Ldap/LdapClientInterface.php b/src/Symfony/Component/Ldap/LdapClientInterface.php index 65dd03b38f8dc..dcdc0818da10b 100644 --- a/src/Symfony/Component/Ldap/LdapClientInterface.php +++ b/src/Symfony/Component/Ldap/LdapClientInterface.php @@ -18,12 +18,11 @@ * * @author Grégoire Pineau * @author Charles Sarrazin + * + * @internal */ interface LdapClientInterface { - const LDAP_ESCAPE_FILTER = 0x01; - const LDAP_ESCAPE_DN = 0x02; - /** * Return a connection bound to the ldap. * diff --git a/src/Symfony/Component/Ldap/README.md b/src/Symfony/Component/Ldap/README.md index 751ce6ad2511d..6de60f10bbb9e 100644 --- a/src/Symfony/Component/Ldap/README.md +++ b/src/Symfony/Component/Ldap/README.md @@ -1,10 +1,14 @@ Ldap Component -============= +============== A Ldap client for PHP on top of PHP's ldap extension. -This component also provides a stub for the missing -`ldap_escape` function in PHP versions lower than 5.6. +Disclaimer +---------- + +This component is currently marked as internal, as it +still needs some work. Breaking changes will be introduced +in the next minor version of Symfony. Documentation ------------- diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php index fab7d80a284e8..adc42ef3b38f5 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php @@ -74,7 +74,7 @@ protected function checkAuthentication(UserInterface $user, UsernamePasswordToke $password = $token->getCredentials(); try { - $username = $this->ldap->escape($username, '', LdapClientInterface::LDAP_ESCAPE_DN); + $username = $this->ldap->escape($username, '', LDAP_ESCAPE_DN); $dn = str_replace('{username}', $username, $this->dnString); $this->ldap->bind($dn, $password); diff --git a/src/Symfony/Component/Security/Core/User/LdapUserProvider.php b/src/Symfony/Component/Security/Core/User/LdapUserProvider.php index ec699fc022739..988a595f58b00 100644 --- a/src/Symfony/Component/Security/Core/User/LdapUserProvider.php +++ b/src/Symfony/Component/Security/Core/User/LdapUserProvider.php @@ -57,7 +57,7 @@ public function loadUserByUsername($username) { try { $this->ldap->bind($this->searchDn, $this->searchPassword); - $username = $this->ldap->escape($username, '', LdapClientInterface::LDAP_ESCAPE_FILTER); + $username = $this->ldap->escape($username, '', LDAP_ESCAPE_FILTER); $query = str_replace('{username}', $username, $this->defaultSearch); $search = $this->ldap->find($this->baseDn, $query); } catch (ConnectionException $e) { From b272ab569f0f7b4b1e44905d22dbba1c304bcc50 Mon Sep 17 00:00:00 2001 From: WouterJ Date: Sat, 28 Nov 2015 23:24:25 +0100 Subject: [PATCH 116/136] Make sure security.role_hierarchy.roles always exists --- .../Bundle/SecurityBundle/Resources/config/security.xml | 1 + .../Tests/DependencyInjection/SecurityExtensionTest.php | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index a729b421f4b09..bbcae99853aa2 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -47,6 +47,7 @@ Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator Symfony\Component\Security\Core\Authorization\ExpressionLanguage + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index 859f5b4e2d73f..dce30c758b976 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -115,10 +115,7 @@ public function testDisableRoleHierarchyVoter() $container->compile(); - $admDefinition = $container->getDefinition('security.access.decision_manager'); - $registeredVoters = array_map('strval', $admDefinition->getArgument(0)); - - $this->assertNotContains('security.access.role_hierarchy_voter', $registeredVoters); + $this->assertFalse($container->hasDefinition('security.access.role_hierarchy_voter')); } protected function getRawContainer() From 7d9237200fc6eb986f5f3e9fb6740e1ec29bfeaf Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 29 Nov 2015 10:45:59 +0100 Subject: [PATCH 117/136] [Bridge/Doctrine] Fix legacy tests --- .../ChoiceList/AbstractEntityChoiceListCompositeIdTest.php | 4 ++++ .../AbstractEntityChoiceListSingleAssociationToIntIdTest.php | 4 ++++ .../ChoiceList/AbstractEntityChoiceListSingleIntIdTest.php | 4 ++++ .../ChoiceList/AbstractEntityChoiceListSingleStringIdTest.php | 4 ++++ .../Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php | 4 ++++ .../Form/ChoiceList/LoadedEntityChoiceListCompositeIdTest.php | 4 ++++ .../LoadedEntityChoiceListSingleAssociationToIntIdTest.php | 4 ++++ .../Form/ChoiceList/LoadedEntityChoiceListSingleIntIdTest.php | 4 ++++ .../ChoiceList/LoadedEntityChoiceListSingleStringIdTest.php | 4 ++++ .../ChoiceList/UnloadedEntityChoiceListCompositeIdTest.php | 4 ++++ ...nloadedEntityChoiceListCompositeIdWithQueryBuilderTest.php | 4 ++++ .../UnloadedEntityChoiceListSingleAssociationToIntIdTest.php | 4 ++++ ...ChoiceListSingleAssociationToIntIdWithQueryBuilderTest.php | 4 ++++ .../ChoiceList/UnloadedEntityChoiceListSingleIntIdTest.php | 4 ++++ ...nloadedEntityChoiceListSingleIntIdWithQueryBuilderTest.php | 4 ++++ .../ChoiceList/UnloadedEntityChoiceListSingleStringIdTest.php | 4 ++++ ...adedEntityChoiceListSingleStringIdWithQueryBuilderTest.php | 4 ++++ 17 files changed, 68 insertions(+) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListCompositeIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListCompositeIdTest.php index 5980d9c734c54..8bf2fb804f939 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListCompositeIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListCompositeIdTest.php @@ -13,6 +13,10 @@ use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleAssociationToIntIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleAssociationToIntIdTest.php index 7324f721ec340..02e117d7baec4 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleAssociationToIntIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleAssociationToIntIdTest.php @@ -15,6 +15,10 @@ use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity; use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * Test choices generated from an entity with a primary foreign key. * diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleIntIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleIntIdTest.php index 74af66db360e2..85ea10a451c22 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleIntIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleIntIdTest.php @@ -13,6 +13,10 @@ use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleStringIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleStringIdTest.php index 56b4c21319826..1bd5ac8de4695 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleStringIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListSingleStringIdTest.php @@ -13,6 +13,10 @@ use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php index 4f3d54a30f15f..b2d5b4a888b37 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/AbstractEntityChoiceListTest.php @@ -16,6 +16,10 @@ use Doctrine\ORM\Tools\SchemaTool; use Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListCompositeIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListCompositeIdTest.php index a2ee7cdc8a64f..21fa4c56a0b57 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListCompositeIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListCompositeIdTest.php @@ -11,6 +11,10 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek * @group legacy diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleAssociationToIntIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleAssociationToIntIdTest.php index 60e3797bac865..73344be670eba 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleAssociationToIntIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleAssociationToIntIdTest.php @@ -11,6 +11,10 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Premi Giorgio * @author Bernhard Schussek diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleIntIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleIntIdTest.php index f655784004fbb..f64e0cec3e538 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleIntIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleIntIdTest.php @@ -11,6 +11,10 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek * @group legacy diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleStringIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleStringIdTest.php index 629b399ac36a7..d0b04b8013656 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleStringIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/LoadedEntityChoiceListSingleStringIdTest.php @@ -11,6 +11,10 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek * @group legacy diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListCompositeIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListCompositeIdTest.php index 114eee661efe5..305f365075ebe 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListCompositeIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListCompositeIdTest.php @@ -11,6 +11,10 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek * @group legacy diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListCompositeIdWithQueryBuilderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListCompositeIdWithQueryBuilderTest.php index 422295feb1e04..75e36f90cf4e3 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListCompositeIdWithQueryBuilderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListCompositeIdWithQueryBuilderTest.php @@ -14,6 +14,10 @@ use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList; use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek * @group legacy diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleAssociationToIntIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleAssociationToIntIdTest.php index 20267bd020775..ee3afeb89909f 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleAssociationToIntIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleAssociationToIntIdTest.php @@ -11,6 +11,10 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Premi Giorgio * @author Bernhard Schussek diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleAssociationToIntIdWithQueryBuilderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleAssociationToIntIdWithQueryBuilderTest.php index 45ab799585cb6..1b637949bbd09 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleAssociationToIntIdWithQueryBuilderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleAssociationToIntIdWithQueryBuilderTest.php @@ -14,6 +14,10 @@ use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList; use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Premi Giorgio * @author Bernhard Schussek diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleIntIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleIntIdTest.php index 0668c09bdb63f..0197f19b3b1fa 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleIntIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleIntIdTest.php @@ -11,6 +11,10 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek * @group legacy diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleIntIdWithQueryBuilderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleIntIdWithQueryBuilderTest.php index c093782ff0ec7..4e75cf7491cca 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleIntIdWithQueryBuilderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleIntIdWithQueryBuilderTest.php @@ -14,6 +14,10 @@ use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList; use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek * @group legacy diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleStringIdTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleStringIdTest.php index 39363bae26a25..3e9847f0e2eff 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleStringIdTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleStringIdTest.php @@ -11,6 +11,10 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek * @group legacy diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleStringIdWithQueryBuilderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleStringIdWithQueryBuilderTest.php index 23329e80df3c2..51adaabba80db 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleStringIdWithQueryBuilderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/UnloadedEntityChoiceListSingleStringIdWithQueryBuilderTest.php @@ -14,6 +14,10 @@ use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList; use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; +if (!class_exists('Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest')) { + return; +} + /** * @author Bernhard Schussek * @group legacy From beb8525fe4baa35f9885601acb239b448857a59c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 29 Nov 2015 10:55:05 +0100 Subject: [PATCH 118/136] [Bridge/Twig] Fix lowest form dep --- src/Symfony/Bridge/Twig/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 7ce35a9fac00b..77239821df374 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.8|~2.8,>2.8-BETA1", "symfony/http-kernel": "~2.3", "symfony/intl": "~2.3", "symfony/routing": "~2.2", From 613804d0cf8871af0e3c151978f5a92f7c274d37 Mon Sep 17 00:00:00 2001 From: Martin Hujer Date: Sun, 29 Nov 2015 08:43:05 +0100 Subject: [PATCH 119/136] [Yaml] minor CS cleaning --- src/Symfony/Component/Yaml/Parser.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 9dffa2781113e..94a1628afaa49 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -311,7 +311,7 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) if (null === $indentation) { $newIndent = $this->getCurrentLineIndentation(); - $unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem($this->currentLine); + $unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem(); if (!$this->isCurrentLineEmpty() && 0 === $newIndent && !$unindentedEmbedBlock) { throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine); @@ -337,7 +337,7 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) return; } - $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem($this->currentLine); + $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); // Comments must not be removed inside a block scalar $removeCommentsPattern = '~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~'; @@ -350,7 +350,7 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) $removeComments = !preg_match($removeCommentsPattern, $this->currentLine); } - if ($isItUnindentedCollection && !$this->isStringUnIndentedCollectionItem($this->currentLine) && $newIndent === $indent) { + if ($isItUnindentedCollection && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) { $this->moveToPreviousLine(); break; } @@ -653,7 +653,7 @@ private function isNextLineUnIndentedCollection() if ( $this->getCurrentLineIndentation() == $currentIndentation && - $this->isStringUnIndentedCollectionItem($this->currentLine) + $this->isStringUnIndentedCollectionItem() ) { $ret = true; } From 4819a702d7af8dc43a395d7686d5873a6a439d13 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 29 Nov 2015 17:07:42 +0100 Subject: [PATCH 120/136] [Bridge/Doctrine+Ldap] Fix tests --- .../Doctrine/Tests/Form/Type/EntityTypeTest.php | 16 ++++++++-------- .../LdapBindAuthenticationProviderTest.php | 3 +++ .../Core/Tests/User/LdapUserProviderTest.php | 3 +++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index fb78d65ef1813..81d00fc7354ba 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -995,13 +995,13 @@ public function testLoaderCaching() 'property3' => 2, )); - $choiceList1 = $form->get('property1')->getConfig()->getOption('choice_list'); - $choiceList2 = $form->get('property2')->getConfig()->getOption('choice_list'); - $choiceList3 = $form->get('property3')->getConfig()->getOption('choice_list'); + $choiceLoader1 = $form->get('property1')->getConfig()->getOption('choice_loader'); + $choiceLoader2 = $form->get('property2')->getConfig()->getOption('choice_loader'); + $choiceLoader3 = $form->get('property3')->getConfig()->getOption('choice_loader'); - $this->assertInstanceOf('Symfony\Component\Form\ChoiceList\ChoiceListInterface', $choiceList1); - $this->assertSame($choiceList1, $choiceList2); - $this->assertSame($choiceList1, $choiceList3); + $this->assertInstanceOf('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface', $choiceLoader1); + $this->assertSame($choiceLoader1, $choiceLoader2); + $this->assertSame($choiceLoader1, $choiceLoader3); } public function testCacheChoiceLists() @@ -1024,8 +1024,8 @@ public function testCacheChoiceLists() 'choice_label' => 'name', )); - $this->assertInstanceOf('Symfony\Component\Form\ChoiceList\ChoiceListInterface', $field1->getConfig()->getOption('choice_list')); - $this->assertSame($field1->getConfig()->getOption('choice_list'), $field2->getConfig()->getOption('choice_list')); + $this->assertInstanceOf('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface', $field1->getConfig()->getOption('choice_loader')); + $this->assertSame($field1->getConfig()->getOption('choice_loader'), $field2->getConfig()->getOption('choice_loader')); } /** diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php index f1b5c0355ff66..844bceff019cb 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php @@ -16,6 +16,9 @@ use Symfony\Component\Security\Core\User\User; use Symfony\Component\Ldap\Exception\ConnectionException; +/** + * @requires extension ldap + */ class LdapBindAuthenticationProviderTest extends \PHPUnit_Framework_TestCase { /** diff --git a/src/Symfony/Component/Security/Core/Tests/User/LdapUserProviderTest.php b/src/Symfony/Component/Security/Core/Tests/User/LdapUserProviderTest.php index f56648b9f1aaa..9b126e95180f3 100644 --- a/src/Symfony/Component/Security/Core/Tests/User/LdapUserProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/User/LdapUserProviderTest.php @@ -14,6 +14,9 @@ use Symfony\Component\Security\Core\User\LdapUserProvider; use Symfony\Component\Ldap\Exception\ConnectionException; +/** + * @requires extension ldap + */ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase { /** From ef61e5481f736cf3ff67dd661282fcbd2a2c1504 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 29 Nov 2015 17:56:39 +0100 Subject: [PATCH 121/136] Forward compatibility with AbstractLayout* 2.8 tests --- ...xtensionBootstrap3HorizontalLayoutTest.php | 35 +++++++++++++++++++ .../FormExtensionBootstrap3LayoutTest.php | 25 +++++++++++++ .../Extension/FormExtensionDivLayoutTest.php | 25 +++++++++++++ .../FormExtensionTableLayoutTest.php | 25 +++++++++++++ .../Helper/FormHelperDivLayoutTest.php | 25 +++++++++++++ .../Helper/FormHelperTableLayoutTest.php | 25 +++++++++++++ 6 files changed, 160 insertions(+) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php index bf26dda05be92..c7195ab577820 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php @@ -115,4 +115,39 @@ 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/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 + } } From 21270585a64836fc4d8772976c4b5aa5a346d71e Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 29 Nov 2015 19:05:35 +0100 Subject: [PATCH 122/136] [Yaml] look for colon in parsed inline string Looking for a colon in an unquoted mapping value can lead to falsely reported parse errors (e.g. when a comment after the mapping value contains a colon). --- src/Symfony/Component/Yaml/Parser.php | 16 +++++++++------- src/Symfony/Component/Yaml/Tests/ParserTest.php | 10 ++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index e595b404d4ed7..a5c0e674c3d5a 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -473,15 +473,17 @@ private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $ob return $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers)); } - if ('mapping' === $context && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($value, ': ')) { - @trigger_error(sprintf('Using a colon in an unquoted mapping value in line %d is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED); + try { + $parsedValue = Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs); - // to be thrown in 3.0 - // throw new ParseException('A colon cannot be used in an unquoted mapping value.'); - } + if ('mapping' === $context && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) { + @trigger_error(sprintf('Using a colon in an unquoted mapping value in line %d is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED); - try { - return Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs); + // to be thrown in 3.0 + // throw new ParseException('A colon cannot be used in an unquoted mapping value.'); + } + + return $parsedValue; } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index e4c02d77b7979..d5a4c35b85cbf 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -808,6 +808,16 @@ public function testColonInMappingValueException() restore_error_handler(); } + + public function testColonInMappingValueExceptionNotTriggeredByColonInComment() + { + $yaml = <<assertSame(array('foo' => array('bar' => 'foobar')), $this->parser->parse($yaml)); + } } class B From 7e89345a0d6d5e13467797c0180d8963512d8b09 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Sun, 29 Nov 2015 22:12:04 +0100 Subject: [PATCH 123/136] [Form] Added getBlockPrefix() to ResolvedFormTypeInterface --- .../Proxy/ResolvedTypeDataCollectorProxy.php | 10 +--------- src/Symfony/Component/Form/ResolvedFormType.php | 4 +--- .../Component/Form/ResolvedFormTypeInterface.php | 7 +++++++ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php index 65430f1d222b0..ede4873be3843 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php @@ -43,20 +43,12 @@ public function __construct(ResolvedFormTypeInterface $proxiedType, FormDataColl $this->dataCollector = $dataCollector; } - /** - * {@inheritdoc} - */ - public function getName() - { - return $this->proxiedType->getName(); - } - /** * {@inheritdoc} */ public function getBlockPrefix() { - return method_exists($this->proxiedType, 'getBlockPrefix') ? $this->proxiedType->getBlockPrefix() : $this->getName(); + return $this->proxiedType->getBlockPrefix(); } /** diff --git a/src/Symfony/Component/Form/ResolvedFormType.php b/src/Symfony/Component/Form/ResolvedFormType.php index 02b101d390fa4..42b0352a88129 100644 --- a/src/Symfony/Component/Form/ResolvedFormType.php +++ b/src/Symfony/Component/Form/ResolvedFormType.php @@ -56,9 +56,7 @@ public function __construct(FormTypeInterface $innerType, array $typeExtensions } /** - * Returns the prefix of the template block name for this type. - * - * @return string The prefix of the template block name + * {@inheritdoc} */ public function getBlockPrefix() { diff --git a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php index f496cdc578899..592f459e25168 100644 --- a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php +++ b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php @@ -20,6 +20,13 @@ */ interface ResolvedFormTypeInterface { + /** + * Returns the prefix of the template block name for this type. + * + * @return string The prefix of the template block name + */ + public function getBlockPrefix(); + /** * Returns the parent type. * From 9afbea27e9f8b7d9a976df14a0e40ee88d7214de Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 30 Nov 2015 09:52:07 +0100 Subject: [PATCH 124/136] [Process] Fix signaling/stopping logic on Windows --- src/Symfony/Component/Process/Process.php | 33 +++++++++++------------ 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 1675ad33994aa..676cddc67eea4 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -647,22 +647,14 @@ public function getStatus() * Stops the process. * * @param int|float $timeout The timeout in seconds - * @param int $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL + * @param int $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9) * * @return int The exit-code of the process - * - * @throws RuntimeException if the process got signaled */ public function stop($timeout = 10, $signal = null) { $timeoutMicro = microtime(true) + $timeout; if ($this->isRunning()) { - if ('\\' === DIRECTORY_SEPARATOR && !$this->isSigchildEnabled()) { - exec(sprintf('taskkill /F /T /PID %d 2>&1', $this->getPid()), $output, $exitCode); - if ($exitCode > 0) { - throw new RuntimeException('Unable to kill the process'); - } - } // given `SIGTERM` may not be defined and that `proc_terminate` uses the constant value and not the constant itself, we use the same here $this->doSignal(15, false); do { @@ -670,13 +662,9 @@ public function stop($timeout = 10, $signal = null) } while ($this->isRunning() && microtime(true) < $timeoutMicro); if ($this->isRunning() && !$this->isSigchildEnabled()) { - if (null !== $signal || defined('SIGKILL')) { - // avoid exception here : - // process is supposed to be running, but it might have stop - // just after this line. - // in any case, let's silently discard the error, we can not do anything - $this->doSignal($signal ?: SIGKILL, false); - } + // Avoid exception here: process is supposed to be running, but it might have stopped just + // after this line. In any case, let's silently discard the error, we cannot do anything. + $this->doSignal($signal ?: 9, false); } } @@ -1200,7 +1188,18 @@ private function doSignal($signal, $throwException) return false; } - if (true !== @proc_terminate($this->process, $signal)) { + if ('\\' === DIRECTORY_SEPARATOR) { + exec(sprintf('taskkill /F /T /PID %d 2>&1', $this->getPid()), $output, $exitCode); + if ($exitCode) { + if ($throwException) { + throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output))); + } + + return false; + } + } + + if (true !== @proc_terminate($this->process, $signal) && '\\' !== DIRECTORY_SEPARATOR) { if ($throwException) { throw new RuntimeException(sprintf('Error while sending signal `%s`.', $signal)); } From 9054bdf3ac075f615663e9d9e8702a8c34ea1be0 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 30 Nov 2015 11:00:36 +0100 Subject: [PATCH 125/136] allow arbitrary types in VoterInterface::vote() --- UPGRADE-3.0.md | 4 ++++ .../Core/Authorization/Voter/AuthenticatedVoter.php | 2 +- .../Core/Authorization/Voter/ExpressionVoter.php | 12 ++++++------ .../Security/Core/Authorization/Voter/RoleVoter.php | 2 +- .../Security/Core/Authorization/Voter/Voter.php | 6 +++--- .../Core/Authorization/Voter/VoterInterface.php | 4 ++-- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index c471e64dd9efd..f8661813a9f59 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -615,6 +615,10 @@ UPGRADE FROM 2.x to 3.0 ### Security + * The `vote()` method from the `VoterInterface` was changed to now accept arbitrary + types and not only objects. You can rely on the new abstract `Voter` class introduced + in 2.8 to ease integrating your own voters. + * The `Resources/` directory was moved to `Core/Resources/` * The `key` settings of `anonymous`, `remember_me` and `http_digest` are diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php index 762e9bc50d2bd..dc1407b9435db 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php @@ -44,7 +44,7 @@ public function __construct(AuthenticationTrustResolverInterface $authentication /** * {@inheritdoc} */ - public function vote(TokenInterface $token, $object, array $attributes) + public function vote(TokenInterface $token, $subject, array $attributes) { $result = VoterInterface::ACCESS_ABSTAIN; foreach ($attributes as $attribute) { diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php index 084285624be38..c85ad9c50de8e 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php @@ -52,7 +52,7 @@ public function addExpressionLanguageProvider(ExpressionFunctionProviderInterfac /** * {@inheritdoc} */ - public function vote(TokenInterface $token, $object, array $attributes) + public function vote(TokenInterface $token, $subject, array $attributes) { $result = VoterInterface::ACCESS_ABSTAIN; $variables = null; @@ -62,7 +62,7 @@ public function vote(TokenInterface $token, $object, array $attributes) } if (null === $variables) { - $variables = $this->getVariables($token, $object); + $variables = $this->getVariables($token, $subject); } $result = VoterInterface::ACCESS_DENIED; @@ -74,7 +74,7 @@ public function vote(TokenInterface $token, $object, array $attributes) return $result; } - private function getVariables(TokenInterface $token, $object) + private function getVariables(TokenInterface $token, $subject) { if (null !== $this->roleHierarchy) { $roles = $this->roleHierarchy->getReachableRoles($token->getRoles()); @@ -85,7 +85,7 @@ private function getVariables(TokenInterface $token, $object) $variables = array( 'token' => $token, 'user' => $token->getUser(), - 'object' => $object, + 'object' => $subject, 'roles' => array_map(function ($role) { return $role->getRole(); }, $roles), 'trust_resolver' => $this->trustResolver, ); @@ -93,8 +93,8 @@ private function getVariables(TokenInterface $token, $object) // this is mainly to propose a better experience when the expression is used // in an access control rule, as the developer does not know that it's going // to be handled by this voter - if ($object instanceof Request) { - $variables['request'] = $object; + if ($subject instanceof Request) { + $variables['request'] = $subject; } return $variables; diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php index 74e2363ed283e..b017c81334a5d 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php @@ -35,7 +35,7 @@ public function __construct($prefix = 'ROLE_') /** * {@inheritdoc} */ - public function vote(TokenInterface $token, $object, array $attributes) + public function vote(TokenInterface $token, $subject, array $attributes) { $result = VoterInterface::ACCESS_ABSTAIN; $roles = $this->extractRoles($token); diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php index 267403418c3a7..ba4d6af5a8b56 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php @@ -24,20 +24,20 @@ abstract class Voter implements VoterInterface /** * {@inheritdoc} */ - public function vote(TokenInterface $token, $object, array $attributes) + public function vote(TokenInterface $token, $subject, array $attributes) { // abstain vote by default in case none of the attributes are supported $vote = self::ACCESS_ABSTAIN; foreach ($attributes as $attribute) { - if (!$this->supports($attribute, $object)) { + if (!$this->supports($attribute, $subject)) { continue; } // as soon as at least one attribute is supported, default is to deny access $vote = self::ACCESS_DENIED; - if ($this->voteOnAttribute($attribute, $object, $token)) { + if ($this->voteOnAttribute($attribute, $subject, $token)) { // grant access as soon as at least one attribute returns a positive response return self::ACCESS_GRANTED; } diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php b/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php index 1697eaf74afc1..4bb73672c069d 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/VoterInterface.php @@ -31,10 +31,10 @@ interface VoterInterface * ACCESS_GRANTED, ACCESS_DENIED, or ACCESS_ABSTAIN. * * @param TokenInterface $token A TokenInterface instance - * @param object|null $object The object to secure + * @param mixed $subject The subject to secure * @param array $attributes An array of attributes associated with the method being invoked * * @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED */ - public function vote(TokenInterface $token, $object, array $attributes); + public function vote(TokenInterface $token, $subject, array $attributes); } From 346943e2f51fa491a58ca1a2185e5987797f8346 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 30 Nov 2015 11:54:38 +0100 Subject: [PATCH 126/136] add subject variable to expression context --- UPGRADE-2.8.md | 3 +++ .../Security/Core/Authorization/Voter/ExpressionVoter.php | 1 + 2 files changed, 4 insertions(+) diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index 797e2a5015b0a..883ef576d328a 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -448,6 +448,9 @@ FrameworkBundle Security -------- + * The `object` variable passed to expressions evaluated by the `ExpressionVoter` + is deprecated. Instead use the new `subject` variable. + * The `AbstractVoter` class was deprecated. Instead, extend the `Voter` class and move your voting logic in the `supports($attribute, $subject)` and `voteOnAttribute($attribute, $object, TokenInterface $token)` methods. diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php index 98b8f50f15d03..96a7ece998cce 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php @@ -102,6 +102,7 @@ private function getVariables(TokenInterface $token, $object) 'token' => $token, 'user' => $token->getUser(), 'object' => $object, + 'subject' => $object, 'roles' => array_map(function ($role) { return $role->getRole(); }, $roles), 'trust_resolver' => $this->trustResolver, ); From 0a54d098a9c72a6a82aa6fd49f62fc260be84657 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Mon, 30 Nov 2015 14:33:56 +0100 Subject: [PATCH 127/136] Fix BC for the default root form name The block prefix is used, to match the previous behavior when using a custom block prefix. --- src/Symfony/Component/Form/FormFactory.php | 22 ++++++-- .../Component/Form/Tests/FormFactoryTest.php | 51 ++++++++++++++++--- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index e00d8ab4fad29..5e92baa64f925 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -74,15 +74,29 @@ public function createBuilder($type = 'Symfony\Component\Form\Extension\Core\Typ $typeName = $type->getName(); } } elseif ($type instanceof FormTypeInterface) { - // BC - $typeName = $type->getName(); + if (method_exists($type, 'getBlockPrefix')) { + // As of Symfony 3.0, the block prefix of the type is used as + // default name + $name = $type->getBlockPrefix(); + } else { + // BC + $typeName = $type->getName(); + } } elseif (is_string($type)) { - // BC - $typeName = $type; + $resolvedType = $this->registry->getType($type); + if (method_exists($resolvedType, 'getBlockPrefix')) { + // As of Symfony 3.0, the block prefix of the type is used as + // default name + $name = $resolvedType->getBlockPrefix(); + } else { + // BC + $typeName = $type; + } } else { throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface'); } + // BC when there is no block prefix if (null === $name) { if (false === strpos($typeName, '\\')) { // No FQCN - leave unchanged for BC diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index 1f65c3c0c1499..0ec0b40590e78 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -302,13 +302,52 @@ public function testCreateThrowsUnderstandableException() $this->factory->create(new \stdClass()); } + public function testCreateUsesBlockPrefixIfTypeGivenAsString() + { + $options = array('a' => '1', 'b' => '2'); + $resolvedOptions = array('a' => '2', 'b' => '3'); + + // the interface does not have the method, so use the real class + $resolvedType = $this->getMockBuilder('Symfony\Component\Form\ResolvedFormType') + ->disableOriginalConstructor() + ->getMock(); + + $resolvedType->expects($this->any()) + ->method('getBlockPrefix') + ->willReturn('TYPE_PREFIX'); + + $this->registry->expects($this->any()) + ->method('getType') + ->with('TYPE') + ->will($this->returnValue($resolvedType)); + + $resolvedType->expects($this->once()) + ->method('createBuilder') + ->with($this->factory, 'TYPE_PREFIX', $options) + ->will($this->returnValue($this->builder)); + + $this->builder->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($resolvedOptions)); + + $resolvedType->expects($this->once()) + ->method('buildForm') + ->with($this->builder, $resolvedOptions); + + $this->builder->expects($this->once()) + ->method('getForm') + ->will($this->returnValue('FORM')); + + $this->assertSame('FORM', $this->factory->create('TYPE', null, $options)); + } + public function testCreateUsesTypeNameIfTypeGivenAsString() { $options = array('a' => '1', 'b' => '2'); $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); - $this->registry->expects($this->once()) + $this->registry->expects($this->any()) ->method('getType') ->with('TYPE') ->will($this->returnValue($resolvedType)); @@ -339,7 +378,7 @@ public function testCreateStripsNamespaceOffTypeName() $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); - $this->registry->expects($this->once()) + $this->registry->expects($this->any()) ->method('getType') ->with('Vendor\Name\Space\UserForm') ->will($this->returnValue($resolvedType)); @@ -370,7 +409,7 @@ public function testLegacyCreateStripsNamespaceOffTypeNameAccessByFQCN() $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); - $this->registry->expects($this->once()) + $this->registry->expects($this->any()) ->method('getType') ->with('userform') ->will($this->returnValue($resolvedType)); @@ -401,7 +440,7 @@ public function testCreateStripsTypeSuffixOffTypeName() $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); - $this->registry->expects($this->once()) + $this->registry->expects($this->any()) ->method('getType') ->with('Vendor\Name\Space\UserType') ->will($this->returnValue($resolvedType)); @@ -432,7 +471,7 @@ public function testCreateDoesNotStripTypeSuffixIfResultEmpty() $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); - $this->registry->expects($this->once()) + $this->registry->expects($this->any()) ->method('getType') ->with('Vendor\Name\Space\Type') ->will($this->returnValue($resolvedType)); @@ -463,7 +502,7 @@ public function testCreateConvertsTypeToUnderscoreSyntax() $resolvedOptions = array('a' => '2', 'b' => '3'); $resolvedType = $this->getMockResolvedType(); - $this->registry->expects($this->once()) + $this->registry->expects($this->any()) ->method('getType') ->with('Vendor\Name\Space\MyProfileHTMLType') ->will($this->returnValue($resolvedType)); From fd8e8829020cd86b40b1ace92ad3e67961c220a5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 30 Nov 2015 16:00:22 +0100 Subject: [PATCH 128/136] [Form] Cleanup --- src/Symfony/Component/Form/FormFactory.php | 47 ++++++------------- .../Component/Form/Tests/FormFactoryTest.php | 18 +++++++ 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index 5e92baa64f925..f7160d550742d 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -62,48 +62,29 @@ public function createForProperty($class, $property, $data = null, array $option public function createBuilder($type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = array()) { $name = null; - $typeName = null; if ($type instanceof ResolvedFormTypeInterface) { - if (method_exists($type, 'getBlockPrefix')) { - // As of Symfony 3.0, the block prefix of the type is used as - // default name - $name = $type->getBlockPrefix(); - } else { - // BC - $typeName = $type->getName(); - } + $typeObject = $type; } elseif ($type instanceof FormTypeInterface) { - if (method_exists($type, 'getBlockPrefix')) { - // As of Symfony 3.0, the block prefix of the type is used as - // default name - $name = $type->getBlockPrefix(); - } else { - // BC - $typeName = $type->getName(); - } + $typeObject = $type; } elseif (is_string($type)) { - $resolvedType = $this->registry->getType($type); - if (method_exists($resolvedType, 'getBlockPrefix')) { - // As of Symfony 3.0, the block prefix of the type is used as - // default name - $name = $resolvedType->getBlockPrefix(); - } else { - // BC - $typeName = $type; - } + $typeObject = $this->registry->getType($type); + $name = $type; } else { throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface'); } - // BC when there is no block prefix - if (null === $name) { - if (false === strpos($typeName, '\\')) { - // No FQCN - leave unchanged for BC - $name = $typeName; - } else { + if (method_exists($typeObject, 'getBlockPrefix')) { + // As of Symfony 3.0, the block prefix of the type is used as default name + $name = $typeObject->getBlockPrefix(); + } else { + // BC when there is no block prefix + if (null === $name) { + $name = $typeObject->getName(); + } + if (false !== strpos($name, '\\')) { // FQCN - $name = StringUtil::fqcnToBlockPrefix($typeName); + $name = StringUtil::fqcnToBlockPrefix($name); } } diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index 0ec0b40590e78..32b6e73394c7c 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -341,6 +341,9 @@ public function testCreateUsesBlockPrefixIfTypeGivenAsString() $this->assertSame('FORM', $this->factory->create('TYPE', null, $options)); } + /** + * @group legacy + */ public function testCreateUsesTypeNameIfTypeGivenAsString() { $options = array('a' => '1', 'b' => '2'); @@ -372,6 +375,9 @@ public function testCreateUsesTypeNameIfTypeGivenAsString() $this->assertSame('FORM', $this->factory->create('TYPE', null, $options)); } + /** + * @group legacy + */ public function testCreateStripsNamespaceOffTypeName() { $options = array('a' => '1', 'b' => '2'); @@ -403,6 +409,9 @@ public function testCreateStripsNamespaceOffTypeName() $this->assertSame('FORM', $this->factory->create('Vendor\Name\Space\UserForm', null, $options)); } + /** + * @group legacy + */ public function testLegacyCreateStripsNamespaceOffTypeNameAccessByFQCN() { $options = array('a' => '1', 'b' => '2'); @@ -434,6 +443,9 @@ public function testLegacyCreateStripsNamespaceOffTypeNameAccessByFQCN() $this->assertSame('FORM', $this->factory->create('userform', null, $options)); } + /** + * @group legacy + */ public function testCreateStripsTypeSuffixOffTypeName() { $options = array('a' => '1', 'b' => '2'); @@ -465,6 +477,9 @@ public function testCreateStripsTypeSuffixOffTypeName() $this->assertSame('FORM', $this->factory->create('Vendor\Name\Space\UserType', null, $options)); } + /** + * @group legacy + */ public function testCreateDoesNotStripTypeSuffixIfResultEmpty() { $options = array('a' => '1', 'b' => '2'); @@ -496,6 +511,9 @@ public function testCreateDoesNotStripTypeSuffixIfResultEmpty() $this->assertSame('FORM', $this->factory->create('Vendor\Name\Space\Type', null, $options)); } + /** + * @group legacy + */ public function testCreateConvertsTypeToUnderscoreSyntax() { $options = array('a' => '1', 'b' => '2'); From 5be63e5ad03be56f74553b84392064097d469306 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 30 Nov 2015 18:25:03 +0100 Subject: [PATCH 129/136] updated CHANGELOG for 2.8.0 --- CHANGELOG-2.8.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index f36da583f128a..34168508a3cb1 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,57 @@ in 2.8 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.8.0...v2.8.1 +* 2.8.0 (2015-11-30) + + * bug #16758 Fix BC for the default root form name (stof) + * bug #16753 [Process] Fix signaling/stopping logic on Windows (nicolas-grekas) + * feature #16755 [Security] add subject variable to expression context (xabbuh) + * bug #16642 [DI][autowiring] throw exception when many services use the same class. (aitboudad) + * bug #16745 [Yaml] look for colon in parsed inline string (xabbuh) + * bug #16733 [Console] do not encode backslashes in console default description (Tobion) + * feature #16735 [WIP] [Ldap] Marked the Ldap component as internal (csarrazi) + * bug #16734 Make sure security.role_hierarchy.roles always exists (WouterJ) + * feature #16722 [Security][SecurityBundle] Use csrf_token_id instead of deprecated intention (jakzal) + * 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) + * feature #16709 [Bridge\PhpUnit] Display the stack trace of a deprecation on-demand (nicolas-grekas) + * bug #16704 [Form+SecurityBundle] Trigger deprecation for csrf_provider+intention options (nicolas-grekas) + * feature #16706 [HttpFoundation] Deprecate $deep parameter on ParameterBag (nicolas-grekas) + * bug #16705 [Form] Deprecated setting "choices_as_values" to "false" (webmozart) + * feature #16690 [Form] Deprecated ArrayKeyChoiceList (webmozart) + * feature #16687 [Form] Deprecated TimezoneType::getTimezones() (webmozart) + * bug #16681 [Form] Deprecated setting "choices_as_values" to "false" (webmozart) + * bug #16695 [SecurityBundle] disable the init:acl command if ACL is not used (Tobion) + * bug #16677 [Form] Fixed wrong usages of the "text" type (webmozart) + * bug #16679 [Form] Disabled view data validation if "data_class" is set to null (webmozart) + * bug #16621 [Console] Fix bug with $output overloading (WouterJ) + * feature #16601 [Security] Deprecate "AbstractVoter" in favor of "Voter" (nicolas-grekas, lyrixx) + * 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 #16498 fix unused variable warning (eventhorizonpl) + * feature #16031 [Translation][Form] Do not translate form labels and placeholders when 'translation_domain' is false (Restless-ET) + * bug #16651 [Debug] Ensure class declarations are loaded only once (nicolas-grekas) + * 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 #16633 [Filesystem] Fixed failing test due to tempdir symlink (toretto460) + * bug #16609 [HttpKernel] Don't reset on shutdown but in FrameworkBundle/Test/KernelTestCase (nicolas-grekas) + * bug #16477 [Routing] Changing RouteCollectionBuilder::import() behavior to add to the builder (weaverryan) + * bug #16588 Sent out a status text for unknown HTTP headers. (dawehner) + * bug #16295 [DependencyInjection] Unescape parameters for all types of injection (Nicofuma) + * bug #16377 [WebProfilerBundle] Fix minitoolbar height (rvanlaak) + * bug #16585 Add support for HTTP status code 418 back (dawehner) + * bug #16574 [Process] Fix PhpProcess with phpdbg runtime (nicolas-grekas) + * bug #16581 Fix call to undefined function json_last_error_message (dawehner) + * bug #16573 [FrameworkBundle] Fix PropertyInfo extractor namespace in framework bundle (jvasseur) + * bug #16578 [Console] Fix bug in windows detection (kbond) + * bug #16546 [Serializer] ObjectNormalizer: don't serialize static methods and props (dunglas) + * 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) + * 2.8.0-BETA1 (2015-11-16) * feature #16156 [Filesystem] Changed dumpFile to allow dumping to streams (markchalloner, pierredup) From a62dbb8e7fd57409a7917b1bc7a891d24ebc7b23 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 30 Nov 2015 18:25:56 +0100 Subject: [PATCH 130/136] updated VERSION for 2.8.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 2b573fe860471..c53d4f43a962c 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.0-DEV'; + const VERSION = '2.8.0'; const VERSION_ID = 20800; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From 2ca214fc019ee92d424c13c0e77529ff7f1a06ef Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 30 Nov 2015 21:37:20 +0100 Subject: [PATCH 131/136] bumped Symfony version to 2.8.1 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index c53d4f43a962c..b411d6b0aba2b 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.0'; - const VERSION_ID = 20800; + const VERSION = '2.8.1-DEV'; + const VERSION_ID = 20801; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; - const RELEASE_VERSION = 0; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 1; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From bc642fb6330958a8db383fcbc54b8d23892b2cc9 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 30 Nov 2015 21:53:55 +0100 Subject: [PATCH 132/136] fixed EOM/EOL dates --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index b411d6b0aba2b..f6d88e2e93595 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -66,8 +66,8 @@ abstract class Kernel implements KernelInterface, TerminableInterface const RELEASE_VERSION = 1; const EXTRA_VERSION = 'DEV'; - const END_OF_MAINTENANCE = '05/2018'; - const END_OF_LIFE = '05/2019'; + const END_OF_MAINTENANCE = '11/2018'; + const END_OF_LIFE = '11/2019'; /** * Constructor. From ee739ae2309bc535e41b0d349e594b4027653da1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 30 Nov 2015 21:54:22 +0100 Subject: [PATCH 133/136] fixed EOM/EOL dates --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 6edb6c95b021b..4418b6824d25a 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -66,8 +66,8 @@ abstract class Kernel implements KernelInterface, TerminableInterface const RELEASE_VERSION = 0; const EXTRA_VERSION = 'DEV'; - const END_OF_MAINTENANCE = '05/2018'; - const END_OF_LIFE = '05/2019'; + const END_OF_MAINTENANCE = '07/2016'; + const END_OF_LIFE = '01/2017'; /** * Constructor. From af74da51b3908be1575cc650eb00e2d8ec9cc834 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 30 Nov 2015 21:58:04 +0100 Subject: [PATCH 134/136] updated CHANGELOG for 3.0.0 --- CHANGELOG-3.0.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index a3ff97d0a51b3..f22b7092d6510 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -7,6 +7,10 @@ in 3.0 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.0.0...v3.0.1 +* 3.0.0 (2015-11-30) + + * + * 3.0.0-BETA1 (2015-11-16) * feature #16516 Remove some more legacy code (nicolas-grekas) From a882401dd236ad21233aa2ad0a8676735b85ceef Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 30 Nov 2015 21:58:52 +0100 Subject: [PATCH 135/136] updated CHANGELOG for 3.0.0 --- CHANGELOG-3.0.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index f22b7092d6510..fae727429ae15 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -9,7 +9,67 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c * 3.0.0 (2015-11-30) - * + * bug #16758 Fix BC for the default root form name (stof) + * feature #16754 [Security] allow arbitrary types in VoterInterface::vote() (xabbuh) + * bug #16753 [Process] Fix signaling/stopping logic on Windows (nicolas-grekas) + * feature #16755 [Security] add subject variable to expression context (xabbuh) + * bug #16642 [DI][autowiring] throw exception when many services use the same class. (aitboudad) + * bug #16745 [Yaml] look for colon in parsed inline string (xabbuh) + * bug #16733 [Console] do not encode backslashes in console default description (Tobion) + * feature #16735 [WIP] [Ldap] Marked the Ldap component as internal (csarrazi) + * bug #16734 Make sure security.role_hierarchy.roles always exists (WouterJ) + * feature #16723 [Form] remove deprecated CSRF options (xabbuh) + * feature #16725 [Form] Removed useless code (webmozart) + * feature #16724 Added getBlockPrefix to FormTypeInterface (WouterJ) + * feature #16722 [Security][SecurityBundle] Use csrf_token_id instead of deprecated intention (jakzal) + * feature #16727 [Form] remove deprecated getTimezones() method (xabbuh) + * 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) + * feature #16715 [Form] Remove choices_as_values option on ChoiceType (nicolas-grekas) + * feature #16692 [Form] Drop remaing CsrfProviderAdapter/Interface mentions (nicolas-grekas) + * feature #16719 [Security] remove deprecated HTTP digest auth key (xabbuh) + * bug #16685 [Form] Fixed: Duplicate choice labels are remembered when using "choices_as_values" = false (webmozart) + * feature #16709 [Bridge\PhpUnit] Display the stack trace of a deprecation on-demand (nicolas-grekas) + * bug #16704 [Form+SecurityBundle] Trigger deprecation for csrf_provider+intention options (nicolas-grekas) + * feature #16629 [HttpFoundation] Remove deprecated class method parameter (belka-ew) + * feature #16706 [HttpFoundation] Deprecate $deep parameter on ParameterBag (nicolas-grekas) + * bug #16705 [Form] Deprecated setting "choices_as_values" to "false" (webmozart) + * feature #16690 [Form] Deprecated ArrayKeyChoiceList (webmozart) + * feature #16687 [Form] Deprecated TimezoneType::getTimezones() (webmozart) + * bug #16681 [Form] Deprecated setting "choices_as_values" to "false" (webmozart) + * feature #16694 [SecurityBundle] make ACL an optional dependency (Tobion) + * bug #16695 [SecurityBundle] disable the init:acl command if ACL is not used (Tobion) + * bug #16677 [Form] Fixed wrong usages of the "text" type (webmozart) + * bug #16679 [Form] Disabled view data validation if "data_class" is set to null (webmozart) + * bug #16621 [Console] Fix bug with $output overloading (WouterJ) + * feature #16601 [Security] Deprecate "AbstractVoter" in favor of "Voter" (nicolas-grekas, lyrixx) + * 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 #16615 fix type assignement (rande) + * bug #16386 Bug #16343 [Router] Too many Routes ? (jelte) + * bug #16498 fix unused variable warning (eventhorizonpl) + * feature #16031 [Translation][Form] Do not translate form labels and placeholders when 'translation_domain' is false (Restless-ET) + * bug #16651 [Debug] Ensure class declarations are loaded only once (nicolas-grekas) + * feature #16637 Removed unneeded polyfill (GrahamCampbell) + * security #16631 n/a (xabbuh) + * security #16630 n/a (xabbuh) + * bug #16633 [Filesystem] Fixed failing test due to tempdir symlink (toretto460) + * bug #16607 [HttpFoundation] Delete not existing session handler proxy member (belka-ew) + * bug #16609 [HttpKernel] Don't reset on shutdown but in FrameworkBundle/Test/KernelTestCase (nicolas-grekas) + * bug #16477 [Routing] Changing RouteCollectionBuilder::import() behavior to add to the builder (weaverryan) + * bug #16588 Sent out a status text for unknown HTTP headers. (dawehner) + * bug #16295 [DependencyInjection] Unescape parameters for all types of injection (Nicofuma) + * bug #16377 [WebProfilerBundle] Fix minitoolbar height (rvanlaak) + * bug #16585 Add support for HTTP status code 418 back (dawehner) + * bug #16574 [Process] Fix PhpProcess with phpdbg runtime (nicolas-grekas) + * bug #16581 Fix call to undefined function json_last_error_message (dawehner) + * bug #16573 [FrameworkBundle] Fix PropertyInfo extractor namespace in framework bundle (jvasseur) + * bug #16578 [Console] Fix bug in windows detection (kbond) + * bug #16546 [Serializer] ObjectNormalizer: don't serialize static methods and props (dunglas) + * 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) * 3.0.0-BETA1 (2015-11-16) From 72c6b836c9f22cb4efb97a1583026935a471487d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 30 Nov 2015 21:59:24 +0100 Subject: [PATCH 136/136] updated VERSION for 3.0.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 4418b6824d25a..94754bf47b4b0 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '3.0.0-DEV'; + const VERSION = '3.0.0'; const VERSION_ID = 30000; const MAJOR_VERSION = 3; const MINOR_VERSION = 0; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '07/2016'; const END_OF_LIFE = '01/2017';