Permalink
Browse files

Merge branch '3.4'

* 3.4:
  [Yaml] Deprecate tags using colon
  better errors when security deps are missing
  • Loading branch information...
xabbuh committed Aug 4, 2017
2 parents 257b2c9 + 978eca9 commit b27c96558d8861024711b4f9993c71c9e3a43b3f
View
@@ -158,6 +158,24 @@ Validator
Yaml
----
* using the `!php/object:` tag is deprecated and won't be supported in 4.0. Use
the `!php/object` tag (without the colon) instead.
* using the `!php/const:` tag is deprecated and won't be supported in 4.0. Use
the `!php/const` tag (without the colon) instead.
Before:
```yml
!php/const:PHP_INT_MAX
```
After:
```yml
!php/const PHP_INT_MAX
```
* Support for the `!str` tag is deprecated, use the `!!str` tag instead.
* Using the non-specific tag `!` is deprecated and will have a different
View
@@ -871,3 +871,21 @@ Yaml
* The behavior of the non-specific tag `!` is changed and now forces
non-evaluating your values.
* The `!php/object:` tag was removed in favor of the `!php/object` tag (without
the colon).
* The `!php/const:` tag was removed in favor of the `!php/const` tag (without
the colon).
Before:
```yml
!php/const:PHP_INT_MAX
```
After:
```yml
!php/const PHP_INT_MAX
```
@@ -0,0 +1,50 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\LogicException;
/**
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
*/
class WorkflowGuardListenerPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasParameter('workflow.has_guard_listeners')) {
return;
}
$container->getParameterBag()->remove('workflow.has_guard_listeners');
if (!$container->has('security.token_storage')) {
throw new LogicException('The "security.token_storage" service is needed to be able to use the workflow guard listener.');
}
if (!$container->has('security.authorization_checker')) {
throw new LogicException('The "security.authorization_checker" service is needed to be able to use the workflow guard listener.');
}
if (!$container->has('security.authentication.trust_resolver')) {
throw new LogicException('The "security.authentication.trust_resolver" service is needed to be able to use the workflow guard listener.');
}
if (!$container->has('security.role_hierarchy')) {
throw new LogicException('The "security.role_hierarchy" service is needed to be able to use the workflow guard listener.');
}
}
}
@@ -50,6 +50,7 @@
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader;
use Symfony\Component\Routing\Loader\AnnotationFileLoader;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Encoder\CsvEncoder;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
@@ -559,6 +560,10 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde
throw new LogicException('Cannot guard workflows as the ExpressionLanguage component is not installed.');
}
if (!class_exists(Security::class)) {
throw new LogicException('Cannot guard workflows as the Security component is not installed.');
}
$eventName = sprintf('workflow.%s.guard.%s', $name, $transitionName);
$guard->addTag('kernel.event_listener', array('event' => $eventName, 'method' => 'onTransition'));
$configuration[$eventName] = $config['guard'];
@@ -574,6 +579,7 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde
));
$container->setDefinition(sprintf('%s.listener.guard', $workflowId), $guard);
$container->setParameter('workflow.has_guard_listeners', true);
}
}
}
@@ -24,6 +24,7 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddExpressionLanguageProvidersPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\WorkflowGuardListenerPass;
use Symfony\Component\Config\DependencyInjection\ConfigCachePass;
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
use Symfony\Component\HttpKernel\DependencyInjection\AddCacheClearerPass;
@@ -103,6 +104,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new CachePoolPrunerPass(), PassConfig::TYPE_AFTER_REMOVING);
$this->addCompilerPassIfExists($container, FormPass::class);
$container->addCompilerPass(new WorkflowGuardListenerPass());
if ($container->getParameter('kernel.debug')) {
$container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
@@ -0,0 +1,127 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\WorkflowGuardListenerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Workflow\EventListener\GuardListener;
class WorkflowGuardListenerPassTest extends TestCase
{
private $container;
private $compilerPass;
protected function setUp()
{
$this->container = new ContainerBuilder();
$this->container->register('foo.listener.guard', GuardListener::class);
$this->container->register('bar.listener.guard', GuardListener::class);
$this->compilerPass = new WorkflowGuardListenerPass();
}
public function testListenersAreNotRemovedIfParameterIsNotSet()
{
$this->compilerPass->process($this->container);
$this->assertTrue($this->container->hasDefinition('foo.listener.guard'));
$this->assertTrue($this->container->hasDefinition('bar.listener.guard'));
}
public function testParameterIsRemovedWhenThePassIsProcessed()
{
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
try {
$this->compilerPass->process($this->container);
} catch (LogicException $e) {
// Here, we are not interested in the exception handling. This is tested further down.
}
$this->assertFalse($this->container->hasParameter('workflow.has_guard_listeners'));
}
public function testListenersAreNotRemovedIfAllDependenciesArePresent()
{
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
$this->container->register('security.token_storage', TokenStorageInterface::class);
$this->container->register('security.authorization_checker', AuthorizationCheckerInterface::class);
$this->container->register('security.authentication.trust_resolver', AuthenticationTrustResolverInterface::class);
$this->container->register('security.role_hierarchy', RoleHierarchy::class);
$this->compilerPass->process($this->container);
$this->assertTrue($this->container->hasDefinition('foo.listener.guard'));
$this->assertTrue($this->container->hasDefinition('bar.listener.guard'));
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
* @expectedExceptionMessage The "security.token_storage" service is needed to be able to use the workflow guard listener.
*/
public function testListenersAreRemovedIfTheTokenStorageServiceIsNotPresent()
{
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
$this->container->register('security.authorization_checker', AuthorizationCheckerInterface::class);
$this->container->register('security.authentication.trust_resolver', AuthenticationTrustResolverInterface::class);
$this->container->register('security.role_hierarchy', RoleHierarchy::class);
$this->compilerPass->process($this->container);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
* @expectedExceptionMessage The "security.authorization_checker" service is needed to be able to use the workflow guard listener.
*/
public function testListenersAreRemovedIfTheAuthorizationCheckerServiceIsNotPresent()
{
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
$this->container->register('security.token_storage', TokenStorageInterface::class);
$this->container->register('security.authentication.trust_resolver', AuthenticationTrustResolverInterface::class);
$this->container->register('security.role_hierarchy', RoleHierarchy::class);
$this->compilerPass->process($this->container);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
* @expectedExceptionMessage The "security.authentication.trust_resolver" service is needed to be able to use the workflow guard listener.
*/
public function testListenersAreRemovedIfTheAuthenticationTrustResolverServiceIsNotPresent()
{
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
$this->container->register('security.token_storage', TokenStorageInterface::class);
$this->container->register('security.authorization_checker', AuthorizationCheckerInterface::class);
$this->container->register('security.role_hierarchy', RoleHierarchy::class);
$this->compilerPass->process($this->container);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
* @expectedExceptionMessage The "security.role_hierarchy" service is needed to be able to use the workflow guard listener.
*/
public function testListenersAreRemovedIfTheRoleHierarchyServiceIsNotPresent()
{
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
$this->container->register('security.token_storage', TokenStorageInterface::class);
$this->container->register('security.authorization_checker', AuthorizationCheckerInterface::class);
$this->container->register('security.authentication.trust_resolver', AuthenticationTrustResolverInterface::class);
$this->compilerPass->process($this->container);
}
}
@@ -5,7 +5,7 @@ parameters:
- false
- 0
- 1000.3
- !php/const:PHP_INT_MAX
- !php/const PHP_INT_MAX
bar: foo
escape: '@@escapeme'
foo_bar: '@foo_bar'
@@ -34,6 +34,7 @@
"conflict": {
"symfony/config": "<3.4",
"symfony/finder": "<3.4",
"symfony/proxy-manager-bridge": "<3.4",
"symfony/yaml": "<3.4"
},
"provide": {
@@ -61,9 +61,9 @@ public function testContext()
$obj = new \stdClass();
$obj->bar = 2;
$this->assertEquals(" foo: !php/object:O:8:\"stdClass\":1:{s:3:\"bar\";i:2;}\n", $encoder->encode(array('foo' => $obj), 'yaml'));
$this->assertEquals(" foo: !php/object 'O:8:\"stdClass\":1:{s:3:\"bar\";i:2;}'\n", $encoder->encode(array('foo' => $obj), 'yaml'));
$this->assertEquals(' { foo: null }', $encoder->encode(array('foo' => $obj), 'yaml', array('yaml_inline' => 0, 'yaml_indent' => 2, 'yaml_flags' => 0)));
$this->assertEquals(array('foo' => $obj), $encoder->decode('foo: !php/object:O:8:"stdClass":1:{s:3:"bar";i:2;}', 'yaml'));
$this->assertEquals(array('foo' => null), $encoder->decode('foo: !php/object:O:8:"stdClass":1:{s:3:"bar";i:2;}', 'yaml', array('yaml_flags' => 0)));
$this->assertEquals(array('foo' => $obj), $encoder->decode("foo: !php/object 'O:8:\"stdClass\":1:{s:3:\"bar\";i:2;}'", 'yaml'));
$this->assertEquals(array('foo' => null), $encoder->decode("foo: !php/object 'O:8:\"stdClass\":1:{s:3:\"bar\";i:2;}'", 'yaml', array('yaml_flags' => 0)));
}
}
@@ -5,4 +5,4 @@ Symfony\Component\Validator\Tests\Fixtures\Entity:
properties:
firstName:
- Range:
max: !php/const:PHP_INT_MAX
max: !php/const PHP_INT_MAX
@@ -34,6 +34,12 @@ CHANGELOG
3.4.0
-----
* Deprecated the `!php/object:` tag which will be replaced by the
`!php/object` tag (without the colon) in 4.0.
* Deprecated the `!php/const:` tag which will be replaced by the
`!php/const` tag (without the colon) in 4.0.
* Support for the `!str` tag is deprecated, use the `!!str` tag instead.
* Deprecated using the non-specific tag `!` as its behavior will change in 4.0.
@@ -120,7 +120,7 @@ public static function dump($value, $flags = 0)
}
if (Yaml::DUMP_OBJECT & $flags) {
return '!php/object:'.serialize($value);
return '!php/object '.self::dump(serialize($value));
}
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
@@ -556,16 +556,42 @@ private static function evaluateScalar($scalar, $flags, $references = array())
return substr($scalar, 2);
case 0 === strpos($scalar, '!php/object:'):
if (self::$objectSupport) {
@trigger_error('The !php/object: tag to indicate dumped PHP objects is deprecated since version 3.4 and will be removed in 4.0. Use the !php/object (without the colon) tag instead.', E_USER_DEPRECATED);
return unserialize(substr($scalar, 12));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!!php/object:'):
if (self::$objectSupport) {
@trigger_error('The !!php/object: tag to indicate dumped PHP objects is deprecated since version 3.1 and will be removed in 4.0. Use the !php/object (without the colon) tag instead.', E_USER_DEPRECATED);
return unserialize(substr($scalar, 13));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!php/object'):
if (self::$objectSupport) {
return unserialize(self::parseScalar(substr($scalar, 12)));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!php/const:'):
if (self::$constantSupport) {
@trigger_error('The !php/const: tag to indicate dumped PHP constants is deprecated since version 3.4 and will be removed in 4.0. Use the !php/const (without the colon) tag instead.', E_USER_DEPRECATED);
if (defined($const = substr($scalar, 11))) {
return constant($const);
}
@@ -576,6 +602,19 @@ private static function evaluateScalar($scalar, $flags, $references = array())
throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar));
}
return;
case 0 === strpos($scalar, '!php/const'):
if (self::$constantSupport) {
if (defined($const = self::parseScalar(substr($scalar, 11)))) {
return constant($const);
}
throw new ParseException(sprintf('The constant "%s" is not defined.', $const));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar));
}
return;
case 0 === strpos($scalar, '!!float '):
return (float) substr($scalar, 8);
@@ -169,7 +169,7 @@ private function doParse($value, $flags)
$this->refs[$isRef] = end($data);
}
} elseif (
self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?(?:![^\s]++\s++)?[^ \'"\[\{!].*?) *\:(\s++(?P<value>.+))?$#u', rtrim($this->currentLine), $values)
self::preg_match('#^(?P<key>(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(\s++(?P<value>.+))?$#u', rtrim($this->currentLine), $values)
&& (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'")))
) {
if ($context && 'sequence' == $context) {
Oops, something went wrong.

0 comments on commit b27c965

Please sign in to comment.