diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3af6c2a83bc18..e51cf88761451 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | master / 2.7, 2.8, 3.3, or 3.4 +| Branch? | master for features / 2.7 up to 4.0 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | BC breaks? | yes/no @@ -14,6 +14,5 @@ - Bug fixes must be submitted against the lowest branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the master branch. -- Please fill in this template according to the PR you're about to submit. - Replace this comment by a description of what your PR is solving. --> diff --git a/CHANGELOG-4.0.md b/CHANGELOG-4.0.md index 3cdd1f358add2..fc1f989d485f7 100644 --- a/CHANGELOG-4.0.md +++ b/CHANGELOG-4.0.md @@ -7,6 +7,22 @@ in 4.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/v4.0.0...v4.0.1 +* 4.0.0-RC2 (2017-11-24) + + * bug #25146 [DI] Dont resolve envs in service ids (nicolas-grekas) + * bug #25113 [Routing] Fix "config-file-relative" annotation loader resources (nicolas-grekas, sroze) + * bug #25065 [FrameworkBundle] Update translation commands to work with default paths (yceruto) + * bug #25109 Make debug:container search command case-insensitive (jzawadzki) + * bug #25121 [FrameworkBundle] Fix AssetsInstallCommand (nicolas-grekas) + * bug #25102 [Form] Fixed ContextErrorException in FileType (chihiro-adachi) + * bug #25130 [DI] Fix handling of inlined definitions by ContainerBuilder (nicolas-grekas) + * bug #25119 [DI] Fix infinite loop when analyzing references (nicolas-grekas) + * bug #25094 [FrameworkBundle][DX] Display a nice error message if an enabled component is missing (derrabus) + * bug #25100 [SecurityBundle] providerIds is undefined error when firewall provider is not specified (karser) + * bug #25100 [SecurityBundle] providerIds is undefined error when firewall provider is not specified (karser) + * bug #25100 [SecurityBundle] providerIds is undefined error when firewall provider is not specified (karser) + * bug #25097 [Bridge\PhpUnit] Turn "preserveGlobalState" to false by default, revert "Blacklist" removal (nicolas-grekas) + * 4.0.0-RC1 (2017-11-21) * bug #25077 [Bridge/Twig] Let getFlashes starts the session (MatTheCat) diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index e4aec3709008d..80451f5d61a4c 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -323,7 +323,7 @@ Form ```php class MyTimezoneType extends AbstractType { - public function. getParent() + public function getParent() { return TimezoneType::class; } diff --git a/phpunit b/phpunit index 86f4cdd5ae0a2..c0ffe8ddef9e9 100755 --- a/phpunit +++ b/phpunit @@ -1,7 +1,7 @@ #!/usr/bin/env php - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\PhpUnit; - -/** - * Utility class replacing PHPUnit's implementation of the same class. - * - * All files are blacklisted so that process-isolated tests don't start with broken - * "require_once" statements. Composer is the only supported way to load code there. - */ -class Blacklist -{ - public static $blacklistedClassNames = array(); - - public function getBlacklistedDirectories() - { - $blacklist = array(); - - foreach (get_declared_classes() as $class) { - if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) { - $r = new \ReflectionClass($class); - $v = dirname(dirname($r->getFileName())); - if (file_exists($v.'/composer/installed.json')) { - $blacklist[] = $v; - } - } - } - - return $blacklist; - } - - public function isBlacklisted($file) - { - return true; - } -} - -if (class_exists('PHPUnit\Util\Test')) { - class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit\Util\Blacklist'); -} -if (class_exists('PHPUnit_Util_Test')) { - class_alias('Symfony\Bridge\PhpUnit\Blacklist', 'PHPUnit_Util_Blacklist'); -} diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index 419b087d0d3b9..cc18d51659c6f 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; +use PHPUnit\Util\Blacklist; use Symfony\Bridge\PhpUnit\ClockMock; use Symfony\Bridge\PhpUnit\DnsMock; @@ -45,6 +46,12 @@ class SymfonyTestsListenerTrait */ public function __construct(array $mockedNamespaces = array()) { + if (class_exists('PHPUnit_Util_Blacklist')) { + \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait'] = 2; + } else { + Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait'] = 2; + } + foreach ($mockedNamespaces as $type => $namespaces) { if (!is_array($namespaces)) { $namespaces = array($namespaces); @@ -82,7 +89,7 @@ public function globalListenerDisabled() public function startTestSuite($suite) { - if (class_exists('PHPUnit_Util_Test', false)) { + if (class_exists('PHPUnit_Util_Blacklist', false)) { $Test = 'PHPUnit_Util_Test'; } else { $Test = 'PHPUnit\Util\Test'; @@ -90,6 +97,15 @@ public function startTestSuite($suite) $suiteName = $suite->getName(); $this->testsWithWarnings = array(); + foreach ($suite->tests() as $test) { + if (!($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) { + continue; + } + if (null === $Test::getPreserveGlobalStateSettings(get_class($test), $test->getName(false))) { + $test->setPreserveGlobalState(false); + } + } + if (-1 === $this->state) { echo "Testing $suiteName\n"; $this->state = 0; @@ -169,7 +185,7 @@ public function startTest($test) putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$this->runsInSeparateProcess); } - if (class_exists('PHPUnit_Util_Test', false)) { + if (class_exists('PHPUnit_Util_Blacklist', false)) { $Test = 'PHPUnit_Util_Test'; $AssertionFailedError = 'PHPUnit_Framework_AssertionFailedError'; } else { @@ -215,7 +231,7 @@ public function addWarning($test, $e, $time) public function endTest($test, $time) { - if (class_exists('PHPUnit_Util_Test', false)) { + if (class_exists('PHPUnit_Util_Blacklist', false)) { $Test = 'PHPUnit_Util_Test'; $BaseTestRunner = 'PHPUnit_Runner_BaseTestRunner'; $Warning = 'PHPUnit_Framework_Warning'; diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 3a89787f4f797..562d018124a37 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -11,7 +11,7 @@ */ // Please update when phpunit needs to be reinstalled with fresh deps: -// Cache-Id-Version: 2016-10-20 14:00 UTC +// Cache-Id-Version: 2017-11-22 09:30 UTC error_reporting(-1); @@ -98,6 +98,17 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ define('PHPUNIT_COMPOSER_INSTALL', __DIR__.'/vendor/autoload.php'); require PHPUNIT_COMPOSER_INSTALL; +if (!class_exists('SymfonyBlacklistPhpunit', false)) { + class SymfonyBlacklistPhpunit {} +} +if (class_exists('PHPUnit_Util_Blacklist')) { + PHPUnit_Util_Blacklist::$blacklistedClassNames['SymfonyBlacklistPhpunit'] = 1; + PHPUnit_Util_Blacklist::$blacklistedClassNames['SymfonyBlacklistSimplePhpunit'] = 1; +} else { + PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyBlacklistPhpunit'] = 1; + PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyBlacklistSimplePhpunit'] = 1; +} + Symfony\Bridge\PhpUnit\TextUI\Command::main(); EOPHP @@ -216,6 +227,9 @@ if ($components) { } } } elseif (!isset($argv[1]) || 'install' !== $argv[1] || file_exists('install')) { + if (!class_exists('SymfonyBlacklistSimplePhpunit', false)) { + class SymfonyBlacklistSimplePhpunit {} + } array_splice($argv, 1, 0, array('--colors=always')); $_SERVER['argv'] = $argv; $_SERVER['argc'] = ++$argc; diff --git a/src/Symfony/Bridge/PhpUnit/bootstrap.php b/src/Symfony/Bridge/PhpUnit/bootstrap.php index 8e85feaa34269..a265a129e6fdc 100644 --- a/src/Symfony/Bridge/PhpUnit/bootstrap.php +++ b/src/Symfony/Bridge/PhpUnit/bootstrap.php @@ -12,11 +12,6 @@ use Doctrine\Common\Annotations\AnnotationRegistry; use Symfony\Bridge\PhpUnit\DeprecationErrorHandler; -// Replace the native phpunit Blacklist, it's a broken artifact from the past -if (!class_exists('Symfony\Bridge\PhpUnit\Blacklist', false)) { - require_once __DIR__.'/Blacklist.php'; -} - // Detect if we need to serialize deprecations to a file. if ($file = getenv('SYMFONY_DEPRECATIONS_SERIALIZE')) { DeprecationErrorHandler::collectDeprecations($file); diff --git a/src/Symfony/Bundle/DebugBundle/Tests/DependencyInjection/DebugExtensionTest.php b/src/Symfony/Bundle/DebugBundle/Tests/DependencyInjection/DebugExtensionTest.php index 9c03e9988224a..0c285a02ac180 100644 --- a/src/Symfony/Bundle/DebugBundle/Tests/DependencyInjection/DebugExtensionTest.php +++ b/src/Symfony/Bundle/DebugBundle/Tests/DependencyInjection/DebugExtensionTest.php @@ -40,7 +40,6 @@ private function createContainer() { $container = new ContainerBuilder(new ParameterBag(array( 'kernel.cache_dir' => __DIR__, - 'kernel.root_dir' => __DIR__.'/Fixtures', 'kernel.charset' => 'UTF-8', 'kernel.debug' => true, 'kernel.bundles' => array('DebugBundle' => 'Symfony\\Bundle\\DebugBundle\\DebugBundle'), diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php index 06a9c2ea41d2d..ea122cf80305a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php @@ -226,6 +226,7 @@ private function absoluteSymlinkWithFallback(string $originDir, string $targetDi private function symlink(string $originDir, string $targetDir, bool $relative = false) { if ($relative) { + $this->filesystem->mkdir(dirname($targetDir)); $originDir = $this->filesystem->makePathRelative($originDir, realpath(dirname($targetDir))); } $this->filesystem->symlink($originDir, $targetDir); diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index fb5d2536f5f8f..c9b9fefaf5f62 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -221,9 +221,8 @@ private function findServiceIdsContaining(ContainerBuilder $builder, $name) { $serviceIds = $builder->getServiceIds(); $foundServiceIds = array(); - $name = strtolower($name); foreach ($serviceIds as $serviceId) { - if (false === strpos($serviceId, $name)) { + if (false === stripos($serviceId, $name)) { continue; } $foundServiceIds[] = $serviceId; diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php index 4bcea1082770d..a444df3a5affb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php @@ -46,14 +46,18 @@ class TranslationDebugCommand extends Command private $translator; private $reader; private $extractor; + private $defaultTransPath; + private $defaultViewsPath; - public function __construct(TranslatorInterface $translator, TranslationReaderInterface $reader, ExtractorInterface $extractor) + public function __construct(TranslatorInterface $translator, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultTransPath = null, string $defaultViewsPath = null) { parent::__construct(); $this->translator = $translator; $this->reader = $reader; $this->extractor = $extractor; + $this->defaultTransPath = $defaultTransPath; + $this->defaultViewsPath = $defaultViewsPath; } /** @@ -117,20 +121,34 @@ protected function execute(InputInterface $input, OutputInterface $output) /** @var KernelInterface $kernel */ $kernel = $this->getApplication()->getKernel(); - // Define Root Path to App folder - $transPaths = array($kernel->getRootDir().'/Resources/'); + // Define Root Paths + $transPaths = array($kernel->getRootDir().'/Resources/translations'); + if ($this->defaultTransPath) { + $transPaths[] = $this->defaultTransPath; + } + $viewsPaths = array($kernel->getRootDir().'/Resources/views'); + if ($this->defaultViewsPath) { + $viewsPaths[] = $this->defaultViewsPath; + } // Override with provided Bundle info if (null !== $input->getArgument('bundle')) { try { $bundle = $kernel->getBundle($input->getArgument('bundle')); - $transPaths = array( - $bundle->getPath().'/Resources/', - sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName()), - ); + $transPaths = array($bundle->getPath().'/Resources/translations'); + if ($this->defaultTransPath) { + $transPaths[] = $this->defaultTransPath.'/'.$bundle->getName(); + } + $transPaths[] = sprintf('%s/Resources/%s/translations', $kernel->getRootDir(), $bundle->getName()); + $viewsPaths = array($bundle->getPath().'/Resources/views'); + if ($this->defaultViewsPath) { + $viewsPaths[] = $this->defaultViewsPath.'/bundles/'.$bundle->getName(); + } + $viewsPaths[] = sprintf('%s/Resources/%s/views', $kernel->getRootDir(), $bundle->getName()); } catch (\InvalidArgumentException $e) { // such a bundle does not exist, so treat the argument as path - $transPaths = array($input->getArgument('bundle').'/Resources/'); + $transPaths = array($input->getArgument('bundle').'/Resources/translations'); + $viewsPaths = array($input->getArgument('bundle').'/Resources/views'); if (!is_dir($transPaths[0])) { throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0])); @@ -138,13 +156,21 @@ protected function execute(InputInterface $input, OutputInterface $output) } } elseif ($input->getOption('all')) { foreach ($kernel->getBundles() as $bundle) { - $transPaths[] = $bundle->getPath().'/Resources/'; - $transPaths[] = sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName()); + $transPaths[] = $bundle->getPath().'/Resources/translations'; + if ($this->defaultTransPath) { + $transPaths[] = $this->defaultTransPath.'/'.$bundle->getName(); + } + $transPaths[] = sprintf('%s/Resources/%s/translations', $kernel->getRootDir(), $bundle->getName()); + $viewsPaths[] = $bundle->getPath().'/Resources/views'; + if ($this->defaultViewsPath) { + $viewsPaths[] = $this->defaultViewsPath.'/bundles/'.$bundle->getName(); + } + $viewsPaths[] = sprintf('%s/Resources/%s/views', $kernel->getRootDir(), $bundle->getName()); } } // Extract used messages - $extractedCatalogue = $this->extractMessages($locale, $transPaths); + $extractedCatalogue = $this->extractMessages($locale, $viewsPaths); // Load defined messages $currentCatalogue = $this->loadCurrentMessages($locale, $transPaths); @@ -268,7 +294,6 @@ private function extractMessages(string $locale, array $transPaths): MessageCata { $extractedCatalogue = new MessageCatalogue($locale); foreach ($transPaths as $path) { - $path = $path.'views'; if (is_dir($path)) { $this->extractor->extract($path, $extractedCatalogue); } @@ -281,7 +306,6 @@ private function loadCurrentMessages(string $locale, array $transPaths): Message { $currentCatalogue = new MessageCatalogue($locale); foreach ($transPaths as $path) { - $path = $path.'translations'; if (is_dir($path)) { $this->reader->read($path, $currentCatalogue); } @@ -304,7 +328,6 @@ private function loadFallbackCatalogues(string $locale, array $transPaths): arra $fallbackCatalogue = new MessageCatalogue($fallbackLocale); foreach ($transPaths as $path) { - $path = $path.'translations'; if (is_dir($path)) { $this->reader->read($path, $fallbackCatalogue); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index c16c4dcf14a2a..2404dbdba7c5f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -13,6 +13,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Translation\Catalogue\TargetOperation; use Symfony\Component\Translation\Catalogue\MergeOperation; use Symfony\Component\Console\Input\InputInterface; @@ -40,8 +41,10 @@ class TranslationUpdateCommand extends Command private $reader; private $extractor; private $defaultLocale; + private $defaultTransPath; + private $defaultViewsPath; - public function __construct(TranslationWriterInterface $writer, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultLocale) + public function __construct(TranslationWriterInterface $writer, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultLocale, string $defaultTransPath = null, string $defaultViewsPath = null) { parent::__construct(); @@ -49,6 +52,8 @@ public function __construct(TranslationWriterInterface $writer, TranslationReade $this->reader = $reader; $this->extractor = $extractor; $this->defaultLocale = $defaultLocale; + $this->defaultTransPath = $defaultTransPath; + $this->defaultViewsPath = $defaultViewsPath; } /** @@ -110,24 +115,39 @@ protected function execute(InputInterface $input, OutputInterface $output) return 1; } + /** @var KernelInterface $kernel */ $kernel = $this->getApplication()->getKernel(); - // Define Root Path to App folder - $transPaths = array($kernel->getRootDir().'/Resources/'); + // Define Root Paths + $transPaths = array($kernel->getRootDir().'/Resources/translations'); + if ($this->defaultTransPath) { + $transPaths[] = $this->defaultTransPath; + } + $viewsPaths = array($kernel->getRootDir().'/Resources/views'); + if ($this->defaultViewsPath) { + $viewsPaths[] = $this->defaultViewsPath; + } $currentName = 'app folder'; // Override with provided Bundle info if (null !== $input->getArgument('bundle')) { try { $foundBundle = $kernel->getBundle($input->getArgument('bundle')); - $transPaths = array( - $foundBundle->getPath().'/Resources/', - sprintf('%s/Resources/%s/', $kernel->getRootDir(), $foundBundle->getName()), - ); + $transPaths = array($foundBundle->getPath().'/Resources/translations'); + if ($this->defaultTransPath) { + $transPaths[] = $this->defaultTransPath.'/'.$foundBundle->getName(); + } + $transPaths[] = sprintf('%s/Resources/%s/translations', $kernel->getRootDir(), $foundBundle->getName()); + $viewsPaths = array($foundBundle->getPath().'/Resources/views'); + if ($this->defaultViewsPath) { + $viewsPaths[] = $this->defaultViewsPath.'/bundles/'.$foundBundle->getName(); + } + $viewsPaths[] = sprintf('%s/Resources/%s/views', $kernel->getRootDir(), $foundBundle->getName()); $currentName = $foundBundle->getName(); } catch (\InvalidArgumentException $e) { // such a bundle does not exist, so treat the argument as path - $transPaths = array($input->getArgument('bundle').'/Resources/'); + $transPaths = array($input->getArgument('bundle').'/Resources/translations'); + $viewsPaths = array($input->getArgument('bundle').'/Resources/views'); $currentName = $transPaths[0]; if (!is_dir($transPaths[0])) { @@ -143,8 +163,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $extractedCatalogue = new MessageCatalogue($input->getArgument('locale')); $errorIo->comment('Parsing templates...'); $this->extractor->setPrefix($input->getOption('prefix')); - foreach ($transPaths as $path) { - $path .= 'views'; + foreach ($viewsPaths as $path) { if (is_dir($path)) { $this->extractor->extract($path, $extractedCatalogue); } @@ -154,7 +173,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $currentCatalogue = new MessageCatalogue($input->getArgument('locale')); $errorIo->comment('Loading translation files...'); foreach ($transPaths as $path) { - $path .= 'translations'; if (is_dir($path)) { $this->reader->read($path, $currentCatalogue); } @@ -222,14 +240,13 @@ protected function execute(InputInterface $input, OutputInterface $output) $bundleTransPath = false; foreach ($transPaths as $path) { - $path .= 'translations'; if (is_dir($path)) { $bundleTransPath = $path; } } if (!$bundleTransPath) { - $bundleTransPath = end($transPaths).'translations'; + $bundleTransPath = end($transPaths); } $this->writer->write($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->defaultLocale)); diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 4a2fd5e269c27..4874b1bba3d2c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -137,10 +137,6 @@ public function load(array $configs, ContainerBuilder $container) throw new LogicException('Translation support cannot be enabled as the Translation component is not installed.'); } - if (!class_exists('Symfony\Component\Translation\Translator') && $this->isConfigEnabled($container, $config['validation'])) { - throw new LogicException('Validation support cannot be enabled as the Translation component is not installed.'); - } - if (class_exists(Translator::class)) { $loader->load('identity_translator.xml'); } @@ -184,6 +180,10 @@ public function load(array $configs, ContainerBuilder $container) } if ($this->isConfigEnabled($container, $config['form'])) { + if (!class_exists('Symfony\Component\Form\Form')) { + throw new LogicException('Form support cannot be enabled as the Form component is not installed.'); + } + $this->formConfigEnabled = true; $this->registerFormConfiguration($config, $container, $loader); @@ -231,6 +231,10 @@ public function load(array $configs, ContainerBuilder $container) $this->registerPropertyAccessConfiguration($config['property_access'], $container, $loader); if ($this->isConfigEnabled($container, $config['serializer'])) { + if (!class_exists('Symfony\Component\Serializer\Serializer')) { + throw new LogicException('Serializer support cannot be enabled as the Serializer component is not installed.'); + } + $this->registerSerializerConfiguration($config['serializer'], $container, $loader); } @@ -923,6 +927,7 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder return 2 === substr_count($file->getBasename(), '.') && preg_match('/\.\w+$/', $file->getBasename()); }) ->in($dirs) + ->sortByName() ; foreach ($finder as $file) { @@ -1032,7 +1037,7 @@ private function registerValidatorMapping(ContainerBuilder $container, array $co private function registerMappingFilesFromDir($dir, callable $fileRecorder) { - foreach (Finder::create()->followLinks()->files()->in($dir)->name('/\.(xml|ya?ml)$/') as $file) { + foreach (Finder::create()->followLinks()->files()->in($dir)->name('/\.(xml|ya?ml)$/')->sortByName() as $file) { $fileRecorder($file->getExtension(), $file->getRealPath()); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 9484b985bfad4..34f47a0599b31 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -78,6 +78,8 @@ + %translator.default_path% + @@ -86,6 +88,8 @@ %kernel.default_locale% + %translator.default_path% + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml index 5d4aa8625eefd..82d5b4c6621cf 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml @@ -52,7 +52,7 @@ - %kernel.root_dir% + %kernel.project_dir% %kernel.charset% diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php index 0d702a0aca7ab..01e6df156a8ea 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php @@ -64,6 +64,21 @@ public function testDebugDefaultDirectory() $this->assertRegExp('/unused/', $tester->getDisplay()); } + public function testDebugDefaultRootDirectory() + { + $this->fs->remove($this->translationDir); + $this->fs = new Filesystem(); + $this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true); + $this->fs->mkdir($this->translationDir.'/translations'); + $this->fs->mkdir($this->translationDir.'/templates'); + + $tester = $this->createCommandTester(array('foo' => 'foo'), array('bar' => 'bar')); + $tester->execute(array('locale' => 'en')); + + $this->assertRegExp('/missing/', $tester->getDisplay()); + $this->assertRegExp('/unused/', $tester->getDisplay()); + } + public function testDebugCustomDirectory() { $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')->getMock(); @@ -100,6 +115,8 @@ protected function setUp() $this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true); $this->fs->mkdir($this->translationDir.'/Resources/translations'); $this->fs->mkdir($this->translationDir.'/Resources/views'); + $this->fs->mkdir($this->translationDir.'/translations'); + $this->fs->mkdir($this->translationDir.'/templates'); } protected function tearDown() @@ -174,7 +191,7 @@ private function createCommandTester($extractedMessages = array(), $loadedMessag ->method('getContainer') ->will($this->returnValue($this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock())); - $command = new TranslationDebugCommand($translator, $loader, $extractor); + $command = new TranslationDebugCommand($translator, $loader, $extractor, $this->translationDir.'/translations', $this->translationDir.'/templates'); $application = new Application($kernel); $application->add($command); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php index a2a0c97e4aaed..9232b7b027e0f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php @@ -31,6 +31,19 @@ public function testDumpMessagesAndClean() $this->assertRegExp('/1 message was successfully extracted/', $tester->getDisplay()); } + public function testDumpMessagesAndCleanInRootDirectory() + { + $this->fs->remove($this->translationDir); + $this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true); + $this->fs->mkdir($this->translationDir.'/translations'); + $this->fs->mkdir($this->translationDir.'/templates'); + + $tester = $this->createCommandTester(array('messages' => array('foo' => 'foo'))); + $tester->execute(array('command' => 'translation:update', 'locale' => 'en', '--dump-messages' => true, '--clean' => true)); + $this->assertRegExp('/foo/', $tester->getDisplay()); + $this->assertRegExp('/1 message was successfully extracted/', $tester->getDisplay()); + } + public function testDumpTwoMessagesAndClean() { $tester = $this->createCommandTester(array('messages' => array('foo' => 'foo', 'bar' => 'bar'))); @@ -55,6 +68,18 @@ public function testWriteMessages() $this->assertRegExp('/Translation files were successfully updated./', $tester->getDisplay()); } + public function testWriteMessagesInRootDirectory() + { + $this->fs->remove($this->translationDir); + $this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true); + $this->fs->mkdir($this->translationDir.'/translations'); + $this->fs->mkdir($this->translationDir.'/templates'); + + $tester = $this->createCommandTester(array('messages' => array('foo' => 'foo'))); + $tester->execute(array('command' => 'translation:update', 'locale' => 'en', '--force' => true)); + $this->assertRegExp('/Translation files were successfully updated./', $tester->getDisplay()); + } + public function testWriteMessagesForSpecificDomain() { $tester = $this->createCommandTester(array('messages' => array('foo' => 'foo'), 'mydomain' => array('bar' => 'bar'))); @@ -68,6 +93,8 @@ protected function setUp() $this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true); $this->fs->mkdir($this->translationDir.'/Resources/translations'); $this->fs->mkdir($this->translationDir.'/Resources/views'); + $this->fs->mkdir($this->translationDir.'/translations'); + $this->fs->mkdir($this->translationDir.'/templates'); } protected function tearDown() @@ -152,7 +179,7 @@ private function createCommandTester($extractedMessages = array(), $loadedMessag ->method('getContainer') ->will($this->returnValue($this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock())); - $command = new TranslationUpdateCommand($writer, $loader, $extractor, 'en'); + $command = new TranslationUpdateCommand($writer, $loader, $extractor, 'en', $this->translationDir.'/translations', $this->translationDir.'/templates'); $application = new Application($kernel); $application->add($command); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php index 2b2b3f45f0a8d..a97daeef1d131 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php @@ -21,7 +21,7 @@ 'enabled' => false, ), 'router' => array( - 'resource' => '%kernel.root_dir%/config/routing.xml', + 'resource' => '%kernel.project_dir%/config/routing.xml', 'type' => 'xml', ), 'session' => array( @@ -54,7 +54,7 @@ 'translator' => array( 'enabled' => true, 'fallback' => 'fr', - 'paths' => array('%kernel.root_dir%/Fixtures/translations'), + 'paths' => array('%kernel.project_dir%/Fixtures/translations'), ), 'validation' => array( 'enabled' => true, diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_mapping.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_mapping.php index 4e437bf4e8e1c..f2b928ff2d693 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_mapping.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_mapping.php @@ -6,9 +6,9 @@ 'enable_annotations' => true, 'mapping' => array( 'paths' => array( - '%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files', - '%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml', - '%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yaml', + '%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files', + '%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml', + '%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yaml', ), ), ), diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_mapping.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_mapping.php index 51bbb90ef48a6..5d44c6c215a17 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_mapping.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_mapping.php @@ -4,9 +4,9 @@ 'validation' => array( 'mapping' => array( 'paths' => array( - '%kernel.root_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/files', - '%kernel.root_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yml', - '%kernel.root_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yaml', + '%kernel.project_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/files', + '%kernel.project_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yml', + '%kernel.project_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yaml', ), ), ), diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml index 81f7823eecb87..6920efebed320 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml @@ -14,7 +14,7 @@ - + @@ -37,7 +37,7 @@ - %kernel.root_dir%/Fixtures/translations + %kernel.project_dir%/Fixtures/translations diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_mapping.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_mapping.xml index 9fec09f0dbf0f..1ae06c85e13c1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_mapping.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_mapping.xml @@ -8,9 +8,9 @@ - %kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files - %kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml - %kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yaml + %kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files + %kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml + %kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yaml diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_mapping.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_mapping.xml index c011269bd370d..8d74ebb2118f9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_mapping.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_mapping.xml @@ -7,9 +7,9 @@ - %kernel.root_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/files - %kernel.root_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yml - %kernel.root_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yaml + %kernel.project_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/files + %kernel.project_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yml + %kernel.project_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yaml diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml index 116062e1369a7..3194a0fab2e1a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -14,7 +14,7 @@ framework: only_exceptions: true enabled: false router: - resource: '%kernel.root_dir%/config/routing.xml' + resource: '%kernel.project_dir%/config/routing.xml' type: xml session: storage_id: session.storage.native @@ -42,8 +42,8 @@ framework: translator: enabled: true fallback: fr - default_path: '%kernel.root_dir%/translations' - paths: ['%kernel.root_dir%/Fixtures/translations'] + default_path: '%kernel.project_dir%/translations' + paths: ['%kernel.project_dir%/Fixtures/translations'] validation: enabled: true annotations: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_mapping.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_mapping.yml index b977dc89be52f..77c9d517a33b0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_mapping.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_mapping.yml @@ -5,6 +5,6 @@ framework: enable_annotations: true mapping: paths: - - "%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files" - - "%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml" - - "%kernel.root_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yaml" + - "%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files" + - "%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml" + - "%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yaml" diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_mapping.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_mapping.yml index 7d79bc9a1c477..f05e33bb6c134 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_mapping.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_mapping.yml @@ -2,6 +2,6 @@ framework: validation: mapping: paths: - - "%kernel.root_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/files" - - "%kernel.root_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yml" - - "%kernel.root_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yaml" + - "%kernel.project_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/files" + - "%kernel.project_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yml" + - "%kernel.project_dir%/Fixtures/TestBundle/Resources/config/validation_mapping/validation.yaml" diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index d4e6d0e771b67..e015e78a94a3a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -315,7 +315,7 @@ public function testRouter() $this->assertTrue($container->has('router'), '->registerRouterConfiguration() loads routing.xml'); $arguments = $container->findDefinition('router')->getArguments(); - $this->assertEquals($container->getParameter('kernel.root_dir').'/config/routing.xml', $container->getParameter('router.resource'), '->registerRouterConfiguration() sets routing resource'); + $this->assertEquals($container->getParameter('kernel.project_dir').'/config/routing.xml', $container->getParameter('router.resource'), '->registerRouterConfiguration() sets routing resource'); $this->assertEquals('%router.resource%', $arguments[1], '->registerRouterConfiguration() sets routing resource'); $this->assertEquals('xml', $arguments[2]['resource_type'], '->registerRouterConfiguration() sets routing resource type'); } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 8351c86112212..4b5270659e7b5 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -349,7 +349,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a // Switch user listener if (isset($firewall['switch_user'])) { $listenerKeys[] = 'switch_user'; - $listeners[] = new Reference($this->createSwitchUserListener($container, $id, $firewall['switch_user'], $defaultProvider, $firewall['stateless'])); + $listeners[] = new Reference($this->createSwitchUserListener($container, $id, $firewall['switch_user'], $defaultProvider, $firewall['stateless'], $providerIds)); } // Access listener @@ -594,7 +594,7 @@ private function createExceptionListener($container, $config, $id, $defaultEntry return $exceptionListenerId; } - private function createSwitchUserListener($container, $id, $config, $defaultProvider = null, $stateless) + private function createSwitchUserListener($container, $id, $config, $defaultProvider, $stateless, $providerIds) { $userProvider = isset($config['provider']) ? $this->getUserProviderId($config['provider']) : $defaultProvider; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index 6a6b5125291bc..d60da7386cac8 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -168,6 +168,31 @@ public function testPerListenerProvider() $this->addToAssertionCount(1); } + /** + * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException + * @expectedExceptionMessage Not configuring explicitly the provider for the "http_basic" listener on "ambiguous" firewall is ambiguous as there is more than one registered provider. + */ + public function testMissingProviderForListener() + { + $container = $this->getRawContainer(); + $container->loadFromExtension('security', array( + 'providers' => array( + 'first' => array('id' => 'foo'), + 'second' => array('id' => 'bar'), + ), + + 'firewalls' => array( + 'ambiguous' => array( + 'http_basic' => true, + 'form_login' => array('provider' => 'second'), + 'logout_on_user_change' => true, + ), + ), + )); + + $container->compile(); + } + protected function getRawContainer() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index bc06403c6a6f5..23a9a4087ef4d 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -30,7 +30,7 @@ "symfony/dom-crawler": "~3.4|~4.0", "symfony/event-dispatcher": "~3.4|~4.0", "symfony/form": "~3.4|~4.0", - "symfony/framework-bundle": "~3.4|~4.0", + "symfony/framework-bundle": "~3.4-rc1|~4.0-rc1", "symfony/http-foundation": "~3.4|~4.0", "symfony/translation": "~3.4|~4.0", "symfony/twig-bundle": "~3.4|~4.0", @@ -40,7 +40,7 @@ "symfony/var-dumper": "~3.4|~4.0", "symfony/yaml": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", - "doctrine/doctrine-bundle": "~1.4", + "doctrine/doctrine-bundle": "~1.5", "twig/twig": "~1.34|~2.4" }, "conflict": { diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig index 87a60d4197072..f0ca2f5b048ee 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig @@ -22,7 +22,7 @@ table th { background-color: #E0E0E0; font-weight: bold; text-align: left; } .hidden { display: none; } .nowrap { white-space: nowrap; } .newline { display: block; } -.break-long-words { -ms-word-break: break-all; word-break: break-all; word-break: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; } +.break-long-words { word-wrap: break-word; overflow-wrap: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; min-width: 0; } .text-small { font-size: 12px !important; } .text-muted { color: #999; } .text-bold { font-weight: bold; } diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/ExtensionPassTest.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/ExtensionPassTest.php index 6ce77c54970c0..00c2217f07b3a 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/ExtensionPassTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/ExtensionPassTest.php @@ -22,7 +22,6 @@ public function testProcessDoesNotDropExistingFileLoaderMethodCalls() { $container = new ContainerBuilder(); $container->setParameter('kernel.debug', false); - $container->setParameter('kernel.root_dir', __DIR__); $container->register('twig.app_variable', '\Symfony\Bridge\Twig\AppVariable'); $container->register('templating', '\Symfony\Bundle\TwigBundle\TwigEngine'); diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/full.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/full.php index 839d037fdcd00..47b9e5d835e7e 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/full.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/full.php @@ -17,7 +17,7 @@ 'charset' => 'ISO-8859-1', 'debug' => true, 'strict_variables' => true, - 'default_path' => '%kernel.root_dir%/templates', + 'default_path' => '%kernel.project_dir%/Fixtures/templates', 'paths' => array( 'path1', 'path2', diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/full.xml b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/full.xml index 702e34617d6b9..116b128fe6c51 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/full.xml +++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/full.xml @@ -6,7 +6,7 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/twig http://symfony.com/schema/dic/twig/twig-1.0.xsd"> - + MyBundle::form.html.twig @@qux diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/full.yml index 07d4abe767a41..24c10c23fe8f1 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -13,7 +13,7 @@ twig: charset: ISO-8859-1 debug: true strict_variables: true - default_path: '%kernel.root_dir%/templates' + default_path: '%kernel.project_dir%/Fixtures/templates' paths: path1: '' path2: '' diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Functional/CacheWarmingTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Functional/CacheWarmingTest.php index 83bedda6773c3..a7a330859f688 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Functional/CacheWarmingTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Functional/CacheWarmingTest.php @@ -99,13 +99,18 @@ public function registerContainerConfiguration(LoaderInterface $loader) $container->loadFromExtension('framework', array( 'secret' => '$ecret', 'templating' => array('engines' => array('twig')), - 'router' => array('resource' => '%kernel.root_dir%/Resources/config/empty_routing.yml'), + 'router' => array('resource' => '%kernel.project_dir%/Resources/config/empty_routing.yml'), 'form' => array('enabled' => false), )); }); } } + public function getProjectDir() + { + return __DIR__; + } + public function getCacheDir() { return sys_get_temp_dir().'/'.Kernel::VERSION.'/CacheWarmingKernel/cache/'.$this->environment; diff --git a/src/Symfony/Bundle/WebProfilerBundle/DependencyInjection/WebProfilerExtension.php b/src/Symfony/Bundle/WebProfilerBundle/DependencyInjection/WebProfilerExtension.php index e8e3ee87e9c1c..8f74d05f43d05 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/DependencyInjection/WebProfilerExtension.php +++ b/src/Symfony/Bundle/WebProfilerBundle/DependencyInjection/WebProfilerExtension.php @@ -51,24 +51,6 @@ public function load(array $configs, ContainerBuilder $container) $container->setParameter('web_profiler.debug_toolbar.intercept_redirects', $config['intercept_redirects']); $container->setParameter('web_profiler.debug_toolbar.mode', $config['toolbar'] ? WebDebugToolbarListener::ENABLED : WebDebugToolbarListener::DISABLED); } - - $baseDir = array(); - $rootDir = $container->getParameter('kernel.root_dir'); - $rootDir = explode(DIRECTORY_SEPARATOR, realpath($rootDir) ?: $rootDir); - $bundleDir = explode(DIRECTORY_SEPARATOR, __DIR__); - for ($i = 0; isset($rootDir[$i], $bundleDir[$i]); ++$i) { - if ($rootDir[$i] !== $bundleDir[$i]) { - break; - } - $baseDir[] = $rootDir[$i]; - } - $baseDir = implode(DIRECTORY_SEPARATOR, $baseDir); - - $profilerController = $container->getDefinition('web_profiler.controller.profiler'); - $profilerController->replaceArgument(5, $baseDir); - - $fileLinkFormatter = $container->getDefinition('debug.file_link_formatter'); - $fileLinkFormatter->replaceArgument(2, $baseDir); } /** diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml index 538bea8ef3087..e5f9423ce5b86 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml @@ -13,7 +13,7 @@ %data_collector.templates% - null + %kernel.project_dir% @@ -54,7 +54,7 @@ %debug.file_link_format% - null + %kernel.project_dir% /_profiler/open?file=%%f&line=%%l#line%%l 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 6a86c951efaea..ed940b770c2ac 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig @@ -40,6 +40,7 @@ -moz-box-sizing: content-box; box-sizing: content-box; vertical-align: baseline; + letter-spacing: normal; } .sf-toolbarreset { diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php index e0df0459bf13c..4069cdd6c9268 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php @@ -60,7 +60,7 @@ protected function setUp() $this->container->setParameter('kernel.bundles', array()); $this->container->setParameter('kernel.cache_dir', __DIR__); $this->container->setParameter('kernel.debug', false); - $this->container->setParameter('kernel.root_dir', __DIR__); + $this->container->setParameter('kernel.project_dir', __DIR__); $this->container->setParameter('kernel.charset', 'UTF-8'); $this->container->setParameter('debug.file_link_format', null); $this->container->setParameter('profiler.class', array('Symfony\\Component\\HttpKernel\\Profiler\\Profiler')); diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index cafd87865a73f..2845613b330b6 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -120,8 +120,8 @@ public function run(InputInterface $input = null, OutputInterface $output = null try { $exitCode = $this->doRun($input, $output); - } catch (\Throwable $e) { - if (!$this->catchExceptions || !$e instanceof \Exception) { + } catch (\Exception $e) { + if (!$this->catchExceptions) { throw $e; } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php index a8a652c7a2319..ba6356f4aceb9 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php @@ -77,16 +77,20 @@ public function process(ContainerBuilder $container) } } - $resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs); - if (null !== $usedEnvs) { - throw new EnvParameterException(array($resolvedId), null, 'A service name ("%s") cannot contain dynamic values.'); + if ($definition->isPublic() && !$definition->isPrivate()) { + $resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs); + if (null !== $usedEnvs) { + throw new EnvParameterException(array($resolvedId), null, 'A service name ("%s") cannot contain dynamic values.'); + } } } foreach ($container->getAliases() as $id => $alias) { - $resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs); - if (null !== $usedEnvs) { - throw new EnvParameterException(array($resolvedId), null, 'An alias name ("%s") cannot contain dynamic values.'); + if ($alias->isPublic() && !$alias->isPrivate()) { + $resolvedId = $container->resolveEnvPlaceholders($id, null, $usedEnvs); + if (null !== $usedEnvs) { + throw new EnvParameterException(array($resolvedId), null, 'An alias name ("%s") cannot contain dynamic values.'); + } } } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveEnvPlaceholdersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveEnvPlaceholdersPass.php index 8e44008317c27..f42107c6f7fd2 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveEnvPlaceholdersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveEnvPlaceholdersPass.php @@ -35,7 +35,7 @@ protected function processValue($value, $isRoot = false) $value = parent::processValue($value, $isRoot); - if ($value && is_array($value)) { + if ($value && is_array($value) && !$isRoot) { $value = array_combine($this->container->resolveEnvPlaceholders(array_keys($value), true), $value); } diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index f2d121be5a9fd..3707b163d0dcd 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -544,7 +544,7 @@ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INV $this->{$loading}[$id] = true; try { - $service = $this->createService($definition, $id); + $service = $this->createService($definition, new \SplObjectStorage(), $id); } finally { unset($this->{$loading}[$id]); } @@ -978,8 +978,12 @@ public function findDefinition($id) * @throws RuntimeException When the service is a synthetic service * @throws InvalidArgumentException When configure callable is not callable */ - private function createService(Definition $definition, $id, $tryProxy = true) + private function createService(Definition $definition, \SplObjectStorage $inlinedDefinitions, $id = null, $tryProxy = true) { + if (null === $id && isset($inlinedDefinitions[$definition])) { + return $inlinedDefinitions[$definition]; + } + if ($definition instanceof ChildDefinition) { throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id)); } @@ -998,11 +1002,11 @@ private function createService(Definition $definition, $id, $tryProxy = true) ->instantiateProxy( $this, $definition, - $id, function () use ($definition, $id) { - return $this->createService($definition, $id, false); + $id, function () use ($definition, $inlinedDefinitions, $id) { + return $this->createService($definition, $inlinedDefinitions, $id, false); } ); - $this->shareService($definition, $proxy, $id); + $this->shareService($definition, $proxy, $id, $inlinedDefinitions); return $proxy; } @@ -1013,7 +1017,7 @@ private function createService(Definition $definition, $id, $tryProxy = true) require_once $parameterBag->resolveValue($definition->getFile()); } - $arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments()))); + $arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlinedDefinitions); if (null !== $id && $definition->isShared() && isset($this->services[$id]) && ($tryProxy || !$definition->isLazy())) { return $this->services[$id]; @@ -1021,7 +1025,7 @@ private function createService(Definition $definition, $id, $tryProxy = true) if (null !== $factory = $definition->getFactory()) { if (is_array($factory)) { - $factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]); + $factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlinedDefinitions), $factory[1]); } elseif (!is_string($factory)) { throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id)); } @@ -1047,16 +1051,16 @@ private function createService(Definition $definition, $id, $tryProxy = true) if ($tryProxy || !$definition->isLazy()) { // share only if proxying failed, or if not a proxy - $this->shareService($definition, $service, $id); + $this->shareService($definition, $service, $id, $inlinedDefinitions); } - $properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties()))); + $properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlinedDefinitions); foreach ($properties as $name => $value) { $service->$name = $value; } foreach ($definition->getMethodCalls() as $call) { - $this->callMethod($service, $call); + $this->callMethod($service, $call, $inlinedDefinitions); } if ($callable = $definition->getConfigurator()) { @@ -1066,7 +1070,7 @@ private function createService(Definition $definition, $id, $tryProxy = true) if ($callable[0] instanceof Reference) { $callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior()); } elseif ($callable[0] instanceof Definition) { - $callable[0] = $this->createService($callable[0], null); + $callable[0] = $this->createService($callable[0], $inlinedDefinitions); } } @@ -1089,10 +1093,15 @@ private function createService(Definition $definition, $id, $tryProxy = true) * the real service instances and all expressions evaluated */ public function resolveServices($value) + { + return $this->doResolveServices($value, new \SplObjectStorage()); + } + + private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions) { if (is_array($value)) { foreach ($value as $k => $v) { - $value[$k] = $this->resolveServices($v); + $value[$k] = $this->doResolveServices($v, $inlinedDefinitions); } } elseif ($value instanceof ServiceClosureArgument) { $reference = $value->getValues()[0]; @@ -1137,7 +1146,7 @@ public function resolveServices($value) } elseif ($value instanceof Reference) { $value = $this->get((string) $value, $value->getInvalidBehavior()); } elseif ($value instanceof Definition) { - $value = $this->createService($value, null); + $value = $this->createService($value, $inlinedDefinitions); } elseif ($value instanceof Expression) { $value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this)); } @@ -1253,7 +1262,7 @@ public function getAutoconfiguredInstanceof() * true to resolve to the actual values of the referenced env vars * @param array &$usedEnvs Env vars found while resolving are added to this array * - * @return string The string with env parameters resolved + * @return mixed The value with env parameters resolved if a string or an array is passed */ public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs = null) { @@ -1434,7 +1443,7 @@ private function getProxyInstantiator(): InstantiatorInterface return $this->proxyInstantiator; } - private function callMethod($service, $call) + private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitions) { foreach (self::getServiceConditionals($call[1]) as $s) { if (!$this->has($s)) { @@ -1447,7 +1456,7 @@ private function callMethod($service, $call) } } - call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])))); + call_user_func_array(array($service, $call[0]), $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlinedDefinitions)); } /** @@ -1457,9 +1466,14 @@ private function callMethod($service, $call) * @param object $service * @param string|null $id */ - private function shareService(Definition $definition, $service, $id) + private function shareService(Definition $definition, $service, $id, \SplObjectStorage $inlinedDefinitions) { - if (null !== $id && $definition->isShared()) { + if (!$definition->isShared()) { + return; + } + if (null === $id) { + $inlinedDefinitions[$definition] = $service; + } else { $this->services[$id] = $service; unset($this->loading[$id], $this->alreadyLoading[$id]); } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index c7af2c2e2c757..baf9613d841ad 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -199,7 +199,7 @@ public function dump(array $options = array()) sort($ids); $c = "export($id)." => true,\n"; + $c .= ' '.$this->doExport($id)." => true,\n"; } $files['removed-ids.php'] = $c .= ");\n"; } @@ -353,6 +353,7 @@ private function analyzeCircularReferences(array $edges, &$checkedNodes, &$curre if (isset($checkedNodes[$id])) { continue; } + $checkedNodes[$id] = true; if ($node->getValue() && ($edge->isLazy() || $edge->isWeak())) { // no-op @@ -364,10 +365,8 @@ private function analyzeCircularReferences(array $edges, &$checkedNodes, &$curre } else { $currentPath[$id] = $id; $this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath); + array_pop($currentPath); } - - $checkedNodes[$id] = true; - array_pop($currentPath); } } @@ -821,6 +820,7 @@ private function generateServiceFiles() private function addNewInstance(Definition $definition, $return, $instantiation, $id) { $class = $this->dumpValue($definition->getClass()); + $return = ' '.$return.$instantiation; $arguments = array(); foreach ($definition->getArguments() as $value) { @@ -836,7 +836,7 @@ private function addNewInstance(Definition $definition, $return, $instantiation, if ($callable[0] instanceof Reference || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) { - return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf("%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); } $class = $this->dumpValue($callable[0]); @@ -846,24 +846,24 @@ private function addNewInstance(Definition $definition, $return, $instantiation, throw new RuntimeException(sprintf('Cannot dump definition: The "%s" service is defined to be created by a factory but is missing the service reference, did you forget to define the factory service id or class?', $id)); } - return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf("%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : ''); } if (0 === strpos($class, 'new ')) { - return sprintf(" $return{$instantiation}(%s)->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf("(%s)->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); } - return sprintf(" $return{$instantiation}[%s, '%s'](%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf("[%s, '%s'](%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); } - return sprintf(" $return{$instantiation}%s(%s);\n", $this->dumpLiteralClass($this->dumpValue($callable)), $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf("%s(%s);\n", $this->dumpLiteralClass($this->dumpValue($callable)), $arguments ? implode(', ', $arguments) : ''); } if (false !== strpos($class, '$')) { - return sprintf(" \$class = %s;\n\n $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments)); + return sprintf(" \$class = %s;\n\n%snew \$class(%s);\n", $class, $return, implode(', ', $arguments)); } - return sprintf(" $return{$instantiation}new %s(%s);\n", $this->dumpLiteralClass($class), implode(', ', $arguments)); + return $return.sprintf("new %s(%s);\n", $this->dumpLiteralClass($class), implode(', ', $arguments)); } private function startClass(string $class, string $baseClass): string @@ -987,7 +987,7 @@ private function addSyntheticIds(): string ksort($definitions); foreach ($definitions as $id => $definition) { if ($definition->isSynthetic() && 'service_container' !== $id) { - $code .= ' '.$this->export($id)." => true,\n"; + $code .= ' '.$this->doExport($id)." => true,\n"; } } @@ -1012,7 +1012,7 @@ private function addRemovedIds(): string $ids = array_keys($ids); sort($ids); foreach ($ids as $id) { - $code .= ' '.$this->export($id)." => true,\n"; + $code .= ' '.$this->doExport($id)." => true,\n"; } $code = "array(\n{$code} )"; @@ -1035,7 +1035,7 @@ private function addMethodMap(): string ksort($definitions); foreach ($definitions as $id => $definition) { if (!$definition->isSynthetic() && $definition->isPublic() && (!$this->asFiles || !$definition->isShared() || $this->isHotPath($definition))) { - $code .= ' '.$this->export($id).' => '.$this->export($this->generateMethodName($id)).",\n"; + $code .= ' '.$this->doExport($id).' => '.$this->doExport($this->generateMethodName($id)).",\n"; } } @@ -1049,7 +1049,7 @@ private function addFileMap(): string ksort($definitions); foreach ($definitions as $id => $definition) { if (!$definition->isSynthetic() && $definition->isPublic() && $definition->isShared() && !$this->isHotPath($definition)) { - $code .= sprintf(" %s => __DIR__.'/%s.php',\n", $this->export($id), $this->generateMethodName($id)); + $code .= sprintf(" %s => __DIR__.'/%s.php',\n", $this->doExport($id), $this->generateMethodName($id)); } } @@ -1069,7 +1069,7 @@ private function addAliases(): string while (isset($aliases[$id])) { $id = (string) $aliases[$id]; } - $code .= ' '.$this->export($alias).' => '.$this->export($id).",\n"; + $code .= ' '.$this->doExport($alias).' => '.$this->doExport($id).",\n"; } return $code." );\n"; @@ -1744,9 +1744,9 @@ private function isHotPath(Definition $definition) private function export($value) { if (null !== $this->targetDirRegex && is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) { - $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1])).'.' : ''; + $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : ''; $suffix = $matches[0][1] + strlen($matches[0][0]); - $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix)) : ''; + $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : ''; $dirname = '__DIR__'; $offset = 1 + $this->targetDirMaxMatches - count($matches); @@ -1761,10 +1761,10 @@ private function export($value) return $dirname; } - return $this->doExport($value); + return $this->doExport($value, true); } - private function doExport($value) + private function doExport($value, $resolveEnv = false) { if (is_string($value) && false !== strpos($value, "\n")) { $cleanParts = explode("\n", $value); @@ -1774,7 +1774,7 @@ private function doExport($value) $export = var_export($value, true); } - if ("'" === $export[0] && $export !== $resolvedExport = $this->container->resolveEnvPlaceholders($export, "'.\$this->getEnv('string:%s').'")) { + if ($resolveEnv && "'" === $export[0] && $export !== $resolvedExport = $this->container->resolveEnvPlaceholders($export, "'.\$this->getEnv('string:%s').'")) { $export = $resolvedExport; if (".''" === substr($export, -3)) { $export = substr($export, 0, -3); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php index 473d5667d448e..f698ed02dc744 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php @@ -79,11 +79,11 @@ public function testInvalidTags() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvParameterException */ - public function testDynamicServiceName() + public function testDynamicPublicServiceName() { $container = new ContainerBuilder(); $env = $container->getParameterBag()->get('env(BAR)'); - $container->register("foo.$env", 'class'); + $container->register("foo.$env", 'class')->setPublic(true); $this->process($container); } @@ -91,15 +91,27 @@ public function testDynamicServiceName() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvParameterException */ - public function testDynamicAliasName() + public function testDynamicPublicAliasName() { $container = new ContainerBuilder(); $env = $container->getParameterBag()->get('env(BAR)'); - $container->setAlias("foo.$env", 'class'); + $container->setAlias("foo.$env", 'class')->setPublic(true); $this->process($container); } + public function testDynamicPrivateName() + { + $container = new ContainerBuilder(); + $env = $container->getParameterBag()->get('env(BAR)'); + $container->register("foo.$env", 'class'); + $container->setAlias("bar.$env", 'class'); + + $this->process($container); + + $this->addToAssertionCount(1); + } + protected function process(ContainerBuilder $container) { $pass = new CheckDefinitionValidityPass(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index be71581497ac7..5bcb915bc139c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -716,6 +716,29 @@ public function testEnvAreNullable() $this->assertNull($container->get('foo')->fake); } + public function testEnvInId() + { + $container = include __DIR__.'/Fixtures/containers/container_env_in_id.php'; + $container->compile(true); + + $expected = array( + 'service_container', + 'foo', + 'bar', + 'bar_%env(BAR)%', + ); + $this->assertSame($expected, array_keys($container->getDefinitions())); + + $expected = array( + PsrContainerInterface::class => true, + ContainerInterface::class => true, + 'baz_%env(BAR)%' => true, + ); + $this->assertSame($expected, $container->getRemovedIds()); + + $this->assertSame(array('baz_bar'), array_keys($container->getDefinition('foo')->getArgument(1))); + } + /** * @expectedException \Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException * @expectedExceptionMessage Circular reference detected for parameter "env(resolve:DUMMY_ENV_VAR)" ("env(resolve:DUMMY_ENV_VAR)" > "env(resolve:DUMMY_ENV_VAR)"). @@ -1051,6 +1074,28 @@ public function testLazyLoadedService() $this->assertTrue($classInList); } + public function testInlinedDefinitions() + { + $container = new ContainerBuilder(); + + $definition = new Definition('BarClass'); + + $container->register('bar_user', 'BarUserClass') + ->addArgument($definition) + ->setProperty('foo', $definition); + + $container->register('bar', 'BarClass') + ->setProperty('foo', $definition) + ->addMethodCall('setBaz', array($definition)); + + $barUser = $container->get('bar_user'); + $bar = $container->get('bar'); + + $this->assertSame($barUser->foo, $barUser->bar); + $this->assertSame($bar->foo, $bar->getBaz()); + $this->assertNotSame($bar->foo, $barUser->foo); + } + public function testInitializePropertiesBeforeMethodCalls() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 86c3eceb9b279..e1a5a28f159fd 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -325,6 +325,15 @@ public function testDumpAutowireData() $this->assertStringEqualsFile(self::$fixturesPath.'/php/services24.php', $dumper->dump()); } + public function testEnvInId() + { + $container = include self::$fixturesPath.'/containers/container_env_in_id.php'; + $container->compile(); + $dumper = new PhpDumper($container); + + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_env_in_id.php', $dumper->dump()); + } + public function testEnvParameter() { $rand = mt_rand(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_env_in_id.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_env_in_id.php new file mode 100644 index 0000000000000..4699f41011a41 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_env_in_id.php @@ -0,0 +1,22 @@ +setParameter('env(BAR)', 'bar'); + +$container->register('foo', 'stdClass')->setPublic(true) + ->addArgument(new Reference('bar_%env(BAR)%')) + ->addArgument(array('baz_%env(BAR)%' => new Reference('baz_%env(BAR)%'))); + +$container->register('bar', 'stdClass')->setPublic(true) + ->addArgument(new Reference('bar_%env(BAR)%')); + +$container->register('bar_%env(BAR)%', 'stdClass')->setPublic(false); +$container->register('baz_%env(BAR)%', 'stdClass')->setPublic(false); + +return $container; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php index ab07fadc25052..bc653a744c9c5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php @@ -9,7 +9,7 @@ function sc_configure($instance) $instance->configure(); } -class BarClass +class BarClass extends BazClass { protected $baz; public $foo = 'foo'; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php new file mode 100644 index 0000000000000..b6afb3cf15580 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php @@ -0,0 +1,149 @@ +parameters = $this->getDefaultParameters(); + + $this->services = $this->privates = array(); + $this->methodMap = array( + 'bar' => 'getBarService', + 'foo' => 'getFooService', + ); + + $this->aliases = array(); + } + + public function reset() + { + $this->privates = array(); + parent::reset(); + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function getRemovedIds() + { + return array( + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + 'bar_%env(BAR)%' => true, + 'baz_%env(BAR)%' => true, + ); + } + + /** + * Gets the public 'bar' shared service. + * + * @return \stdClass + */ + protected function getBarService() + { + return $this->services['bar'] = new \stdClass(($this->privates['bar_%env(BAR)%'] ?? $this->privates['bar_%env(BAR)%'] = new \stdClass())); + } + + /** + * Gets the public 'foo' shared service. + * + * @return \stdClass + */ + protected function getFooService() + { + return $this->services['foo'] = new \stdClass(($this->privates['bar_%env(BAR)%'] ?? $this->privates['bar_%env(BAR)%'] = new \stdClass()), array('baz_'.$this->getEnv('string:BAR') => new \stdClass())); + } + + public function getParameter($name) + { + $name = (string) $name; + + if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { + throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); + } + if (isset($this->loadedDynamicParameters[$name])) { + return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + + return $this->parameters[$name]; + } + + public function hasParameter($name) + { + $name = (string) $name; + + return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); + } + + public function setParameter($name, $value) + { + throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); + } + + public function getParameterBag() + { + if (null === $this->parameterBag) { + $parameters = $this->parameters; + foreach ($this->loadedDynamicParameters as $name => $loaded) { + $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + $this->parameterBag = new FrozenParameterBag($parameters); + } + + return $this->parameterBag; + } + + private $loadedDynamicParameters = array(); + private $dynamicParameters = array(); + + /** + * Computes a dynamic parameter. + * + * @param string The name of the dynamic parameter to load + * + * @return mixed The value of the dynamic parameter + * + * @throws InvalidArgumentException When the dynamic parameter does not exist + */ + private function getDynamicParameter($name) + { + throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); + } + + /** + * Gets the default parameters. + * + * @return array An array of the default parameters + */ + protected function getDefaultParameters() + { + return array( + 'env(BAR)' => 'bar', + ); + } +} diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php index b801101cbae7f..b67736b0ec8ed 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php @@ -34,8 +34,13 @@ public function buildForm(FormBuilderInterface $builder, array $options) if ($options['multiple']) { $data = array(); + $files = $event->getData(); - foreach ($event->getData() as $file) { + if (!is_array($files)) { + $files = array(); + } + + foreach ($files as $file) { if ($requestHandler->isFileUpload($file)) { $data[] = $file; } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php index 8ac62c8dfb1da..5ba1dc5a5101d 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php @@ -159,6 +159,24 @@ public function testMultipleSubmittedFilePathsAreDropped(RequestHandlerInterface $this->assertCount(1, $form->getData()); } + /** + * @dataProvider requestHandlerProvider + */ + public function testSubmitNonArrayValueWhenMultiple(RequestHandlerInterface $requestHandler) + { + $form = $this->factory + ->createBuilder(static::TESTED_TYPE, null, array( + 'multiple' => true, + )) + ->setRequestHandler($requestHandler) + ->getForm(); + $form->submit(null); + + $this->assertSame(array(), $form->getData()); + $this->assertSame(array(), $form->getNormData()); + $this->assertSame(array(), $form->getViewData()); + } + public function requestHandlerProvider() { return array( diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index ca019c32cb9cc..b0cd20167fe81 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -63,12 +63,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.0.0-RC1'; + const VERSION = '4.0.0-RC2'; const VERSION_ID = 40000; const MAJOR_VERSION = 4; const MINOR_VERSION = 0; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'RC1'; + const EXTRA_VERSION = 'RC2'; const END_OF_MAINTENANCE = '07/2018'; const END_OF_LIFE = '01/2019'; diff --git a/src/Symfony/Component/Lock/Tests/Store/MemcachedStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/MemcachedStoreTest.php index eb030fba0f9de..f4ab571f567a6 100644 --- a/src/Symfony/Component/Lock/Tests/Store/MemcachedStoreTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/MemcachedStoreTest.php @@ -26,7 +26,10 @@ public static function setupBeforeClass() { $memcached = new \Memcached(); $memcached->addServer(getenv('MEMCACHED_HOST'), 11211); - if (false === $memcached->getStats()) { + $memcached->get('foo'); + $code = $memcached->getResultCode(); + + if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) { self::markTestSkipped('Unable to connect to the memcache host'); } } diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 4dc52d36b8fdf..8bcbd159338ac 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1452,20 +1452,7 @@ public function testRawCommandLine() ) EOTXT; - - if (\PHP_VERSION_ID >= 70200) { - $expected = << Standard input code - [1] => a - [2] => - [3] => b -) - -EOTXT; - } - $this->assertSame($expected, $p->getOutput()); + $this->assertSame($expected, str_replace('Standard input code', '-', $p->getOutput())); } public function provideEscapeArgument() diff --git a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php index 616d01ef4cda4..4574a0201c0c3 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php @@ -34,7 +34,9 @@ class AnnotationDirectoryLoader extends AnnotationFileLoader */ public function load($path, $type = null) { - $dir = $this->locator->locate($path); + if (!is_dir($dir = $this->locator->locate($path))) { + return parent::supports($path, $type) ? parent::load($path, $type) : new RouteCollection(); + } $collection = new RouteCollection(); $collection->addResource(new DirectoryResource($dir, '/\.php$/')); @@ -74,16 +76,18 @@ function (\SplFileInfo $current) { */ public function supports($resource, $type = null) { - if (!is_string($resource)) { + if ('annotation' === $type) { + return true; + } + + if ($type || !is_string($resource)) { return false; } try { - $path = $this->locator->locate($resource); + return is_dir($this->locator->locate($resource)); } catch (\Exception $e) { return false; } - - return is_dir($path) && (!$type || 'annotation' === $type); } } diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php index 78cec4be2a159..1e8ee394015e1 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php @@ -69,6 +69,24 @@ public function testSupports() $this->assertFalse($this->loader->supports($fixturesDir, 'foo'), '->supports() checks the resource type if specified'); } + public function testItSupportsAnyAnnotation() + { + $this->assertTrue($this->loader->supports(__DIR__.'/../Fixtures/even-with-not-existing-folder', 'annotation')); + } + + public function testLoadFileIfLocatedResourceIsFile() + { + $this->reader->expects($this->exactly(1))->method('getClassAnnotation'); + + $this->reader + ->expects($this->any()) + ->method('getMethodAnnotations') + ->will($this->returnValue(array())) + ; + + $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php'); + } + private function expectAnnotationsToBeReadFrom(array $classes) { $this->reader->expects($this->exactly(count($classes))) diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 67ce5cefaa123..9593f8d3b4c22 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -43,7 +43,6 @@ class ContextListener implements ListenerInterface private $dispatcher; private $registered; private $trustResolver; - private $logoutOnUserChange = true; /** * @param TokenStorageInterface $tokenStorage diff --git a/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php b/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php index 199702b4692f4..7ec06684f5155 100644 --- a/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php +++ b/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php @@ -21,12 +21,16 @@ class TranslatorPass implements CompilerPassInterface private $translatorServiceId; private $readerServiceId; private $loaderTag; + private $debugCommandServiceId; + private $updateCommandServiceId; - public function __construct(string $translatorServiceId = 'translator.default', string $readerServiceId = 'translation.reader', string $loaderTag = 'translation.loader') + public function __construct(string $translatorServiceId = 'translator.default', string $readerServiceId = 'translation.reader', string $loaderTag = 'translation.loader', string $debugCommandServiceId = 'console.command.translation_debug', string $updateCommandServiceId = 'console.command.translation_update') { $this->translatorServiceId = $translatorServiceId; $this->readerServiceId = $readerServiceId; $this->loaderTag = $loaderTag; + $this->debugCommandServiceId = $debugCommandServiceId; + $this->updateCommandServiceId = $updateCommandServiceId; } public function process(ContainerBuilder $container) @@ -59,5 +63,10 @@ public function process(ContainerBuilder $container) ->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs)) ->replaceArgument(3, $loaders) ; + + if ($container->hasParameter('twig.default_path')) { + $container->getDefinition($this->debugCommandServiceId)->replaceArgument(4, $container->getParameter('twig.default_path')); + $container->getDefinition($this->updateCommandServiceId)->replaceArgument(5, $container->getParameter('twig.default_path')); + } } }