diff --git a/.github/rm-invalid-lowest-lock-files.php b/.github/rm-invalid-lowest-lock-files.php
index 3105942a09..c036fd356f 100644
--- a/.github/rm-invalid-lowest-lock-files.php
+++ b/.github/rm-invalid-lowest-lock-files.php
@@ -104,8 +104,7 @@ foreach ($composerJsons as list($dir, $lockedPackages)) {
}
}
-if (!$referencedCommits || (isset($_SERVER['TRAVIS_PULL_REQUEST']) && 'false' !== $_SERVER['TRAVIS_PULL_REQUEST'])) {
- // cached commits cannot be stale for PRs
+if (!$referencedCommits) {
return;
}
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000..d211dd419d
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,83 @@
+Code of Conduct
+===============
+
+Our Pledge
+----------
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnic origin, gender identity and expression, level of
+experience, education, socio-economic status, nationality, personal appearance,
+religion, or sexual identity and orientation.
+
+Our Standards
+-------------
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+Our Responsibilities
+--------------------
+
+[CoC Active Response Ensurers, or CARE][1], are responsible for clarifying the
+standards of acceptable behavior and are expected to take appropriate and fair
+corrective action in response to any instances of unacceptable behavior.
+
+CARE team members have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, or to ban temporarily or permanently any
+contributor for other behaviors that they deem inappropriate, threatening,
+offensive, or harmful.
+
+Scope
+-----
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by CARE team members.
+
+Enforcement
+-----------
+
+Instances of abusive, harassing, or otherwise unacceptable behavior
+[may be reported][2] by contacting the [CARE team members][1].
+All complaints will be reviewed and investigated and will result in a response
+that is deemed necessary and appropriate to the circumstances. The CARE team is
+obligated to maintain confidentiality with regard to the reporter of an
+incident. Further details of specific enforcement policies may be posted
+separately.
+
+CARE team members who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by the
+[core team][3].
+
+Attribution
+-----------
+
+This Code of Conduct is adapted from the [Contributor Covenant version 1.4][4].
+
+[1]: https://symfony.com/doc/current/contributing/code_of_conduct/care_team.html
+[2]: https://symfony.com/doc/current/contributing/code_of_conduct/reporting_guidelines.html
+[3]: https://symfony.com/doc/current/contributing/code/core_team.html
+[4]: https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 327166cf65..0106b2ac3b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -22,6 +22,7 @@ use Symfony\Component\Form\Form;
use Symfony\Component\Lock\Lock;
use Symfony\Component\Lock\Store\SemaphoreStore;
use Symfony\Component\Messenger\MessageBusInterface;
+use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Translation\Translator;
@@ -833,7 +834,7 @@ class Configuration implements ConfigurationInterface
->children()
->arrayNode('property_info')
->info('Property info configuration')
- ->canBeEnabled()
+ ->{!class_exists(FullStack::class) && interface_exists(PropertyInfoExtractorInterface::class) ? 'canBeDisabled' : 'canBeEnabled'}()
->end()
->end()
;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index 2dbe54b5d9..f4832939bc 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -260,6 +260,8 @@
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
index 9d3639b621..9c67da6642 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
@@ -218,7 +218,7 @@ class ConfigurationTest extends TestCase
'throw_exception_on_invalid_index' => false,
),
'property_info' => array(
- 'enabled' => false,
+ 'enabled' => !class_exists(FullStack::class),
),
'router' => array(
'enabled' => false,
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index b3dc2cc163..2557d19549 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -1155,12 +1155,6 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertFalse($container->hasDefinition('serializer'));
}
- public function testPropertyInfoDisabled()
- {
- $container = $this->createContainerFromFile('default_config');
- $this->assertFalse($container->has('property_info'));
- }
-
public function testPropertyInfoEnabled()
{
$container = $this->createContainerFromFile('property_info');
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
index af2c517744..4aea6a70fe 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
@@ -58,9 +58,7 @@ class MainConfiguration implements ConfigurationInterface
return false;
})
->then(function ($v) {
- $v['access_decision_manager'] = array(
- 'strategy' => AccessDecisionManager::STRATEGY_AFFIRMATIVE,
- );
+ $v['access_decision_manager']['strategy'] = AccessDecisionManager::STRATEGY_AFFIRMATIVE;
return $v;
})
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
index 8434a451d5..2f977d397d 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
@@ -438,11 +438,22 @@ abstract class CompleteConfigurationTest extends TestCase
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
- * @expectedExceptionMessage "strategy" and "service" cannot be used together.
+ * @expectedExceptionMessage Invalid configuration for path "security.access_decision_manager": "strategy" and "service" cannot be used together.
*/
public function testAccessDecisionManagerServiceAndStrategyCannotBeUsedAtTheSameTime()
{
- $container = $this->getContainer('access_decision_manager_service_and_strategy');
+ $this->getContainer('access_decision_manager_service_and_strategy');
+ }
+
+ public function testAccessDecisionManagerOptionsAreNotOverriddenByImplicitStrategy()
+ {
+ $container = $this->getContainer('access_decision_manager_customized_config');
+
+ $accessDecisionManagerDefinition = $container->getDefinition('security.access.decision_manager');
+
+ $this->assertSame(AccessDecisionManager::STRATEGY_AFFIRMATIVE, $accessDecisionManagerDefinition->getArgument(1));
+ $this->assertTrue($accessDecisionManagerDefinition->getArgument(2));
+ $this->assertFalse($accessDecisionManagerDefinition->getArgument(3));
}
/**
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/access_decision_manager_customized_config.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/access_decision_manager_customized_config.php
new file mode 100644
index 0000000000..cd3cc12000
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/access_decision_manager_customized_config.php
@@ -0,0 +1,20 @@
+loadFromExtension('security', array(
+ 'access_decision_manager' => array(
+ 'allow_if_all_abstain' => true,
+ 'allow_if_equal_granted_denied' => false,
+ ),
+ 'providers' => array(
+ 'default' => array(
+ 'memory' => array(
+ 'users' => array(
+ 'foo' => array('password' => 'foo', 'roles' => 'ROLE_USER'),
+ ),
+ ),
+ ),
+ ),
+ 'firewalls' => array(
+ 'simple' => array('pattern' => '/login', 'security' => false),
+ ),
+));
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access_decision_manager_customized_config.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access_decision_manager_customized_config.xml
new file mode 100644
index 0000000000..22123dfa21
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access_decision_manager_customized_config.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/access_decision_manager_customized_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/access_decision_manager_customized_config.yml
new file mode 100644
index 0000000000..a8d044f1de
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/access_decision_manager_customized_config.yml
@@ -0,0 +1,11 @@
+security:
+ access_decision_manager:
+ allow_if_all_abstain: true
+ allow_if_equal_granted_denied: false
+ providers:
+ default:
+ memory:
+ users:
+ foo: { password: foo, roles: ROLE_USER }
+ firewalls:
+ simple: { pattern: /login, security: false }
diff --git a/src/Symfony/Bundle/WebServerBundle/Command/ServerStatusCommand.php b/src/Symfony/Bundle/WebServerBundle/Command/ServerStatusCommand.php
index 5ee29905fd..938c5ca24a 100644
--- a/src/Symfony/Bundle/WebServerBundle/Command/ServerStatusCommand.php
+++ b/src/Symfony/Bundle/WebServerBundle/Command/ServerStatusCommand.php
@@ -40,7 +40,7 @@ class ServerStatusCommand extends Command
new InputOption('pidfile', null, InputOption::VALUE_REQUIRED, 'PID file'),
new InputOption('filter', null, InputOption::VALUE_REQUIRED, 'The value to display (one of port, host, or address)'),
))
- ->setDescription('Outputs the status of the local web server for the given address')
+ ->setDescription('Outputs the status of the local web server')
->setHelp(<<<'EOF'
%command.name% shows the details of the given local web
server, such as the address and port where it is listening to:
diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php
index 3bf2f3a533..656ab14c98 100644
--- a/src/Symfony/Component/Console/Command/Command.php
+++ b/src/Symfony/Component/Console/Command/Command.php
@@ -361,10 +361,12 @@ class Command
/**
* Adds an argument.
*
- * @param string $name The argument name
- * @param int $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
- * @param string $description A description text
- * @param mixed $default The default value (for InputArgument::OPTIONAL mode only)
+ * @param string $name The argument name
+ * @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL
+ * @param string $description A description text
+ * @param string|string[]|null $default The default value (for self::OPTIONAL mode only)
+ *
+ * @throws InvalidArgumentException When argument mode is not valid
*
* @return $this
*/
@@ -378,11 +380,13 @@ class Command
/**
* Adds an option.
*
- * @param string $name The option name
- * @param string $shortcut The shortcut (can be null)
- * @param int $mode The option mode: One of the InputOption::VALUE_* constants
- * @param string $description A description text
- * @param mixed $default The default value (must be null for InputOption::VALUE_NONE)
+ * @param string $name The option name
+ * @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
+ * @param int|null $mode The option mode: One of the VALUE_* constants
+ * @param string $description A description text
+ * @param string|string[]|bool|null $default The default value (must be null for self::VALUE_NONE)
+ *
+ * @throws InvalidArgumentException If option mode is invalid or incompatible
*
* @return $this
*/
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index 764b1d6c7f..706a4bbed2 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -489,10 +489,6 @@ EOF;
}
}
- if (false !== strpos($this->dumpLiteralClass($this->dumpValue($definition->getClass())), '$')) {
- return false;
- }
-
return true;
}
@@ -559,18 +555,16 @@ EOF;
$return = array();
if ($class = $definition->getClass()) {
- $class = $this->container->resolveEnvPlaceholders($class);
+ $class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class);
$return[] = sprintf(0 === strpos($class, '%') ? '@return object A %1$s instance' : '@return \%s', ltrim($class, '\\'));
} elseif ($definition->getFactory()) {
$factory = $definition->getFactory();
if (\is_string($factory)) {
$return[] = sprintf('@return object An instance returned by %s()', $factory);
} elseif (\is_array($factory) && (\is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) {
- if (\is_string($factory[0]) || $factory[0] instanceof Reference) {
- $return[] = sprintf('@return object An instance returned by %s::%s()', (string) $factory[0], $factory[1]);
- } elseif ($factory[0] instanceof Definition) {
- $return[] = sprintf('@return object An instance returned by %s::%s()', $factory[0]->getClass(), $factory[1]);
- }
+ $class = $factory[0] instanceof Definition ? $factory[0]->getClass() : (string) $factory[0];
+ $class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class);
+ $return[] = sprintf('@return object An instance returned by %s::%s()', $class, $factory[1]);
}
}
@@ -671,7 +665,7 @@ EOF;
if (\is_array($argument)) {
$hasSelfRef = $this->addInlineVariables($head, $tail, $id, $argument, $forConstructor) || $hasSelfRef;
} elseif ($argument instanceof Reference) {
- $hasSelfRef = $this->addInlineReference($head, $tail, $id, $argument, $forConstructor) || $hasSelfRef;
+ $hasSelfRef = $this->addInlineReference($head, $id, $argument, $forConstructor) || $hasSelfRef;
} elseif ($argument instanceof Definition) {
$hasSelfRef = $this->addInlineService($head, $tail, $id, $argument, $forConstructor) || $hasSelfRef;
}
@@ -680,37 +674,31 @@ EOF;
return $hasSelfRef;
}
- private function addInlineReference(string &$head, string &$tail, string $id, string $targetId, bool $forConstructor): bool
+ private function addInlineReference(string &$code, string $id, string $targetId, bool $forConstructor): bool
{
+ $hasSelfRef = isset($this->circularReferences[$id][$targetId]);
+
if ('service_container' === $targetId || isset($this->referenceVariables[$targetId])) {
- return isset($this->circularReferences[$id][$targetId]);
+ return $hasSelfRef;
}
list($callCount, $behavior) = $this->serviceCalls[$targetId];
- if (2 > $callCount && (!$forConstructor || !isset($this->circularReferences[$id][$targetId]))) {
- return isset($this->circularReferences[$id][$targetId]);
+ if (2 > $callCount && (!$hasSelfRef || !$forConstructor)) {
+ return $hasSelfRef;
}
$name = $this->getNextVariableName();
$this->referenceVariables[$targetId] = new Variable($name);
$reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $behavior ? new Reference($targetId, $behavior) : null;
- $code = sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($targetId, $reference));
+ $code .= sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($targetId, $reference));
- if (!isset($this->circularReferences[$id][$targetId])) {
- $head .= $code;
-
- return false;
+ if (!$hasSelfRef || !$forConstructor) {
+ return $hasSelfRef;
}
- if (!$forConstructor) {
- $tail .= $code;
-
- return true;
- }
-
- $head .= $code.sprintf(<<<'EOTXT'
+ $code .= sprintf(<<<'EOTXT'
if (isset($this->%s['%s'])) {
return $this->%1$s['%2$s'];
@@ -733,7 +721,7 @@ EOTXT
$arguments = array($definition->getArguments(), $definition->getFactory());
- if (2 > $this->inlinedDefinitions[$definition] && !$definition->getMethodCalls() && !$definition->getProperties() && !$definition->getConfigurator() && false === strpos($this->dumpValue($definition->getClass()), '$')) {
+ if (2 > $this->inlinedDefinitions[$definition] && !$definition->getMethodCalls() && !$definition->getProperties() && !$definition->getConfigurator()) {
return $this->addInlineVariables($head, $tail, $id, $arguments, $forConstructor);
}
@@ -741,9 +729,13 @@ EOTXT
$this->definitionVariables[$definition] = new Variable($name);
$code = '';
- $hasSelfRef = $this->addInlineVariables($code, $tail, $id, $arguments, $forConstructor);
+ if ($forConstructor) {
+ $hasSelfRef = $this->addInlineVariables($code, $tail, $id, $arguments, $forConstructor);
+ } else {
+ $hasSelfRef = $this->addInlineVariables($code, $code, $id, $arguments, $forConstructor);
+ }
$code .= $this->addNewInstance($definition, '$'.$name, ' = ', $id);
- $hasSelfRef ? $tail .= ('' !== $tail ? "\n" : '').$code : $head .= ('' !== $head ? "\n" : '').$code;
+ $hasSelfRef && !$forConstructor ? $tail .= ('' !== $tail ? "\n" : '').$code : $head .= ('' !== $head ? "\n" : '').$code;
$code = '';
$arguments = array($definition->getProperties(), $definition->getMethodCalls(), $definition->getConfigurator());
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index c992d110ae..8cb11568f2 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -903,6 +903,28 @@ class PhpDumperTest extends TestCase
$this->assertEquals((object) array('p2' => (object) array('p3' => (object) array())), $container->get('foo')->bClone);
}
+ public function testInlineSelfRef()
+ {
+ $container = new ContainerBuilder();
+
+ $bar = (new Definition('App\Bar'))
+ ->setProperty('foo', new Reference('App\Foo'));
+
+ $baz = (new Definition('App\Baz'))
+ ->setProperty('bar', $bar)
+ ->addArgument($bar);
+
+ $container->register('App\Foo')
+ ->setPublic(true)
+ ->addArgument($baz);
+
+ $passConfig = $container->getCompiler()->getPassConfig();
+ $container->compile();
+
+ $dumper = new PhpDumper($container);
+ $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_inline_self_ref.php', $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Inline_Self_Ref')));
+ }
+
public function testHotPathOptimizations()
{
$container = include self::$fixturesPath.'/containers/container_inline_requires.php';
@@ -980,6 +1002,18 @@ class PhpDumperTest extends TestCase
$this->assertEquals((object) array('foo' => (object) array(123)), $container->get('bar'));
}
+ public function testAdawsonContainer()
+ {
+ $container = new ContainerBuilder();
+ $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
+ $loader->load('services_adawson.yml');
+ $container->compile();
+
+ $dumper = new PhpDumper($container);
+ $dump = $dumper->dump();
+ $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_adawson.php', $dumper->dump());
+ }
+
/**
* This test checks the trigger of a deprecation note and should not be removed in major releases.
*
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container19.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container19.php
index 823a77f534..300a5cc769 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container19.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container19.php
@@ -7,9 +7,12 @@ require_once __DIR__.'/../includes/classes.php';
$container = new ContainerBuilder();
+$container->setParameter('env(FOO)', 'Bar\FaooClass');
+$container->setParameter('foo', '%env(FOO)%');
+
$container
- ->register('service_from_anonymous_factory', 'Bar\FooClass')
- ->setFactory(array(new Definition('Bar\FooClass'), 'getInstance'))
+ ->register('service_from_anonymous_factory', '%foo%')
+ ->setFactory(array(new Definition('%foo%'), 'getInstance'))
->setPublic(true)
;
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php
index 673c9d54bb..73e1c4cc1c 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php
@@ -26,6 +26,8 @@ class ProjectServiceContainer extends Container
public function __construct()
{
+ $this->parameters = $this->getDefaultParameters();
+
$this->services = $this->privates = array();
$this->methodMap = array(
'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService',
@@ -62,11 +64,11 @@ class ProjectServiceContainer extends Container
/**
* Gets the public 'service_from_anonymous_factory' shared service.
*
- * @return \Bar\FooClass
+ * @return object A %env(FOO)% instance
*/
protected function getServiceFromAnonymousFactoryService()
{
- return $this->services['service_from_anonymous_factory'] = (new \Bar\FooClass())->getInstance();
+ return $this->services['service_from_anonymous_factory'] = (new ${($_ = $this->getEnv('FOO')) && false ?: "_"}())->getInstance();
}
/**
@@ -82,4 +84,80 @@ class ProjectServiceContainer extends Container
return $instance;
}
+
+ public function getParameter($name)
+ {
+ $name = (string) $name;
+
+ if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
+ throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
+ }
+ if (isset($this->loadedDynamicParameters[$name])) {
+ return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
+ }
+
+ return $this->parameters[$name];
+ }
+
+ public function hasParameter($name)
+ {
+ $name = (string) $name;
+
+ return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
+ }
+
+ public function setParameter($name, $value)
+ {
+ throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
+ }
+
+ public function getParameterBag()
+ {
+ if (null === $this->parameterBag) {
+ $parameters = $this->parameters;
+ foreach ($this->loadedDynamicParameters as $name => $loaded) {
+ $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
+ }
+ $this->parameterBag = new FrozenParameterBag($parameters);
+ }
+
+ return $this->parameterBag;
+ }
+
+ private $loadedDynamicParameters = array(
+ 'foo' => false,
+ );
+ private $dynamicParameters = array();
+
+ /**
+ * Computes a dynamic parameter.
+ *
+ * @param string The name of the dynamic parameter to load
+ *
+ * @return mixed The value of the dynamic parameter
+ *
+ * @throws InvalidArgumentException When the dynamic parameter does not exist
+ */
+ private function getDynamicParameter($name)
+ {
+ switch ($name) {
+ case 'foo': $value = $this->getEnv('FOO'); break;
+ default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name));
+ }
+ $this->loadedDynamicParameters[$name] = true;
+
+ return $this->dynamicParameters[$name] = $value;
+ }
+
+ /**
+ * Gets the default parameters.
+ *
+ * @return array An array of the default parameters
+ */
+ protected function getDefaultParameters()
+ {
+ return array(
+ 'env(FOO)' => 'Bar\\FaooClass',
+ );
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_adawson.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_adawson.php
new file mode 100644
index 0000000000..f2d4cebdd5
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_adawson.php
@@ -0,0 +1,120 @@
+services = $this->privates = array();
+ $this->methodMap = array(
+ 'App\\Bus' => 'getBusService',
+ 'App\\Db' => 'getDbService',
+ );
+
+ $this->aliases = array();
+ }
+
+ public function reset()
+ {
+ $this->privates = array();
+ parent::reset();
+ }
+
+ public function compile()
+ {
+ throw new LogicException('You cannot compile a dumped container that was already compiled.');
+ }
+
+ public function isCompiled()
+ {
+ return true;
+ }
+
+ public function getRemovedIds()
+ {
+ return array(
+ 'App\\Handler1' => true,
+ 'App\\Handler2' => true,
+ 'App\\Processor' => true,
+ 'App\\Registry' => true,
+ 'App\\Schema' => true,
+ 'Psr\\Container\\ContainerInterface' => true,
+ 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
+ );
+ }
+
+ /**
+ * Gets the public 'App\Bus' shared service.
+ *
+ * @return \App\Bus
+ */
+ protected function getBusService()
+ {
+ $a = ($this->services['App\Db'] ?? $this->getDbService());
+
+ $this->services['App\Bus'] = $instance = new \App\Bus($a);
+
+ $b = ($this->privates['App\Schema'] ?? $this->getSchemaService());
+
+ $d = new \App\Registry();
+
+ $d->processor = array(0 => $a, 1 => $instance);
+ $c = new \App\Processor($d, $a);
+
+ $instance->handler1 = new \App\Handler1($a, $b, $c);
+ $instance->handler2 = new \App\Handler2($a, $b, $c);
+
+ return $instance;
+ }
+
+ /**
+ * Gets the public 'App\Db' shared service.
+ *
+ * @return \App\Db
+ */
+ protected function getDbService()
+ {
+ $this->services['App\Db'] = $instance = new \App\Db();
+
+ $instance->schema = ($this->privates['App\Schema'] ?? $this->getSchemaService());
+
+ return $instance;
+ }
+
+ /**
+ * Gets the private 'App\Schema' shared service.
+ *
+ * @return \App\Schema
+ */
+ protected function getSchemaService()
+ {
+ $a = ($this->services['App\Db'] ?? $this->getDbService());
+
+ if (isset($this->privates['App\Schema'])) {
+ return $this->privates['App\Schema'];
+ }
+
+ return $this->privates['App\Schema'] = new \App\Schema($a);
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_self_ref.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_self_ref.php
new file mode 100644
index 0000000000..d28ee816c6
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_self_ref.php
@@ -0,0 +1,79 @@
+services = $this->privates = array();
+ $this->methodMap = array(
+ 'App\\Foo' => 'getFooService',
+ );
+
+ $this->aliases = array();
+ }
+
+ public function reset()
+ {
+ $this->privates = array();
+ parent::reset();
+ }
+
+ public function compile()
+ {
+ throw new LogicException('You cannot compile a dumped container that was already compiled.');
+ }
+
+ public function isCompiled()
+ {
+ return true;
+ }
+
+ public function getRemovedIds()
+ {
+ return array(
+ 'Psr\\Container\\ContainerInterface' => true,
+ 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
+ );
+ }
+
+ /**
+ * Gets the public 'App\Foo' shared service.
+ *
+ * @return \App\Foo
+ */
+ protected function getFooService()
+ {
+ $b = new \App\Bar();
+ $a = new \App\Baz($b);
+
+ $this->services['App\Foo'] = $instance = new \App\Foo($a);
+
+ $b->foo = $instance;
+
+ $a->bar = $b;
+
+ return $instance;
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_adawson.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_adawson.yml
new file mode 100644
index 0000000000..2a26f38a83
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_adawson.yml
@@ -0,0 +1,28 @@
+services:
+ App\Db:
+ public: true
+ properties:
+ schema: '@App\Schema'
+
+ App\Bus:
+ public: true
+ arguments: ['@App\Db']
+ properties:
+ handler1: '@App\Handler1'
+ handler2: '@App\Handler2'
+
+ App\Handler1:
+ ['@App\Db', '@App\Schema', '@App\Processor']
+
+ App\Handler2:
+ ['@App\Db', '@App\Schema', '@App\Processor']
+
+ App\Processor:
+ ['@App\Registry', '@App\Db']
+
+ App\Registry:
+ properties:
+ processor: ['@App\Db', '@App\Bus']
+
+ App\Schema:
+ arguments: ['@App\Db']
diff --git a/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php b/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php
index 9cf68c987f..b63f69df14 100644
--- a/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php
+++ b/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php
@@ -31,8 +31,6 @@ class GenericEventTest extends TestCase
*/
protected function setUp()
{
- parent::setUp();
-
$this->subject = new \stdClass();
$this->event = new GenericEvent($this->subject, array('name' => 'Event'));
}
@@ -44,8 +42,6 @@ class GenericEventTest extends TestCase
{
$this->subject = null;
$this->event = null;
-
- parent::tearDown();
}
public function testConstruct()
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php
index 45cc5c641b..1838113f9d 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php
@@ -68,7 +68,7 @@ class DateTimeToRfc3339Transformer extends BaseDateTimeTransformer
return;
}
- if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})T\d{2}:\d{2}(?::\d{2})?(?:\.\d)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))$/', $rfc3339, $matches)) {
+ if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})T\d{2}:\d{2}(?::\d{2})?(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))$/', $rfc3339, $matches)) {
throw new TransformationFailedException(sprintf('The date "%s" is not a valid date.', $rfc3339));
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
index f21c01b7cc..053cb62864 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
@@ -67,6 +67,7 @@ class DateTimeToRfc3339TransformerTest extends TestCase
array('UTC', 'UTC', '2010-02-03 04:05:00 UTC', '2010-02-03T04:05Z'),
array('America/New_York', 'Asia/Hong_Kong', '2010-02-03 04:05:00 America/New_York', '2010-02-03T17:05+08:00'),
array('Europe/Amsterdam', 'Europe/Amsterdam', '2013-08-21 10:30:00 Europe/Amsterdam', '2013-08-21T08:30:00Z'),
+ array('UTC', 'UTC', '2018-10-03T10:00:00.000Z', '2018-10-03T10:00:00.000Z'),
));
}
diff --git a/src/Symfony/Component/HttpFoundation/StreamedResponse.php b/src/Symfony/Component/HttpFoundation/StreamedResponse.php
index 40f785c866..06d053eadd 100644
--- a/src/Symfony/Component/HttpFoundation/StreamedResponse.php
+++ b/src/Symfony/Component/HttpFoundation/StreamedResponse.php
@@ -17,7 +17,7 @@ namespace Symfony\Component\HttpFoundation;
* A StreamedResponse uses a callback for its content.
*
* The callback should use the standard PHP functions like echo
- * to stream the response back to the client. The flush() method
+ * to stream the response back to the client. The flush() function
* can also be used if needed.
*
* @see flush()
diff --git a/src/Symfony/Component/Lock/Factory.php b/src/Symfony/Component/Lock/Factory.php
index e9fdde97e8..f35ad6d8ef 100644
--- a/src/Symfony/Component/Lock/Factory.php
+++ b/src/Symfony/Component/Lock/Factory.php
@@ -36,9 +36,9 @@ class Factory implements LoggerAwareInterface
/**
* Creates a lock for the given resource.
*
- * @param string $resource The resource to lock
- * @param float $ttl Maximum expected lock duration in seconds
- * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed
+ * @param string $resource The resource to lock
+ * @param float|null $ttl Maximum expected lock duration in seconds
+ * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed
*
* @return Lock
*/
diff --git a/src/Symfony/Component/Process/Pipes/WindowsPipes.php b/src/Symfony/Component/Process/Pipes/WindowsPipes.php
index 9240102a38..7130589cec 100644
--- a/src/Symfony/Component/Process/Pipes/WindowsPipes.php
+++ b/src/Symfony/Component/Process/Pipes/WindowsPipes.php
@@ -28,6 +28,7 @@ class WindowsPipes extends AbstractPipes
{
private $files = array();
private $fileHandles = array();
+ private $lockHandles = array();
private $readBytes = array(
Process::STDOUT => 0,
Process::STDERR => 0,
@@ -47,31 +48,33 @@ class WindowsPipes extends AbstractPipes
Process::STDOUT => Process::OUT,
Process::STDERR => Process::ERR,
);
- $tmpCheck = false;
$tmpDir = sys_get_temp_dir();
$lastError = 'unknown reason';
set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
for ($i = 0;; ++$i) {
foreach ($pipes as $pipe => $name) {
$file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
- if (file_exists($file) && !unlink($file)) {
- continue 2;
- }
- $h = fopen($file, 'xb');
- if (!$h) {
- $error = $lastError;
- if ($tmpCheck || $tmpCheck = unlink(tempnam(false, 'sf_check_'))) {
- continue;
- }
+
+ if (!$h = fopen($file.'.lock', 'w')) {
restore_error_handler();
- throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error));
+ throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $lastError));
}
- if (!$h || !$this->fileHandles[$pipe] = fopen($file, 'rb')) {
+ if (!flock($h, LOCK_EX | LOCK_NB)) {
continue 2;
}
- if (isset($this->files[$pipe])) {
- unlink($this->files[$pipe]);
+ if (isset($this->lockHandles[$pipe])) {
+ flock($this->lockHandles[$pipe], LOCK_UN);
+ fclose($this->lockHandles[$pipe]);
}
+ $this->lockHandles[$pipe] = $h;
+
+ if (!fclose(fopen($file, 'w')) || !$h = fopen($file, 'r')) {
+ flock($this->lockHandles[$pipe], LOCK_UN);
+ fclose($this->lockHandles[$pipe]);
+ unset($this->lockHandles[$pipe]);
+ continue 2;
+ }
+ $this->fileHandles[$pipe] = $h;
$this->files[$pipe] = $file;
}
break;
@@ -85,7 +88,6 @@ class WindowsPipes extends AbstractPipes
public function __destruct()
{
$this->close();
- $this->removeFiles();
}
/**
@@ -145,8 +147,11 @@ class WindowsPipes extends AbstractPipes
$read[$type] = $data;
}
if ($close) {
+ ftruncate($fileHandle, 0);
fclose($fileHandle);
- unset($this->fileHandles[$type]);
+ flock($this->lockHandles[$type], LOCK_UN);
+ fclose($this->lockHandles[$type]);
+ unset($this->fileHandles[$type], $this->lockHandles[$type]);
}
}
@@ -175,22 +180,12 @@ class WindowsPipes extends AbstractPipes
public function close()
{
parent::close();
- foreach ($this->fileHandles as $handle) {
+ foreach ($this->fileHandles as $type => $handle) {
+ ftruncate($handle, 0);
fclose($handle);
+ flock($this->lockHandles[$type], LOCK_UN);
+ fclose($this->lockHandles[$type]);
}
- $this->fileHandles = array();
- }
-
- /**
- * Removes temporary files.
- */
- private function removeFiles()
- {
- foreach ($this->files as $filename) {
- if (file_exists($filename)) {
- @unlink($filename);
- }
- }
- $this->files = array();
+ $this->fileHandles = $this->lockHandles = array();
}
}
diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php
index 4508a44583..cce915a045 100644
--- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php
+++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php
@@ -161,6 +161,7 @@ class ContextListener implements ListenerInterface
}
$userNotFoundByProvider = false;
+ $userDeauthenticated = false;
foreach ($this->userProviders as $provider) {
if (!$provider instanceof UserProviderInterface) {
@@ -169,17 +170,26 @@ class ContextListener implements ListenerInterface
try {
$refreshedUser = $provider->refreshUser($user);
- $token->setUser($refreshedUser);
+ $newToken = unserialize(serialize($token));
+ $newToken->setUser($refreshedUser);
// tokens can be deauthenticated if the user has been changed.
- if (!$token->isAuthenticated()) {
- if (null !== $this->logger) {
- $this->logger->debug('Token was deauthenticated after trying to refresh it.', array('username' => $refreshedUser->getUsername(), 'provider' => \get_class($provider)));
+ if (!$newToken->isAuthenticated()) {
+ if ($this->logoutOnUserChange) {
+ $userDeauthenticated = true;
+
+ if (null !== $this->logger) {
+ $this->logger->debug('Cannot refresh token because user has changed.', array('username' => $refreshedUser->getUsername(), 'provider' => \get_class($provider)));
+ }
+
+ continue;
}
return null;
}
+ $token->setUser($refreshedUser);
+
if (null !== $this->logger) {
$context = array('provider' => \get_class($provider), 'username' => $refreshedUser->getUsername());
@@ -205,6 +215,14 @@ class ContextListener implements ListenerInterface
}
}
+ if ($userDeauthenticated) {
+ if (null !== $this->logger) {
+ $this->logger->debug('Token was deauthenticated after trying to refresh it.');
+ }
+
+ return null;
+ }
+
if ($userNotFoundByProvider) {
return null;
}
diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php
index f38ddfdf97..02acb2490e 100644
--- a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php
@@ -260,6 +260,15 @@ class ContextListenerTest extends TestCase
$this->assertNull($tokenStorage->getToken());
}
+ public function testIfTokenIsNotDeauthenticated()
+ {
+ $tokenStorage = new TokenStorage();
+ $badRefreshedUser = new User('foobar', 'baz');
+ $goodRefreshedUser = new User('foobar', 'bar');
+ $this->handleEventWithPreviousSession($tokenStorage, array(new SupportingUserProvider($badRefreshedUser), new SupportingUserProvider($goodRefreshedUser)), $goodRefreshedUser, true);
+ $this->assertSame($goodRefreshedUser, $tokenStorage->getToken()->getUser());
+ }
+
public function testTryAllUserProvidersUntilASupportingUserProviderIsFound()
{
$tokenStorage = new TokenStorage();
diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php
index ac79ab4dc7..544c82f6c0 100644
--- a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php
+++ b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php
@@ -97,7 +97,7 @@ interface ExecutionContextInterface
* {
* $validator = $this->context->getValidator();
*
- * $violations = $validator->validateValue($value, new Length(array('min' => 3)));
+ * $violations = $validator->validate($value, new Length(array('min' => 3)));
*
* if (count($violations) > 0) {
* // ...
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf
index 4a06dbd45b..bdbc9da09c 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf
@@ -318,6 +318,10 @@
Error
Feeler
+
+ This is not a valid UUID.
+ Dëst ass keng gëlteg UUID.
+