8000 Merge branch '3.4' · symfony/symfony@3fde0f0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3fde0f0

Browse files
Merge branch '3.4'
* 3.4: Adding a shortcuts for the main security functionality [DI] Reference tagged services in config
2 parents 1c8b650 + 648a895 commit 3fde0f0

34 files changed

+480
-16
lines changed

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ CHANGELOG
1717
3.4.0
1818
-----
1919

20+
* Added new `security.helper` service that is an instance of `Symfony\Component\Security\Core\Security`
21+
and provides shortcuts for common security tasks.
2022
* Tagging voters with the `security.voter` tag without implementing the
2123
`VoterInterface` on the class is now deprecated and will be removed in 4.0.
2224
* [BC BREAK] `FirewallContext::getListeners()` now returns `\Traversable|array`

src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@
2626
</service>
2727
<service id="Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface" alias="security.token_storage" />
2828

29+
<service id="security.helper" class="Symfony\Component\Security\Core\Security">
30+
<argument type="service">
31+
<service class="Symfony\Component\DependencyInjection\ServiceLocator">
32+
<tag name="container.service_locator" />
33+
<argument type="collection">
34+
<argument key="security.token_storage" type="service" id="security.token_storage" />
35+
<argument key="security.authorization_checker" type="service" id="security.authorization_checker" />
36+
</argument>
37+
</service>
38+
</argument>
39+
</service>
40+
<service id="Symfony\Component\Security\Core\Security" alias="security.helper" />
41+
2942
<service id="security.user_value_resolver" class="Symfony\Bundle\SecurityBundle\SecurityUserValueResolver">
3043
<argument type="service" id="security.token_storage" />
3144
<tag name="controller.argument_value_resolver" priority="40" />
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
13+
14+
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
15+
use Symfony\Component\Security\Core\User\User;
16+
17+
class SecurityTest extends WebTestCase
18+
{
19+
public function testServiceIsFunctional()
20+
{
21+
$kernel = self::createKernel(array('test_case' => 'SecurityHelper', 'root_config' => 'config.yml'));
22+
$kernel->boot();
23+
F42D $container = $kernel->getContainer();
24+
25+
// put a token into the storage so the final calls can function
26+
$user = new User('foo', 'pass');
27+
$token = new UsernamePasswordToken($user, '', 'provider', array('ROLE_USER'));
28+
$container->get('security.token_storage')->setToken($token);
29+
30+
$security = $container->get('functional_test.security.helper');
31+
$this->assertTrue($security->isGranted('ROLE_USER'));
32+
$this->assertSame($token, $security->getToken());
33+
}
34+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Symfony\Bundle\TwigBundle\TwigBundle;
13+
use Symfony\Bundle\SecurityBundle\SecurityBundle;
14+
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
15+
16+
return array(
17+
new FrameworkBundle(),
18+
new SecurityBundle(),
19+
new TwigBundle(),
20+
);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
imports:
2+
- { resource: ./../config/default.yml }
3+
4+
services:
5+
# alias the service so we can access it in the tests
6+
functional_test.security.helper:
7+
alias: security.helper
8+
public: true
9+
10+
security:
11+
providers:
12+
in_memory:
13+
memory:
14+
users: []
15+
16+
firewalls:
17+
default:
18+
anonymous: ~
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Argument;
13+
14+
/**
15+
* Represents a collection of services found by tag name to lazily iterate over.
16+
*
17+
* @author Roland Franssen <franssen.roland@gmail.com>
18+
*/
19+
class TaggedIteratorArgument extends IteratorArgument
20+
{
21+
private $tag;
22+
23+
/**
24+
* @param string $tag
25+
*/
26+
public function __construct($tag)
27+
{
28+
parent::__construct(array());
29+
30+
$this->tag = (string) $tag;
31+
}
32+
33+
public function getTag()
34+
{
35+
return $this->tag;
36+
}
37+
}

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ CHANGELOG
3535
* deprecated support for top-level anonymous services in XML
3636
* deprecated case insensitivity of parameter names
3737
* deprecated the `ResolveDefinitionTemplatesPass` class in favor of `ResolveChildDefinitionsPass`
38+
* added `TaggedIteratorArgument` with YAML (`!tagged foo`) and XML (`<service type="tagged"/>`) support
3839

3940
3.3.0
4041
-----

src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public function __construct()
6060
new AutowireRequiredMethodsPass(),
6161
new ResolveBindingsPass(),
6262
new AutowirePass(false),
63+
new ResolveTaggedIteratorArgumentPass(),
6364
new ResolveServiceSubscribersPass(),
6465
new ResolveReferencesToAliasesPass(),
6566
new ResolveInvalidReferencesPass(),
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
15+
16+
/**
17+
* Resolves all TaggedIteratorArgument arguments.
18+
*
19+
* @author Roland Franssen <franssen.roland@gmail.com>
20+
*/
21+
class ResolveTaggedIteratorArgumentPass extends AbstractRecursivePass
22+
{
23+
use PriorityTaggedServiceTrait;
24+
25+
/**
26+
* {@inheritdoc}
27+
*/
28+
protected function processValue($value, $isRoot = false)
29+
{
30+
if (!$value instanceof TaggedIteratorArgument) {
31+
return parent::processValue($value, $isRoot);
32+
}
33+
34+
$value->setValues($this->findAndSortTaggedServices($value->getTag(), $this->container));
35+
36+
return $value;
37+
}
38+
}

src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
1515
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
16+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1617
use Symfony\Component\DependencyInjection\ContainerInterface;
1718
use Symfony\Component\DependencyInjection\Parameter;
1819
use Symfony\Component\DependencyInjection\Reference;
@@ -291,6 +292,9 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent
291292
if (is_array($value)) {
292293
$element->setAttribute('type', 'collection');
293294
$this->convertParameters($value, $type, $element, 'key');
295+
} elseif ($value instanceof TaggedIteratorArgument) {
296+
$element->setAttribute('type', 'tagged');
297+
$element->setAttribute('tag', $value->getTag());
294298
} elseif ($value instanceof IteratorArgument) {
295299
$element->setAttribute('type', 'iterator');
296300
$this->convertParameters($value->getValues(), $type, $element, 'key');

src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
2020
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
2121
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
22+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
2223
use Symfony\Component\DependencyInjection\ContainerInterface;
2324
use Symfony\Component\DependencyInjection\Definition;
2425
use Symfony\Component\DependencyInjection\Parameter;
@@ -255,6 +256,9 @@ private function dumpValue($value)
255256
$value = $value->getValues()[0];
256257
}
257258
if ($value instanceof ArgumentInterface) {
259+
if ($value instanceof TaggedIteratorArgument) {
260+
return new TaggedValue('tagged', $value->getTag());
261+
}
258262
if ($value instanceof IteratorArgument) {
259263
$tag = 'iterator';
260264
} else {

src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1313

1414
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
15+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\DependencyInjection\Definition;
1718
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
@@ -115,6 +116,18 @@ function iterator(array $values)
115116
return new IteratorArgument(AbstractConfigurator::processValue($values, true));
116117
}
117118

119+
/**
120+
* Creates a lazy iterator by tag name.
121+
*
122+
* @param string $tag
123+
*
124+
* @return TaggedIteratorArgument
125+
*/
126+
function tagged($tag)
127+
{
128+
return new TaggedIteratorArgument($tag);
129+
}
130+
118131
/**
119132
* Creates an expression.
120133
*

src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\DependencyInjection\Loader;
1313

1414
use Symfony\Component\Config\Util\XmlUtils;
15+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1516
use Symfony\Component\DependencyInjection\ContainerInterface;
1617
use Symfony\Component\DependencyInjection\Alias;
1718
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
@@ -500,6 +501,12 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase =
500501
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="iterator" only accepts collections of type="service" references in "%s".', $name, $file));
501502
}
502503
break;
504+
case 'tagged':
505+
if (!$arg->getAttribute('tag')) {
506+
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file));
507+
}
508+
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'));
509+
break;
503510
case 'string':
504511
$arguments[$key] = $arg->nodeValue;
505512
break;

src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1616
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
1717
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
18+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1819
use Symfony\Component\DependencyInjection\ChildDefinition;
1920
use Symfony\Component\DependencyInjection\ContainerBuilder;
2021
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -708,6 +709,13 @@ private function resolveServices($value, $file, $isParameter = false)
708709
throw new InvalidArgumentException(sprintf('"!iterator" tag only accepts arrays of "@service" references in "%s".', $file));
709710
}
710711
}
712+
if ('tagged' === $value->getTag()) {
713+
if (!is_string($argument) || !$argument) {
714+
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file));
715+
}
716+
717+
return new TaggedIteratorArgument($argument);
718+
}
711719
if ('service' === $value->getTag()) {
712720
if ($isParameter) {
713721
throw new InvalidArgumentException(sprintf('Using an anonymous service in a parameter is not allowed in "%s".', $file));

src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@
206206
<xsd:attribute name="key" type="xsd:string" />
207207
<xsd:attribute name="name" type="xsd:string" />
208208
<xsd:attribute name="on-invalid" type="invalid_sequence" />
209+
<xsd:attribute name="tag" type="xsd:string" />
209210
</xsd:complexType>
210211

211212
<xsd:complexType name="bind" mixed="true">
@@ -230,6 +231,7 @@
230231
<xsd:attribute name="key" type="xsd:string" />
231232
<xsd:attribute name="index" type="xsd:integer" />
232233
<xsd:attribute name="on-invalid" type="invalid_sequence" />
234+
<xsd:attribute name="tag" type="xsd:string" />
233235
</xsd:complexType>
234236

235237
<xsd:complexType name="call">
@@ -255,6 +257,7 @@
255257
<xsd:enumeration value="string" />
256258
<xsd:enumeration value="constant" />
257259
<xsd:enumeration value="iterator" />
260+
<xsd:enumeration value="tagged" />
258261
</xsd:restriction>
259262
</xsd:simpleType>
260263

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
16+
use Symfony\Component\DependencyInjection\Compiler\ResolveTaggedIteratorArgumentPass;
17+
use Symfony\Component\DependencyInjection\ContainerBuilder;
18+
use Symfony\Component\DependencyInjection\Reference;
19+
20+
/**
21+
* @author Roland Franssen <franssen.roland@gmail.com>
22+
*/
23+
class ResolveTaggedIteratorArgumentPassTest extends TestCase
24+
{
25+
public function testProcess()
26+
{
27+
$container = new ContainerBuilder();
28+
$container->register('a', 'stdClass')->addTag('foo');
29+
$container->register('b', 'stdClass')->addTag('foo', array('priority' => 20));
30+
$container->register('c', 'stdClass')->addTag('foo', array('priority' => 10));
31+
$container->register('d', 'stdClass')->setProperty('foos', new TaggedIteratorArgument('foo'));
32+
33+
(new ResolveTaggedIteratorArgumentPass())->process($container);
34+
35+
$properties = $container->getDefinition('d')->getProperties();
36+
$expected = new TaggedIteratorArgument('foo');
37+
$expected->setValues(array(new Reference('b'), new Reference('c'), new Reference('a')));
38+
$this->assertEquals($expected, $properties['foos']);
39+
}
40+
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/basic.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
use App\BarService;
66

77
return function (ContainerConfigurator $c) {
8-
98
$s = $c->services();
109
$s->set(BarService::class)
1110
->args(array(inline('FooClass')));
12-
1311
};

src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/child.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use App\BarService;
66

77
return function (ContainerConfigurator $c) {
8-
98
$c->services()
109
->set('bar', 'Class1')
1110
->set(BarService::class)
@@ -20,5 +19,4 @@
2019
->parent('bar')
2120
->parent(BarService::class)
2221
;
23-
2422
};

0 commit comments

Comments
 (0)
0