Skip to content

Commit 1e9fc3f

Browse files
committed
[Workflow] Add a profiler
1 parent d660091 commit 1e9fc3f

File tree

6 files changed

+153
-0
lines changed

6 files changed

+153
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ public function load(array $configs, ContainerBuilder $container)
280280
$this->readConfigEnabled('translator', $container, $config['translator']);
281281
$this->readConfigEnabled('property_access', $container, $config['property_access']);
282282
$this->readConfigEnabled('profiler', $container, $config['profiler']);
283+
$this->readConfigEnabled('workflows', $container, $config['workflows']);
283284

284285
// A translator must always be registered (as support is included by
285286
// default in the Form and Validator component). If disabled, an identity
@@ -876,6 +877,10 @@ private function registerProfilerConfiguration(array $config, ContainerBuilder $
876877
$loader->load('mailer_debug.php');
877878
}
878879

880+
if ($this->isInitializedConfigEnabled('workflows')) {
881+
$loader->load('workflow_debug.php');
882+
}
883+
879884
if ($this->isInitializedConfigEnabled('http_client')) {
880885
$loader->load('http_client_debug.php');
881886
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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\Loader\Configurator;
13+
14+
use Symfony\Component\Workflow\DataCollector\WorkflowDataCollector;
15+
16+
return static function (ContainerConfigurator $container) {
17+
$container->services()
18+
->set('data_collector.workflow', WorkflowDataCollector::class)
19+
->tag('data_collector', [
20+
'template' => '@WebProfiler/Collector/workflow.html.twig',
21+
'id' => 'workflow',
22+
])
23+
->args([
24+
tagged_iterator('workflow', 'name'),
25+
])
26+
;
27+
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
2+
3+
{% block menu %}
4+
<span class="label {{ collector.dumps|length == 0 ? 'disabled' }}">
5+
<span class="icon">
6+
{{ source('@WebProfiler/Icon/workflow.svg') }}
7+
</span>
8+
<strong>Workflow</strong>
9+
</span>
10+
{% endblock %}
11+
12+
{% block panel %}
13+
<h2>Workflow</h2>
14+
15+
{% if collector.dumps|length == 0 %}
16+
<div class="empty empty-panel">
17+
<p>There are no workflows configured.</p>
18+
</div>
19+
{% else %}
20+
<script type="module">
21+
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
22+
// We do not load all mermaid diagrams at once, but only when the tab is opened
23+
// This is because mermaid diagrams are in a tab, and cannot be renderer with a
24+
// "good size" if they are not visible
25+
document.addEventListener('DOMContentLoaded', () => {
26+
document.querySelectorAll('.tab').forEach((el) => {
27+
const observer = new MutationObserver(() => {
28+
if (!el.classList.contains('block')) {
29+
return;
30+
}
31+
const mEl = el.querySelector('.sf-mermaid');
32+
if (mEl.dataset.processed) {
33+
console.log('A');
34+
return;
35+
}
36+
mermaid.run({
37+
flowchart: { useMaxWidth: false },
38+
securityLevel: 'loose',
39+
nodes: [mEl],
40+
});
41+
});
42+
observer.observe(el, { attributeFilter: ['class'] });
43+
});
44+
});
45+
</script>
46+
47+
<h2>Definitions</h2>
48+
<div class="sf-tabs js-tabs">
49+
{% for name, dump in collector.dumps %}
50+
<div class="tab">
51+
<h3 class="tab-title">{{ name }}</h3>
52+
<div class="tab-content">
53+
<pre class="sf-mermaid">
54+
{{ dump|raw }}
55+
</pre>
56+
</div>
57+
</div>
58+
{% endfor %}
59+
</div>
60+
{% endif %}
61+
{% endblock %}
Lines changed: 1 addition & 0 deletions
Loading

src/Symfony/Component/Workflow/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Add `with-metadata` option to the `workflow:dump` command to include places,
88
transitions and workflow's metadata into dumped graph
9+
* Add a profiler
910

1011
6.2
1112
---
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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\Workflow\DataCollector;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
17+
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
18+
use Symfony\Component\Workflow\Dumper\MermaidDumper;
19+
use Symfony\Component\Workflow\StateMachine;
20+
21+
/**
22+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
23+
*/
24+
final class WorkflowDataCollector extends DataCollector implements LateDataCollectorInterface
25+
{
26+
public function __construct(
27+
private readonly iterable $workflows,
28+
) {
29+
}
30+
31+
public function collect(Request $request, Response $response, \Throwable $exception = null)
32+
{
33+
}
34+
35+
public function lateCollect()
36+
{
37+
foreach ($this->workflows as $workflow) {
38+
$type = $workflow instanceof StateMachine ? MermaidDumper::TRANSITION_TYPE_STATEMACHINE : MermaidDumper::TRANSITION_TYPE_WORKFLOW;
39+
$dumper = new MermaidDumper($type);
40+
$this->data['dumps'][$workflow->getName()] = $dumper->dump($workflow->getDefinition());
41+
}
42+
}
43+
44+
public function getName()
45+
{
46+
return 'workflow';
47+
}
48+
49+
public function reset(): void
50+
{
51+
$this->data = [];
52+
}
53+
54+
public function getDumps(): array
55+
{
56+
return $this->data['dumps'] ?? [];
57+
}
58+
}

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