Skip to content

Commit 797b643

Browse files
committed
[FrameworkBundle] Allow to leverage autoconfiguration for DataCollectors with template
1 parent eb0098b commit 797b643

File tree

5 files changed

+135
-3
lines changed

5 files changed

+135
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* Added `framework.trusted_proxies` and `framework.trusted_headers` configuration options
99
* Deprecated the public `form.factory`, `form.type.file`, `translator`, `security.csrf.token_manager`, `serializer`,
1010
`cache_clearer`, `filesystem` and `validator` services to private.
11+
* Added `TemplateAwareDataCollectorInterface` and `AbstractDataCollector` to simplify custom data collector creation and leverage autoconfiguration
1112

1213
5.1.0
1314
-----
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\Bundle\FrameworkBundle\DataCollector;
13+
14+
/**
15+
* @author Laurent VOULLEMIER <laurent.voullemier@gmail.com>
16+
*/
17+
abstract class AbstractDataCollector implements TemplateAwareDataCollectorInterface
18+
{
19+
/**
20+
* @var array
21+
*/
22+
protected $data = [];
23+
24+
public function getName(): string
25+
{
26+
return static::class;
27+
}
28+
29+
public function reset(): void
30+
{
31+
$this->data = [];
32+
}
33+
34+
public static function getTemplate(): ?string
35+
{
36+
return null;
37+
}
38+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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\FrameworkBundle\DataCollector;
13+
14+
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
15+
16+
/**
17+
* @author Laurent VOULLEMIER <laurent.voullemier@gmail.com>
18+
*/
19+
interface TemplateAwareDataCollectorInterface extends DataCollectorInterface
20+
{
21+
public static function getTemplate(): ?string;
22+
}

DependencyInjection/Compiler/ProfilerPass.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
1313

14+
use Symfony\Bundle\FrameworkBundle\DataCollector\TemplateAwareDataCollectorInterface;
1415
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
@@ -37,11 +38,14 @@ public function process(ContainerBuilder $container)
3738
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
3839
$template = null;
3940

40-
if (isset($attributes[0]['template'])) {
41-
if (!isset($attributes[0]['id'])) {
41+
$collectorClass = $container->findDefinition($id)->getClass();
42+
$isTemplateAware = is_subclass_of($collectorClass, TemplateAwareDataCollectorInterface::class);
43+
if (isset($attributes[0]['template']) || $isTemplateAware) {
44+
$idForTemplate = $attributes[0]['id'] ?? $collectorClass;
45+
if (!$idForTemplate) {
4246
throw new InvalidArgumentException(sprintf('Data collector service "%s" must have an id attribute in order to specify a template.', $id));
4347
}
44-
$template = [$attributes[0]['id'], $attributes[0]['template']];
48+
$template = [$idForTemplate, $attributes[0]['template'] ?? $collectorClass::getTemplate()];
4549
}
4650

4751
$collectors->insert([$id, $template], [$priority, --$order]);

Tests/DependencyInjection/Compiler/ProfilerPassTest.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,15 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
16+
use Symfony\Bundle\FrameworkBundle\DataCollector\TemplateAwareDataCollectorInterface;
1517
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass;
18+
use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
19+
use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass;
1620
use Symfony\Component\DependencyInjection\ContainerBuilder;
21+
use Symfony\Component\HttpFoundation\Request;
22+
use Symfony\Component\HttpFoundation\Response;
23+
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
1724

1825
class ProfilerPassTest extends TestCase
1926
{
@@ -54,4 +61,64 @@ public function testValidCollector()
5461
$this->assertCount(1, $methodCalls);
5562
$this->assertEquals('add', $methodCalls[0][0]); // grab the method part of the first call
5663
}
64+
65+
public function provideValidCollectorWithTemplateUsingAutoconfigure(): \Generator
66+
{
67+
yield [new class() implements TemplateAwareDataCollectorInterface {
68+
public function collect(Request $request, Response $response, \Throwable $exception = null)
69+
{
70+
}
71+
72+
public function getName(): string
73+
{
74+
return static::class;
75+
}
76+
77+
public function reset()
78+
{
79+
}
80+
81+
public static function getTemplate(): string
82+
{
83+
return 'foo';
84+
}
85+
}];
86+
87+
yield [new class() extends AbstractDataCollector {
88+
public function collect(Request $request, Response $response, \Throwable $exception = null)
89+
{
90+
}
91+
92+
public static function getTemplate(): string
93+
{
94+
return 'foo';
95+
}
96+
}];
97+
}
98+
99+
/**
100+
* @dataProvider provideValidCollectorWithTemplateUsingAutoconfigure
101+
*/
102+
public function testValidCollectorWithTemplateUsingAutoconfigure(TemplateAwareDataCollectorInterface $dataCollector)
103+
{
104+
$container = new ContainerBuilder();
105+
$profilerDefinition = $container->register('profiler', 'ProfilerClass');
106+
107+
$container->registerForAutoconfiguration(DataCollectorInterface::class)->addTag('data_collector');
108+
$container->register('mydatacollector', \get_class($dataCollector))->setAutoconfigured(true);
109+
110+
(new ResolveInstanceofConditionalsPass())->process($container);
111+
(new ProfilerPass())->process($container);
112+
113+
$idForTemplate = \get_class($dataCollector);
114+
$this->assertSame(['mydatacollector' => [$idForTemplate, 'foo']], $container->getParameter('data_collector.templates'));
115+
116+
// grab the method calls off of the "profiler" definition
117+
$methodCalls = $profilerDefinition->getMethodCalls();
118+
$this->assertCount(1, $methodCalls);
119+
$this->assertEquals('add', $methodCalls[0][0]); // grab the method part of the first call
120+
121+
(new ResolveChildDefinitionsPass())->process($container);
122+
$this->assertSame($idForTemplate, $container->get('mydatacollector')->getName());
123+
}
57124
}

0 commit comments

Comments
 (0)