diff --git a/src/TwigComponent/CHANGELOG.md b/src/TwigComponent/CHANGELOG.md
index 2a42f9d5897..a4578a1c545 100644
--- a/src/TwigComponent/CHANGELOG.md
+++ b/src/TwigComponent/CHANGELOG.md
@@ -1,5 +1,10 @@
# CHANGELOG
+## 2.32
+
+- Add option `profiler.collect_components` to control component data collection
+ in the profiler (enabled in debug mode by default)
+
## 2.30
- Ensure compatibility with PHP 8.5
diff --git a/src/TwigComponent/config/debug.php b/src/TwigComponent/config/debug.php
index 6afabb82245..4d23c7a7bb5 100644
--- a/src/TwigComponent/config/debug.php
+++ b/src/TwigComponent/config/debug.php
@@ -15,6 +15,7 @@
use Symfony\UX\TwigComponent\DataCollector\TwigComponentDataCollector;
use Symfony\UX\TwigComponent\EventListener\TwigComponentLoggerListener;
+use function Symfony\Component\DependencyInjection\Loader\Configurator\abstract_arg;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
return static function (ContainerConfigurator $container) {
@@ -27,6 +28,7 @@
->args([
service('ux.twig_component.component_logger_listener'),
service('twig'),
+ abstract_arg('profiler collect components'),
])
->tag('data_collector', [
'template' => '@TwigComponent/Collector/twig_component.html.twig',
diff --git a/src/TwigComponent/src/DataCollector/TwigComponentDataCollector.php b/src/TwigComponent/src/DataCollector/TwigComponentDataCollector.php
index 1ee94c71bdb..cda4ad385b5 100644
--- a/src/TwigComponent/src/DataCollector/TwigComponentDataCollector.php
+++ b/src/TwigComponent/src/DataCollector/TwigComponentDataCollector.php
@@ -35,6 +35,7 @@ final class TwigComponentDataCollector extends AbstractDataCollector implements
public function __construct(
private readonly TwigComponentLoggerListener $logger,
private readonly Environment $twig,
+ private readonly bool $collectComponents = true,
) {
$this->hasStub = class_exists(ClassStub::class);
}
@@ -130,12 +131,15 @@ private function collectDataFromLogger(): void
'input_props' => $mountedComponent->getInputProps(),
'attributes' => $mountedComponent->getAttributes()->all(),
'template_index' => $event->getTemplateIndex(),
- 'component' => $mountedComponent->getComponent(),
'depth' => \count($ongoingRenders),
'children' => [],
'render_start' => $profile[0],
];
+ if ($this->collectComponents) {
+ $renders[$renderId]['component'] = $mountedComponent->getComponent();
+ }
+
if ($parentId = end($ongoingRenders)) {
$renders[$parentId]['children'][] = $renderId;
}
diff --git a/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php b/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php
index dc71c610931..9aee30bccc4 100644
--- a/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php
+++ b/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php
@@ -150,8 +150,11 @@ static function (ChildDefinition $definition, AsTwigComponent $attribute) {
$container->setAlias('console.command.stimulus_component_debug', 'ux.twig_component.command.debug')
->setDeprecated('symfony/ux-twig-component', '2.13', '%alias_id%');
- if ($container->getParameter('kernel.debug') && $config['profiler']) {
+ if ($config['profiler']['enabled']) {
$loader->load('debug.php');
+
+ $container->getDefinition('ux.twig_component.data_collector')
+ ->setArgument(2, $config['profiler']['collect_components']);
}
$loader->load('cache.php');
@@ -215,9 +218,13 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarNode('anonymous_template_directory')
->info('Defaults to `components`')
->end()
- ->booleanNode('profiler')
- ->info('Enables the profiler for Twig Component (in debug mode)')
- ->defaultValue('%kernel.debug%')
+ ->arrayNode('profiler')
+ ->info('Enables the profiler for Twig Component')
+ ->canBeEnabled()
+ ->children()
+ ->booleanNode('enabled')->defaultValue('%kernel.debug%')->end()
+ ->booleanNode('collect_components')->info('Collect components instances')->defaultTrue()->end()
+ ->end()
->end()
->scalarNode('controllers_json')
->setDeprecated('symfony/ux-twig-component', '2.18', 'The "twig_component.controllers_json" config option is deprecated, and will be removed in 3.0.')
diff --git a/src/TwigComponent/templates/Collector/twig_component.html.twig b/src/TwigComponent/templates/Collector/twig_component.html.twig
index c2098156f22..7bd88387fbc 100644
--- a/src/TwigComponent/templates/Collector/twig_component.html.twig
+++ b/src/TwigComponent/templates/Collector/twig_component.html.twig
@@ -293,10 +293,12 @@
Attributes |
{{ profiler_dump(render.attributes) }} |
+ {% if render.component is defined %}
| Component |
{{ profiler_dump(render.component) }} |
+ {% endif %}
{% endfor %}
diff --git a/src/TwigComponent/tests/Unit/DataCollector/TwigComponentDataCollectorTest.php b/src/TwigComponent/tests/Unit/DataCollector/TwigComponentDataCollectorTest.php
index a547c64e04d..e0cca8e8f47 100644
--- a/src/TwigComponent/tests/Unit/DataCollector/TwigComponentDataCollectorTest.php
+++ b/src/TwigComponent/tests/Unit/DataCollector/TwigComponentDataCollectorTest.php
@@ -14,9 +14,16 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
+use Symfony\UX\TwigComponent\ComponentAttributes;
+use Symfony\UX\TwigComponent\ComponentMetadata;
use Symfony\UX\TwigComponent\DataCollector\TwigComponentDataCollector;
+use Symfony\UX\TwigComponent\Event\PostRenderEvent;
+use Symfony\UX\TwigComponent\Event\PreRenderEvent;
use Symfony\UX\TwigComponent\EventListener\TwigComponentLoggerListener;
+use Symfony\UX\TwigComponent\MountedComponent;
use Twig\Environment;
+use Twig\Loader\ArrayLoader;
+use Twig\Runtime\EscaperRuntime;
/**
* @author Simon André
@@ -35,7 +42,7 @@ public function testCollectDoesNothing()
$this->assertSame([], $dataCollector->getData());
}
- public function testLateCollect()
+ public function testLateCollectWithNoCollectedData()
{
$logger = new TwigComponentLoggerListener();
$twig = $this->createMock(Environment::class);
@@ -54,6 +61,44 @@ public function testLateCollect()
$this->assertEquals(0.0, $dataCollector->getRenderTime());
}
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testLateCollectWithCollectedData(bool $collectComponents)
+ {
+ $logger = new TwigComponentLoggerListener();
+ $twig = new Environment(new ArrayLoader());
+ $dataCollector = new TwigComponentDataCollector($logger, $twig, $collectComponents);
+
+ // Trigger some events to be logged
+ $mounted = new MountedComponent('foo', new \stdClass(), new ComponentAttributes([], new EscaperRuntime()));
+ $eventA = new PreRenderEvent($mounted, new ComponentMetadata(['key' => 'foo', 'template' => 'bar']), []);
+ $logger->onPreRender($eventA);
+ $eventB = new PostRenderEvent($mounted);
+ $logger->onPostRender($eventB);
+
+ $dataCollector->lateCollect();
+
+ $this->assertSame(1, $dataCollector->getComponentCount());
+ $this->assertIsIterable($dataCollector->getComponents());
+ $this->assertNotEmpty($dataCollector->getComponents());
+
+ $this->assertSame(1, $dataCollector->getRenderCount());
+ $this->assertIsIterable($dataCollector->getRenders());
+ $this->assertNotEmpty($dataCollector->getRenders());
+
+ foreach ($dataCollector->getRenders() as $render) {
+ if ($collectComponents) {
+ $this->assertNotNull($render['component']);
+ } else {
+ $this->assertNull($render['component']);
+ }
+ }
+
+ $this->assertGreaterThan(0.0, $dataCollector->getRenderTime());
+ }
+
public function testReset()
{
$logger = new TwigComponentLoggerListener();
diff --git a/src/TwigComponent/tests/Unit/DependencyInjection/TwigComponentExtensionTest.php b/src/TwigComponent/tests/Unit/DependencyInjection/TwigComponentExtensionTest.php
index 6695e064caf..f2edd97aa72 100644
--- a/src/TwigComponent/tests/Unit/DependencyInjection/TwigComponentExtensionTest.php
+++ b/src/TwigComponent/tests/Unit/DependencyInjection/TwigComponentExtensionTest.php
@@ -37,9 +37,10 @@ public function testDataCollectorWithDebugMode()
$this->compileContainer($container);
$this->assertTrue($container->hasDefinition('ux.twig_component.data_collector'));
+ $this->assertTrue($container->getDefinition('ux.twig_component.data_collector')->getArgument(2));
}
- public function testDataCollectorWithDebugModeCanBeDisabled()
+ public function testDataCollectorWithCollectComponentsDisabled()
{
$container = $this->createContainer();
$container->setParameter('kernel.debug', true);
@@ -47,22 +48,25 @@ public function testDataCollectorWithDebugModeCanBeDisabled()
$container->loadFromExtension('twig_component', [
'defaults' => [],
'anonymous_template_directory' => 'components/',
- 'profiler' => false,
+ 'profiler' => [
+ 'collect_components' => false,
+ ],
]);
$this->compileContainer($container);
- $this->assertFalse($container->hasDefinition('ux.twig_component.data_collector'));
+ $this->assertTrue($container->hasDefinition('ux.twig_component.data_collector'));
+ $this->assertFalse($container->getDefinition('ux.twig_component.data_collector')->getArgument(2));
}
- public function testDataCollectorWithoutDebugMode()
+ public function testDataCollectorWithDebugModeCanBeDisabled()
{
$container = $this->createContainer();
- $container->setParameter('kernel.debug', false);
+ $container->setParameter('kernel.debug', true);
$container->registerExtension(new TwigComponentExtension());
$container->loadFromExtension('twig_component', [
'defaults' => [],
'anonymous_template_directory' => 'components/',
- 'profiler' => true,
+ 'profiler' => false,
]);
$this->compileContainer($container);