Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WebProfiler] Add copy button on runnable and formatted queries #1056

Merged
merged 3 commits into from Jan 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 14 additions & 3 deletions Resources/views/Collector/db.html.twig
Expand Up @@ -144,6 +144,8 @@
.time-container { position: relative; }
.time-container .nowrap { position: relative; z-index: 1; text-shadow: 0 0 2px #fff; }
.time-bar { display: block; position: absolute; top: 0; left: 0; bottom: 0; background: #e0e0e0; }
.sql-runnable.sf-toggle-content.sf-toggle-visible { display: flex; flex-direction: column; }
.sql-runnable button { align-self: end; }
</style>

{% if profiler_markup_version > 1 %}
Expand Down Expand Up @@ -237,7 +239,7 @@
<td class="nowrap">{{ '%0.2f'|format(query.executionMS * 1000) }}&nbsp;ms</td>
{% endif %}
<td>
{{ query.sql|doctrine_pretty_query(highlight_only = true) }}
{{ query.sql|doctrine_prettify_sql }}

<div>
<strong class="font-normal text-small">Parameters</strong>: {{ profiler_dump(query.params, 2) }}
Expand All @@ -263,12 +265,15 @@
</div>

<div id="formatted-query-{{ i }}-{{ loop.parent.loop.index }}" class="sql-runnable hidden">
{{ query.sql|doctrine_pretty_query }}
{{ query.sql|doctrine_format_sql(highlight = true) }}
<button class="btn btn-sm" data-clipboard-text="{{ query.sql|doctrine_format_sql(highlight = false)|e('html_attr') }}">Copy</button>
</div>

{% if query.runnable %}
<div id="original-query-{{ i }}-{{ loop.parent.loop.index }}" class="sql-runnable hidden">
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)|doctrine_pretty_query(highlight_only = true) }}
{% set runnable_sql = (query.sql ~ ';')|doctrine_replace_query_parameters(query.params) %}
{{ runnable_sql|doctrine_prettify_sql }}
<button class="btn btn-sm" data-clipboard-text="{{ runnable_sql|e('html_attr') }}">Copy</button>
</div>
{% endif %}

Expand Down Expand Up @@ -505,6 +510,12 @@
}
{% endif %}

document.querySelectorAll('[data-clipboard-text]').forEach(function(button) {
button.addEventListener('click', function() {
navigator.clipboard.writeText(button.getAttribute('data-clipboard-text'));
})
});

//]]></script>
{% endblock %}

Expand Down
11 changes: 9 additions & 2 deletions Tests/ProfilerTest.php
Expand Up @@ -67,7 +67,7 @@ public function testRender()
{
$this->logger->queries = [
[
'sql' => 'SELECT * FROM foo WHERE bar IN (?, ?)',
'sql' => 'SELECT * FROM foo WHERE bar IN (?, ?) AND "" >= ""',
'params' => ['foo', 'bar'],
'types' => null,
'executionMS' => 1,
Expand All @@ -88,6 +88,13 @@ public function testRender()
]);

$output = str_replace(["\e[37m", "\e[0m", "\e[32;1m", "\e[34;1m"], '', $output);
$this->assertContains("SELECT * FROM foo WHERE bar IN ('foo', 'bar');", $output);
$this->assertContains("SELECT * FROM foo WHERE bar IN ('foo', 'bar') AND \"\" >= \"\";", $output);

$expectedEscapedSql = 'SELECT&#x20;&#x0A;&#x20;&#x20;&#x2A;&#x20;&#x0A;FROM&#x20;&#x0A;&#x20;&#x20;foo&#x20;&#x0A;WHERE&#x20;&#x0A;&#x20;&#x20;bar&#x20;IN&#x20;&#x28;&#x3F;,&#x20;&#x3F;&#x29;&#x20;&#x0A;&#x20;&#x20;AND&#x20;&quot;&quot;&#x20;&gt;&#x3D;&#x20;&quot;&quot;';
$this->assertContains($expectedEscapedSql, $output);
$this->assertSame(
"SELECT \n * \nFROM \n foo \nWHERE \n bar IN (?, ?) \n AND \"\" >= \"\"",
html_entity_decode($expectedEscapedSql)
);
}
}
45 changes: 34 additions & 11 deletions Twig/DoctrineExtension.php
Expand Up @@ -20,7 +20,9 @@ class DoctrineExtension extends AbstractExtension
public function getFilters()
{
return [
new TwigFilter('doctrine_pretty_query', [$this, 'formatQuery'], ['is_safe' => ['html']]),
new TwigFilter('doctrine_pretty_query', [$this, 'formatQuery'], ['is_safe' => ['html'], 'deprecated' => true]),
new TwigFilter('doctrine_prettify_sql', [$this, 'prettifySql'], ['is_safe' => ['html']]),
new TwigFilter('doctrine_format_sql', [$this, 'formatSql'], ['is_safe' => ['html']]),
new TwigFilter('doctrine_replace_query_parameters', [$this, 'replaceQueryParameters']),
];
}
Expand Down Expand Up @@ -169,16 +171,9 @@ static function ($matches) use ($parameters, &$i) {
*/
public function formatQuery($sql, $highlightOnly = false)
{
SqlFormatter::$pre_attributes = 'class="highlight highlight-sql"';
SqlFormatter::$quote_attributes = 'class="string"';
SqlFormatter::$backtick_quote_attributes = 'class="string"';
SqlFormatter::$reserved_attributes = 'class="keyword"';
SqlFormatter::$boundary_attributes = 'class="symbol"';
SqlFormatter::$number_attributes = 'class="number"';
SqlFormatter::$word_attributes = 'class="word"';
SqlFormatter::$error_attributes = 'class="error"';
SqlFormatter::$comment_attributes = 'class="comment"';
SqlFormatter::$variable_attributes = 'class="variable"';
@trigger_error(sprintf('The "%s()" method is deprecated and will be removed in DoctrineBundle 3.0.', __METHOD__), E_USER_DEPRECATED);

$this->setUpSqlFormatter();

if ($highlightOnly) {
$html = SqlFormatter::highlight($sql);
Expand All @@ -191,6 +186,34 @@ public function formatQuery($sql, $highlightOnly = false)
return $html;
}

public function prettifySql(string $sql) : string
{
$this->setUpSqlFormatter();

return SqlFormatter::highlight($sql);
}

public function formatSql(string $sql, bool $highlight) : string
{
$this->setUpSqlFormatter();

return SqlFormatter::format($sql, $highlight);
}

private function setUpSqlFormatter() : void
{
SqlFormatter::$pre_attributes = 'class="highlight highlight-sql"';
SqlFormatter::$quote_attributes = 'class="string"';
SqlFormatter::$backtick_quote_attributes = 'class="string"';
SqlFormatter::$reserved_attributes = 'class="keyword"';
SqlFormatter::$boundary_attributes = 'class="symbol"';
SqlFormatter::$number_attributes = 'class="number"';
SqlFormatter::$word_attributes = 'class="word"';
SqlFormatter::$error_attributes = 'class="error"';
SqlFormatter::$comment_attributes = 'class="comment"';
SqlFormatter::$variable_attributes = 'class="variable"';
}

/**
* Get the name of the extension
*
Expand Down