Merge branch '2.8'

* 2.8: (65 commits)
  [VarDumper] Fix tests for HHVM
  Update DateTimeToArrayTransformer.php
  Mock microtime() and time() in transient tests
  Azerbaijani language pluralization rule
  Move HHVM tests out of the allowed failures
  Fix merge
  [2.6] Towards 100% HHVM compat
  [Security/Http] Fix test
  [Stopwatch] Fix test
  Minor fixes
  [Validator] Added missing error codes and turned codes into UUIDs
  Towards 100% HHVM compat
  Warmup twig templates in non-standard paths (closes #12507)
  [Bridge/PhpUnit] Enforce a consistent locale
  Fix param order of assertEquals (expected, actual) in test for Finder\Glob
  Fix choice translation domain for expanded choice widget
  unify default AccessDeniedExeption message
  trigger event with right user (add test)
  [Security] Initialize SwitchUserEvent::targetUser on attemptExitUser
  fixed CS
  ...

Conflicts:
	UPGRADE-2.8.md
	src/Symfony/Bridge/ProxyManager/composer.json
	src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
	src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
	src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
	src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
	src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php
	src/Symfony/Bundle/FrameworkBundle/Resources/config/old_assets.xml
	src/Symfony/Bundle/FrameworkBundle/Resources/config/test.xml
	src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.txt
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_1.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_1.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_1.txt
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_1.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_2.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_2.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_2.txt
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_2.xml
	src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/CsrfFormLoginBundle/Form/UserLoginFormType.php
	src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CsrfFormLogin/config.yml
	src/Symfony/Bundle/SecurityBundle/composer.json
	src/Symfony/Component/Debug/ErrorHandler.php
	src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php
	src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
	src/Symfony/Component/DependencyInjection/Definition.php
	src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
	src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
	src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
	src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
	src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php
	src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/legacy-container9.php
	src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/legacy-services9.dot
	src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/legacy-services6.xml
	src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/legacy-services9.xml
	src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/legacy-services6.yml
	src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/legacy-services9.yml
	src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
	src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php
	src/Symfony/Component/Form/ResolvedFormType.php
	src/Symfony/Component/Form/Tests/CompoundFormTest.php
	src/Symfony/Component/Process/Tests/AbstractProcessTest.php
	src/Symfony/Component/VarDumper/Tests/CliDumperTest.php
	src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php
This commit is contained in:
Nicolas Grekas 2015-07-01 22:40:29 +02:00
commit d994a748dc
293 changed files with 3231 additions and 1102 deletions

View File

@ -20,7 +20,6 @@ matrix:
- php: hhvm - php: hhvm
allow_failures: allow_failures:
- php: nightly - php: nightly
- php: hhvm
fast_finish: true fast_finish: true
services: mongodb services: mongodb

View File

@ -50,30 +50,7 @@ class DbalLogger implements SQLLogger
} }
if (is_array($params)) { if (is_array($params)) {
foreach ($params as $index => $param) { $params = $this->normalizeParams($params);
if (!is_string($params[$index])) {
continue;
}
// non utf-8 strings break json encoding
if (!preg_match('//u', $params[$index])) {
$params[$index] = self::BINARY_DATA_VALUE;
continue;
}
// detect if the too long string must be shorten
if (function_exists('mb_strlen')) {
if (self::MAX_STRING_LENGTH < mb_strlen($params[$index], 'UTF-8')) {
$params[$index] = mb_substr($params[$index], 0, self::MAX_STRING_LENGTH - 6, 'UTF-8').' [...]';
continue;
}
} else {
if (self::MAX_STRING_LENGTH < strlen($params[$index])) {
$params[$index] = substr($params[$index], 0, self::MAX_STRING_LENGTH - 6).' [...]';
continue;
}
}
}
} }
if (null !== $this->logger) { if (null !== $this->logger) {
@ -101,4 +78,40 @@ class DbalLogger implements SQLLogger
{ {
$this->logger->debug($message, $params); $this->logger->debug($message, $params);
} }
private function normalizeParams(array $params)
{
foreach ($params as $index => $param) {
// normalize recursively
if (is_array($param)) {
$params[$index] = $this->normalizeParams($param);
continue;
}
if (!is_string($params[$index])) {
continue;
}
// non utf-8 strings break json encoding
if (!preg_match('//u', $params[$index])) {
$params[$index] = self::BINARY_DATA_VALUE;
continue;
}
// detect if the too long string must be shorten
if (function_exists('mb_strlen')) {
if (self::MAX_STRING_LENGTH < mb_strlen($params[$index], 'UTF-8')) {
$params[$index] = mb_substr($params[$index], 0, self::MAX_STRING_LENGTH - 6, 'UTF-8').' [...]';
continue;
}
} else {
if (self::MAX_STRING_LENGTH < strlen($params[$index])) {
$params[$index] = substr($params[$index], 0, self::MAX_STRING_LENGTH - 6).' [...]';
continue;
}
}
}
return $params;
}
} }

View File

@ -73,6 +73,37 @@ class DbalLoggerTest extends \PHPUnit_Framework_TestCase
)); ));
} }
public function testLogNonUtf8Array()
{
$logger = $this->getMock('Psr\\Log\\LoggerInterface');
$dbalLogger = $this
->getMockBuilder('Symfony\\Bridge\\Doctrine\\Logger\\DbalLogger')
->setConstructorArgs(array($logger, null))
->setMethods(array('log'))
->getMock()
;
$dbalLogger
->expects($this->once())
->method('log')
->with('SQL', array(
'utf8' => 'foo',
array(
'nonutf8' => DbalLogger::BINARY_DATA_VALUE,
)
)
)
;
$dbalLogger->startQuery('SQL', array(
'utf8' => 'foo',
array(
'nonutf8' => "\x7F\xFF",
)
));
}
public function testLogLongString() public function testLogLongString()
{ {
$logger = $this->getMock('Psr\\Log\\LoggerInterface'); $logger = $this->getMock('Psr\\Log\\LoggerInterface');

View File

@ -82,7 +82,7 @@ class UniqueEntityValidator extends ConstraintValidator
$criteria = array(); $criteria = array();
foreach ($fields as $fieldName) { foreach ($fields as $fieldName) {
if (!$class->hasField($fieldName) && !$class->hasAssociation($fieldName)) { if (!$class->hasField($fieldName) && !$class->hasAssociation($fieldName)) {
throw new ConstraintDefinitionException(sprintf("The field '%s' is not mapped by Doctrine, so it cannot be validated for uniqueness.", $fieldName)); throw new ConstraintDefinitionException(sprintf('The field "%s" is not mapped by Doctrine, so it cannot be validated for uniqueness.', $fieldName));
} }
$criteria[$fieldName] = $class->reflFields[$fieldName]->getValue($entity); $criteria[$fieldName] = $class->reflFields[$fieldName]->getValue($entity);

View File

@ -21,10 +21,10 @@ use Symfony\Component\HttpKernel\Event\GetResponseEvent;
*/ */
class WebProcessor extends BaseWebProcessor class WebProcessor extends BaseWebProcessor
{ {
public function __construct() public function __construct(array $extraFields = null)
{ {
// Pass an empty array as the default null value would access $_SERVER // Pass an empty array as the default null value would access $_SERVER
parent::__construct(array()); parent::__construct(array(), $extraFields);
} }
public function onKernelRequest(GetResponseEvent $event) public function onKernelRequest(GetResponseEvent $event)

View File

@ -18,6 +18,42 @@ use Symfony\Component\HttpFoundation\Request;
class WebProcessorTest extends \PHPUnit_Framework_TestCase class WebProcessorTest extends \PHPUnit_Framework_TestCase
{ {
public function testUsesRequestServerData() public function testUsesRequestServerData()
{
list($event, $server) = $this->createRequestEvent();
$processor = new WebProcessor();
$processor->onKernelRequest($event);
$record = $processor($this->getRecord());
$this->assertCount(5, $record['extra']);
$this->assertEquals($server['REQUEST_URI'], $record['extra']['url']);
$this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']);
$this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']);
$this->assertEquals($server['SERVER_NAME'], $record['extra']['server']);
$this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']);
}
public function testCanBeConstructedWithExtraFields()
{
if (!$this->isExtraFieldsSupported()) {
$this->markTestSkipped('WebProcessor of the installed Monolog version does not support $extraFields parameter');
}
list($event, $server) = $this->createRequestEvent();
$processor = new WebProcessor(array('url', 'referrer'));
$processor->onKernelRequest($event);
$record = $processor($this->getRecord());
$this->assertCount(2, $record['extra']);
$this->assertEquals($server['REQUEST_URI'], $record['extra']['url']);
$this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']);
}
/**
* @return array
*/
private function createRequestEvent()
{ {
$server = array( $server = array(
'REQUEST_URI' => 'A', 'REQUEST_URI' => 'A',
@ -40,15 +76,7 @@ class WebProcessorTest extends \PHPUnit_Framework_TestCase
->method('getRequest') ->method('getRequest')
->will($this->returnValue($request)); ->will($this->returnValue($request));
$processor = new WebProcessor(); return array($event, $server);
$processor->onKernelRequest($event);
$record = $processor($this->getRecord());
$this->assertEquals($server['REQUEST_URI'], $record['extra']['url']);
$this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']);
$this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']);
$this->assertEquals($server['SERVER_NAME'], $record['extra']['server']);
$this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']);
} }
/** /**
@ -57,7 +85,7 @@ class WebProcessorTest extends \PHPUnit_Framework_TestCase
* *
* @return array Record * @return array Record
*/ */
protected function getRecord($level = Logger::WARNING, $message = 'test') private function getRecord($level = Logger::WARNING, $message = 'test')
{ {
return array( return array(
'message' => $message, 'message' => $message,
@ -69,4 +97,17 @@ class WebProcessorTest extends \PHPUnit_Framework_TestCase
'extra' => array(), 'extra' => array(),
); );
} }
private function isExtraFieldsSupported()
{
$monologWebProcessorClass = new \ReflectionClass('Monolog\Processor\WebProcessor');
foreach ($monologWebProcessorClass->getConstructor()->getParameters() as $parameter) {
if ('extraFields' === $parameter->getName()) {
return true;
}
}
return false;
}
} }

View File

@ -6,6 +6,7 @@ Provides utilities for PHPUnit, especially user deprecation notices management.
It comes with the following features: It comes with the following features:
* disable the garbage collector; * disable the garbage collector;
* enforce a consistent `C` locale;
* auto-register `class_exists` to load Doctrine annotations; * auto-register `class_exists` to load Doctrine annotations;
* print a user deprecation notices summary at the end of the test suite. * print a user deprecation notices summary at the end of the test suite.

View File

@ -12,6 +12,9 @@ if (!defined('PHPUNIT_COMPOSER_INSTALL') && !class_exists('PHPUnit_TextUI_Comman
// https://bugs.php.net/bug.php?id=53976 // https://bugs.php.net/bug.php?id=53976
gc_disable(); gc_disable();
// Enforce a consistent locale
setlocale(LC_ALL, 'C');
if (class_exists('Doctrine\Common\Annotations\AnnotationRegistry')) { if (class_exists('Doctrine\Common\Annotations\AnnotationRegistry')) {
AnnotationRegistry::registerLoader('class_exists'); AnnotationRegistry::registerLoader('class_exists');
} }

View File

@ -68,9 +68,9 @@ class ProxyDumper implements DumperInterface
{ {
$instantiation = 'return'; $instantiation = 'return';
if (ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) { if ($definition->isShared() && ContainerInterface::SCOPE_CONTAINER === $definition->getScope(false)) {
$instantiation .= " \$this->services['$id'] ="; $instantiation .= " \$this->services['$id'] =";
} elseif (ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) { } elseif ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
$instantiation .= " \$this->services['$id'] = \$this->scopedServices['$scope']['$id'] ="; $instantiation .= " \$this->services['$id'] = \$this->scopedServices['$scope']['$id'] =";
} }

View File

@ -98,6 +98,7 @@
{%- for child in form %} {%- for child in form %}
{{- form_widget(child, { {{- form_widget(child, {
parent_label_class: label_attr.class|default(''), parent_label_class: label_attr.class|default(''),
translation_domain: choice_translation_domain,
}) -}} }) -}}
{% endfor -%} {% endfor -%}
</div> </div>
@ -106,6 +107,7 @@
{%- for child in form %} {%- for child in form %}
{{- form_widget(child, { {{- form_widget(child, {
parent_label_class: label_attr.class|default(''), parent_label_class: label_attr.class|default(''),
translation_domain: choice_translation_domain,
}) -}} }) -}}
{% endfor -%} {% endfor -%}
</div> </div>
@ -156,7 +158,7 @@
{%- endblock radio_label %} {%- endblock radio_label %}
{% block checkbox_radio_label %} {% block checkbox_radio_label %}
{# Do no display the label if widget is not defined in order to prevent double label rendering #} {# Do not display the label if widget is not defined in order to prevent double label rendering #}
{% if widget is defined %} {% if widget is defined %}
{% if required %} {% if required %}
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %} {% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
@ -169,7 +171,7 @@
{% endif %} {% endif %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}> <label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{- widget|raw -}} {{- widget|raw -}}
{{- label is not sameas(false) ? label|trans({}, translation_domain) -}} {{- label is not sameas(false) ? (translation_domain is sameas(false) ? label : label|trans({}, translation_domain)) -}}
</label> </label>
{% endif %} {% endif %}
{% endblock checkbox_radio_label %} {% endblock checkbox_radio_label %}

View File

@ -46,7 +46,7 @@
<div {{ block('widget_container_attributes') }}> <div {{ block('widget_container_attributes') }}>
{%- for child in form %} {%- for child in form %}
{{- form_widget(child) -}} {{- form_widget(child) -}}
{{- form_label(child) -}} {{- form_label(child, null, {translation_domain: choice_translation_domain}) -}}
{% endfor -%} {% endfor -%}
</div> </div>
{%- endblock choice_widget_expanded -%} {%- endblock choice_widget_expanded -%}
@ -57,7 +57,7 @@
{%- endif -%} {%- endif -%}
<select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}> <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
{%- if placeholder is not none -%} {%- if placeholder is not none -%}
<option value=""{% if required and value is empty %} selected="selected"{% endif %}>{{ placeholder|trans({}, translation_domain) }}</option> <option value=""{% if required and value is empty %} selected="selected"{% endif %}>{{ placeholder != '' ? placeholder|trans({}, translation_domain) }}</option>
{%- endif -%} {%- endif -%}
{%- if preferred_choices|length > 0 -%} {%- if preferred_choices|length > 0 -%}
{% set options = preferred_choices %} {% set options = preferred_choices %}
@ -225,7 +225,7 @@
{% set label = name|humanize %} {% set label = name|humanize %}
{%- endif -%} {%- endif -%}
{%- endif -%} {%- endif -%}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label> <label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ translation_domain is sameas(false) ? label : label|trans({}, translation_domain) }}</label>
{%- endif -%} {%- endif -%}
{%- endblock form_label -%} {%- endblock form_label -%}

View File

@ -37,6 +37,7 @@ class ServerStartCommand extends ServerCommand
new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'), new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'),
new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root', null), new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root', null),
new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script'), new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script'),
new InputOption('force', 'f', InputOption::VALUE_NONE, 'Force web server startup'),
)) ))
->setName('server:start') ->setName('server:start')
->setDescription('Starts PHP built-in web server in the background') ->setDescription('Starts PHP built-in web server in the background')
@ -110,8 +111,9 @@ EOF
$address = $address.':'.$input->getOption('port'); $address = $address.':'.$input->getOption('port');
} }
if ($this->isOtherServerProcessRunning($address)) { if (!$input->getOption('force') && $this->isOtherServerProcessRunning($address)) {
$output->writeln(sprintf('<error>A process is already listening on http://%s.</error>', $address)); $output->writeln(sprintf('<error>A process is already listening on http://%s.</error>', $address));
$output->writeln(sprintf('<error>Use the --force option if the server process terminated unexpectedly to start a new web server process.</error>'));
return 1; return 1;
} }

View File

@ -100,106 +100,103 @@ EOF
$kernel = $this->getContainer()->get('kernel'); $kernel = $this->getContainer()->get('kernel');
// Define Root Path to App folder // Define Root Path to App folder
$rootPaths = array($kernel->getRootDir()); $transPaths = array($kernel->getRootDir().'/Resources/');
// Override with provided Bundle info // Override with provided Bundle info
if (null !== $input->getArgument('bundle')) { if (null !== $input->getArgument('bundle')) {
try { try {
$rootPaths = array($kernel->getBundle($input->getArgument('bundle'))->getPath()); $bundle = $kernel->getBundle($input->getArgument('bundle'));
$transPaths = array(
$bundle->getPath().'/Resources/',
sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName()),
);
} catch (\InvalidArgumentException $e) { } catch (\InvalidArgumentException $e) {
// such a bundle does not exist, so treat the argument as path // such a bundle does not exist, so treat the argument as path
$rootPaths = array($input->getArgument('bundle')); $transPaths = array($input->getArgument('bundle').'/Resources/');
if (!is_dir($rootPaths[0])) { if (!is_dir($transPaths[0])) {
throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.</error>', $rootPaths[0])); throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
} }
} }
} elseif ($input->getOption('all')) { } elseif ($input->getOption('all')) {
foreach ($kernel->getBundles() as $bundle) { foreach ($kernel->getBundles() as $bundle) {
$rootPaths[] = $bundle->getPath(); $transPaths[] = $bundle->getPath().'/Resources/';
$transPaths[] = sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName());
} }
} }
foreach ($rootPaths as $rootPath) { // Extract used messages
// get bundle directory $extractedCatalogue = $this->extractMessages($locale, $transPaths);
$translationsPath = $rootPath.'/Resources/translations';
$output->writeln(sprintf('Translations in <info>%s</info>', $translationsPath)); // Load defined messages
$currentCatalogue = $this->loadCurrentMessages($locale, $transPaths, $loader);
// Extract used messages // Merge defined and extracted messages to get all message ids
$extractedCatalogue = $this->extractMessages($locale, $rootPath); $mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue);
$allMessages = $mergeOperation->getResult()->all($domain);
if (null !== $domain) {
$allMessages = array($domain => $allMessages);
}
// Load defined messages // No defined or extracted messages
$currentCatalogue = $this->loadCurrentMessages($locale, $translationsPath, $loader); if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) {
$outputMessage = sprintf('No defined or extracted messages for locale "%s"', $locale);
// Merge defined and extracted messages to get all message ids
$mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue);
$allMessages = $mergeOperation->getResult()->all($domain);
if (null !== $domain) { if (null !== $domain) {
$allMessages = array($domain => $allMessages); $outputMessage .= sprintf(' and domain "%s"', $domain);
} }
// No defined or extracted messages $output->warning($outputMessage);
if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) {
$outputMessage = sprintf('<info>No defined or extracted messages for locale "%s"</info>', $locale);
if (null !== $domain) { return;
$outputMessage .= sprintf(' <info>and domain "%s"</info>', $domain);
}
$output->writeln($outputMessage);
continue;
}
// 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;
}
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;
break;
}
}
$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;
}
}
$output->table($headers, $rows);
} }
// Load the fallback catalogues
$fallbackCatalogues = $this->loadFallbackCatalogues($locale, $transPaths, $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());
}
$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;
}
} 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;
}
foreach ($fallbackCatalogues as $fallbackCatalogue) {
if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) {
$states[] = self::MESSAGE_EQUALS_FALLBACK;
break;
}
}
$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;
}
}
$output->table($headers, $rows);
} }
private function formatState($state) private function formatState($state)
@ -251,15 +248,18 @@ EOF
/** /**
* @param string $locale * @param string $locale
* @param string $rootPath * @param array $transPaths
* *
* @return MessageCatalogue * @return MessageCatalogue
*/ */
private function extractMessages($locale, $rootPath) private function extractMessages($locale, $transPaths)
{ {
$extractedCatalogue = new MessageCatalogue($locale); $extractedCatalogue = new MessageCatalogue($locale);
if (is_dir($rootPath.'/Resources/views')) { foreach ($transPaths as $path) {
$this->getContainer()->get('translation.extractor')->extract($rootPath.'/Resources/views', $extractedCatalogue); $path = $path.'views';
if (is_dir($path)) {
$this->getContainer()->get('translation.extractor')->extract($path, $extractedCatalogue);
}
} }
return $extractedCatalogue; return $extractedCatalogue;
@ -267,16 +267,19 @@ EOF
/** /**
* @param string $locale * @param string $locale
* @param string $translationsPath * @param array $transPaths
* @param TranslationLoader $loader * @param TranslationLoader $loader
* *
* @return MessageCatalogue * @return MessageCatalogue
*/ */
private function loadCurrentMessages($locale, $translationsPath, TranslationLoader $loader) private function loadCurrentMessages($locale, $transPaths, TranslationLoader $loader)
{ {
$currentCatalogue = new MessageCatalogue($locale); $currentCatalogue = new MessageCatalogue($locale);
if (is_dir($translationsPath)) { foreach ($transPaths as $path) {
$loader->loadMessages($translationsPath, $currentCatalogue); $path = $path.'translations';
if (is_dir($path)) {
$loader->loadMessages($path, $currentCatalogue);
}
} }
return $currentCatalogue; return $currentCatalogue;
@ -284,12 +287,12 @@ EOF
/** /**
* @param string $locale * @param string $locale
* @param string $translationsPath * @param array $transPaths
* @param TranslationLoader $loader * @param TranslationLoader $loader
* *
* @return MessageCatalogue[] * @return MessageCatalogue[]
*/ */
private function loadFallbackCatalogues($locale, $translationsPath, TranslationLoader $loader) private function loadFallbackCatalogues($locale, $transPaths, TranslationLoader $loader)
{ {
$fallbackCatalogues = array(); $fallbackCatalogues = array();
$translator = $this->getContainer()->get('translator'); $translator = $this->getContainer()->get('translator');
@ -300,7 +303,12 @@ EOF
} }
$fallbackCatalogue = new MessageCatalogue($fallbackLocale); $fallbackCatalogue = new MessageCatalogue($fallbackLocale);
$loader->loadMessages($translationsPath, $fallbackCatalogue); foreach ($transPaths as $path) {
$path = $path.'translations';
if (is_dir($path)) {
$loader->loadMessages($path, $fallbackCatalogue);
}
}
$fallbackCatalogues[] = $fallbackCatalogue; $fallbackCatalogues[] = $fallbackCatalogue;
} }
} }

View File

@ -69,6 +69,8 @@ EOF
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
$output = new SymfonyStyle($input, $output); $output = new SymfonyStyle($input, $output);
$kernel = $this->getContainer()->get('kernel');
// check presence of force or dump-message // check presence of force or dump-message
if ($input->getOption('force') !== true && $input->getOption('dump-messages') !== true) { if ($input->getOption('force') !== true && $input->getOption('dump-messages') !== true) {
$output->error('You must choose one of --force or --dump-messages'); $output->error('You must choose one of --force or --dump-messages');
@ -87,30 +89,30 @@ EOF
$kernel = $this->getContainer()->get('kernel'); $kernel = $this->getContainer()->get('kernel');
// Define Root Path to App folder // Define Root Path to App folder
$rootPath = $kernel->getRootDir(); $transPaths = array($kernel->getRootDir().'/Resources/');
$currentName = 'app folder'; $currentName = 'app folder';
// Override with provided Bundle info // Override with provided Bundle info
if (null !== $input->getArgument('bundle')) { if (null !== $input->getArgument('bundle')) {
try { try {
$foundBundle = $kernel->getBundle($input->getArgument('bundle')); $foundBundle = $kernel->getBundle($input->getArgument('bundle'));
$rootPath = $foundBundle->getPath(); $transPaths = array(
$foundBundle->getPath().'/Resources/',
sprintf('%s/Resources/%s/', $kernel->getRootDir(), $foundBundle->getName()),
);
$currentName = $foundBundle->getName(); $currentName = $foundBundle->getName();
} catch (\InvalidArgumentException $e) { } catch (\InvalidArgumentException $e) {
// such a bundle does not exist, so treat the argument as path // such a bundle does not exist, so treat the argument as path
$rootPath = $input->getArgument('bundle'); $transPaths = array($input->getArgument('bundle').'/Resources/');
$currentName = $rootPath; $currentName = $transPaths[0];
if (!is_dir($rootPath)) { if (!is_dir($transPaths[0])) {
throw new \InvalidArgumentException(sprintf('<error>"%s" is neither an enabled bundle nor a directory.</error>', $rootPath)); throw new \InvalidArgumentException(sprintf('<error>"%s" is neither an enabled bundle nor a directory.</error>', $transPaths[0]));
} }
} }
} }
$output->title('Symfony translation update command'); $output->title('Symfony translation update command');
// get bundle directory
$translationsPath = $rootPath.'/Resources/translations';
$output->text(sprintf('Generating "<info>%s</info>" translation files for "<info>%s</info>"', $input->getArgument('locale'), $currentName)); $output->text(sprintf('Generating "<info>%s</info>" translation files for "<info>%s</info>"', $input->getArgument('locale'), $currentName));
// load any messages from templates // load any messages from templates
@ -118,13 +120,23 @@ EOF
$output->text('Parsing templates'); $output->text('Parsing templates');
$extractor = $this->getContainer()->get('translation.extractor'); $extractor = $this->getContainer()->get('translation.extractor');
$extractor->setPrefix($input->getOption('prefix')); $extractor->setPrefix($input->getOption('prefix'));
$extractor->extract($rootPath.'/Resources/views/', $extractedCatalogue); foreach ($transPaths as $path) {
$path = $path.'views';
if (is_dir($path)) {
$extractor->extract($path, $extractedCatalogue);
}
}
// load any existing messages from the translation files // load any existing messages from the translation files
$currentCatalogue = new MessageCatalogue($input->getArgument('locale')); $currentCatalogue = new MessageCatalogue($input->getArgument('locale'));
$output->text('Loading translation files'); $output->text('Loading translation files');
$loader = $this->getContainer()->get('translation.loader'); $loader = $this->getContainer()->get('translation.loader');
$loader->loadMessages($translationsPath, $currentCatalogue); foreach ($transPaths as $path) {
$path = $path.'translations';
if (is_dir($path)) {
$loader->loadMessages($path, $currentCatalogue);
}
}
// process catalogues // process catalogues
$operation = $input->getOption('clean') $operation = $input->getOption('clean')
@ -150,7 +162,7 @@ EOF
array_map(function ($id) { array_map(function ($id) {
return sprintf('<fg=green>%s</>', $id); return sprintf('<fg=green>%s</>', $id);
}, $newKeys), }, $newKeys),
array_map(function($id) { array_map(function ($id) {
return sprintf('<fg=red>%s</>', $id); return sprintf('<fg=red>%s</>', $id);
}, array_keys($operation->getObsoleteMessages($domain))) }, array_keys($operation->getObsoleteMessages($domain)))
)); ));
@ -168,7 +180,18 @@ EOF
// save the files // save the files
if ($input->getOption('force') === true) { if ($input->getOption('force') === true) {
$output->text('Writing files'); $output->text('Writing files');
$writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $translationsPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale')));
$bundleTransPath = false;
foreach ($transPaths as $path) {
$path = $path.'translations';
if (is_dir($path)) {
$bundleTransPath = $path;
}
}
if ($bundleTransPath) {
$writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale')));
}
} }
$output->newLine(); $output->newLine();

View File

@ -210,12 +210,16 @@ class JsonDescriptor extends Descriptor
{ {
$data = array( $data = array(
'class' => (string) $definition->getClass(), 'class' => (string) $definition->getClass(),
'scope' => $definition->getScope(), 'scope' => $definition->getScope(false),
'public' => $definition->isPublic(), 'public' => $definition->isPublic(),
'synthetic' => $definition->isSynthetic(), 'synthetic' => $definition->isSynthetic(),
'lazy' => $definition->isLazy(), 'lazy' => $definition->isLazy(),
); );
if (method_exists($definition, 'isShared')) {
$data['shared'] = $definition->isShared();
}
$data['abstract'] = $definition->isAbstract(); $data['abstract'] = $definition->isAbstract();
$data['file'] = $definition->getFile(); $data['file'] = $definition->getFile();

View File

@ -176,12 +176,16 @@ class MarkdownDescriptor extends Descriptor
protected function describeContainerDefinition(Definition $definition, array $options = array()) protected function describeContainerDefinition(Definition $definition, array $options = array())
{ {
$output = '- Class: `'.$definition->getClass().'`' $output = '- Class: `'.$definition->getClass().'`'
."\n".'- Scope: `'.$definition->getScope().'`' ."\n".'- Scope: `'.$definition->getScope(false).'`'
."\n".'- Public: '.($definition->isPublic() ? 'yes' : 'no') ."\n".'- Public: '.($definition->isPublic() ? 'yes' : 'no')
."\n".'- Synthetic: '.($definition->isSynthetic() ? 'yes' : 'no') ."\n".'- Synthetic: '.($definition->isSynthetic() ? 'yes' : 'no')
."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no') ."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no')
; ;
if (method_exists($definition, 'isShared')) {
$output .= "\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no');
}
$output .= "\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no'); $output .= "\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no');
if ($definition->getFile()) { if ($definition->getFile()) {

View File

@ -170,7 +170,7 @@ class TextDescriptor extends Descriptor
$serviceIds = isset($options['tag']) && $options['tag'] ? array_keys($builder->findTaggedServiceIds($options['tag'])) : $builder->getServiceIds(); $serviceIds = isset($options['tag']) && $options['tag'] ? array_keys($builder->findTaggedServiceIds($options['tag'])) : $builder->getServiceIds();
$maxTags = array(); $maxTags = array();
foreach ($serviceIds as $key => $serviceId) { foreach ($serviceIds as $key => $serviceId) {
$definition = $this->resolveServiceDefinition($builder, $serviceId); $definition = $this->resolveServiceDefinition($builder, $serviceId);
if ($definition instanceof Definition) { if ($definition instanceof Definition) {
// filter out private services unless shown explicitly // filter out private services unless shown explicitly
@ -256,10 +256,13 @@ class TextDescriptor extends Descriptor
$description[] = '<comment>Tags</comment> -'; $description[] = '<comment>Tags</comment> -';
} }
$description[] = sprintf('<comment>Scope</comment> %s', $definition->getScope()); $description[] = sprintf('<comment>Scope</comment> %s', $definition->getScope(false));
$description[] = sprintf('<comment>Public</comment> %s', $definition->isPublic() ? 'yes' : 'no'); $description[] = sprintf('<comment>Public</comment> %s', $definition->isPublic() ? 'yes' : 'no');
$description[] = sprintf('<comment>Synthetic</comment> %s', $definition->isSynthetic() ? 'yes' : 'no'); $description[] = sprintf('<comment>Synthetic</comment> %s', $definition->isSynthetic() ? 'yes' : 'no');
$description[] = sprintf('<comment>Lazy</comment> %s', $definition->isLazy() ? 'yes' : 'no'); $description[] = sprintf('<comment>Lazy</comment> %s', $definition->isLazy() ? 'yes' : 'no');
if (method_exists($definition, 'isShared')) {
$description[] = sprintf('<comment>Shared</comment> %s', $definition->isShared() ? 'yes' : 'no');
}
$description[] = sprintf('<comment>Abstract</comment> %s', $definition->isAbstract() ? 'yes' : 'no'); $description[] = sprintf('<comment>Abstract</comment> %s', $definition->isAbstract() ? 'yes' : 'no');
if ($definition->getFile()) { if ($definition->getFile()) {

View File

@ -346,10 +346,13 @@ class XmlDescriptor extends Descriptor
} }
} }
$serviceXML->setAttribute('scope', $definition->getScope()); $serviceXML->setAttribute('scope', $definition->getScope(false));
$serviceXML->setAttribute('public', $definition->isPublic() ? 'true' : 'false'); $serviceXML->setAttribute('public', $definition->isPublic() ? 'true' : 'false');
$serviceXML->setAttribute('synthetic', $definition->isSynthetic() ? 'true' : 'false'); $serviceXML->setAttribute('synthetic', $definition->isSynthetic() ? 'true' : 'false');
$serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false'); $serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false');
if (method_exists($definition, 'isShared')) {
$serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false');
}
$serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false'); $serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false');
$serviceXML->setAttribute('file', $definition->getFile()); $serviceXML->setAttribute('file', $definition->getFile());

View File

@ -119,9 +119,9 @@ abstract class Controller extends ContainerAware
* @param mixed $attributes The attributes * @param mixed $attributes The attributes
* @param mixed $object The object * @param mixed $object The object
* *
* @throws \LogicException
*
* @return bool * @return bool
*
* @throws \LogicException
*/ */
protected function isGranted($attributes, $object = null) protected function isGranted($attributes, $object = null)
{ {
@ -231,7 +231,7 @@ abstract class Controller extends ContainerAware
* *
* @return AccessDeniedException * @return AccessDeniedException
*/ */
protected function createAccessDeniedException($message = 'Access Denied', \Exception $previous = null) protected function createAccessDeniedException($message = 'Access Denied.', \Exception $previous = null)
{ {
return new AccessDeniedException($message, $previous); return new AccessDeniedException($message, $previous);
} }

View File

@ -444,7 +444,7 @@ class FrameworkExtension extends Extension
/** /**
* Loads the request configuration. * Loads the request configuration.
* *
* @param array $config A session configuration array * @param array $config A request configuration array
* @param ContainerBuilder $container A ContainerBuilder instance * @param ContainerBuilder $container A ContainerBuilder instance
* @param XmlFileLoader $loader An XmlFileLoader instance * @param XmlFileLoader $loader An XmlFileLoader instance
*/ */

View File

@ -1,31 +0,0 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="templating.asset.path_package" class="Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage" abstract="true">
<argument type="expression">service('request_stack').getMasterRequest()</argument>
<argument /> <!-- version -->
<argument /> <!-- version format -->
</service>
<service id="templating.asset.url_package" class="Symfony\Component\Templating\Asset\UrlPackage" abstract="true">
<argument /> <!-- base urls -->
<argument /> <!-- version -->
<argument /> <!-- version format -->
</service>
<service id="templating.asset.request_aware_package" class="Symfony\Component\Templating\Asset\PackageInterface" abstract="true">
<factory service="templating.asset.package_factory" method="getPackage" />
<argument type="expression">service('request_stack').getMasterRequest()</argument>
<argument /> <!-- HTTP id -->
<argument /> <!-- SSL id -->
</service>
<service id="templating.asset.package_factory" class="Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageFactory">
<argument type="service" id="service_container" />
</service>
</services>
</container>

View File

@ -9,16 +9,16 @@
</parameters> </parameters>
<services> <services>
<service id="test.client" class="Symfony\Bundle\FrameworkBundle\Client" scope="prototype"> <service id="test.client" class="Symfony\Bundle\FrameworkBundle\Client" shared="false">
<argument type="service" id="kernel" /> <argument type="service" id="kernel" />
<argument>%test.client.parameters%</argument> <argument>%test.client.parameters%</argument>
<argument type="service" id="test.client.history" /> <argument type="service" id="test.client.history" />
<argument type="service" id="test.client.cookiejar" /> <argument type="service" id="test.client.cookiejar" />
</service> </service>
<service id="test.client.history" class="Symfony\Component\BrowserKit\History" scope="prototype" /> <service id="test.client.history" class="Symfony\Component\BrowserKit\History" shared="false" />
<service id="test.client.cookiejar" class="Symfony\Component\BrowserKit\CookieJar" scope="prototype" /> <service id="test.client.cookiejar" class="Symfony\Component\BrowserKit\CookieJar" shared="false" />
<service id="test.session.listener" class="Symfony\Bundle\FrameworkBundle\EventListener\TestSessionListener"> <service id="test.session.listener" class="Symfony\Bundle\FrameworkBundle\EventListener\TestSessionListener">
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />

View File

@ -32,6 +32,16 @@
<argument>%validator.mapping.cache.prefix%</argument> <argument>%validator.mapping.cache.prefix%</argument>
</service> </service>
<service id="validator.mapping.cache.doctrine.apc" class="Symfony\Component\Validator\Mapping\Cache\DoctrineCache" public="false">
<argument type="service">
<service class="Doctrine\Common\Cache\ApcCache">
<call method="setNamespace">
<argument>%validator.mapping.cache.prefix%</argument>
</call>
</service>
</argument>
</service>
<service id="validator.validator_factory" class="Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory" public="false"> <service id="validator.validator_factory" class="Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory" public="false">
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />
<argument type="collection" /> <argument type="collection" />

View File

@ -7,7 +7,7 @@
)) ?> )) ?>
<?php if ($multiple): ?> multiple="multiple"<?php endif ?> <?php if ($multiple): ?> multiple="multiple"<?php endif ?>
> >
<?php if (null !== $placeholder): ?><option value=""<?php if ($required and empty($value) && "0" !== $value): ?> selected="selected"<?php endif?>><?php echo $view->escape($view['translator']->trans($placeholder, array(), $translation_domain)) ?></option><?php endif; ?> <?php if (null !== $placeholder): ?><option value=""<?php if ($required and empty($value) && '0' !== $value): ?> selected="selected"<?php endif?>><?php echo '' != $placeholder ? $view->escape($view['translator']->trans($placeholder, array(), $translation_domain)) : '' ?></option><?php endif; ?>
<?php if (count($preferred_choices) > 0): ?> <?php if (count($preferred_choices) > 0): ?>
<?php echo $view['form']->block($form, 'choice_widget_options', array('choices' => $preferred_choices)) ?> <?php echo $view['form']->block($form, 'choice_widget_options', array('choices' => $preferred_choices)) ?>
<?php if (count($choices) > 0 && null !== $separator): ?> <?php if (count($choices) > 0 && null !== $separator): ?>

View File

@ -1,6 +1,6 @@
<div <?php echo $view['form']->block($form, 'widget_container_attributes') ?>> <div <?php echo $view['form']->block($form, 'widget_container_attributes') ?>>
<?php foreach ($form as $child): ?> <?php foreach ($form as $child): ?>
<?php echo $view['form']->widget($child) ?> <?php echo $view['form']->widget($child) ?>
<?php echo $view['form']->label($child) ?> <?php echo $view['form']->label($child, null, array('translation_domain' => $choice_translation_domain)) ?>
<?php endforeach ?> <?php endforeach ?>
</div> </div>

View File

@ -4,5 +4,5 @@
<?php if (!$label) { $label = isset($label_format) <?php if (!$label) { $label = isset($label_format)
? strtr($label_format, array('%name%' => $name, '%id%' => $id)) ? strtr($label_format, array('%name%' => $name, '%id%' => $id))
: $view['form']->humanize($name); } ?> : $view['form']->humanize($name); } ?>
<label <?php foreach ($label_attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>><?php echo $view->escape($view['translator']->trans($label, array(), $translation_domain)) ?></label> <label <?php foreach ($label_attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>><?php echo $view->escape(false !== $translation_domain ? $view['translator']->trans($label, array(), $translation_domain) : $label) ?></label>
<?php endif ?> <?php endif ?>

View File

@ -14,7 +14,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension; use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
@ -515,14 +515,14 @@ abstract class FrameworkExtensionTest extends TestCase
return $container; return $container;
} }
private function assertPathPackage(ContainerBuilder $container, Definition $package, $basePath, $version, $format) private function assertPathPackage(ContainerBuilder $container, DefinitionDecorator $package, $basePath, $version, $format)
{ {
$this->assertEquals('assets.path_package', $package->getParent()); $this->assertEquals('assets.path_package', $package->getParent());
$this->assertEquals($basePath, $package->getArgument(0)); $this->assertEquals($basePath, $package->getArgument(0));
$this->assertVersionStrategy($container, $package->getArgument(1), $version, $format); $this->assertVersionStrategy($container, $package->getArgument(1), $version, $format);
} }
private function assertUrlPackage(ContainerBuilder $container, Definition $package, $baseUrls, $version, $format) private function assertUrlPackage(ContainerBuilder $container, DefinitionDecorator $package, $baseUrls, $version, $format)
{ {
$this->assertEquals('assets.url_package', $package->getParent()); $this->assertEquals('assets.url_package', $package->getParent());
$this->assertEquals($baseUrls, $package->getArgument(0)); $this->assertEquals($baseUrls, $package->getArgument(0));

View File

@ -6,6 +6,7 @@
"public": true, "public": true,
"synthetic": false, "synthetic": false,
"lazy": true, "lazy": true,
"shared": true,
"abstract": true, "abstract": true,
"file": null, "file": null,
"factory_class": "Full\\Qualified\\FactoryClass", "factory_class": "Full\\Qualified\\FactoryClass",

View File

@ -12,6 +12,7 @@ definition_1
- Public: yes - Public: yes
- Synthetic: no - Synthetic: no
- Lazy: yes - Lazy: yes
- Shared: yes
- Abstract: yes - Abstract: yes
- Factory Class: `Full\Qualified\FactoryClass` - Factory Class: `Full\Qualified\FactoryClass`
- Factory Method: `get` - Factory Method: `get`

View File

@ -2,7 +2,7 @@
<container> <container>
<alias id="alias_1" service="service_1" public="true"/> <alias id="alias_1" service="service_1" public="true"/>
<alias id="alias_2" service="service_2" public="false"/> <alias id="alias_2" service="service_2" public="false"/>
<definition id="definition_1" class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" abstract="true" file=""> <definition id="definition_1" class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" shared="true" abstract="true" file="">
<factory class="Full\Qualified\FactoryClass" method="get"/> <factory class="Full\Qualified\FactoryClass" method="get"/>
</definition> </definition>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerBuilder"/> <service id="service_container" class="Symfony\Component\DependencyInjection\ContainerBuilder"/>

View File

@ -6,6 +6,7 @@
"public": true, "public": true,
"synthetic": false, "synthetic": false,
"lazy": true, "lazy": true,
"shared": true,
"abstract": true, "abstract": true,
"file": null, "file": null,
"factory_class": "Full\\Qualified\\FactoryClass", "factory_class": "Full\\Qualified\\FactoryClass",
@ -20,6 +21,7 @@
"public": false, "public": false,
"synthetic": true, "synthetic": true,
"lazy": false, "lazy": false,
"shared": true,
"abstract": false, "abstract": false,
"file": "\/path\/to\/file", "file": "\/path\/to\/file",
"factory_service": "factory.service", "factory_service": "factory.service",

View File

@ -12,6 +12,7 @@ definition_1
- Public: yes - Public: yes
- Synthetic: no - Synthetic: no
- Lazy: yes - Lazy: yes
- Shared: yes
- Abstract: yes - Abstract: yes
- Factory Class: `Full\Qualified\FactoryClass` - Factory Class: `Full\Qualified\FactoryClass`
- Factory Method: `get` - Factory Method: `get`
@ -24,6 +25,7 @@ definition_2
- Public: no - Public: no
- Synthetic: yes - Synthetic: yes
- Lazy: no - Lazy: no
- Shared: yes
- Abstract: no - Abstract: no
- File: `/path/to/file` - File: `/path/to/file`
- Factory Service: `factory.service` - Factory Service: `factory.service`

View File

@ -2,10 +2,10 @@
<container> <container>
<alias id="alias_1" service="service_1" public="true"/> <alias id="alias_1" service="service_1" public="true"/>
<alias id="alias_2" service="service_2" public="false"/> <alias id="alias_2" service="service_2" public="false"/>
<definition id="definition_1" class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" abstract="true" file=""> <definition id="definition_1" class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" shared="true" abstract="true" file="">
<factory class="Full\Qualified\FactoryClass" method="get"/> <factory class="Full\Qualified\FactoryClass" method="get"/>
</definition> </definition>
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" abstract="false" file="/path/to/file"> <definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/> <factory service="factory.service" method="get"/>
<tags> <tags>
<tag name="tag1"> <tag name="tag1">

View File

@ -6,6 +6,7 @@
"public": false, "public": false,
"synthetic": true, "synthetic": true,
"lazy": false, "lazy": false,
"shared": true,
"abstract": false, "abstract": false,
"file": "\/path\/to\/file", "file": "\/path\/to\/file",
"factory_service": "factory.service", "factory_service": "factory.service",

View File

@ -12,6 +12,7 @@ definition_2
- Public: no - Public: no
- Synthetic: yes - Synthetic: yes
- Lazy: no - Lazy: no
- Shared: yes
- Abstract: no - Abstract: no
- File: `/path/to/file` - File: `/path/to/file`
- Factory Service: `factory.service` - Factory Service: `factory.service`

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<container> <container>
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" abstract="false" file="/path/to/file"> <definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/> <factory service="factory.service" method="get"/>
<tags> <tags>
<tag name="tag1"> <tag name="tag1">

View File

@ -6,6 +6,7 @@
"public": false, "public": false,
"synthetic": true, "synthetic": true,
"lazy": false, "lazy": false,
"shared": true,
"abstract": false, "abstract": false,
"file": "\/path\/to\/file", "file": "\/path\/to\/file",
"factory_service": "factory.service", "factory_service": "factory.service",
@ -19,6 +20,7 @@
"public": false, "public": false,
"synthetic": true, "synthetic": true,
"lazy": false, "lazy": false,
"shared": true,
"abstract": false, "abstract": false,
"file": "\/path\/to\/file", "file": "\/path\/to\/file",
"factory_service": "factory.service", "factory_service": "factory.service",

View File

@ -12,6 +12,7 @@ definition_2
- Public: no - Public: no
- Synthetic: yes - Synthetic: yes
- Lazy: no - Lazy: no
- Shared: yes
- Abstract: no - Abstract: no
- File: `/path/to/file` - File: `/path/to/file`
- Factory Service: `factory.service` - Factory Service: `factory.service`
@ -29,6 +30,7 @@ definition_2
- Public: no - Public: no
- Synthetic: yes - Synthetic: yes
- Lazy: no - Lazy: no
- Shared: yes
- Abstract: no - Abstract: no
- File: `/path/to/file` - File: `/path/to/file`
- Factory Service: `factory.service` - Factory Service: `factory.service`

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<container> <container>
<tag name="tag1"> <tag name="tag1">
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" abstract="false" file="/path/to/file"> <definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/> <factory service="factory.service" method="get"/>
</definition> </definition>
</tag> </tag>
<tag name="tag2"> <tag name="tag2">
<definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" abstract="false" file="/path/to/file"> <definition id="definition_2" class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/> <factory service="factory.service" method="get"/>
</definition> </definition>
</tag> </tag>

View File

@ -4,6 +4,7 @@
"public": true, "public": true,
"synthetic": false, "synthetic": false,
"lazy": true, "lazy": true,
"shared": true,
"abstract": true, "abstract": true,
"file": null, "file": null,
"factory_class": "Full\\Qualified\\FactoryClass", "factory_class": "Full\\Qualified\\FactoryClass",

View File

@ -3,6 +3,7 @@
- Public: yes - Public: yes
- Synthetic: no - Synthetic: no
- Lazy: yes - Lazy: yes
- Shared: yes
- Abstract: yes - Abstract: yes
- Factory Class: `Full\Qualified\FactoryClass` - Factory Class: `Full\Qualified\FactoryClass`
- Factory Method: `get` - Factory Method: `get`

View File

@ -5,6 +5,7 @@
<comment>Public</comment> yes <comment>Public</comment> yes
<comment>Synthetic</comment> no <comment>Synthetic</comment> no
<comment>Lazy</comment> yes <comment>Lazy</comment> yes
<comment>Shared</comment> yes
<comment>Abstract</comment> yes <comment>Abstract</comment> yes
<comment>Factory Class</comment> Full\Qualified\FactoryClass <comment>Factory Class</comment> Full\Qualified\FactoryClass
<comment>Factory Method</comment> get <comment>Factory Method</comment> get

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<definition class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" abstract="true" file=""> <definition class="Full\Qualified\Class1" scope="container" public="true" synthetic="false" lazy="true" shared="true" abstract="true" file="">
<factory class="Full\Qualified\FactoryClass" method="get"/> <factory class="Full\Qualified\FactoryClass" method="get"/>
</definition> </definition>

View File

@ -4,6 +4,7 @@
"public": false, "public": false,
"synthetic": true, "synthetic": true,
"lazy": false, "lazy": false,
"shared": true,
"abstract": false, "abstract": false,
"file": "\/path\/to\/file", "file": "\/path\/to\/file",
"factory_service": "factory.service", "factory_service": "factory.service",

View File

@ -3,6 +3,7 @@
- Public: no - Public: no
- Synthetic: yes - Synthetic: yes
- Lazy: no - Lazy: no
- Shared: yes
- Abstract: no - Abstract: no
- File: `/path/to/file` - File: `/path/to/file`
- Factory Service: `factory.service` - Factory Service: `factory.service`

View File

@ -8,6 +8,7 @@
<comment>Public</comment> no <comment>Public</comment> no
<comment>Synthetic</comment> yes <comment>Synthetic</comment> yes
<comment>Lazy</comment> no <comment>Lazy</comment> no
<comment>Shared</comment> yes
<comment>Abstract</comment> no <comment>Abstract</comment> no
<comment>Required File</comment> /path/to/file <comment>Required File</comment> /path/to/file
<comment>Factory Service</comment> factory.service <comment>Factory Service</comment> factory.service

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<definition class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" abstract="false" file="/path/to/file"> <definition class="Full\Qualified\Class2" scope="container" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<factory service="factory.service" method="get"/> <factory service="factory.service" method="get"/>
<tags> <tags>
<tag name="tag1"> <tag name="tag1">

View File

@ -4,7 +4,8 @@ imports:
services: services:
csrf_form_login.form.type: csrf_form_login.form.type:
class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\Form\UserLoginFormType class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\CsrfFormLoginBundle\Form\UserLoginFormType
arguments: [ @request_stack ] arguments:
- @request_stack
tags: tags:
- { name: form.type, alias: user_login } - { name: form.type, alias: user_login }

View File

@ -11,9 +11,11 @@
namespace Symfony\Bundle\TwigBundle\CacheWarmer; namespace Symfony\Bundle\TwigBundle\CacheWarmer;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplateFinderInterface; use Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplateFinderInterface;
use Symfony\Component\Templating\TemplateReference;
/** /**
* Generates the Twig cache for all templates. * Generates the Twig cache for all templates.
@ -27,14 +29,16 @@ class TemplateCacheCacheWarmer implements CacheWarmerInterface
{ {
protected $container; protected $container;
protected $finder; protected $finder;
private $paths;
/** /**
* Constructor. * Constructor.
* *
* @param ContainerInterface $container The dependency injection container * @param ContainerInterface $container The dependency injection container
* @param TemplateFinderInterface $finder The template paths cache warmer * @param TemplateFinderInterface $finder The template paths cache warmer
* @param array $paths Additional twig paths to warm
*/ */
public function __construct(ContainerInterface $container, TemplateFinderInterface $finder) public function __construct(ContainerInterface $container, TemplateFinderInterface $finder, array $paths = array())
{ {
// We don't inject the Twig environment directly as it depends on the // We don't inject the Twig environment directly as it depends on the
// template locator (via the loader) which might be a cached one. // template locator (via the loader) which might be a cached one.
@ -42,6 +46,7 @@ class TemplateCacheCacheWarmer implements CacheWarmerInterface
// has been warmed up // has been warmed up
$this->container = $container; $this->container = $container;
$this->finder = $finder; $this->finder = $finder;
$this->paths = $paths;
} }
/** /**
@ -53,7 +58,13 @@ class TemplateCacheCacheWarmer implements CacheWarmerInterface
{ {
$twig = $this->container->get('twig'); $twig = $this->container->get('twig');
foreach ($this->finder->findAllTemplates() as $template) { $templates = $this->finder->findAllTemplates();
foreach ($this->paths as $path => $namespace) {
$templates = array_merge($templates, $this->findTemplatesInFolder($namespace, $path));
}
foreach ($templates as $template) {
if ('twig' !== $template->get('engine')) { if ('twig' !== $template->get('engine')) {
continue; continue;
} }
@ -75,4 +86,32 @@ class TemplateCacheCacheWarmer implements CacheWarmerInterface
{ {
return true; return true;
} }
/**
* Find templates in the given directory.
*
* @param string $namespace The namespace for these templates
* @param string $dir The folder where to look for templates
*
* @return array An array of templates of type TemplateReferenceInterface
*/
private function findTemplatesInFolder($namespace, $dir)
{
if (!is_dir($dir)) {
return array();
}
$templates = array();
$finder = new Finder();
foreach ($finder->files()->followLinks()->in($dir) as $file) {
$name = $file->getRelativePathname();
$templates[] = new TemplateReference(
$namespace ? sprintf('@%s/%s', $namespace, $name) : $name,
'twig'
);
}
return $templates;
}
} }

View File

@ -77,6 +77,8 @@ class TwigExtension extends Extension
} }
} }
$container->getDefinition('twig.cache_warmer')->replaceArgument(2, $config['paths']);
// register bundles as Twig namespaces // register bundles as Twig namespaces
foreach ($container->getParameter('kernel.bundles') as $bundle => $class) { foreach ($container->getParameter('kernel.bundles') as $bundle => $class) {
$dir = $container->getParameter('kernel.root_dir').'/Resources/'.$bundle.'/views'; $dir = $container->getParameter('kernel.root_dir').'/Resources/'.$bundle.'/views';

View File

@ -25,6 +25,7 @@
<service id="twig.cache_warmer" class="Symfony\Bundle\TwigBundle\CacheWarmer\TemplateCacheCacheWarmer" public="false"> <service id="twig.cache_warmer" class="Symfony\Bundle\TwigBundle\CacheWarmer\TemplateCacheCacheWarmer" public="false">
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />
<argument type="service" id="templating.finder" /> <argument type="service" id="templating.finder" />
<argument type="collection" /> <!-- Twig paths -->
</service> </service>
<service id="twig.loader.native_filesystem" class="Twig_Loader_Filesystem" public="false"> <service id="twig.loader.native_filesystem" class="Twig_Loader_Filesystem" public="false">

View File

@ -18,7 +18,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\DependencyInjection\Scope;
class WebProfilerExtensionTest extends TestCase class WebProfilerExtensionTest extends TestCase
{ {
@ -49,8 +48,6 @@ class WebProfilerExtensionTest extends TestCase
$this->kernel = $this->getMock('Symfony\\Component\\HttpKernel\\KernelInterface'); $this->kernel = $this->getMock('Symfony\\Component\\HttpKernel\\KernelInterface');
$this->container = new ContainerBuilder(); $this->container = new ContainerBuilder();
$this->container->addScope(new Scope('request'));
$this->container->register('request', 'Symfony\\Component\\HttpFoundation\\Request')->setScope('request');
$this->container->register('router', $this->getMockClass('Symfony\\Component\\Routing\\RouterInterface')); $this->container->register('router', $this->getMockClass('Symfony\\Component\\Routing\\RouterInterface'));
$this->container->register('twig', 'Twig_Environment'); $this->container->register('twig', 'Twig_Environment');
$this->container->setParameter('kernel.bundles', array()); $this->container->setParameter('kernel.bundles', array());
@ -125,7 +122,6 @@ class WebProfilerExtensionTest extends TestCase
eval('?>'.$dumper->dump(array('class' => $class))); eval('?>'.$dumper->dump(array('class' => $class)));
$container = new $class(); $container = new $class();
$container->enterScope('request');
$container->set('kernel', $this->kernel); $container->set('kernel', $this->kernel);
return $container; return $container;

View File

@ -77,7 +77,7 @@ class Cookie
if (null !== $expires) { if (null !== $expires) {
$timestampAsDateTime = \DateTime::createFromFormat('U', $expires); $timestampAsDateTime = \DateTime::createFromFormat('U', $expires);
if (false === $timestampAsDateTime) { if (false === $timestampAsDateTime) {
throw new \UnexpectedValueException(sprintf('The cookie expiration time "%s" is not valid.'), $expires); throw new \UnexpectedValueException(sprintf('The cookie expiration time "%s" is not valid.', $expires));
} }
$this->expires = $timestampAsDateTime->getTimestamp(); $this->expires = $timestampAsDateTime->getTimestamp();

View File

@ -22,7 +22,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
public function prepare_workspace() public function prepare_workspace()
{ {
$this->workspace = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.time().rand(0, 1000); $this->workspace = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.time().mt_rand(0, 1000);
mkdir($this->workspace, 0777, true); mkdir($this->workspace, 0777, true);
$this->workspace = realpath($this->workspace); $this->workspace = realpath($this->workspace);
} }

View File

@ -29,6 +29,7 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
protected $addIfNotSet = false; protected $addIfNotSet = false;
protected $performDeepMerging = true; protected $performDeepMerging = true;
protected $ignoreExtraKeys = false; protected $ignoreExtraKeys = false;
protected $removeExtraKeys = true;
protected $normalizeKeys = true; protected $normalizeKeys = true;
public function setNormalizeKeys($normalizeKeys) public function setNormalizeKeys($normalizeKeys)
@ -140,10 +141,12 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
* Whether extra keys should just be ignore without an exception. * Whether extra keys should just be ignore without an exception.
* *
* @param bool $boolean To allow extra keys * @param bool $boolean To allow extra keys
* @param bool $remove To remove extra keys
*/ */
public function setIgnoreExtraKeys($boolean) public function setIgnoreExtraKeys($boolean, $remove = true)
{ {
$this->ignoreExtraKeys = (bool) $boolean; $this->ignoreExtraKeys = (bool) $boolean;
$this->removeExtraKeys = $this->ignoreExtraKeys && $remove;
} }
/** /**
@ -300,6 +303,9 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
if (isset($this->children[$name])) { if (isset($this->children[$name])) {
$normalized[$name] = $this->children[$name]->normalize($val); $normalized[$name] = $this->children[$name]->normalize($val);
unset($value[$name]); unset($value[$name]);
} elseif (false === $this->removeExtraKeys) {
$normalized[$name] = $val;
unset($value[$name]);
} }
} }

View File

@ -24,6 +24,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
{ {
protected $performDeepMerging = true; protected $performDeepMerging = true;
protected $ignoreExtraKeys = false; protected $ignoreExtraKeys = false;
protected $removeExtraKeys = true;
protected $children = array(); protected $children = array();
protected $prototype; protected $prototype;
protected $atLeastOne = false; protected $atLeastOne = false;
@ -284,11 +285,14 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
* you want to send an entire configuration array through a special * you want to send an entire configuration array through a special
* tree that processes only part of the array. * tree that processes only part of the array.
* *
* @param bool $remove Whether to remove the extra keys
*
* @return ArrayNodeDefinition * @return ArrayNodeDefinition
*/ */
public function ignoreExtraKeys() public function ignoreExtraKeys($remove = true)
{ {
$this->ignoreExtraKeys = true; $this->ignoreExtraKeys = true;
$this->removeExtraKeys = $remove;
return $this; return $this;
} }
@ -393,7 +397,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
$node->addEquivalentValue(false, $this->falseEquivalent); $node->addEquivalentValue(false, $this->falseEquivalent);
$node->setPerformDeepMerging($this->performDeepMerging); $node->setPerformDeepMerging($this->performDeepMerging);
$node->setRequired($this->required); $node->setRequired($this->required);
$node->setIgnoreExtraKeys($this->ignoreExtraKeys); $node->setIgnoreExtraKeys($this->ignoreExtraKeys, $this->removeExtraKeys);
$node->setNormalizeKeys($this->normalizeKeys); $node->setNormalizeKeys($this->normalizeKeys);
if (null !== $this->normalization) { if (null !== $this->normalization) {

View File

@ -50,6 +50,21 @@ class ArrayNodeTest extends \PHPUnit_Framework_TestCase
$this->assertTrue(true, 'No exception was thrown when setIgnoreExtraKeys is true'); $this->assertTrue(true, 'No exception was thrown when setIgnoreExtraKeys is true');
} }
/**
* Tests that extra keys are not removed when
* ignoreExtraKeys second option is set to false.
*
* Related to testExceptionThrownOnUnrecognizedChild
*/
public function testIgnoreExtraKeysNotRemoved()
{
$node = new ArrayNode('roo');
$node->setIgnoreExtraKeys(true, false);
$data = array('foo' => 'bar');
$this->assertSame($data, $node->normalize($data));
}
/** /**
* @dataProvider getPreNormalizationTests * @dataProvider getPreNormalizationTests
*/ */

View File

@ -69,7 +69,7 @@ class DirectoryResourceTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if the resource has not changed'); $this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if the resource has not changed');
$this->assertFalse($resource->isFresh(time() - 86400), '->isFresh() returns false if the resource has been updated'); $this->assertFalse($resource->isFresh(time() - 86400), '->isFresh() returns false if the resource has been updated');
$resource = new DirectoryResource('/____foo/foobar'.rand(1, 999999)); $resource = new DirectoryResource('/____foo/foobar'.mt_rand(1, 999999));
$this->assertFalse($resource->isFresh(time()), '->isFresh() returns false if the resource does not exist'); $this->assertFalse($resource->isFresh(time()), '->isFresh() returns false if the resource does not exist');
} }

View File

@ -48,7 +48,7 @@ class FileResourceTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($this->resource->isFresh($this->time + 10), '->isFresh() returns true if the resource has not changed'); $this->assertTrue($this->resource->isFresh($this->time + 10), '->isFresh() returns true if the resource has not changed');
$this->assertFalse($this->resource->isFresh($this->time - 86400), '->isFresh() returns false if the resource has been updated'); $this->assertFalse($this->resource->isFresh($this->time - 86400), '->isFresh() returns false if the resource has been updated');
$resource = new FileResource('/____foo/foobar'.rand(1, 999999)); $resource = new FileResource('/____foo/foobar'.mt_rand(1, 999999));
$this->assertFalse($resource->isFresh($this->time), '->isFresh() returns false if the resource does not exist'); $this->assertFalse($resource->isFresh($this->time), '->isFresh() returns false if the resource does not exist');
} }

View File

@ -40,7 +40,7 @@ class TextDescriptor extends Descriptor
$totalWidth = isset($options['total_width']) ? $options['total_width'] : strlen($argument->getName()); $totalWidth = isset($options['total_width']) ? $options['total_width'] : strlen($argument->getName());
$spacingWidth = $totalWidth - strlen($argument->getName()) + 2; $spacingWidth = $totalWidth - strlen($argument->getName()) + 2;
$this->writeText(sprintf(" <info>%s</info>%s%s%s", $this->writeText(sprintf(' <info>%s</info>%s%s%s',
$argument->getName(), $argument->getName(),
str_repeat(' ', $spacingWidth), str_repeat(' ', $spacingWidth),
// + 17 = 2 spaces + <info> + </info> + 2 spaces // + 17 = 2 spaces + <info> + </info> + 2 spaces
@ -77,7 +77,7 @@ class TextDescriptor extends Descriptor
$spacingWidth = $totalWidth - strlen($synopsis) + 2; $spacingWidth = $totalWidth - strlen($synopsis) + 2;
$this->writeText(sprintf(" <info>%s</info>%s%s%s%s", $this->writeText(sprintf(' <info>%s</info>%s%s%s%s',
$synopsis, $synopsis,
str_repeat(' ', $spacingWidth), str_repeat(' ', $spacingWidth),
// + 17 = 2 spaces + <info> + </info> + 2 spaces // + 17 = 2 spaces + <info> + </info> + 2 spaces
@ -207,7 +207,7 @@ class TextDescriptor extends Descriptor
foreach ($namespace['commands'] as $name) { foreach ($namespace['commands'] as $name) {
$this->writeText("\n"); $this->writeText("\n");
$spacingWidth = $width - strlen($name); $spacingWidth = $width - strlen($name);
$this->writeText(sprintf(" <info>%s</info>%s%s", $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)->getDescription()), $options); $this->writeText(sprintf(' <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)->getDescription()), $options);
} }
} }
@ -262,7 +262,8 @@ class TextDescriptor extends Descriptor
{ {
$totalWidth = 0; $totalWidth = 0;
foreach ($options as $option) { foreach ($options as $option) {
$nameLength = 4 + strlen($option->getName()) + 2; // - + shortcut + , + whitespace + name + -- // "-" + shortcut + ", --" + name
$nameLength = 1 + max(strlen($option->getShortcut()), 1) + 4 + strlen($option->getName());
if ($option->acceptValue()) { if ($option->acceptValue()) {
$valueLength = 1 + strlen($option->getName()); // = + value $valueLength = 1 + strlen($option->getName()); // = + value

View File

@ -205,24 +205,26 @@ class Table
public function render() public function render()
{ {
$this->calculateNumberOfColumns(); $this->calculateNumberOfColumns();
$this->rows = $this->buildTableRows($this->rows); $rows = $this->buildTableRows($this->rows);
$this->headers = $this->buildTableRows($this->headers); $headers = $this->buildTableRows($this->headers);
$this->calculateColumnsWidth(array_merge($headers, $rows));
$this->renderRowSeparator(); $this->renderRowSeparator();
if (!empty($this->headers)) { if (!empty($headers)) {
foreach ($this->headers as $header) { foreach ($headers as $header) {
$this->renderRow($header, $this->style->getCellHeaderFormat()); $this->renderRow($header, $this->style->getCellHeaderFormat());
$this->renderRowSeparator(); $this->renderRowSeparator();
} }
} }
foreach ($this->rows as $row) { foreach ($rows as $row) {
if ($row instanceof TableSeparator) { if ($row instanceof TableSeparator) {
$this->renderRowSeparator(); $this->renderRowSeparator();
} else { } else {
$this->renderRow($row, $this->style->getCellRowFormat()); $this->renderRow($row, $this->style->getCellRowFormat());
} }
} }
if (!empty($this->rows)) { if (!empty($rows)) {
$this->renderRowSeparator(); $this->renderRowSeparator();
} }
@ -246,7 +248,7 @@ class Table
$markup = $this->style->getCrossingChar(); $markup = $this->style->getCrossingChar();
for ($column = 0; $column < $count; $column++) { for ($column = 0; $column < $count; $column++) {
$markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->getColumnWidth($column)).$this->style->getCrossingChar(); $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->columnWidths[$column]).$this->style->getCrossingChar();
} }
$this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
@ -292,11 +294,11 @@ class Table
private function renderCell(array $row, $column, $cellFormat) private function renderCell(array $row, $column, $cellFormat)
{ {
$cell = isset($row[$column]) ? $row[$column] : ''; $cell = isset($row[$column]) ? $row[$column] : '';
$width = $this->getColumnWidth($column); $width = $this->columnWidths[$column];
if ($cell instanceof TableCell && $cell->getColspan() > 1) { if ($cell instanceof TableCell && $cell->getColspan() > 1) {
// add the width of the following columns(numbers of colspan). // add the width of the following columns(numbers of colspan).
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
$width += $this->getColumnSeparatorWidth() + $this->getColumnWidth($nextColumn); $width += $this->getColumnSeparatorWidth() + $this->columnWidths[$nextColumn];
} }
} }
@ -509,21 +511,20 @@ class Table
* *
* @return int * @return int
*/ */
private function getColumnWidth($column) private function calculateColumnsWidth($rows)
{ {
if (isset($this->columnWidths[$column])) { for ($column = 0; $column < $this->numberOfColumns; $column++) {
return $this->columnWidths[$column]; $lengths = array();
} foreach ($rows as $row) {
if ($row instanceof TableSeparator) {
continue;
}
foreach (array_merge($this->headers, $this->rows) as $row) { $lengths[] = $this->getCellWidth($row, $column);
if ($row instanceof TableSeparator) {
continue;
} }
$lengths[] = $this->getCellWidth($row, $column); $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
} }
return $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
} }
/** /**

View File

@ -221,7 +221,7 @@ class ArgvInput extends Input
} }
if (null !== $value && !$option->acceptValue()) { if (null !== $value && !$option->acceptValue()) {
throw new \RuntimeException(sprintf('The "--%s" option does not accept a value.', $name, $value)); throw new \RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
} }
if (null === $value && $option->acceptValue() && count($this->parsed)) { if (null === $value && $option->acceptValue() && count($this->parsed)) {

View File

@ -30,6 +30,9 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
*/ */
class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
{ {
/**
* @var StreamOutput
*/
private $stderr; private $stderr;
/** /**
@ -43,14 +46,12 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
*/ */
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null) public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
{ {
$outputStream = 'php://stdout'; $outputStream = $this->hasStdoutSupport() ? 'php://stdout' : 'php://output';
if (!$this->hasStdoutSupport()) { $errorStream = $this->hasStderrSupport() ? 'php://stderr' : 'php://output';
$outputStream = 'php://output';
}
parent::__construct(fopen($outputStream, 'w'), $verbosity, $decorated, $formatter); parent::__construct(fopen($outputStream, 'w'), $verbosity, $decorated, $formatter);
$this->stderr = new StreamOutput(fopen('php://stderr', 'w'), $verbosity, $decorated, $this->getFormatter()); $this->stderr = new StreamOutput(fopen($errorStream, 'w'), $verbosity, $decorated, $this->getFormatter());
} }
/** /**
@ -100,14 +101,32 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
* Returns true if current environment supports writing console output to * Returns true if current environment supports writing console output to
* STDOUT. * STDOUT.
* *
* IBM iSeries (OS400) exhibits character-encoding issues when writing to
* STDOUT and doesn't properly convert ASCII to EBCDIC, resulting in garbage
* output.
*
* @return bool * @return bool
*/ */
protected function hasStdoutSupport() protected function hasStdoutSupport()
{ {
return ('OS400' != php_uname('s')); return false === $this->isRunningOS400();
}
/**
* Returns true if current environment supports writing console output to
* STDERR.
*
* @return bool
*/
protected function hasStderrSupport()
{
return false === $this->isRunningOS400();
}
/**
* Checks if current executing environment is IBM iSeries (OS400), which
* doesn't properly convert character-encodings between ASCII to EBCDIC.
*
* @return bool
*/
private function isRunningOS400()
{
return 'OS400' === php_uname('s');
} }
} }

View File

@ -42,6 +42,7 @@ class ObjectsProvider
'input_option_3' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, 'option description'), 'input_option_3' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, 'option description'),
'input_option_4' => new InputOption('option_name', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'option description', array()), 'input_option_4' => new InputOption('option_name', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'option description', array()),
'input_option_5' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, "multiline\noption description"), 'input_option_5' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, "multiline\noption description"),
'input_option_6' => new InputOption('option_name', array('o', 'O'), InputOption::VALUE_REQUIRED, 'option with multiple shortcuts'),
); );
} }

View File

@ -0,0 +1 @@
{"name":"--option_name","shortcut":"-o|-O","accept_value":true,"is_value_required":true,"is_multiple":false,"description":"option with multiple shortcuts","default":null}

View File

@ -0,0 +1,9 @@
**option_name:**
* Name: `--option_name`
* Shortcut: `-o|-O`
* Accept value: yes
* Is value required: yes
* Is multiple: no
* Description: option with multiple shortcuts
* Default: `NULL`

View File

@ -0,0 +1 @@
<info>-o|O, --option_name=OPTION_NAME</info> option with multiple shortcuts

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<option name="--option_name" shortcut="-o" shortcuts="-o|-O" accept_value="1" is_value_required="1" is_multiple="0">
<description>option with multiple shortcuts</description>
<defaults/>
</option>

View File

@ -427,7 +427,7 @@ TABLE
array('ISBN', 'Author'), array('ISBN', 'Author'),
array( array(
array( array(
new TableCell("9971-5-0210-0", array('rowspan' => 3, 'colspan' => 1)), new TableCell('9971-5-0210-0', array('rowspan' => 3, 'colspan' => 1)),
'Dante Alighieri', 'Dante Alighieri',
), ),
array(new TableSeparator()), array(new TableSeparator()),
@ -554,6 +554,33 @@ TABLE;
$this->assertEquals($table, $table->addRow(new TableSeparator()), 'fluent interface on addRow() with a single TableSeparator() works'); $this->assertEquals($table, $table->addRow(new TableSeparator()), 'fluent interface on addRow() with a single TableSeparator() works');
} }
public function testRenderMultiCalls()
{
$table = new Table($output = $this->getOutputStream());
$table->setRows(array(
array(new TableCell('foo', array('colspan' => 2))),
));
$table->render();
$table->render();
$table->render();
$expected =
<<<TABLE
+---+--+
| foo |
+---+--+
+---+--+
| foo |
+---+--+
+---+--+
| foo |
+---+--+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
protected function getOutputStream() protected function getOutputStream()
{ {
return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, false); return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, false);

View File

@ -95,6 +95,7 @@ class ErrorHandler
private static $reservedMemory; private static $reservedMemory;
private static $stackedErrors = array(); private static $stackedErrors = array();
private static $stackedErrorLevels = array(); private static $stackedErrorLevels = array();
private static $toStringException = null;
/** /**
* Registers the error handler. * Registers the error handler.
@ -351,13 +352,56 @@ class ErrorHandler
} }
if ($throw) { if ($throw) {
if (($this->scopedErrors & $type) && class_exists(ContextErrorException::class)) { if (null !== self::$toStringException) {
// Checking for class existence is a work around for https://bugs.php.net/42098 $throw = self::$toStringException;
self::$toStringException = null;
} elseif (($this->scopedErrors & $type) && class_exists(ContextErrorException::class)) {
$throw = new ContextErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line, $context); $throw = new ContextErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line, $context);
} else { } else {
$throw = new \ErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line); $throw = new \ErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line);
} }
if (E_USER_ERROR & $type) {
$backtrace = $backtrace ?: $throw->getTrace();
for ($i = 1; isset($backtrace[$i]); ++$i) {
if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function'])
&& '__toString' === $backtrace[$i]['function']
&& '->' === $backtrace[$i]['type']
&& !isset($backtrace[$i - 1]['class'])
&& ('trigger_error' === $backtrace[$i - 1]['function'] || 'user_error' === $backtrace[$i - 1]['function'])
) {
// Here, we know trigger_error() has been called from __toString().
// HHVM is fine with throwing from __toString() but PHP triggers a fatal error instead.
// A small convention allows working around the limitation:
// given a caught $e exception in __toString(), quitting the method with
// `return trigger_error($e, E_USER_ERROR);` allows this error handler
// to make $e get through the __toString() barrier.
foreach ($context as $e) {
if (($e instanceof \Exception || $e instanceof \Throwable) && $e->__toString() === $message) {
if (1 === $i) {
// On HHVM
$throw = $e;
break;
}
self::$toStringException = $e;
return true;
}
}
if (1 < $i) {
// On PHP (not on HHVM), display the original error message instead of the default one.
$this->handleException($throw);
// Stop the process by giving back the error to the native handler.
return false;
}
}
}
}
throw $throw; throw $throw;
} }

View File

@ -266,6 +266,33 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
} }
} }
public function testHandleUserError()
{
try {
$handler = ErrorHandler::register();
$handler->throwAt(0, true);
$e = null;
$x = new \Exception('Foo');
try {
$f = new Fixtures\ToStringThrower($x);
$f .= ''; // Trigger $f->__toString()
} catch (\Exception $e) {
}
$this->assertSame($x, $e);
restore_error_handler();
restore_exception_handler();
} catch (\Exception $e) {
restore_error_handler();
restore_exception_handler();
throw $e;
}
}
public function testHandleException() public function testHandleException()
{ {
try { try {

View File

@ -0,0 +1,24 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
class ToStringThrower
{
private $exception;
public function __construct(\Exception $e)
{
$this->exception = $e;
}
public function __toString()
{
try {
throw $this->exception;
} catch (\Exception $e) {
// Using user_error() here is on purpose so we do not forget
// that this alias also should work alongside with trigger_error().
return user_error($e, E_USER_ERROR);
}
}
}

View File

@ -5,6 +5,8 @@ CHANGELOG
----- -----
* allowed specifying a directory to recursively load all configuration files it contains * allowed specifying a directory to recursively load all configuration files it contains
* deprecated the concept of scopes
* added `Definition::setShared()` and `Definition::isShared()`
2.7.0 2.7.0
----- -----

View File

@ -25,6 +25,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
* - non synthetic, non abstract services always have a class set * - non synthetic, non abstract services always have a class set
* - synthetic services are always public * - synthetic services are always public
* - synthetic services are always of non-prototype scope * - synthetic services are always of non-prototype scope
* - shared services are always of non-prototype scope
* *
* @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/ */
@ -46,10 +47,15 @@ class CheckDefinitionValidityPass implements CompilerPassInterface
} }
// synthetic service has non-prototype scope // synthetic service has non-prototype scope
if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) { if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
throw new RuntimeException(sprintf('A synthetic service ("%s") cannot be of scope "prototype".', $id)); throw new RuntimeException(sprintf('A synthetic service ("%s") cannot be of scope "prototype".', $id));
} }
// shared service has non-prototype scope
if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
throw new RuntimeException(sprintf('A shared service ("%s") cannot be of scope "prototype".', $id));
}
// non-synthetic, non-abstract service has class // non-synthetic, non-abstract service has class
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) { if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) {
if ($definition->getFactory()) { if ($definition->getFactory()) {

View File

@ -46,10 +46,10 @@ class CheckReferenceValidityPass implements CompilerPassInterface
{ {
$this->container = $container; $this->container = $container;
$children = $this->container->getScopeChildren(); $children = $this->container->getScopeChildren(false);
$ancestors = array(); $ancestors = array();
$scopes = $this->container->getScopes(); $scopes = $this->container->getScopes(false);
foreach ($scopes as $name => $parent) { foreach ($scopes as $name => $parent) {
$ancestors[$name] = array($parent); $ancestors[$name] = array($parent);
@ -65,7 +65,7 @@ class CheckReferenceValidityPass implements CompilerPassInterface
$this->currentId = $id; $this->currentId = $id;
$this->currentDefinition = $definition; $this->currentDefinition = $definition;
$this->currentScope = $scope = $definition->getScope(); $this->currentScope = $scope = $definition->getScope(false);
if (ContainerInterface::SCOPE_CONTAINER === $scope) { if (ContainerInterface::SCOPE_CONTAINER === $scope) {
$this->currentScopeChildren = array_keys($scopes); $this->currentScopeChildren = array_keys($scopes);
@ -125,7 +125,7 @@ class CheckReferenceValidityPass implements CompilerPassInterface
return; return;
} }
if (!$reference->isStrict()) { if (!$reference->isStrict(false)) {
return; return;
} }
@ -133,7 +133,7 @@ class CheckReferenceValidityPass implements CompilerPassInterface
return; return;
} }
if ($this->currentScope === $scope = $definition->getScope()) { if ($this->currentScope === $scope = $definition->getScope(false)) {
return; return;
} }

View File

@ -48,27 +48,7 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
$this->formatter = $this->compiler->getLoggingFormatter(); $this->formatter = $this->compiler->getLoggingFormatter();
$this->graph = $this->compiler->getServiceReferenceGraph(); $this->graph = $this->compiler->getServiceReferenceGraph();
foreach ($container->getDefinitions() as $id => $definition) { $container->setDefinitions($this->inlineArguments($container, $container->getDefinitions(), true));
$this->currentId = $id;
$definition->setArguments(
$this->inlineArguments($container, $definition->getArguments())
);
$definition->setMethodCalls(
$this->inlineArguments($container, $definition->getMethodCalls())
);
$definition->setProperties(
$this->inlineArguments($container, $definition->getProperties())
);
$configurator = $this->inlineArguments($container, array($definition->getConfigurator()));
$definition->setConfigurator($configurator[0]);
$factory = $this->inlineArguments($container, array($definition->getFactory()));
$definition->setFactory($factory[0]);
}
} }
/** /**
@ -76,12 +56,16 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
* *
* @param ContainerBuilder $container The ContainerBuilder * @param ContainerBuilder $container The ContainerBuilder
* @param array $arguments An array of arguments * @param array $arguments An array of arguments
* @param bool $isRoot If we are processing the root definitions or not
* *
* @return array * @return array
*/ */
private function inlineArguments(ContainerBuilder $container, array $arguments) private function inlineArguments(ContainerBuilder $container, array $arguments, $isRoot = false)
{ {
foreach ($arguments as $k => $argument) { foreach ($arguments as $k => $argument) {
if ($isRoot) {
$this->currentId = $k;
}
if (is_array($argument)) { if (is_array($argument)) {
$arguments[$k] = $this->inlineArguments($container, $argument); $arguments[$k] = $this->inlineArguments($container, $argument);
} elseif ($argument instanceof Reference) { } elseif ($argument instanceof Reference) {
@ -92,7 +76,7 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
if ($this->isInlineableDefinition($container, $id, $definition = $container->getDefinition($id))) { if ($this->isInlineableDefinition($container, $id, $definition = $container->getDefinition($id))) {
$this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId)); $this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId));
if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) { if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope(false)) {
$arguments[$k] = $definition; $arguments[$k] = $definition;
} else { } else {
$arguments[$k] = clone $definition; $arguments[$k] = clone $definition;
@ -102,6 +86,12 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
$argument->setArguments($this->inlineArguments($container, $argument->getArguments())); $argument->setArguments($this->inlineArguments($container, $argument->getArguments()));
$argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls())); $argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls()));
$argument->setProperties($this->inlineArguments($container, $argument->getProperties())); $argument->setProperties($this->inlineArguments($container, $argument->getProperties()));
$configurator = $this->inlineArguments($container, array($argument->getConfigurator()));
$argument->setConfigurator($configurator[0]);
$factory = $this->inlineArguments($container, array($argument->getFactory()));
$argument->setFactory($factory[0]);
} }
} }
@ -119,7 +109,7 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
*/ */
private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition) private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition)
{ {
if (ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) { if (!$definition->isShared() || ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
return true; return true;
} }
@ -148,6 +138,6 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
return false; return false;
} }
return $container->getDefinition(reset($ids))->getScope() === $definition->getScope(); return $container->getDefinition(reset($ids))->getScope(false) === $definition->getScope(false);
} }
} }

View File

@ -21,12 +21,13 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
* merged Definition instance. * merged Definition instance.
* *
* @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*/ */
class ResolveDefinitionTemplatesPass implements CompilerPassInterface class ResolveDefinitionTemplatesPass implements CompilerPassInterface
{ {
private $container;
private $compiler; private $compiler;
private $formatter; private $formatter;
private $currentId;
/** /**
* Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances. * Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances.
@ -35,44 +36,80 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
*/ */
public function process(ContainerBuilder $container) public function process(ContainerBuilder $container)
{ {
$this->container = $container;
$this->compiler = $container->getCompiler(); $this->compiler = $container->getCompiler();
$this->formatter = $this->compiler->getLoggingFormatter(); $this->formatter = $this->compiler->getLoggingFormatter();
foreach ($container->getDefinitions() as $id => $definition) { $container->setDefinitions($this->resolveArguments($container, $container->getDefinitions(), true));
// yes, we are specifically fetching the definition from the }
// container to ensure we are not operating on stale data
$definition = $container->getDefinition($id);
if (!$definition instanceof DefinitionDecorator || $definition->isAbstract()) {
continue;
}
$this->resolveDefinition($id, $definition); /**
* Resolves definition decorator arguments.
*
* @param ContainerBuilder $container The ContainerBuilder
* @param array $arguments An array of arguments
* @param bool $isRoot If we are processing the root definitions or not
*
* @return array
*/
private function resolveArguments(ContainerBuilder $container, array $arguments, $isRoot = false)
{
foreach ($arguments as $k => $argument) {
if ($isRoot) {
// yes, we are specifically fetching the definition from the
// container to ensure we are not operating on stale data
$arguments[$k] = $argument = $container->getDefinition($k);
$this->currentId = $k;
}
if (is_array($argument)) {
$arguments[$k] = $this->resolveArguments($container, $argument);
} elseif ($argument instanceof Definition) {
if ($argument instanceof DefinitionDecorator) {
$arguments[$k] = $argument = $this->resolveDefinition($container, $argument);
if ($isRoot) {
$container->setDefinition($k, $argument);
}
}
$argument->setArguments($this->resolveArguments($container, $argument->getArguments()));
$argument->setMethodCalls($this->resolveArguments($container, $argument->getMethodCalls()));
$argument->setProperties($this->resolveArguments($container, $argument->getProperties()));
$configurator = $this->resolveArguments($container, array($argument->getConfigurator()));
$argument->setConfigurator($configurator[0]);
$factory = $this->resolveArguments($container, array($argument->getFactory()));
$argument->setFactory($factory[0]);
}
} }
return $arguments;
} }
/** /**
* Resolves the definition. * Resolves the definition.
* *
* @param string $id The definition identifier * @param ContainerBuilder $container The ContainerBuilder
* @param DefinitionDecorator $definition * @param DefinitionDecorator $definition
* *
* @return Definition * @return Definition
* *
* @throws \RuntimeException When the definition is invalid * @throws \RuntimeException When the definition is invalid
*/ */
private function resolveDefinition($id, DefinitionDecorator $definition) private function resolveDefinition(ContainerBuilder $container, DefinitionDecorator $definition)
{ {
if (!$this->container->hasDefinition($parent = $definition->getParent())) { if (!$container->hasDefinition($parent = $definition->getParent())) {
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $id)); throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $this->currentId));
} }
$parentDef = $this->container->getDefinition($parent); $parentDef = $container->getDefinition($parent);
if ($parentDef instanceof DefinitionDecorator) { if ($parentDef instanceof DefinitionDecorator) {
$parentDef = $this->resolveDefinition($parent, $parentDef); $id = $this->currentId;
$this->currentId = $parent;
$parentDef = $this->resolveDefinition($container, $parentDef);
$container->setDefinition($parent, $parentDef);
$this->currentId = $id;
} }
$this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $id, $parent)); $this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $this->currentId, $parent));
$def = new Definition(); $def = new Definition();
// merge in parent definition // merge in parent definition
@ -107,6 +144,14 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
if (isset($changes['lazy'])) { if (isset($changes['lazy'])) {
$def->setLazy($definition->isLazy()); $def->setLazy($definition->isLazy());
} }
if (isset($changes['decorated_service'])) {
$decoratedService = $definition->getDecoratedService();
if (null === $decoratedService) {
$def->setDecoratedService($decoratedService);
} else {
$def->setDecoratedService($decoratedService[0], $decoratedService[1]);
}
}
// merge arguments // merge arguments
foreach ($definition->getArguments() as $k => $v) { foreach ($definition->getArguments() as $k => $v) {
@ -135,12 +180,9 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
// these attributes are always taken from the child // these attributes are always taken from the child
$def->setAbstract($definition->isAbstract()); $def->setAbstract($definition->isAbstract());
$def->setScope($definition->getScope()); $def->setScope($definition->getScope(false), false);
$def->setTags($definition->getTags()); $def->setTags($definition->getTags());
// set new definition on container
$this->container->setDefinition($id, $def);
return $def; return $def;
} }
} }

View File

@ -68,7 +68,7 @@ class ResolveReferencesToAliasesPass implements CompilerPassInterface
$defId = $this->getDefinitionId($id = (string) $argument); $defId = $this->getDefinitionId($id = (string) $argument);
if ($defId !== $id) { if ($defId !== $id) {
$arguments[$k] = new Reference($defId, $argument->getInvalidBehavior(), $argument->isStrict()); $arguments[$k] = new Reference($defId, $argument->getInvalidBehavior(), $argument->isStrict(false));
} }
} }
} }

View File

@ -180,6 +180,8 @@ class Container implements IntrospectableContainerInterface
* Setting a service to null resets the service: has() returns false and get() * Setting a service to null resets the service: has() returns false and get()
* behaves in the same way as if the service was never created. * behaves in the same way as if the service was never created.
* *
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier * @param string $id The service identifier
* @param object $service The service instance * @param object $service The service instance
* @param string $scope The scope of the service * @param string $scope The scope of the service
@ -191,6 +193,10 @@ class Container implements IntrospectableContainerInterface
*/ */
public function set($id, $service, $scope = self::SCOPE_CONTAINER) public function set($id, $service, $scope = self::SCOPE_CONTAINER)
{ {
if (!in_array($scope, array('container', 'request')) || ('request' === $scope && 'request' !== $id)) {
@trigger_error('The concept of container scopes is deprecated since version 2.8 and will be removed in 3.0. Omit the third parameter.', E_USER_DEPRECATED);
}
if (self::SCOPE_PROTOTYPE === $scope) { if (self::SCOPE_PROTOTYPE === $scope) {
throw new InvalidArgumentException(sprintf('You cannot set service "%s" of scope "prototype".', $id)); throw new InvalidArgumentException(sprintf('You cannot set service "%s" of scope "prototype".', $id));
} }
@ -389,9 +395,15 @@ class Container implements IntrospectableContainerInterface
* @throws InvalidArgumentException When the scope does not exist * @throws InvalidArgumentException When the scope does not exist
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function enterScope($name) public function enterScope($name)
{ {
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (!isset($this->scopes[$name])) { if (!isset($this->scopes[$name])) {
throw new InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name)); throw new InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name));
} }
@ -437,9 +449,15 @@ class Container implements IntrospectableContainerInterface
* @throws InvalidArgumentException if the scope is not active * @throws InvalidArgumentException if the scope is not active
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function leaveScope($name) public function leaveScope($name)
{ {
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (!isset($this->scopedServices[$name])) { if (!isset($this->scopedServices[$name])) {
throw new InvalidArgumentException(sprintf('The scope "%s" is not active.', $name)); throw new InvalidArgumentException(sprintf('The scope "%s" is not active.', $name));
} }
@ -484,12 +502,17 @@ class Container implements IntrospectableContainerInterface
* @throws InvalidArgumentException * @throws InvalidArgumentException
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function addScope(ScopeInterface $scope) public function addScope(ScopeInterface $scope)
{ {
$name = $scope->getName(); $name = $scope->getName();
$parentScope = $scope->getParentName(); $parentScope = $scope->getParentName();
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) { if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) {
throw new InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name)); throw new InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name));
} }
@ -518,9 +541,15 @@ class Container implements IntrospectableContainerInterface
* @return bool * @return bool
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function hasScope($name) public function hasScope($name)
{ {
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return isset($this->scopes[$name]); return isset($this->scopes[$name]);
} }
@ -534,9 +563,13 @@ class Container implements IntrospectableContainerInterface
* @return bool * @return bool
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function isScopeActive($name) public function isScopeActive($name)
{ {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
return isset($this->scopedServices[$name]); return isset($this->scopedServices[$name]);
} }

View File

@ -358,9 +358,15 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* @return array An array of scopes * @return array An array of scopes
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function getScopes() public function getScopes($triggerDeprecationError = true)
{ {
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scopes; return $this->scopes;
} }
@ -370,15 +376,23 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* @return array An array of scope children. * @return array An array of scope children.
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function getScopeChildren() public function getScopeChildren($triggerDeprecationError = true)
{ {
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scopeChildren; return $this->scopeChildren;
} }
/** /**
* Sets a service. * Sets a service.
* *
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier * @param string $id The service identifier
* @param object $service The service instance * @param object $service The service instance
* @param string $scope The scope * @param string $scope The scope
@ -1126,7 +1140,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/ */
private function shareService(Definition $definition, $service, $id) private function shareService(Definition $definition, $service, $id)
{ {
if (self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) { if ($definition->isShared() && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) { if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
throw new InactiveScopeException($id, $scope); throw new InactiveScopeException($id, $scope);
} }

View File

@ -34,6 +34,8 @@ interface ContainerInterface
/** /**
* Sets a service. * Sets a service.
* *
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier * @param string $id The service identifier
* @param object $service The service instance * @param object $service The service instance
* @param string $scope The scope of the service * @param string $scope The scope of the service
@ -110,6 +112,8 @@ interface ContainerInterface
* @param string $name * @param string $name
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function enterScope($name); public function enterScope($name);
@ -119,6 +123,8 @@ interface ContainerInterface
* @param string $name * @param string $name
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function leaveScope($name); public function leaveScope($name);
@ -128,6 +134,8 @@ interface ContainerInterface
* @param ScopeInterface $scope * @param ScopeInterface $scope
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function addScope(ScopeInterface $scope); public function addScope(ScopeInterface $scope);
@ -139,6 +147,8 @@ interface ContainerInterface
* @return bool * @return bool
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function hasScope($name); public function hasScope($name);
@ -152,6 +162,8 @@ interface ContainerInterface
* @return bool * @return bool
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function isScopeActive($name); public function isScopeActive($name);
} }

View File

@ -26,6 +26,7 @@ class Definition
private $class; private $class;
private $file; private $file;
private $factory; private $factory;
private $shared = true;
private $scope = ContainerInterface::SCOPE_CONTAINER; private $scope = ContainerInterface::SCOPE_CONTAINER;
private $properties = array(); private $properties = array();
private $calls = array(); private $calls = array();
@ -484,6 +485,34 @@ class Definition
return $this->file; return $this->file;
} }
/**
* Sets if the service must be shared or not.
*
* @param bool $shared Whether the service must be shared or not
*
* @return Definition The current instance
*
* @api
*/
public function setShared($shared)
{
$this->shared = (bool) $shared;
return $this;
}
/**
* Whether this service is shared.
*
* @return bool
*
* @api
*/
public function isShared()
{
return $this->shared;
}
/** /**
* Sets the scope of the service. * Sets the scope of the service.
* *
@ -492,9 +521,19 @@ class Definition
* @return Definition The current instance * @return Definition The current instance
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function setScope($scope) public function setScope($scope, $triggerDeprecationError = true)
{ {
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (ContainerInterface::SCOPE_PROTOTYPE === $scope) {
$this->setShared(false);
}
$this->scope = $scope; $this->scope = $scope;
return $this; return $this;
@ -506,9 +545,15 @@ class Definition
* @return string * @return string
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function getScope() public function getScope($triggerDeprecationError = true)
{ {
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scope; return $this->scope;
} }

View File

@ -134,6 +134,16 @@ class DefinitionDecorator extends Definition
return parent::setLazy($boolean); return parent::setLazy($boolean);
} }
/**
* {@inheritdoc}
*/
public function setDecoratedService($id, $renamedId = null)
{
$this->changes['decorated_service'] = true;
return parent::setDecoratedService($id, $renamedId);
}
/** /**
* Gets an argument to pass to the service constructor/factory method. * Gets an argument to pass to the service constructor/factory method.
* *

View File

@ -173,7 +173,7 @@ class GraphvizDumper extends Dumper
} catch (ParameterNotFoundException $e) { } catch (ParameterNotFoundException $e) {
} }
$nodes[$id] = array('class' => str_replace('\\', '\\\\', $className), 'attributes' => array_merge($this->options['node.definition'], array('style' => ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope() ? 'filled' : 'dotted'))); $nodes[$id] = array('class' => str_replace('\\', '\\\\', $className), 'attributes' => array_merge($this->options['node.definition'], array('style' => $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope(false) ? 'filled' : 'dotted')));
$container->setDefinition($id, new Definition('stdClass')); $container->setDefinition($id, new Definition('stdClass'));
} }
@ -201,7 +201,7 @@ class GraphvizDumper extends Dumper
$container->setDefinitions($this->container->getDefinitions()); $container->setDefinitions($this->container->getDefinitions());
$container->setAliases($this->container->getAliases()); $container->setAliases($this->container->getAliases());
$container->setResources($this->container->getResources()); $container->setResources($this->container->getResources());
foreach ($this->container->getScopes() as $scope => $parentScope) { foreach ($this->container->getScopes(false) as $scope => $parentScope) {
$container->addScope(new Scope($scope, $parentScope)); $container->addScope(new Scope($scope, $parentScope));
} }
foreach ($this->container->getExtensions() as $extension) { foreach ($this->container->getExtensions() as $extension) {

View File

@ -377,9 +377,9 @@ class PhpDumper extends Dumper
$isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition); $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
$instantiation = ''; $instantiation = '';
if (!$isProxyCandidate && ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) { if (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_CONTAINER === $definition->getScope(false)) {
$instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance'); $instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
} elseif (!$isProxyCandidate && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) { } elseif (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
$instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance'); $instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
} elseif (!$simple) { } elseif (!$simple) {
$instantiation = '$instance'; $instantiation = '$instance';
@ -569,7 +569,7 @@ class PhpDumper extends Dumper
} }
} }
$scope = $definition->getScope(); $scope = $definition->getScope(false);
if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) { if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
if ($return && 0 === strpos($return[count($return) - 1], '@return')) { if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
$return[] = ''; $return[] = '';
@ -580,7 +580,7 @@ class PhpDumper extends Dumper
$return = implode("\n * ", $return); $return = implode("\n * ", $return);
$doc = ''; $doc = '';
if (ContainerInterface::SCOPE_PROTOTYPE !== $scope) { if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
$doc .= <<<EOF $doc .= <<<EOF
* *
@ -832,10 +832,10 @@ EOF;
EOF; EOF;
if (count($scopes = $this->container->getScopes()) > 0) { if (count($scopes = $this->container->getScopes(false)) > 0) {
$code .= "\n"; $code .= "\n";
$code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n"; $code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n";
$code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n"; $code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren(false)).";\n";
} }
$code .= $this->addMethodMap(); $code .= $this->addMethodMap();
@ -879,9 +879,9 @@ EOF;
EOF; EOF;
$code .= "\n"; $code .= "\n";
if (count($scopes = $this->container->getScopes()) > 0) { if (count($scopes = $this->container->getScopes(false)) > 0) {
$code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n"; $code .= " \$this->scopes = ".$this->dumpValue($scopes).";\n";
$code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n"; $code .= " \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren(false)).";\n";
} else { } else {
$code .= " \$this->scopes = array();\n"; $code .= " \$this->scopes = array();\n";
$code .= " \$this->scopeChildren = array();\n"; $code .= " \$this->scopeChildren = array();\n";
@ -1273,11 +1273,6 @@ EOF;
foreach ($value->getArguments() as $argument) { foreach ($value->getArguments() as $argument) {
$arguments[] = $this->dumpValue($argument); $arguments[] = $this->dumpValue($argument);
} }
$class = $this->dumpValue($value->getClass());
if (false !== strpos($class, '$')) {
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
}
if (null !== $value->getFactory()) { if (null !== $value->getFactory()) {
$factory = $value->getFactory(); $factory = $value->getFactory();
@ -1303,7 +1298,16 @@ EOF;
throw new RuntimeException('Cannot dump definition because of invalid factory'); throw new RuntimeException('Cannot dump definition because of invalid factory');
} }
return sprintf("new \\%s(%s)", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments)); $class = $value->getClass();
if (null === $class) {
throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
}
$class = $this->dumpValue($class);
if (false !== strpos($class, '$')) {
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
}
return sprintf('new \\%s(%s)', substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
} elseif ($value instanceof Variable) { } elseif ($value instanceof Variable) {
return '$'.$value; return '$'.$value;
} elseif ($value instanceof Reference) { } elseif ($value instanceof Reference) {

View File

@ -117,7 +117,10 @@ class XmlDumper extends Dumper
if ($definition->getClass()) { if ($definition->getClass()) {
$service->setAttribute('class', $definition->getClass()); $service->setAttribute('class', $definition->getClass());
} }
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) { if (!$definition->isShared()) {
$service->setAttribute('shared', 'false');
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope(false)) {
$service->setAttribute('scope', $scope); $service->setAttribute('scope', $scope);
} }
if (!$definition->isPublic()) { if (!$definition->isPublic()) {
@ -271,7 +274,7 @@ class XmlDumper extends Dumper
} elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) { } elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
$element->setAttribute('on-invalid', 'ignore'); $element->setAttribute('on-invalid', 'ignore');
} }
if (!$value->isStrict()) { if (!$value->isStrict(false)) {
$element->setAttribute('strict', 'false'); $element->setAttribute('strict', 'false');
} }
} elseif ($value instanceof Definition) { } elseif ($value instanceof Definition) {

View File

@ -112,7 +112,11 @@ class YamlDumper extends Dumper
$code .= sprintf(" calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12)); $code .= sprintf(" calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12));
} }
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) { if (!$definition->isShared()) {
$code .= " shared: false\n";
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope(false)) {
$code .= sprintf(" scope: %s\n", $scope); $code .= sprintf(" scope: %s\n", $scope);
} }
@ -196,7 +200,7 @@ class YamlDumper extends Dumper
} }
/** /**
* Dumps callable to YAML format * Dumps callable to YAML format.
* *
* @param callable $callable * @param callable $callable
* *

View File

@ -148,11 +148,8 @@ class XmlFileLoader extends FileLoader
$definition = new Definition(); $definition = new Definition();
} }
foreach (array('class', 'scope', 'public', 'synthetic', 'lazy', 'abstract') as $key) { foreach (array('class', 'shared', 'public', 'synthetic', 'lazy', 'abstract') as $key) {
if ($value = $service->getAttribute($key)) { if ($value = $service->getAttribute($key)) {
if (in_array($key, array('factory-class', 'factory-method', 'factory-service'))) {
@trigger_error(sprintf('The "%s" attribute in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use the "factory" element instead.', $key, $file), E_USER_DEPRECATED);
}
$method = 'set'.str_replace('-', '', $key); $method = 'set'.str_replace('-', '', $key);
$definition->$method(XmlUtils::phpize($value)); $definition->$method(XmlUtils::phpize($value));
} }

View File

@ -163,8 +163,15 @@ class YamlFileLoader extends FileLoader
$definition->setClass($service['class']); $definition->setClass($service['class']);
} }
if (isset($service['shared'])) {
$definition->setShared($service['shared']);
}
if (isset($service['scope'])) { if (isset($service['scope'])) {
$definition->setScope($service['scope']); if ('request' !== $id) {
@trigger_error(sprintf('The "scope" key of service "%s" in file "%s" is deprecated since version 2.8 and will be removed in 3.0.', $id, $file), E_USER_DEPRECATED);
}
$definition->setScope($service['scope'], false);
} }
if (isset($service['synthetic'])) { if (isset($service['synthetic'])) {

View File

@ -87,6 +87,7 @@
</xsd:choice> </xsd:choice>
<xsd:attribute name="id" type="xsd:string" /> <xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="class" type="xsd:string" /> <xsd:attribute name="class" type="xsd:string" />
<xsd:attribute name="shared" type="boolean" />
<xsd:attribute name="scope" type="xsd:string" /> <xsd:attribute name="scope" type="xsd:string" />
<xsd:attribute name="public" type="boolean" /> <xsd:attribute name="public" type="boolean" />
<xsd:attribute name="synthetic" type="boolean" /> <xsd:attribute name="synthetic" type="boolean" />

View File

@ -27,6 +27,8 @@ class Reference
/** /**
* Constructor. * Constructor.
* *
* Note: The $strict parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier * @param string $id The service identifier
* @param int $invalidBehavior The behavior when the service does not exist * @param int $invalidBehavior The behavior when the service does not exist
* @param bool $strict Sets how this reference is validated * @param bool $strict Sets how this reference is validated
@ -64,9 +66,15 @@ class Reference
* Returns true when this Reference is strict. * Returns true when this Reference is strict.
* *
* @return bool * @return bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
public function isStrict() public function isStrict($triggerDeprecationError = true)
{ {
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->strict; return $this->strict;
} }
} }

View File

@ -17,6 +17,8 @@ namespace Symfony\Component\DependencyInjection;
* @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com>
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
class Scope implements ScopeInterface class Scope implements ScopeInterface
{ {

View File

@ -17,6 +17,8 @@ namespace Symfony\Component\DependencyInjection;
* @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com>
* *
* @api * @api
*
* @deprecated since version 2.8, to be removed in 3.0.
*/ */
interface ScopeInterface interface ScopeInterface
{ {

View File

@ -30,6 +30,7 @@ class CheckDefinitionValidityPassTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @group legacy
*/ */
public function testProcessDetectsSyntheticPrototypeDefinitions() public function testProcessDetectsSyntheticPrototypeDefinitions()
{ {
@ -39,6 +40,18 @@ class CheckDefinitionValidityPassTest extends \PHPUnit_Framework_TestCase
$this->process($container); $this->process($container);
} }
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @group legacy
*/
public function testProcessDetectsSharedPrototypeDefinitions()
{
$container = new ContainerBuilder();
$container->register('a')->setShared(true)->setScope(ContainerInterface::SCOPE_PROTOTYPE);
$this->process($container);
}
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
*/ */

View File

@ -19,6 +19,9 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase
{ {
/**
* @group legacy
*/
public function testProcessIgnoresScopeWideningIfNonStrictReference() public function testProcessIgnoresScopeWideningIfNonStrictReference()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
@ -30,6 +33,7 @@ class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \RuntimeException * @expectedException \RuntimeException
* @group legacy
*/ */
public function testProcessDetectsScopeWidening() public function testProcessDetectsScopeWidening()
{ {
@ -40,6 +44,9 @@ class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase
$this->process($container); $this->process($container);
} }
/**
* @group legacy
*/
public function testProcessIgnoresCrossScopeHierarchyReferenceIfNotStrict() public function testProcessIgnoresCrossScopeHierarchyReferenceIfNotStrict()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
@ -54,6 +61,7 @@ class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \RuntimeException * @expectedException \RuntimeException
* @group legacy
*/ */
public function testProcessDetectsCrossScopeHierarchyReference() public function testProcessDetectsCrossScopeHierarchyReference()
{ {

View File

@ -41,6 +41,29 @@ class InlineServiceDefinitionsPassTest extends \PHPUnit_Framework_TestCase
$this->assertSame($container->getDefinition('inlinable.service'), $arguments[0]); $this->assertSame($container->getDefinition('inlinable.service'), $arguments[0]);
} }
public function testProcessDoesNotInlinesWhenAliasedServiceIsShared()
{
$container = new ContainerBuilder();
$container
->register('foo')
->setPublic(false)
;
$container->setAlias('moo', 'foo');
$container
->register('service')
->setArguments(array($ref = new Reference('foo')))
;
$this->process($container);
$arguments = $container->getDefinition('service')->getArguments();
$this->assertSame($ref, $arguments[0]);
}
/**
* @group legacy
*/
public function testProcessDoesNotInlineWhenAliasedServiceIsNotOfPrototypeScope() public function testProcessDoesNotInlineWhenAliasedServiceIsNotOfPrototypeScope()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
@ -61,6 +84,38 @@ class InlineServiceDefinitionsPassTest extends \PHPUnit_Framework_TestCase
$this->assertSame($ref, $arguments[0]); $this->assertSame($ref, $arguments[0]);
} }
public function testProcessDoesInlineNonSharedService()
{
$container = new ContainerBuilder();
$container
->register('foo')
->setShared(false)
;
$container
->register('bar')
->setPublic(false)
->setShared(false)
;
$container->setAlias('moo', 'bar');
$container
->register('service')
->setArguments(array(new Reference('foo'), $ref = new Reference('moo'), new Reference('bar')))
;
$this->process($container);
$arguments = $container->getDefinition('service')->getArguments();
$this->assertEquals($container->getDefinition('foo'), $arguments[0]);
$this->assertNotSame($container->getDefinition('foo'), $arguments[0]);
$this->assertSame($ref, $arguments[1]);
$this->assertEquals($container->getDefinition('bar'), $arguments[2]);
$this->assertNotSame($container->getDefinition('bar'), $arguments[2]);
}
/**
* @group legacy
*/
public function testProcessDoesInlineServiceOfPrototypeScope() public function testProcessDoesInlineServiceOfPrototypeScope()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
@ -188,6 +243,9 @@ class InlineServiceDefinitionsPassTest extends \PHPUnit_Framework_TestCase
$this->assertSame($ref, $args[0]); $this->assertSame($ref, $args[0]);
} }
/**
* @group legacy
*/
public function testProcessInlinesOnlyIfSameScope() public function testProcessInlinesOnlyIfSameScope()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();

View File

@ -79,6 +79,9 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($def->isAbstract()); $this->assertFalse($def->isAbstract());
} }
/**
* @group legacy
*/
public function testProcessDoesNotCopyScope() public function testProcessDoesNotCopyScope()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
@ -117,6 +120,25 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(), $def->getTags()); $this->assertEquals(array(), $def->getTags());
} }
public function testProcessDoesNotCopyDecoratedService()
{
$container = new ContainerBuilder();
$container
->register('parent')
->setDecoratedService('foo')
;
$container
->setDefinition('child', new DefinitionDecorator('parent'))
;
$this->process($container);
$def = $container->getDefinition('child');
$this->assertNull($def->getDecoratedService());
}
public function testProcessHandlesMultipleInheritance() public function testProcessHandlesMultipleInheritance()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
@ -173,6 +195,55 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($container->getDefinition('child1')->isLazy()); $this->assertTrue($container->getDefinition('child1')->isLazy());
} }
public function testDeepDefinitionsResolving()
{
$container = new ContainerBuilder();
$container->register('parent', 'parentClass');
$container->register('sibling', 'siblingClass')
->setConfigurator(new DefinitionDecorator('parent'), 'foo')
->setFactory(array(new DefinitionDecorator('parent'), 'foo'))
->addArgument(new DefinitionDecorator('parent'))
->setProperty('prop', new DefinitionDecorator('parent'))
->addMethodCall('meth', array(new DefinitionDecorator('parent')))
;
$this->process($container);
$configurator = $container->getDefinition('sibling')->getConfigurator();
$this->assertSame('Symfony\Component\DependencyInjection\Definition', get_class($configurator));
$this->assertSame('parentClass', $configurator->getClass());
$factory = $container->getDefinition('sibling')->getFactory();
$this->assertSame('Symfony\Component\DependencyInjection\Definition', get_class($factory[0]));
$this->assertSame('parentClass', $factory[0]->getClass());
$argument = $container->getDefinition('sibling')->getArgument(0);
$this->assertSame('Symfony\Component\DependencyInjection\Definition', get_class($argument));
$this->assertSame('parentClass', $argument->getClass());
$properties = $container->getDefinition('sibling')->getProperties();
$this->assertSame('Symfony\Component\DependencyInjection\Definition', get_class($properties['prop']));
$this->assertSame('parentClass', $properties['prop']->getClass());
$methodCalls = $container->getDefinition('sibling')->getMethodCalls();
$this->assertSame('Symfony\Component\DependencyInjection\Definition', get_class($methodCalls[0][1][0]));
$this->assertSame('parentClass', $methodCalls[0][1][0]->getClass());
}
public function testSetDecoratedServiceOnServiceHasParent()
{
$container = new ContainerBuilder();
$container->register('parent', 'stdClass');
$container->setDefinition('child1', new DefinitionDecorator('parent'))
->setDecoratedService('foo', 'foo_inner')
;
$this->assertEquals(array('foo', 'foo_inner'), $container->getDefinition('child1')->getDecoratedService());
}
protected function process(ContainerBuilder $container) protected function process(ContainerBuilder $container)
{ {
$pass = new ResolveDefinitionTemplatesPass(); $pass = new ResolveDefinitionTemplatesPass();

View File

@ -61,6 +61,9 @@ class ResolveInvalidReferencesPassTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(), $def->getProperties()); $this->assertEquals(array(), $def->getProperties());
} }
/**
* @group legacy
*/
public function testStrictFlagIsPreserved() public function testStrictFlagIsPreserved()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();

View File

@ -117,10 +117,21 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('Circular reference detected for service "baz", path: "baz".', $e->getMessage(), '->get() throws a LogicException if the service has a circular reference to itself'); $this->assertEquals('Circular reference detected for service "baz", path: "baz".', $e->getMessage(), '->get() throws a LogicException if the service has a circular reference to itself');
} }
$builder->register('foobar', 'stdClass')->setScope('container');
$this->assertTrue($builder->get('bar') === $builder->get('bar'), '->get() always returns the same instance if the service is shared'); $this->assertTrue($builder->get('bar') === $builder->get('bar'), '->get() always returns the same instance if the service is shared');
} }
/**
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::get
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::setShared
*/
public function testNonSharedServicesReturnsDifferentInstances()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass')->setShared(false);
$this->assertNotSame($builder->get('bar'), $builder->get('bar'));
}
/** /**
* @covers \Symfony\Component\DependencyInjection\ContainerBuilder::get * @covers \Symfony\Component\DependencyInjection\ContainerBuilder::get
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
@ -143,6 +154,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
/** /**
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::get * @covers Symfony\Component\DependencyInjection\ContainerBuilder::get
* @group legacy
*/ */
public function testGetReturnsNullOnInactiveScope() public function testGetReturnsNullOnInactiveScope()
{ {
@ -154,6 +166,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
/** /**
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::get * @covers Symfony\Component\DependencyInjection\ContainerBuilder::get
* @group legacy
*/ */
public function testGetReturnsNullOnInactiveScopeWhenServiceIsCreatedByAMethod() public function testGetReturnsNullOnInactiveScopeWhenServiceIsCreatedByAMethod()
{ {

View File

@ -171,6 +171,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \InvalidArgumentException * @expectedException \InvalidArgumentException
* @group legacy
*/ */
public function testSetDoesNotAllowPrototypeScope() public function testSetDoesNotAllowPrototypeScope()
{ {
@ -180,6 +181,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \RuntimeException * @expectedException \RuntimeException
* @group legacy
*/ */
public function testSetDoesNotAllowInactiveScope() public function testSetDoesNotAllowInactiveScope()
{ {
@ -188,6 +190,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$c->set('foo', new \stdClass(), 'foo'); $c->set('foo', new \stdClass(), 'foo');
} }
/**
* @group legacy
*/
public function testSetAlsoSetsScopedService() public function testSetAlsoSetsScopedService()
{ {
$c = new Container(); $c = new Container();
@ -264,6 +269,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @covers Symfony\Component\DependencyInjection\Container::get * @covers Symfony\Component\DependencyInjection\Container::get
* @group legacy
*/ */
public function testGetReturnsNullOnInactiveScope() public function testGetReturnsNullOnInactiveScope()
{ {
@ -302,6 +308,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($sc->initialized('alias'), '->initialized() returns true for alias if aliased service is initialized'); $this->assertTrue($sc->initialized('alias'), '->initialized() returns true for alias if aliased service is initialized');
} }
/**
* @group legacy
*/
public function testEnterLeaveCurrentScope() public function testEnterLeaveCurrentScope()
{ {
$container = new ProjectServiceContainer(); $container = new ProjectServiceContainer();
@ -327,6 +336,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertSame($scopedFoo1, $scopedFoo3); $this->assertSame($scopedFoo1, $scopedFoo3);
} }
/**
* @group legacy
*/
public function testEnterLeaveScopeWithChildScopes() public function testEnterLeaveScopeWithChildScopes()
{ {
$container = new Container(); $container = new Container();
@ -357,6 +369,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($container->has('a')); $this->assertFalse($container->has('a'));
} }
/**
* @group legacy
*/
public function testEnterScopeRecursivelyWithInactiveChildScopes() public function testEnterScopeRecursivelyWithInactiveChildScopes()
{ {
$container = new Container(); $container = new Container();
@ -398,6 +413,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($container->has('a')); $this->assertTrue($container->has('a'));
} }
/**
* @group legacy
*/
public function testEnterChildScopeRecursively() public function testEnterChildScopeRecursively()
{ {
$container = new Container(); $container = new Container();
@ -435,6 +453,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \InvalidArgumentException * @expectedException \InvalidArgumentException
* @group legacy
*/ */
public function testEnterScopeNotAdded() public function testEnterScopeNotAdded()
{ {
@ -444,6 +463,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \RuntimeException * @expectedException \RuntimeException
* @group legacy
*/ */
public function testEnterScopeDoesNotAllowInactiveParentScope() public function testEnterScopeDoesNotAllowInactiveParentScope()
{ {
@ -453,6 +473,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$container->enterScope('bar'); $container->enterScope('bar');
} }
/**
* @group legacy
*/
public function testLeaveScopeNotActive() public function testLeaveScopeNotActive()
{ {
$container = new Container(); $container = new Container();
@ -477,7 +500,8 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \InvalidArgumentException * @expectedException \InvalidArgumentException
* @dataProvider getBuiltInScopes * @dataProvider getLegacyBuiltInScopes
* @group legacy
*/ */
public function testAddScopeDoesNotAllowBuiltInScopes($scope) public function testAddScopeDoesNotAllowBuiltInScopes($scope)
{ {
@ -487,6 +511,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \InvalidArgumentException * @expectedException \InvalidArgumentException
* @group legacy
*/ */
public function testAddScopeDoesNotAllowExistingScope() public function testAddScopeDoesNotAllowExistingScope()
{ {
@ -497,7 +522,8 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \InvalidArgumentException * @expectedException \InvalidArgumentException
* @dataProvider getInvalidParentScopes * @dataProvider getLegacyInvalidParentScopes
* @group legacy
*/ */
public function testAddScopeDoesNotAllowInvalidParentScope($scope) public function testAddScopeDoesNotAllowInvalidParentScope($scope)
{ {
@ -505,6 +531,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$c->addScope(new Scope('foo', $scope)); $c->addScope(new Scope('foo', $scope));
} }
/**
* @group legacy
*/
public function testAddScope() public function testAddScope()
{ {
$c = new Container(); $c = new Container();
@ -520,6 +549,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array('foo' => array('bar', 'baz'), 'bar' => array('baz'), 'baz' => array()), $this->getField($c, 'scopeChildren')); $this->assertSame(array('foo' => array('bar', 'baz'), 'bar' => array('baz'), 'baz' => array()), $this->getField($c, 'scopeChildren'));
} }
/**
* @group legacy
*/
public function testHasScope() public function testHasScope()
{ {
$c = new Container(); $c = new Container();
@ -568,6 +600,9 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($c->initialized('throws_exception_on_service_configuration')); $this->assertFalse($c->initialized('throws_exception_on_service_configuration'));
} }
/**
* @group legacy
*/
public function testIsScopeActive() public function testIsScopeActive()
{ {
$c = new Container(); $c = new Container();
@ -584,7 +619,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($c->isScopeActive('foo')); $this->assertFalse($c->isScopeActive('foo'));
} }
public function getInvalidParentScopes() public function getLegacyInvalidParentScopes()
{ {
return array( return array(
array(ContainerInterface::SCOPE_PROTOTYPE), array(ContainerInterface::SCOPE_PROTOTYPE),
@ -592,7 +627,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
); );
} }
public function getBuiltInScopes() public function getLegacyBuiltInScopes()
{ {
return array( return array(
array(ContainerInterface::SCOPE_CONTAINER), array(ContainerInterface::SCOPE_CONTAINER),

Some files were not shown because too many files have changed in this diff Show More