diff --git a/.travis.yml b/.travis.yml index 96e6b5f7f60b5..95dbc421be64f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,5 +51,5 @@ install: script: - if [ "$deps" = "no" ]; then echo "$components" | parallel --gnu --keep-order 'echo -e "\\nRunning {} tests"; phpunit --exclude-group tty,benchmark,intl-data {} || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; - if [ "$deps" = "no" ]; then echo -e "\\nRunning tests requiring tty"; phpunit --group tty || (echo -e "\\e[41mKO\\e[0m tty group" && $(exit 1)); fi; - - if [ "$deps" = "high" ]; then echo "$components" | parallel --gnu --keep-order -j10% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source update; phpunit --exclude-group tty,benchmark,intl-data || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; + - if [ "$deps" = "high" ]; then echo "$components" | parallel --gnu --keep-order -j10% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source update; phpunit --exclude-group tty,benchmark,intl-data,legacy || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; - if [ "$deps" = "low" ]; then echo "$components" | parallel --gnu --keep-order -j10% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source --prefer-lowest --prefer-stable update; phpunit --exclude-group tty,benchmark,intl-data || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md new file mode 100644 index 0000000000000..a58bb1834fe3e --- /dev/null +++ b/UPGRADE-2.8.md @@ -0,0 +1,67 @@ +UPGRADE FROM 2.7 to 2.8 +======================= + +Form +---- + + * The "cascade_validation" option was deprecated. Use the "constraints" + option together with the `Valid` constraint instead. Contrary to + "cascade_validation", "constraints" must be set on the respective child forms, + not the parent form. + + Before: + + ```php + $form = $this->createForm('form', $article, array('cascade_validation' => true)) + ->add('author', new AuthorType()) + ->getForm(); + ``` + + After: + + ```php + use Symfony\Component\Validator\Constraints\Valid; + + $form = $this->createForm('form', $article) + ->add('author', new AuthorType(), array( + 'constraints' => new Valid(), + )) + ->getForm(); + ``` + + Alternatively, you can set the `Valid` constraint in the model itself: + + ```php + use Symfony\Component\Validator\Constraints as Assert; + + class Article + { + /** + * @Assert\Valid + */ + private $author; + } + ``` + +Translator +---------- + + * The `getMessages()` method of the `Symfony\Component\Translation\Translator` was deprecated and will be removed in + Symfony 3.0. You should use the `getCatalogue()` method of the `Symfony\Component\Translation\TranslatorBagInterface`. + + Before: + + ```php + $messages = $translator->getMessages(); + ``` + + After: + + ```php + $catalogue = $translator->getCatalogue($locale); + $messages = $catalogue->all(); + + while ($catalogue = $catalogue->getFallbackCatalogue()) { + $messages = array_replace_recursive($catalogue->all(), $messages); + } + ``` diff --git a/composer.json b/composer.json index 115adbfc16f6a..1b7d12551747f 100644 --- a/composer.json +++ b/composer.json @@ -97,7 +97,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index ea8b88b101b62..b76704cba7154 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -20,16 +20,16 @@ "doctrine/common": "~2.3" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7", - "symfony/stopwatch": "~2.2", - "symfony/dependency-injection": "~2.2", - "symfony/form": "~2.7,>=2.7.1", - "symfony/http-kernel": "~2.2", - "symfony/property-access": "~2.3", - "symfony/security": "~2.2", - "symfony/expression-language": "~2.2", - "symfony/validator": "~2.5,>=2.5.5", - "symfony/translation": "~2.0,>=2.0.5", + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/stopwatch": "~2.2|~3.0.0", + "symfony/dependency-injection": "~2.2|~3.0.0", + "symfony/form": "~2.7,>=2.7.1|~3.0.0", + "symfony/http-kernel": "~2.2|~3.0.0", + "symfony/property-access": "~2.3|~3.0.0", + "symfony/security": "~2.2|~3.0.0", + "symfony/expression-language": "~2.2|~3.0.0", + "symfony/validator": "~2.5,>=2.5.5|~3.0.0", + "symfony/translation": "~2.0,>=2.0.5|~3.0.0", "doctrine/data-fixtures": "1.0.*", "doctrine/dbal": "~2.2", "doctrine/orm": "~2.2,>=2.2.3" @@ -47,7 +47,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php b/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php index c959a5a94fcb7..f1046c96a6ad1 100644 --- a/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php @@ -35,6 +35,7 @@ public function getLogs() 'priority' => $record['level'], 'priorityName' => $record['level_name'], 'context' => $record['context'], + 'channel' => isset($record['channel']) ? $record['channel'] : '', ); } diff --git a/src/Symfony/Bridge/Monolog/composer.json b/src/Symfony/Bridge/Monolog/composer.json index a3a4e374130e2..61b6ff02d3518 100644 --- a/src/Symfony/Bridge/Monolog/composer.json +++ b/src/Symfony/Bridge/Monolog/composer.json @@ -20,10 +20,10 @@ "monolog/monolog": "~1.11" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7", - "symfony/http-kernel": "~2.4", - "symfony/console": "~2.4", - "symfony/event-dispatcher": "~2.2" + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/http-kernel": "~2.4|~3.0.0", + "symfony/console": "~2.4|~3.0.0", + "symfony/event-dispatcher": "~2.2|~3.0.0" }, "suggest": { "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", @@ -36,7 +36,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 8412a277bae98..90ac8e5d9dd19 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 24a8edea01b45..1e0209760eb0f 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -17,12 +17,12 @@ ], "require": { "php": ">=5.3.9", - "symfony/dependency-injection": "~2.3", + "symfony/dependency-injection": "~2.3|~3.0.0", "ocramius/proxy-manager": "~0.4|~1.0" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7", - "symfony/config": "~2.3" + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/config": "~2.3|~3.0.0" }, "autoload": { "psr-4": { "Symfony\\Bridge\\ProxyManager\\": "" } @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bridge/Swiftmailer/composer.json b/src/Symfony/Bridge/Swiftmailer/composer.json index 6d3fa5057cd9d..3e5fcc3bf837a 100644 --- a/src/Symfony/Bridge/Swiftmailer/composer.json +++ b/src/Symfony/Bridge/Swiftmailer/composer.json @@ -20,7 +20,7 @@ "swiftmailer/swiftmailer": ">=4.2.0,<6.0-dev" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7" + "symfony/phpunit-bridge": "~2.7|~3.0.0" }, "suggest": { "symfony/http-kernel": "" @@ -31,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index de54d49c30456..a5da6c30adabb 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -176,6 +176,11 @@ {{ block('form_widget_simple') }} {%- endblock email_widget -%} +{%- block range_widget -%} + {% set type = type|default('range') %} + {{- block('form_widget_simple') -}} +{%- endblock range_widget %} + {%- block button_widget -%} {%- if label is empty -%} {%- if label_format is not empty -%} @@ -314,7 +319,6 @@ {%- block widget_attributes -%} id="{{ id }}" name="{{ full_name }}" - {%- if read_only %} readonly="readonly"{% endif -%} {%- if disabled %} disabled="disabled"{% endif -%} {%- if required %} required="required"{% endif -%} {%- for attrname, attrvalue in attr -%} diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 8b2081e92e0dd..1963ece7f1256 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -20,21 +20,21 @@ "twig/twig": "~1.18" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7", - "symfony/asset": "~2.7", - "symfony/finder": "~2.3", - "symfony/form": "~2.7,>=2.7.1", - "symfony/http-kernel": "~2.3", - "symfony/intl": "~2.3", - "symfony/routing": "~2.2", - "symfony/templating": "~2.1", - "symfony/translation": "~2.7", - "symfony/yaml": "~2.0,>=2.0.5", - "symfony/security": "~2.6", - "symfony/stopwatch": "~2.2", - "symfony/console": "~2.7", - "symfony/var-dumper": "~2.6", - "symfony/expression-language": "~2.4" + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/asset": "~2.7|~3.0.0", + "symfony/finder": "~2.3|~3.0.0", + "symfony/form": "~2.8|~3.0.0", + "symfony/http-kernel": "~2.3|~3.0.0", + "symfony/intl": "~2.3|~3.0.0", + "symfony/routing": "~2.2|~3.0.0", + "symfony/templating": "~2.1|~3.0.0", + "symfony/translation": "~2.7|~3.0.0", + "symfony/yaml": "~2.0,>=2.0.5|~3.0.0", + "symfony/security": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.2|~3.0.0", + "symfony/console": "~2.7|~3.0.0", + "symfony/var-dumper": "~2.6|~3.0.0", + "symfony/expression-language": "~2.4|~3.0.0" }, "suggest": { "symfony/finder": "", @@ -56,7 +56,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bundle/DebugBundle/composer.json b/src/Symfony/Bundle/DebugBundle/composer.json index e7ccc9a4b11f1..66d77643479dd 100644 --- a/src/Symfony/Bundle/DebugBundle/composer.json +++ b/src/Symfony/Bundle/DebugBundle/composer.json @@ -17,15 +17,15 @@ ], "require": { "php": ">=5.3.9", - "symfony/http-kernel": "~2.6", - "symfony/twig-bridge": "~2.6", - "symfony/var-dumper": "~2.6" + "symfony/http-kernel": "~2.6|~3.0.0", + "symfony/twig-bridge": "~2.6|~3.0.0", + "symfony/var-dumper": "~2.6|~3.0.0" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7", - "symfony/config": "~2.3", - "symfony/dependency-injection": "~2.3", - "symfony/web-profiler-bundle": "~2.3" + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/config": "~2.3|~3.0.0", + "symfony/dependency-injection": "~2.3|~3.0.0", + "symfony/web-profiler-bundle": "~2.3|~3.0.0" }, "suggest": { "symfony/config": "For service container configuration", @@ -37,7 +37,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php index 6af52feaaec57..44ebdeb36e7d4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php @@ -44,7 +44,8 @@ protected function configure() { $this ->setDefinition(array( - new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'), + new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1'), + new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'), new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root', null), new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script'), )) @@ -99,9 +100,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $address = $input->getArgument('address'); if (false === strpos($address, ':')) { - $output->writeln('The address has to be of the form bind-address:port.'); - - return 1; + $address = $address.':'.$input->getOption('port'); } if ($this->isOtherServerProcessRunning($address)) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php index 04906317fa944..d9eccc4d613e2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php @@ -33,7 +33,8 @@ protected function configure() { $this ->setDefinition(array( - new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'), + new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1'), + new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'), new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root', null), new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script'), )) @@ -106,9 +107,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $address = $input->getArgument('address'); if (false === strpos($address, ':')) { - $output->writeln('The address has to be of the form bind-address:port.'); - - return 1; + $address = $address.':'.$input->getOption('port'); } if ($this->isOtherServerProcessRunning($address)) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStopCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStopCommand.php index 9b0656c220b66..c40952059a294 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStopCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStopCommand.php @@ -14,6 +14,7 @@ use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Input\InputOption; /** * Stops a background process running PHP's built-in web server. @@ -29,7 +30,8 @@ protected function configure() { $this ->setDefinition(array( - new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'), + new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1'), + new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'), )) ->setName('server:stop') ->setDescription('Stops PHP\'s built-in web server that was started with the server:start command') @@ -53,6 +55,10 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { $address = $input->getArgument('address'); + if (false === strpos($address, ':')) { + $address = $address.':'.$input->getOption('port'); + } + $lockFile = $this->getLockFile($address); if (!file_exists($lockFile)) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php index 79736ebd68415..16cfcdb3a3be1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php @@ -11,12 +11,15 @@ namespace Symfony\Bundle\FrameworkBundle\Command; +use Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader; +use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\Translation\Catalogue\MergeOperation; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\Translation\Catalogue\MergeOperation; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\Translator; @@ -48,6 +51,7 @@ protected function configure() new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'The messages domain'), new InputOption('only-missing', null, InputOption::VALUE_NONE, 'Displays only missing messages'), new InputOption('only-unused', null, InputOption::VALUE_NONE, 'Displays only unused messages'), + new InputOption('all', null, InputOption::VALUE_NONE, 'Load messages from all registered bundles'), )) ->setDescription('Displays translation messages information') ->setHelp(<<php %command.full_name% en +You can display information about translations in all registered bundles in a specific locale: + + php %command.full_name% --all en + EOF ) ; @@ -92,119 +100,112 @@ protected function execute(InputInterface $input, OutputInterface $output) $locale = $input->getArgument('locale'); $domain = $input->getOption('domain'); + /** @var TranslationLoader $loader */ $loader = $this->getContainer()->get('translation.loader'); + /** @var Kernel $kernel */ $kernel = $this->getContainer()->get('kernel'); // Define Root Path to App folder - $rootPath = $kernel->getRootDir(); + $rootPaths = array($kernel->getRootDir()); // Override with provided Bundle info if (null !== $input->getArgument('bundle')) { try { - $rootPath = $kernel->getBundle($input->getArgument('bundle'))->getPath(); + $rootPaths = array($kernel->getBundle($input->getArgument('bundle'))->getPath()); } catch (\InvalidArgumentException $e) { // such a bundle does not exist, so treat the argument as path - $rootPath = $input->getArgument('bundle'); + $rootPaths = array($input->getArgument('bundle')); - if (!is_dir($rootPath)) { - throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $rootPath)); + if (!is_dir($rootPaths[0])) { + throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $rootPaths[0])); } } + } elseif ($input->getOption('all')) { + foreach ($kernel->getBundles() as $bundle) { + $rootPaths[] = $bundle->getPath(); + } } - // get bundle directory - $translationsPath = $rootPath.'/Resources/translations'; + foreach ($rootPaths as $rootPath) { + // get bundle directory + $translationsPath = $rootPath.'/Resources/translations'; - // Extract used messages - $extractedCatalogue = new MessageCatalogue($locale); - if (is_dir($rootPath.'/Resources/views')) { - $this->getContainer()->get('translation.extractor')->extract($rootPath.'/Resources/views', $extractedCatalogue); - } + $output->writeln(sprintf('Translations in %s', $translationsPath)); - // Load defined messages - $currentCatalogue = new MessageCatalogue($locale); - if (is_dir($translationsPath)) { - $loader->loadMessages($translationsPath, $currentCatalogue); - } - - // Merge defined and extracted messages to get all message ids - $mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue); - $allMessages = $mergeOperation->getResult()->all($domain); - if (null !== $domain) { - $allMessages = array($domain => $allMessages); - } + // Extract used messages + $extractedCatalogue = $this->extractMessages($locale, $rootPath); - // No defined or extracted messages - if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) { - $outputMessage = sprintf('No defined or extracted messages for locale "%s"', $locale); + // Load defined messages + $currentCatalogue = $this->loadCurrentMessages($locale, $translationsPath, $loader); + // Merge defined and extracted messages to get all message ids + $mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue); + $allMessages = $mergeOperation->getResult()->all($domain); if (null !== $domain) { - $outputMessage .= sprintf(' and domain "%s"', $domain); + $allMessages = array($domain => $allMessages); } - $output->warning($outputMessage); - - return; - } + // No defined or extracted messages + if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) { + $outputMessage = sprintf('No defined or extracted messages for locale "%s"', $locale); - // Load the fallback catalogues - $fallbackCatalogues = array(); - $translator = $this->getContainer()->get('translator'); - if ($translator instanceof Translator) { - foreach ($translator->getFallbackLocales() as $fallbackLocale) { - if ($fallbackLocale === $locale) { - continue; + if (null !== $domain) { + $outputMessage .= sprintf(' and domain "%s"', $domain); } - $fallbackCatalogue = new MessageCatalogue($fallbackLocale); - $loader->loadMessages($translationsPath, $fallbackCatalogue); - $fallbackCatalogues[] = $fallbackCatalogue; + $output->writeln($outputMessage); + + continue; } - } - // Display header line - $headers = array('State', 'Domain', 'Id', sprintf('Message Preview (%s)', $locale)); - foreach ($fallbackCatalogues as $fallbackCatalogue) { - $headers[] = sprintf('Fallback Message Preview (%s)', $fallbackCatalogue->getLocale()); - } - $rows = array(); - // Iterate all message ids and determine their state - foreach ($allMessages as $domain => $messages) { - foreach (array_keys($messages) as $messageId) { - $value = $currentCatalogue->get($messageId, $domain); - $states = array(); - - if ($extractedCatalogue->defines($messageId, $domain)) { - if (!$currentCatalogue->defines($messageId, $domain)) { - $states[] = self::MESSAGE_MISSING; + // Load the fallback catalogues + $fallbackCatalogues = $this->loadFallbackCatalogues($locale, $translationsPath, $loader); + + // Display header line + $headers = array('State', 'Domain', 'Id', sprintf('Message Preview (%s)', $locale)); + foreach ($fallbackCatalogues as $fallbackCatalogue) { + $headers[] = sprintf('Fallback Message Preview (%s)', $fallbackCatalogue->getLocale()); + } + + // Iterate all message ids and determine their state + $rows = array(); + foreach ($allMessages as $domain => $messages) { + foreach (array_keys($messages) as $messageId) { + $value = $currentCatalogue->get($messageId, $domain); + $states = array(); + + if ($extractedCatalogue->defines($messageId, $domain)) { + if (!$currentCatalogue->defines($messageId, $domain)) { + $states[] = self::MESSAGE_MISSING; + } + } elseif ($currentCatalogue->defines($messageId, $domain)) { + $states[] = self::MESSAGE_UNUSED; } - } elseif ($currentCatalogue->defines($messageId, $domain)) { - $states[] = self::MESSAGE_UNUSED; - } - if (!in_array(self::MESSAGE_UNUSED, $states) && true === $input->getOption('only-unused') - || !in_array(self::MESSAGE_MISSING, $states) && true === $input->getOption('only-missing')) { - continue; - } + if (!in_array(self::MESSAGE_UNUSED, $states) && true === $input->getOption('only-unused') + || !in_array(self::MESSAGE_MISSING, $states) && true === $input->getOption('only-missing')) { + continue; + } - foreach ($fallbackCatalogues as $fallbackCatalogue) { - if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) { - $states[] = self::MESSAGE_EQUALS_FALLBACK; + foreach ($fallbackCatalogues as $fallbackCatalogue) { + if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) { + $states[] = self::MESSAGE_EQUALS_FALLBACK; - break; + break; + } } - } - $row = array($this->formatStates($states), $domain, $this->formatId($messageId), $this->sanitizeString($value)); - foreach ($fallbackCatalogues as $fallbackCatalogue) { - $row[] = $this->sanitizeString($fallbackCatalogue->get($messageId, $domain)); - } + $row = array($this->formatStates($states), $domain, $this->formatId($messageId), $this->sanitizeString($value)); + foreach ($fallbackCatalogues as $fallbackCatalogue) { + $row[] = $this->sanitizeString($fallbackCatalogue->get($messageId, $domain)); + } - $rows[] = $row; + $rows[] = $row; + } } - } - $output->table($headers, $rows); + $output->table($headers, $rows); + } } private function formatState($state) @@ -253,4 +254,63 @@ private function sanitizeString($string, $length = 40) return $string; } + + /** + * @param string $locale + * @param string $rootPath + * + * @return MessageCatalogue + */ + private function extractMessages($locale, $rootPath) + { + $extractedCatalogue = new MessageCatalogue($locale); + if (is_dir($rootPath.'/Resources/views')) { + $this->getContainer()->get('translation.extractor')->extract($rootPath.'/Resources/views', $extractedCatalogue); + } + + return $extractedCatalogue; + } + + /** + * @param string $locale + * @param string $translationsPath + * @param TranslationLoader $loader + * + * @return MessageCatalogue + */ + private function loadCurrentMessages($locale, $translationsPath, TranslationLoader $loader) + { + $currentCatalogue = new MessageCatalogue($locale); + if (is_dir($translationsPath)) { + $loader->loadMessages($translationsPath, $currentCatalogue); + } + + return $currentCatalogue; + } + + /** + * @param string $locale + * @param string $translationsPath + * @param TranslationLoader $loader + * + * @return MessageCatalogue[] + */ + private function loadFallbackCatalogues($locale, $translationsPath, TranslationLoader $loader) + { + $fallbackCatalogues = array(); + $translator = $this->getContainer()->get('translator'); + if ($translator instanceof Translator) { + foreach ($translator->getFallbackLocales() as $fallbackLocale) { + if ($fallbackLocale === $locale) { + continue; + } + + $fallbackCatalogue = new MessageCatalogue($fallbackLocale); + $loader->loadMessages($translationsPath, $fallbackCatalogue); + $fallbackCatalogues[] = $fallbackCatalogue; + } + } + + return $fallbackCatalogues; + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index f61af1cc959ce..5981a700c77a1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -290,17 +290,27 @@ private function getEventDispatcherListenersData(EventDispatcherInterface $event { $data = array(); - $registeredListeners = $eventDispatcher->getListeners($event); + $registeredListeners = $eventDispatcher->getListeners($event, true); if (null !== $event) { - foreach ($registeredListeners as $listener) { - $data[] = $this->getCallableData($listener); + krsort($registeredListeners); + foreach ($registeredListeners as $priority => $listeners) { + foreach ($listeners as $listener) { + $listener = $this->getCallableData($listener); + $listener['priority'] = $priority; + $data[] = $listener; + } } } else { ksort($registeredListeners); foreach ($registeredListeners as $eventListened => $eventListeners) { - foreach ($eventListeners as $eventListener) { - $data[$eventListened][] = $this->getCallableData($eventListener); + krsort($eventListeners); + foreach ($eventListeners as $priority => $listeners) { + foreach ($listeners as $listener) { + $listener = $this->getCallableData($listener); + $listener['priority'] = $priority; + $data[$eventListened][] = $listener; + } } } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index 84877461c832a..8231c874779d3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -113,7 +113,7 @@ protected function describeContainerService($service, array $options = array()) } elseif ($service instanceof Definition) { $this->describeContainerDefinition($service, $childOptions); } else { - $this->write(sprintf("**`%s`:** `%s`", $options['id'], get_class($service))); + $this->write(sprintf('**`%s`:** `%s`', $options['id'], get_class($service))); } } @@ -269,21 +269,30 @@ protected function describeEventDispatcherListeners(EventDispatcherInterface $ev $this->write(sprintf('# %s', $title)."\n"); - $registeredListeners = $eventDispatcher->getListeners($event); + $registeredListeners = $eventDispatcher->getListeners($event, true); if (null !== $event) { - foreach ($registeredListeners as $order => $listener) { - $this->write("\n".sprintf('## Listener %d', $order + 1)."\n"); - $this->describeCallable($listener); + krsort($registeredListeners); + $order = 1; + foreach ($registeredListeners as $priority => $listeners) { + foreach ($listeners as $listener) { + $this->write("\n".sprintf('## Listener %d', $order++)."\n"); + $this->describeCallable($listener); + $this->write(sprintf('- Priority: `%d`', $priority)."\n"); + } } } else { ksort($registeredListeners); foreach ($registeredListeners as $eventListened => $eventListeners) { $this->write("\n".sprintf('## %s', $eventListened)."\n"); - - foreach ($eventListeners as $order => $eventListener) { - $this->write("\n".sprintf('### Listener %d', $order + 1)."\n"); - $this->describeCallable($eventListener); + krsort($eventListeners); + $order = 1; + foreach ($eventListeners as $priority => $listeners) { + foreach ($listeners as $listener) { + $this->write("\n".sprintf('### Listener %d', $order++)."\n"); + $this->describeCallable($listener); + $this->write(sprintf('- Priority: `%d`', $priority)."\n"); + } } } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 56ffa455faca8..6916832060773 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -212,7 +212,7 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o foreach ($definition->getTag($showTag) as $key => $tag) { $tagValues = array(); foreach ($tagsNames as $tagName) { - $tagValues[] = isset($tag[$tagName]) ? $tag[$tagName] : ""; + $tagValues[] = isset($tag[$tagName]) ? $tag[$tagName] : ''; } if (0 === $key) { $table->addRow(array_merge(array($serviceId), $tagValues, array($definition->getClass()))); @@ -225,10 +225,10 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o } } elseif ($definition instanceof Alias) { $alias = $definition; - $table->addRow(array_merge(array($serviceId, sprintf('alias for "%s"', $alias)), $tagsCount ? array_fill(0, $tagsCount, "") : array())); + $table->addRow(array_merge(array($serviceId, sprintf('alias for "%s"', $alias)), $tagsCount ? array_fill(0, $tagsCount, '') : array())); } else { // we have no information (happens with "service_container") - $table->addRow(array_merge(array($serviceId, get_class($definition)), $tagsCount ? array_fill(0, $tagsCount, "") : array())); + $table->addRow(array_merge(array($serviceId, get_class($definition)), $tagsCount ? array_fill(0, $tagsCount, '') : array())); } } @@ -245,7 +245,7 @@ protected function describeContainerDefinition(Definition $definition, array $op : array(); $description[] = sprintf('Service Id %s', isset($options['id']) ? $options['id'] : '-'); - $description[] = sprintf('Class %s', $definition->getClass() ?: "-"); + $description[] = sprintf('Class %s', $definition->getClass() ?: '-'); $tags = $definition->getTags(); if (count($tags)) { @@ -336,33 +336,16 @@ protected function describeEventDispatcherListeners(EventDispatcherInterface $ev $this->writeText($this->formatSection('event_dispatcher', $label)."\n", $options); - $registeredListeners = $eventDispatcher->getListeners($event); + $registeredListeners = $eventDispatcher->getListeners($event, true); if (null !== $event) { $this->writeText("\n"); - $table = new Table($this->getOutput()); - $table->getStyle()->setCellHeaderFormat('%s'); - $table->setHeaders(array('Order', 'Callable')); - - foreach ($registeredListeners as $order => $listener) { - $table->addRow(array(sprintf('#%d', $order + 1), $this->formatCallable($listener))); - } - - $table->render(); + $this->renderEventListenerTable($registeredListeners); } else { ksort($registeredListeners); foreach ($registeredListeners as $eventListened => $eventListeners) { $this->writeText(sprintf("\n[Event] %s\n", $eventListened), $options); - - $table = new Table($this->getOutput()); - $table->getStyle()->setCellHeaderFormat('%s'); - $table->setHeaders(array('Order', 'Callable')); - - foreach ($eventListeners as $order => $eventListener) { - $table->addRow(array(sprintf('#%d', $order + 1), $this->formatCallable($eventListener))); - } - - $table->render(); + $this->renderEventListenerTable($eventListeners); } } } @@ -375,6 +358,26 @@ protected function describeCallable($callable, array $options = array()) $this->writeText($this->formatCallable($callable), $options); } + /** + * @param array $array + */ + private function renderEventListenerTable(array $eventListeners) + { + $table = new Table($this->getOutput()); + $table->getStyle()->setCellHeaderFormat('%s'); + $table->setHeaders(array('Order', 'Callable', 'Priority')); + + krsort($eventListeners); + $order = 1; + foreach ($eventListeners as $priority => $listeners) { + foreach ($listeners as $listener) { + $table->addRow(array(sprintf('#%d', $order++), $this->formatCallable($listener), $priority)); + } + } + + $table->render(); + } + /** * @param array $array * diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index c37a9009fcff5..e62c71a2a018e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -446,13 +446,9 @@ private function getEventDispatcherListenersDocument(EventDispatcherInterface $e $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($eventDispatcherXML = $dom->createElement('event-dispatcher')); - $registeredListeners = $eventDispatcher->getListeners($event); + $registeredListeners = $eventDispatcher->getListeners($event, true); if (null !== $event) { - foreach ($registeredListeners as $listener) { - $callableXML = $this->getCallableDocument($listener); - - $eventDispatcherXML->appendChild($eventDispatcherXML->ownerDocument->importNode($callableXML->childNodes->item(0), true)); - } + $this->appendEventListenerDocument($eventDispatcherXML, $registeredListeners); } else { ksort($registeredListeners); @@ -460,17 +456,30 @@ private function getEventDispatcherListenersDocument(EventDispatcherInterface $e $eventDispatcherXML->appendChild($eventXML = $dom->createElement('event')); $eventXML->setAttribute('name', $eventListened); - foreach ($eventListeners as $eventListener) { - $callableXML = $this->getCallableDocument($eventListener); - - $eventXML->appendChild($eventXML->ownerDocument->importNode($callableXML->childNodes->item(0), true)); - } + $this->appendEventListenerDocument($eventXML, $eventListeners); } } return $dom; } + /** + * @param DOMElement $element + * @param array $eventListeners + */ + private function appendEventListenerDocument(\DOMElement $element, array $eventListeners) + { + krsort($eventListeners); + foreach ($eventListeners as $priority => $listeners) { + foreach ($listeners as $listener) { + $callableXML = $this->getCallableDocument($listener); + $callableXML->childNodes->item(0)->setAttribute('priority', $priority); + + $element->appendChild($element->ownerDocument->importNode($callableXML->childNodes->item(0), true)); + } + } + } + /** * @param callable $callable * diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 655e95cf93061..977c0669c409c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -575,6 +575,7 @@ private function addTranslatorSection(ArrayNodeDefinition $rootNode) ->info('translator configuration') ->canBeEnabled() ->fixXmlConfig('fallback') + ->fixXmlConfig('path') ->children() ->arrayNode('fallbacks') ->beforeNormalization()->ifString()->then(function ($v) { return array($v); })->end() @@ -582,6 +583,9 @@ private function addTranslatorSection(ArrayNodeDefinition $rootNode) ->defaultValue(array('en')) ->end() ->booleanNode('logging')->defaultValue($this->debug)->end() + ->arrayNode('paths') + ->prototype('scalar')->end() + ->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index a7d8aab22079c..e2e8a84163859 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -692,6 +692,13 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder $dirs[] = $dir; } } + foreach ($config['paths'] as $dir) { + if (is_dir($dir)) { + $dirs[] = $dir; + } else { + throw new \UnexpectedValueException(sprintf('%s defined in translator.paths does not exist or is not a directory', $dir)); + } + } if (is_dir($dir = $container->getParameter('kernel.root_dir').'/Resources/translations')) { $dirs[] = $dir; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml index 5090309101631..a7d09848e47a7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml @@ -113,6 +113,9 @@ + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml index 6b2f7c9688699..78a98177287db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml @@ -45,6 +45,11 @@ + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index fa7aa2b2bd808..e1ca041e6114f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -183,6 +183,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/range_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/range_widget.html.php new file mode 100644 index 0000000000000..4c628f8e005bc --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/range_widget.html.php @@ -0,0 +1 @@ +block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'range')); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php index 118e764c8555a..ac5a481d0b55e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php @@ -1,12 +1,11 @@ -id="escape($id) ?>" name="escape($full_name) ?>" readonly="readonly" -disabled="disabled" -required="required" +id="escape($id) ?>" name="escape($full_name) ?>" disabled="disabled" + required="required" $v): ?> -escape($k), $view->escape($view['translator']->trans($v, array(), $translation_domain))) ?> +escape($k), $view->escape($view['translator']->trans($v, array(), $translation_domain))) ?> -escape($k), $view->escape($k)) ?> +escape($k), $view->escape($k)) ?> -escape($k), $view->escape($v)) ?> +escape($k), $view->escape($v)) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php index 94db08b5bdc91..810038909d90c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php @@ -114,6 +114,7 @@ public static function getContainerDefinitions() /** * @deprecated since version 2.7, to be removed in 3.0 + * * @internal */ public static function getLegacyContainerDefinitions() @@ -157,8 +158,8 @@ public static function getEventDispatchers() { $eventDispatcher = new EventDispatcher(); - $eventDispatcher->addListener('event1', 'global_function'); - $eventDispatcher->addListener('event1', function () { return 'Closure'; }); + $eventDispatcher->addListener('event1', 'global_function', 255); + $eventDispatcher->addListener('event1', function () { return 'Closure'; }, -1); $eventDispatcher->addListener('event2', new CallableClass()); return array('event_dispatcher_1' => $eventDispatcher); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 617be624fdb9f..f553d6387f26c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -146,6 +146,7 @@ protected static function getBundleDefaultConfig() 'enabled' => false, 'fallbacks' => array('en'), 'logging' => true, + 'paths' => array(), ), 'validation' => array( 'enabled' => false, 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 5022aeaf9f207..a035b56d70029 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php @@ -50,6 +50,7 @@ 'translator' => array( 'enabled' => true, 'fallback' => 'fr', + 'paths' => array('%kernel.root_dir%/Fixtures/translations'), ), 'validation' => array( 'enabled' => true, diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/translations/test_paths.en.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/translations/test_paths.en.yml new file mode 100644 index 0000000000000..d4e682c47c9ca --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/translations/test_paths.en.yml @@ -0,0 +1,2 @@ +custom: + paths: test 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 5b16a59796091..bf4537b910e8b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml @@ -34,7 +34,9 @@ theme2 - + + %kernel.root_dir%/Fixtures/translations + 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 be1b41e25f894..47513b1f665b5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -39,6 +39,7 @@ framework: translator: enabled: true fallback: fr + paths: ['%kernel.root_dir%/Fixtures/translations'] validation: enabled: true cache: apc diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 918c676afe1a1..21ae0ac775dd4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -244,6 +244,11 @@ public function testTranslator() $files, '->registerTranslatorConfiguration() finds Security translation resources' ); + $this->assertContains( + strtr(__DIR__.'/Fixtures/translations/test_paths.en.yml', '/', DIRECTORY_SEPARATOR), + $files, + '->registerTranslatorConfiguration() finds translation resources in custom paths' + ); $calls = $container->getDefinition('translator.default')->getMethodCalls(); $this->assertEquals(array('fr'), $calls[0][1][0]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.json index e40e130d453cb..4b68f0cefc0e4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.json @@ -1,9 +1,11 @@ [ { "type": "function", - "name": "global_function" + "name": "global_function", + "priority": 255 }, { - "type": "closure" + "type": "closure", + "priority": -1 } ] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.md index 206c44f717526..98b81ecdce422 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.md @@ -4,7 +4,9 @@ - Type: `function` - Name: `global_function` +- Priority: `255` ## Listener 2 - Type: `closure` +- Priority: `-1` diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.txt index 22b17a19cfb91..45035d12d6228 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.txt @@ -1,8 +1,8 @@ [event_dispatcher] Registered listeners for event event1 -+-------+-------------------+ -| Order | Callable | -+-------+-------------------+ -| #1 | global_function() | -| #2 | \Closure() | -+-------+-------------------+ ++-------+-------------------+----------+ +| Order | Callable | Priority | ++-------+-------------------+----------+ +| #1 | global_function() | 255 | +| #2 | \Closure() | -1 | ++-------+-------------------+----------+ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.xml index 4806f1f1280c7..bc03189af7b80 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.xml @@ -1,5 +1,5 @@ - - + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.json index 56fc7a4f1e546..30772d9a4a212 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.json @@ -2,16 +2,19 @@ "event1": [ { "type": "function", - "name": "global_function" + "name": "global_function", + "priority": 255 }, { - "type": "closure" + "type": "closure", + "priority": -1 } ], "event2": [ { "type": "object", - "name": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass" + "name": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\CallableClass", + "priority": 0 } ] } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.md index ad4b79e3117fa..eb809789d5f17 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.md @@ -6,10 +6,12 @@ - Type: `function` - Name: `global_function` +- Priority: `255` ### Listener 2 - Type: `closure` +- Priority: `-1` ## event2 @@ -17,3 +19,4 @@ - Type: `object` - Name: `Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass` +- Priority: `0` diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.txt index 95a5b4648e939..88e5dc9c89692 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.txt @@ -1,16 +1,16 @@ [event_dispatcher] Registered listeners by event [Event] event1 -+-------+-------------------+ -| Order | Callable | -+-------+-------------------+ -| #1 | global_function() | -| #2 | \Closure() | -+-------+-------------------+ ++-------+-------------------+----------+ +| Order | Callable | Priority | ++-------+-------------------+----------+ +| #1 | global_function() | 255 | +| #2 | \Closure() | -1 | ++-------+-------------------+----------+ [Event] event2 -+-------+-----------------------------------------------------------------------------------+ -| Order | Callable | -+-------+-----------------------------------------------------------------------------------+ -| #1 | Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::__invoke() | -+-------+-----------------------------------------------------------------------------------+ ++-------+-----------------------------------------------------------------------------------+----------+ +| Order | Callable | Priority | ++-------+-----------------------------------------------------------------------------------+----------+ +| #1 | Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\CallableClass::__invoke() | 0 | ++-------+-----------------------------------------------------------------------------------+----------+ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.xml index 3e4b20d823798..d7443f9743666 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.xml @@ -1,10 +1,10 @@ - - + + - + diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index d56a84ed1d5fb..af5e02f4c8f99 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -17,36 +17,36 @@ ], "require": { "php": ">=5.3.9", - "symfony/asset": "~2.7", - "symfony/dependency-injection" : "~2.6,>=2.6.2", + "symfony/asset": "~2.7|~3.0.0", + "symfony/dependency-injection" : "~2.8", "symfony/config" : "~2.4", - "symfony/event-dispatcher": "~2.5", - "symfony/http-foundation": "~2.4.9|~2.5,>=2.5.4", - "symfony/http-kernel": "~2.7", - "symfony/filesystem": "~2.3", - "symfony/routing": "~2.6,>2.6.4", - "symfony/security-core": "~2.6", - "symfony/security-csrf": "~2.6", - "symfony/stopwatch": "~2.3", - "symfony/templating": "~2.1", - "symfony/translation": "~2.7", + "symfony/event-dispatcher": "~2.5|~3.0.0", + "symfony/http-foundation": "~2.4.9|~2.5,>=2.5.4|~3.0.0", + "symfony/http-kernel": "~2.7|~3.0.0", + "symfony/filesystem": "~2.3|~3.0.0", + "symfony/routing": "~2.6,>2.6.4|~3.0.0", + "symfony/security-core": "~2.6|~3.0.0", + "symfony/security-csrf": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0", + "symfony/templating": "~2.1|~3.0.0", + "symfony/translation": "~2.7|~3.0.0", "doctrine/annotations": "~1.0" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7", - "symfony/browser-kit": "~2.4", - "symfony/console": "~2.7", - "symfony/css-selector": "~2.0,>=2.0.5", - "symfony/dom-crawler": "~2.0,>=2.0.5", - "symfony/finder": "~2.0,>=2.0.5", - "symfony/intl": "~2.3", - "symfony/security": "~2.6", - "symfony/form": "~2.7", - "symfony/class-loader": "~2.1", - "symfony/expression-language": "~2.6", - "symfony/process": "~2.0,>=2.0.5", - "symfony/validator": "~2.5", - "symfony/yaml": "~2.0,>=2.0.5" + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/browser-kit": "~2.4|~3.0.0", + "symfony/console": "~2.7|~3.0.0", + "symfony/css-selector": "~2.0,>=2.0.5|~3.0.0", + "symfony/dom-crawler": "~2.0,>=2.0.5|~3.0.0", + "symfony/finder": "~2.0,>=2.0.5|~3.0.0", + "symfony/intl": "~2.3|~3.0.0", + "symfony/security": "~2.6|~3.0.0", + "symfony/form": "~2.8|~3.0.0", + "symfony/class-loader": "~2.1|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/process": "~2.0,>=2.0.5|~3.0.0", + "symfony/validator": "~2.5|~3.0.0", + "symfony/yaml": "~2.0,>=2.0.5|~3.0.0" }, "suggest": { "symfony/console": "For using the console commands", @@ -62,7 +62,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php index 497807174d24a..099b1b48b7261 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php @@ -14,6 +14,7 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Exception\LogicException; /** * Adds all configured security voters to the access decision manager. @@ -40,6 +41,10 @@ public function process(ContainerBuilder $container) $voters = iterator_to_array($voters); ksort($voters); - $container->getDefinition('security.access.decision_manager')->replaceArgument(0, array_values($voters)); + if (!$voters) { + throw new LogicException('No security voters found. You need to tag at least one with "security.voter"'); + } + + $container->getDefinition('security.access.decision_manager')->addMethodCall('setVoters', array(array_values($voters))); } } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig index 923be83810648..a495829d3e517 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig @@ -32,8 +32,7 @@ {% endset %} {% set icon %} - - {% if collector.user %}
{{ collector.user }}
{% endif %} + {{ collector.user }} {% endset %} {% include '@WebProfiler/Profiler/toolbar_item.html.twig' with { 'link': profiler_url } %} {% endblock %} diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 55c251a40be69..94847e822be59 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -17,25 +17,25 @@ ], "require": { "php": ">=5.3.9", - "symfony/security": "~2.7", - "symfony/http-kernel": "~2.2" + "symfony/security": "~2.8|~3.0.0", + "symfony/http-kernel": "~2.2|~3.0.0" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7", - "symfony/browser-kit": "~2.4", - "symfony/console": "~2.7", - "symfony/css-selector": "~2.0,>=2.0.5", - "symfony/dependency-injection": "~2.6,>=2.6.6", - "symfony/dom-crawler": "~2.0,>=2.0.5", - "symfony/form": "~2.7", - "symfony/framework-bundle": "~2.7", - "symfony/http-foundation": "~2.3", - "symfony/twig-bundle": "~2.7", - "symfony/twig-bridge": "~2.7", - "symfony/process": "~2.0,>=2.0.5", - "symfony/validator": "~2.5", - "symfony/yaml": "~2.0,>=2.0.5", - "symfony/expression-language": "~2.6", + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/browser-kit": "~2.4|~3.0.0", + "symfony/console": "~2.7|~3.0.0", + "symfony/css-selector": "~2.0,>=2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6,>=2.6.6|~3.0.0", + "symfony/dom-crawler": "~2.0,>=2.0.5|~3.0.0", + "symfony/form": "~2.7|~3.0.0", + "symfony/framework-bundle": "~2.7|~3.0.0", + "symfony/http-foundation": "~2.3|~3.0.0", + "symfony/twig-bundle": "~2.7|~3.0.0", + "symfony/twig-bridge": "~2.7|~3.0.0", + "symfony/process": "~2.0,>=2.0.5|~3.0.0", + "symfony/validator": "~2.5|~3.0.0", + "symfony/yaml": "~2.0,>=2.0.5|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", "doctrine/doctrine-bundle": "~1.2", "twig/twig": "~1.12", "ircmaxell/password-compat": "~1.0" @@ -46,7 +46,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index 8b28042bd4b6b..df49f8b37217f 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\TwigBundle\DependencyInjection; use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Resource\FileExistenceResource; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; @@ -78,19 +79,25 @@ public function load(array $configs, ContainerBuilder $container) // register bundles as Twig namespaces foreach ($container->getParameter('kernel.bundles') as $bundle => $class) { - if (is_dir($dir = $container->getParameter('kernel.root_dir').'/Resources/'.$bundle.'/views')) { + $dir = $container->getParameter('kernel.root_dir').'/Resources/'.$bundle.'/views'; + if (is_dir($dir)) { $this->addTwigPath($twigFilesystemLoaderDefinition, $dir, $bundle); } + $container->addResource(new FileExistenceResource($dir)); $reflection = new \ReflectionClass($class); - if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/views')) { + $dir = dirname($reflection->getFilename()).'/Resources/views'; + if (is_dir($dir)) { $this->addTwigPath($twigFilesystemLoaderDefinition, $dir, $bundle); } + $container->addResource(new FileExistenceResource($dir)); } - if (is_dir($dir = $container->getParameter('kernel.root_dir').'/Resources/views')) { + $dir = $container->getParameter('kernel.root_dir').'/Resources/views'; + if (is_dir($dir)) { $twigFilesystemLoaderDefinition->addMethodCall('addPath', array($dir)); } + $container->addResource(new FileExistenceResource($dir)); if (!empty($config['globals'])) { $def = $container->getDefinition('twig'); diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json index 61c85d33e3ed0..1f73c781e9f3b 100644 --- a/src/Symfony/Bundle/TwigBundle/composer.json +++ b/src/Symfony/Bundle/TwigBundle/composer.json @@ -17,20 +17,20 @@ ], "require": { "php": ">=5.3.9", - "symfony/asset": "~2.7", - "symfony/twig-bridge": "~2.7", - "symfony/http-foundation": "~2.5", + "symfony/asset": "~2.7|~3.0.0", + "symfony/twig-bridge": "~2.7|~3.0.0", + "symfony/http-foundation": "~2.5|~3.0.0", "symfony/http-kernel": "~2.7" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7", - "symfony/stopwatch": "~2.2", - "symfony/dependency-injection": "~2.6,>=2.6.6", - "symfony/expression-language": "~2.4", - "symfony/config": "~2.2", - "symfony/routing": "~2.1", - "symfony/templating": "~2.1", - "symfony/framework-bundle": "~2.7" + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/stopwatch": "~2.2|~3.0.0", + "symfony/dependency-injection": "~2.6,>=2.6.6|~3.0.0", + "symfony/expression-language": "~2.4|~3.0.0", + "symfony/config": "~2.8|~3.0.0", + "symfony/routing": "~2.1|~3.0.0", + "symfony/templating": "~2.1|~3.0.0", + "symfony/framework-bundle": "~2.7|~3.0.0" }, "autoload": { "psr-4": { "Symfony\\Bundle\\TwigBundle\\": "" } @@ -38,7 +38,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } } } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig index d25122b90bf27..485cb57c9bff6 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig @@ -69,8 +69,7 @@ {% set debug_status_class %}sf-toolbar-status sf-toolbar-status-{{ collector.debug ? 'green' : 'red' }}{% endset %} {% set icon %} - - {{ token }} + {{ token }} {% if 'n/a' != collector.appname or 'n/a' != collector.env %} {{ collector.appname }} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig index ffcc6609d68da..a6707da12d77e 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig @@ -87,20 +87,30 @@ {% if collector.logs %} -