Skip to content

Commit fee690a

Browse files
committed
feature #37332 [FrameworkBundle] Allow to leverage autoconfiguration for DataCollectors with template (l-vo)
This PR was merged into the 5.2-dev branch. Discussion ---------- [FrameworkBundle] Allow to leverage autoconfiguration for DataCollectors with template | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | | License | MIT | Doc PR | When creating a datacollector with a template for the profiler display, an id must be set in the `data_collector` tag and must be the same as this returned by `DataCollectorInterface::getName`. A template path can also be added to the tag. We lose in this case the ability to use autoconfigure. This PR suggests: - To guess the id configured in the `data_collector` tag. To follow the principle already used for services ids or events names, if not specified, the id is the data collector class name. - To allow data collectors to provide the template path from the code. Note that the template path configuration via the `data_collector` tags still takes precedence over configuration from the code. This PR also provides an `AbstractDataCollector` to avoid to implement methods that might be considered as boilerplate: `reset` and `getName`. Commits ------- 986a0a2 [FrameworkBundle] Allow to leverage autoconfiguration for DataCollectors with template
2 parents 31c194f + 986a0a2 commit fee690a

File tree

5 files changed

+135
-3
lines changed

5 files changed

+135
-3
lines changed

src/Symfony/Bundle/FrameworkBundle/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+
}

src/Symfony/Bundle/FrameworkBundle/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]);

src/Symfony/Bundle/FrameworkBundle/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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy