diff --git a/.composer/composer.json b/.composer/composer.json index 655ee13805..d69e9f7626 100644 --- a/.composer/composer.json +++ b/.composer/composer.json @@ -1,6 +1,5 @@ { "require": { - "php": ">=5.3.7", - "hirak/prestissimo": "^0.1.15" + "hirak/prestissimo": "^0.1.18" } } diff --git a/.composer/composer.lock b/.composer/composer.lock index 8e037ebb4a..7027e21d9a 100644 --- a/.composer/composer.lock +++ b/.composer/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "aa7aa2d143fd85800595242996021ada", - "content-hash": "51e9161b78dda1fe149a9e9c106be90b", + "hash": "e02685ff7d2409d34fa87e306fc86ec5", + "content-hash": "2854c05c76a78113c693dbbdd3f9c518", "packages": [ { "name": "hirak/prestissimo", @@ -65,8 +65,6 @@ "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, - "platform": { - "php": ">=5.3.7" - }, + "platform": [], "platform-dev": [] } diff --git a/.travis.yml b/.travis.yml index d82550017d..3918b9c4d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,44 +35,46 @@ cache: services: mongodb before_install: + - PHP=$TRAVIS_PHP_VERSION # Matrix lines for intermediate PHP versions are skipped for pull requests - - if [[ ! $deps && ! $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && $TRAVIS_PHP_VERSION != hhvm && $TRAVIS_PULL_REQUEST != false ]]; then deps=skip; fi; + - if [[ ! $deps && ! $PHP = ${MIN_PHP%.*} && $PHP != hhvm && $TRAVIS_PULL_REQUEST != false ]]; then deps=skip; skip=1; fi # A sigchild-enabled-PHP is used to test the Process component on the lowest PHP matrix line - - if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then wget http://museum.php.net/php5/php-$MIN_PHP.tar.bz2 -O - | tar -xj; (cd php-$MIN_PHP; ./configure --enable-sigchild --enable-pcntl; make -j2); fi; - - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; else INI_FILE=/etc/hhvm/php.ini; fi; - - echo memory_limit = -1 >> $INI_FILE - - echo session.gc_probability = 0 >> $INI_FILE - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo extension = mongo.so >> $INI_FILE; fi; - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo extension = memcache.so >> $INI_FILE; fi; - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.10 && echo apc.enable_cli = 1 >> $INI_FILE); fi; - - if [[ $TRAVIS_PHP_VERSION = 7.* ]]; then (echo yes | pecl install -f apcu-5.1.2 && echo apc.enable_cli = 1 >> $INI_FILE); fi; - - if [[ $TRAVIS_PHP_VERSION = 5.* && ! $deps ]]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo extension = $(pwd)/modules/symfony_debug.so >> $INI_FILE); fi; - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then pecl install -f memcached-2.1.0; fi; - - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then echo extension = ldap.so >> $INI_FILE; fi; - - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then phpenv config-rm xdebug.ini; fi; - - if [[ $deps != skip ]]; then composer self-update; fi; - - if [[ $deps != skip && $TRAVIS_REPO_SLUG = symfony/symfony ]]; then cp .composer/* ~/.composer/; composer global install; fi; - - if [[ $deps != skip ]]; then ./phpunit install; fi; - - export PHPUNIT=$(readlink -f ./phpunit) + - if [[ ! $deps && $PHP = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then wget http://museum.php.net/php5/php-$MIN_PHP.tar.bz2 -O - | tar -xj; (cd php-$MIN_PHP; ./configure --enable-sigchild --enable-pcntl; make -j2); fi + - if [[ $PHP != hhvm ]]; then INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; else INI_FILE=/etc/hhvm/php.ini; fi + - if [[ ! $skip ]]; then echo memory_limit = -1 >> $INI_FILE; fi + - if [[ ! $skip ]]; then echo session.gc_probability = 0 >> $INI_FILE; fi + - if [[ ! $skip && $PHP = 5.* ]]; then echo extension = mongo.so >> $INI_FILE; fi + - if [[ ! $skip && $PHP = 5.* ]]; then echo extension = memcache.so >> $INI_FILE; fi + - if [[ ! $skip && $PHP = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.10 && echo apc.enable_cli = 1 >> $INI_FILE); fi + - if [[ ! $skip && $PHP = 7.* ]]; then (echo yes | pecl install -f apcu-5.1.2 && echo apc.enable_cli = 1 >> $INI_FILE); fi + - if [[ ! $deps && $PHP = 5.* ]]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo extension = $(pwd)/modules/symfony_debug.so >> $INI_FILE); fi + - if [[ ! $skip && $PHP = 5.* ]]; then pecl install -f memcached-2.1.0; fi + - if [[ ! $skip && $PHP != hhvm ]]; then echo extension = ldap.so >> $INI_FILE; fi + - if [[ ! $skip && $PHP != hhvm ]]; then phpenv config-rm xdebug.ini; fi + - if [[ ! $skip ]]; then composer self-update; fi + - if [[ ! $skip ]]; then cp .composer/* ~/.composer/; composer global install; fi + - if [[ ! $skip ]]; then ./phpunit install; fi + - if [[ ! $skip && $deps ]]; then composer global remove hirak/prestissimo; fi + - if [[ ! $skip ]]; then export PHPUNIT=$(readlink -f ./phpunit); fi install: - - if [[ $deps != skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi; + - if [[ ! $skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components - - if [[ $deps != skip && $deps ]]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $COMPONENTS; fi; + - if [[ ! $skip && $deps ]]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $COMPONENTS; fi # For the master branch when deps=high, the version before master is checked out and tested with the locally patched components - - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//); else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*'); fi; - - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); ./phpunit install; fi; + - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//); else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*'); fi + - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); ./phpunit install; fi # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number than the next one - - if [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]]; then LEGACY=,legacy; fi; - - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev; - - if [[ ! $deps ]]; then composer update; else export SYMFONY_DEPRECATIONS_HELPER=weak; fi; - - if [[ $TRAVIS_BRANCH = master ]]; then export SYMFONY_PHPUNIT_OVERLOAD=1; fi; - - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi; + - if [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]]; then LEGACY=,legacy; fi + - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev + - if [[ ! $deps ]]; then composer update; else export SYMFONY_DEPRECATIONS_HELPER=weak; fi + - if [[ $TRAVIS_BRANCH = master ]]; then export SYMFONY_PHPUNIT_OVERLOAD=1; fi + - if [[ $PHP != hhvm ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi script: - - if [[ ! $deps ]]; then echo "$COMPONENTS" | parallel --gnu '$PHPUNIT --exclude-group tty,benchmark,intl-data {}'; fi; - - if [[ ! $deps ]]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty; fi; - - if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} ]]; then echo -e "1\\n0" | xargs -I{} sh -c 'echo "\\nPHP --enable-sigchild enhanced={}" && ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/'; fi; - - if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update; $PHPUNIT --exclude-group tty,benchmark,intl-data'$LEGACY; fi; - - if [[ $deps = low ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --prefer-lowest --prefer-stable; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi; - - if [[ $deps = skip ]]; then echo This matrix line is skipped for pull requests.; fi; + - if [[ $skip ]]; then echo -e "\\n\\e[1;34mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"; fi + - if [[ ! $deps ]]; then echo "$COMPONENTS" | parallel --gnu '$PHPUNIT --exclude-group tty,benchmark,intl-data {}'; fi + - if [[ ! $deps ]]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty; fi + - if [[ ! $deps && $PHP = ${MIN_PHP%.*} ]]; then echo -e "1\\n0" | xargs -I{} sh -c 'echo "\\nPHP --enable-sigchild enhanced={}" && ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/'; fi + - if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --no-progress --ansi; $PHPUNIT --exclude-group tty,benchmark,intl-data'$LEGACY; fi + - if [[ $deps = low ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --no-progress --ansi --prefer-lowest --prefer-stable; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi diff --git a/appveyor.yml b/appveyor.yml index 8524cfb3ce..5ef438b1d9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -54,8 +54,8 @@ install: - copy /Y php.ini-max php.ini - cd c:\projects\symfony - mkdir %APPDATA%\Composer - - IF %APPVEYOR_REPO_NAME%==symfony/symfony copy /Y .composer\* %APPDATA%\Composer\ - - IF %APPVEYOR_REPO_NAME%==symfony/symfony composer global install --no-progress --ansi || echo curl.cainfo needs PHP 5.3.7 + - copy /Y .composer\* %APPDATA%\Composer\ + - composer global install --no-progress --ansi - php phpunit install - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) - composer update --no-progress --ansi diff --git a/composer.json b/composer.json index 288b9d9b0d..ad54861696 100644 --- a/composer.json +++ b/composer.json @@ -93,7 +93,11 @@ }, "autoload": { "psr-4": { - "Symfony\\Bridge\\": "src/Symfony/Bridge/", + "Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/", + "Symfony\\Bridge\\Monolog\\": "src/Symfony/Bridge/Monolog/", + "Symfony\\Bridge\\ProxyManager\\": "src/Symfony/Bridge/ProxyManager/", + "Symfony\\Bridge\\Swiftmailer\\": "src/Symfony/Bridge/Swiftmailer/", + "Symfony\\Bridge\\Twig\\": "src/Symfony/Bridge/Twig/", "Symfony\\Bundle\\": "src/Symfony/Bundle/", "Symfony\\Component\\": "src/Symfony/Component/" }, @@ -104,6 +108,11 @@ "**/Tests/" ] }, + "autoload-dev": { + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "src/Symfony/Bridge/PhpUnit/" + } + }, "minimum-stability": "dev", "extra": { "branch-alias": { diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php index 6804ded30d..31593b9b80 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php @@ -78,6 +78,10 @@ class ControllerResolver extends BaseControllerResolver */ protected function instantiateController($class) { + if ($this->container->has($class)) { + return $this->container->get($class); + } + $controller = parent::instantiateController($class); if ($controller instanceof ContainerAwareInterface) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php index 76a3489fe1..b4dc8ada55 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php @@ -87,6 +87,8 @@ class ControllerResolverTest extends BaseControllerResolverTest public function testGetControllerInvokableService() { + $invokableController = new InvokableController('bar'); + $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') @@ -96,7 +98,7 @@ class ControllerResolverTest extends BaseControllerResolverTest $container->expects($this->once()) ->method('get') ->with('foo') - ->will($this->returnValue($this)) + ->will($this->returnValue($invokableController)) ; $resolver = $this->createControllerResolver(null, null, $container); @@ -105,7 +107,33 @@ class ControllerResolverTest extends BaseControllerResolverTest $controller = $resolver->getController($request); - $this->assertInstanceOf(get_class($this), $controller); + $this->assertEquals($invokableController, $controller); + } + + public function testGetControllerInvokableServiceWithClassNameAsName() + { + $invokableController = new InvokableController('bar'); + $className = __NAMESPACE__.'\InvokableController'; + + $container = $this->createMockContainer(); + $container->expects($this->once()) + ->method('has') + ->with($className) + ->will($this->returnValue(true)) + ; + $container->expects($this->once()) + ->method('get') + ->with($className) + ->will($this->returnValue($invokableController)) + ; + + $resolver = $this->createControllerResolver(null, null, $container); + $request = Request::create('/'); + $request->attributes->set('_controller', $className); + + $controller = $resolver->getController($request); + + $this->assertEquals($invokableController, $controller); } /** @@ -178,3 +206,14 @@ class ContainerAwareController implements ContainerAwareInterface { } } + +class InvokableController +{ + public function __construct($bar) // mandatory argument to prevent automatic instantiation + { + } + + public function __invoke() + { + } +} diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php index e1a018ce96..e80d3ccbf7 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php @@ -25,7 +25,6 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface { private $compiler; private $formatter; - private $sourceId; /** * Process the Container to replace aliases with service definitions. @@ -36,118 +35,110 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface */ public function process(ContainerBuilder $container) { + // Setup $this->compiler = $container->getCompiler(); $this->formatter = $this->compiler->getLoggingFormatter(); - - foreach ($container->getAliases() as $id => $alias) { - $aliasId = (string) $alias; - - if ('service_container' === $aliasId) { + // First collect all alias targets that need to be replaced + $seenAliasTargets = array(); + $replacements = array(); + foreach ($container->getAliases() as $definitionId => $target) { + $targetId = (string) $target; + // Special case: leave this target alone + if ('service_container' === $targetId) { continue; } - - try { - $definition = $container->getDefinition($aliasId); - } catch (InvalidArgumentException $e) { - throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $id, $alias), null, $e); + // Check if target needs to be replaces + if (isset($replacements[$targetId])) { + $container->setAlias($definitionId, $replacements[$targetId]); + } + // No neeed to process the same target twice + if (isset($seenAliasTargets[$targetId])) { + continue; + } + // Process new target + $seenAliasTargets[$targetId] = true; + try { + $definition = $container->getDefinition($targetId); + } catch (InvalidArgumentException $e) { + throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $definitionId, $targetId), null, $e); } - if ($definition->isPublic()) { continue; } - + // Remove private definition and schedule for replacement $definition->setPublic(true); - $container->setDefinition($id, $definition); - $container->removeDefinition($aliasId); + $container->setDefinition($definitionId, $definition); + $container->removeDefinition($targetId); + $replacements[$targetId] = $definitionId; + } - $this->updateReferences($container, $aliasId, $id); - - // we have to restart the process due to concurrent modification of - // the container - $this->process($container); - - break; + // Now replace target instances in all definitions + foreach ($container->getDefinitions() as $definitionId => $definition) { + $definition->setArguments($this->updateArgumentReferences($replacements, $definitionId, $definition->getArguments())); + $definition->setMethodCalls($this->updateArgumentReferences($replacements, $definitionId, $definition->getMethodCalls())); + $definition->setProperties($this->updateArgumentReferences($replacements, $definitionId, $definition->getProperties())); + $definition->setFactoryService($this->updateFactoryReferenceId($replacements, $definition->getFactoryService(false)), false); + $definition->setFactory($this->updateFactoryReference($replacements, $definition->getFactory())); } } /** - * Updates references to remove aliases. + * Recursively updates references in an array. * - * @param ContainerBuilder $container The container - * @param string $currentId The alias identifier being replaced - * @param string $newId The id of the service the alias points to - */ - private function updateReferences($container, $currentId, $newId) - { - foreach ($container->getAliases() as $id => $alias) { - if ($currentId === (string) $alias) { - $container->setAlias($id, $newId); - } - } - - foreach ($container->getDefinitions() as $id => $definition) { - $this->sourceId = $id; - - $definition->setArguments( - $this->updateArgumentReferences($definition->getArguments(), $currentId, $newId) - ); - - $definition->setMethodCalls( - $this->updateArgumentReferences($definition->getMethodCalls(), $currentId, $newId) - ); - - $definition->setProperties( - $this->updateArgumentReferences($definition->getProperties(), $currentId, $newId) - ); - - $definition->setFactoryService($this->updateFactoryServiceReference($definition->getFactoryService(false), $currentId, $newId), false); - $definition->setFactory($this->updateFactoryReference($definition->getFactory(), $currentId, $newId)); - } - } - - /** - * Updates argument references. - * - * @param array $arguments An array of Arguments - * @param string $currentId The alias identifier - * @param string $newId The identifier the alias points to + * @param array $replacements Table of aliases to replace + * @param string $definitionId Identifier of this definition + * @param array $arguments Where to replace the aliases * * @return array */ - private function updateArgumentReferences(array $arguments, $currentId, $newId) + private function updateArgumentReferences(array $replacements, $definitionId, array $arguments) { foreach ($arguments as $k => $argument) { + // Handle recursion step if (is_array($argument)) { - $arguments[$k] = $this->updateArgumentReferences($argument, $currentId, $newId); - } elseif ($argument instanceof Reference) { - if ($currentId === (string) $argument) { - $arguments[$k] = new Reference($newId, $argument->getInvalidBehavior()); - $this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $this->sourceId, $currentId, $newId)); - } + $arguments[$k] = $this->updateArgumentReferences($replacements, $definitionId, $argument); + continue; } + // Skip arguments that don't need replacement + if (!$argument instanceof Reference) { + continue; + } + $referenceId = (string) $argument; + if (!isset($replacements[$referenceId])) { + continue; + } + // Perform the replacement + $newId = $replacements[$referenceId]; + $arguments[$k] = new Reference($newId, $argument->getInvalidBehavior()); + $this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $definitionId, $referenceId, $newId)); } return $arguments; } - private function updateFactoryServiceReference($factoryService, $currentId, $newId) + /** + * Returns the updated reference for the factory service. + * + * @param array $replacements Table of aliases to replace + * @param string|null $referenceId Factory service reference identifier + * + * @return string|null + */ + private function updateFactoryReferenceId(array $replacements, $referenceId) { - if (null === $factoryService) { + if (null === $referenceId) { return; } - return $currentId === $factoryService ? $newId : $factoryService; + return isset($replacements[$referenceId]) ? $replacements[$referenceId] : $referenceId; } - private function updateFactoryReference($factory, $currentId, $newId) + private function updateFactoryReference(array $replacements, $factory) { - if (null === $factory || !is_array($factory) || !$factory[0] instanceof Reference) { - return $factory; + if (is_array($factory) && $factory[0] instanceof Reference && isset($replacements[$referenceId = (string) $factory[0]])) { + $factory[0] = new Reference($replacements[$referenceId], $factory[0]->getInvalidBehavior()); } - if ($currentId === (string) $factory[0]) { - $factory[0] = new Reference($newId, $factory[0]->getInvalidBehavior()); - } return $factory; } diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 15bf3d3150..315a3f9f6f 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -766,11 +766,7 @@ class Form implements \IteratorAggregate, FormInterface return true; } - if (count($this->getErrors(true)) > 0) { - return false; - } - - return true; + return 0 === count($this->getErrors(true)); } /** diff --git a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php index 6b869e0ab4..ace70db905 100644 --- a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php +++ b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php @@ -50,7 +50,7 @@ class UploadedFile extends File /** * The file size provided by the uploader. * - * @var string + * @var int|null */ private $size; @@ -75,12 +75,12 @@ class UploadedFile extends File * * Calling any other method on an non-valid instance will cause an unpredictable result. * - * @param string $path The full temporary path to the file - * @param string $originalName The original file name - * @param string $mimeType The type of the file as provided by PHP - * @param int $size The file size - * @param int $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants) - * @param bool $test Whether the test mode is active + * @param string $path The full temporary path to the file + * @param string $originalName The original file name + * @param string|null $mimeType The type of the file as provided by PHP; null defaults to application/octet-stream + * @param int|null $size The file size + * @param int|null $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK + * @param bool $test Whether the test mode is active * * @throws FileException If file_uploads is disabled * @throws FileNotFoundException If the file does not exist diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 679d33a5e3..08742df2d9 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -1087,7 +1087,7 @@ class Process throw new LogicException('Input can not be set while the process is running.'); } - $this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input); + $this->input = ProcessUtils::validateInput(__METHOD__, $input); return $this; } diff --git a/src/Symfony/Component/Process/ProcessBuilder.php b/src/Symfony/Component/Process/ProcessBuilder.php index a782fd69e9..0f4764638a 100644 --- a/src/Symfony/Component/Process/ProcessBuilder.php +++ b/src/Symfony/Component/Process/ProcessBuilder.php @@ -177,7 +177,7 @@ class ProcessBuilder */ public function setInput($input) { - $this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input); + $this->input = ProcessUtils::validateInput(__METHOD__, $input); return $this; } diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 8d2d7dd613..33a9e45d04 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -75,6 +75,11 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt '%7C' => '|', ); + /** + * @var string This regexp matches all characters that are not or should not be encoded by rawurlencode (see list in array above). + */ + private $urlEncodingSkipRegexp = '#[^-.~a-zA-Z0-9_/@:;,=+!*|]#'; + /** * Constructor. * @@ -196,19 +201,21 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt if ('' === $url) { $url = '/'; + } elseif (preg_match($this->urlEncodingSkipRegexp, $url)) { + // the context base URL is already encoded (see Symfony\Component\HttpFoundation\Request) + $url = strtr(rawurlencode($url), $this->decodedChars); } - // the contexts base URL is already encoded (see Symfony\Component\HttpFoundation\Request) - $url = strtr(rawurlencode($url), $this->decodedChars); - // the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3 // so we need to encode them as they are not used for this purpose here // otherwise we would generate a URI that, when followed by a user agent (e.g. browser), does not match this route - $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/')); - if ('/..' === substr($url, -3)) { - $url = substr($url, 0, -2).'%2E%2E'; - } elseif ('/.' === substr($url, -2)) { - $url = substr($url, 0, -1).'%2E'; + if (false !== strpos($url, '/.')) { + $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/')); + if ('/..' === substr($url, -3)) { + $url = substr($url, 0, -2).'%2E%2E'; + } elseif ('/.' === substr($url, -2)) { + $url = substr($url, 0, -1).'%2E'; + } } $schemeAuthority = ''; @@ -282,7 +289,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt if ($extra && $query = http_build_query($extra, '', '&')) { // "/" and "?" can be left decoded for better user experience, see // http://tools.ietf.org/html/rfc3986#section-3.4 - $url .= '?'.strtr($query, array('%2F' => '/')); + $url .= '?'.(false === strpos($query, '%2F') ? $query : strtr($query, array('%2F' => '/'))); } return $url; diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php index 1fd348bfb1..cfa0e99c92 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php @@ -110,6 +110,7 @@ class EmailValidatorTest extends AbstractConstraintValidatorTest /** * @dataProvider getDnsChecks + * @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts */ public function testDnsChecks($type, $violation) { @@ -144,6 +145,9 @@ class EmailValidatorTest extends AbstractConstraintValidatorTest ); } + /** + * @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts + */ public function testHostnameIsProperlyParsed() { DnsMock::withMockedHosts(array('baz.com' => array(array('type' => 'MX')))); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index 71636661b4..23610c31f6 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -195,6 +195,7 @@ class UrlValidatorTest extends AbstractConstraintValidatorTest /** * @dataProvider getCheckDns + * @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts */ public function testCheckDns($violation) {