Symfony2 / Doctrine2:如何覆盖在doctrine DataCollector中使用的DebugStack类? [英] Symfony2 / Doctrine2 : How to override DebugStack class used in doctrine DataCollector?

查看:345
本文介绍了Symfony2 / Doctrine2:如何覆盖在doctrine DataCollector中使用的DebugStack类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了更好地管理我使用Doctrine进行数据库调用,我调查了如何将php debug_backtrace添加到symfony doctrine db collector 。



我设法确定了我必须做的修改,但是我还没有找到一个很好的方法来覆盖DebugStack类(除了覆盖供应商类)。



该类位于此处:

  vendor / doctrine / dbal / lib / Doctrine /DBAL/Logging/DebugStack.php 

对于有兴趣的人,这里是结果: p>



为此,您需要:



覆盖 vendor / doctrine / doctrine-bundle / Resources / views /Collector/db.html.twig 文件



将此文件复制到 app \resources\DoctrineBundle\ views\Collector\db.html.twig



你会看到我的修改在两个 ==== MODIFIED ===评论之下:

  {%extends app.request.isXmlHttpRequest? 'WebProfilerBundle:Profiler:ajax_layout.html.twig':'WebProfilerBundle:Profiler:layout.html.twig'%} 

{%block toolbar%}
{%set icon%}
将IMG WIDTH = 20 HEIGHT = 28 ALT = 数据库 SRC =数据:图像/ PNG; BASE64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAcCAYAAABh2p9gAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQRJREFUeNpi / P // PwM1ARMDlcGogZQDlpMnT7pxc3NbA9nhQKxOpL5rQLwJiPeBsI6Ozl + YBOOOHTv + AOllQNwtLS39F2owKYZ / gRq8G4i3ggxEToggWzvc3d2Pk + 1lNL4fFAs6ODi8JzdS7mMRVyDVoAMHDsANdAPiOCC + jCQvQKqBQB / BDbwBxK5AHA3E / kB8nKJkA8TMQBwLxaBIKQbi70AvTADSBiSadwFXpCikpKQU8PDwkGTaly9fHFigkaKIJid4584dkiMFFI6jkTJII0WVmpHCAixZQEXWYhDeuXMnyLsVlEQKI45qFBQZ8eRECi4DBaAlDqle / 8A48ip6gAADANdQY88Uc0oGAAAAAE1FTkSuQmCC/>
< span class =sf-toolbar-status {%if 50< collector.querycount%} sf-toolbar-status-yellow {%endif%}> {{collector.querycount}}& /跨度>
{%if collector.querycount> 0%}
< span class =sf-toolbar-info-piece-additional-detail> in {{'%0.2f'| format(collector.time * 1000)}} ms< / span> ;
{%endif%}
{%如果collector.invalidEntityCount> 0%}
< span class =sf-toolbar-info-piece-additional sf-toolbar-status sf-toolbar-status-red> {{collector.invalidEntityCount}}< / span>
{%endif%}
{%if collector.cacheEnabled%}
< span class =sf-toolbar-info-piece-additional sf-toolbar-status sf-toolbar-status -greentitle =启用二级缓存> 2l缓存< / span>
{%endif%}
{%endset%}
{%set text%}
< div class =sf-toolbar-info-piece>
< b>数据库查询< / b>
< span> {{collector.querycount}}< / span>
< / div>
< div class =sf-toolbar-info-piece>
< b>查询时间< / b>
< span> {{'%0.2f'| format(collector.time * 1000)}} ms< / span>
< / div>
< div class =sf-toolbar-info-piece>
< b>无效实体< / b>
< span class =sf-toolbar-status sf-toolbar-status - {{collector.invalidEntityCount> 0?'red':'green'}}> {{collector.invalidEntityCount}}< ; /跨度>
< / div>
{%if collector.cacheEnabled%}
< div class =sf-toolbar-info-piece>
< b>缓存命中< / b>
< span class =sf-toolbar-status sf-toolbar-status-green> {{collector.cacheHitsCount}}< / span>
< / div>
< div class =sf-toolbar-info-piece>
< b>缓存未命中< / b>
< span class =sf-toolbar-status sf-toolbar-status - {{collector.cacheMissesCount> 0?'yellow':'green'}}> {{collector.cacheMissesCount}}< ; /跨度>
< / div>
< div class =sf-toolbar-info-piece>
< b>缓存放置< / b>
< span class =sf-toolbar-status sf-toolbar-status - {{collector.cachePutsCount> 0?'yellow':'green'}}> {{collector.cachePutsCount}}< ; /跨度>
< / div>
{%endif%}
{%endset%}
{%include'WebProfilerBundle:Profiler:toolbar_item.html.twig'with {'link':profiler_url}%}
{%endblock%}

{%block menu%}
< span class =label>
将跨度类= 图标 >< IMG SRC =数据:图像/ PNG; BASE64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAYAAAB / E6 / TAAABLUlEQVR42u3TP0vDQBiA8UK / gDiLzi0IhU4OEunk5OQUAhGSOBUCzqWfIKSzX8DRySF0URCcMjWLIJjFD9Cpk / D6HITecEPUuz​​hIAz8CIdyTP / f2iqI4qaqqDx8l5Ic2uIeP / bquezCokOAFF + oCN3t4gPzSEjc4NEPaCldQbzjELTYW0RJzHDchwwem + ons6ZBpLSJ7nueJC22h0V + FzmwWV0ee59vQNV67CGVZJmEYbkNjfpY6X6I0Qo4 / 3RMmTdDDspuQVsJvgkP3IdMbIkIjLPBoadG2646iKJI0Ta2wxm6OdnP0 / Tk6DYJgHcfxpw21RtscDTDDnaVZ26474GkkSRIrrPEv5sgMTfHe + cA2O6wPH6vOBpYQNALneHb96XTEDI6dzpEZ0VzO0Rf3pP5LMLI4tAAAAABJRU5ErkJggg ==alt =/>< / span>
< strong> Doctrine< / strong>
< span class =count>
< span> {{collector.querycount}}< / span>
< span> {{'%0.0f'| format(collector.time * 1000)}} ms< / span>
< / span>
< / span>
{%endblock%}

{%block panel%}
{%if'explain'== page%}
{{render(controller('DoctrineBundle :Profiler:explain',{
'token':token,
'panel':'db',
'connectionName':app.request.query.get('connection'
'query':app.request.query.get('query')
})}}
{%else%}
{{block('queries') }}
{%endif%}
{%endblock%}

{%block queries%}
< h2"查询< / h2>

{#==================================== = MODIFIED =============================#}
< script src ={{asset(' vendor / jquery / jquery-2.1.1.min.js')}}>< / script>
< style rel =stylesheet>
.hidden {display:none;}
< / style>
< script>
$(function(){
$('。trace')。on('click',function(e){
e.preventDefault();
$ ).next()。toggleClass('hidden');
});
});
< / script>

{%用于连接,collector.queries%中的查询}
< h3> Connection< em> {{connection}}< / em>< / h3>
{%如果查询为空%}
< p>
< em>无查询。< / em>
< / p>
{%else%}
< p>
< button type =buttonclass =sf-buttononclick =expandAllQueries(this);数据行动=扩大>
< span class =border-l>
< span class =border-r>
< span class =btn-bg>展开所有查询< / span>
< / span>
< / span>
< / button>
< / p>
< table class =altid =queriesPlaceholder - {{loop.index}}>
< thead>
< tr>
< th onclick =javascript:sortTable(this,0,'queries - {{loop.index}})data-sort-direction = - 1style =cursor:pointer;> ;#<跨度>&安培;#9650;< /跨度>< /第>
< th onclick =javascript:sortTable(this,1,'queries - {{loop.index}})style =cursor:pointer;> Time< span>< / span> < /第>
< th style =width:100%;> Info< / th>
< / tr>
< / thead>
< tbody id =queries - {{loop.index}}>
{%for i,query in queries%}
< tr id =queryNo - {{i}} - {{loop.parent.loop.index}}class ={{cycle (['odd','even'],i)}}>
< td> {{loop.index}}< / td>
< td> {{'%0.2f'| format(query.executionMS * 1000)}}& nbsp; ms< / td>
< td>
< div class =query-sectiondata-state =collapsedonclick =return expandQuery(this); title =Expand querydata-target-id =code - {{i}} - {{loop.parent.loop.index}}style =cursor:pointer;>
将IMG ALT = + SRC =数据:图像/ GIF; BASE64,R0lGODlhEgASAMQTANft99 / V + Ga44bHb8ITG52S44dXs9 + Z1 + UPX + YvK6WC24G + 944 / M6W28443L6dnu + Ge54v / + / l614P /// wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5 / VFID / DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7style =display:inline; />
将IMG ALT = - SRC = 数据:图像/ GIF; BASE64,R0lGODlhEgASAMQSANft94TG57Hb8GS44ez1 + mC24IvK6ePx + Wa44dXs92 + 942e54o3L6W2844 / M6dnu + P / + / l614P /// wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABIALAAAAAASABIAQAVCoCQBTBOd6Kk4gJhGBCTPxysJb44K0qD / ER / wlxjmisZkMqBEBW5NHrMZmVKvv9hMVsO + hE0EoNAstEYGxG9heIhCADs = style =display:none; />
< span style =display:none>收缩查询< / span>
< span id =smallcode - {{i}} - {{loop.parent.loop.index}}>
{{query.sql | doctrine_minify_query | raw}}
< / span>
< / div>
< code id =code - {{i}} - {{loop.parent.loop.index}}>
{{query.sql | doctrine_pretty_query(i,loop.parent.loop.index)| raw}}
< / code>
< span id =original-query - {{i}} - {{loop.parent.loop.index}}style =display:none;>
{{query.sql | doctrine_replace_query_parameters(query.params)| raw}}
< / span>
< small>
< strong>参数< / strong> ;: {{query.params | yaml_encode}}< br />
[< span id =expandParams - {{i}} - {{loop.parent.loop.index}}onclick =javascript:toggleRunnableQuery(this); target-data-id =original-query - {{i}} - {{loop.parent.loop.index}}style =cursor:pointer;>显示可运行的查询< / span>]< br />
< / small>

{%if query.explainable%}
[< a href ={{path('_ profiler',{'panel':'db','token' 'page':'explain','connection':connection,'query':i})}}onclick =return explain(this); style =text-decoration:none; title =解释查询data-target-id =explain - {{i}} - {{loop.parent.loop.index}}>
将IMG ALT = + SRC =数据:图像/ GIF; BASE64,R0lGODlhEgASAMQTANft99 / V + Ga44bHb8ITG52S44dXs9 + Z1 + UPX + YvK6WC24G + 944 / M6W28443L6dnu + Ge54v / + / l614P /// wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5 / VFID / DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7style =display:inline; width:12px; height:12px; />
将IMG ALT = - SRC = 数据:图像/ GIF; BASE64,R0lGODlhEgASAMQSANft94TG57Hb8GS44ez1 + mC24IvK6ePx + Wa44dXs92 + 942e54o3L6W2844 / M6dnu + P / + / l614P /// wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABIALAAAAAASABIAQAVCoCQBTBOd6Kk4gJhGBCTPxysJb44K0qD / ER / wlxjmisZkMqBEBW5NHrMZmVKvv9hMVsO + hE0EoNAstEYGxG9heIhCADs = style =display:none; width:12px; height:12px; />
< span style =vertical-align:top>解释查询< / span>
< / a>]
{%else%}
无法解释此查询
{%endif%}

{%如果查询。 explainable%}
< div id =explain - {{i}} - {{loop.parent.loop.index}}class =loading>< / div>
{%endif%}

{#=========================== ========== MODIFIED =============================#}
{%如果query.trace被定义为%}
< div>
[< a href =#/style =text-decoration:none; title =显示跟踪class =trace>
将IMG ALT = + SRC =数据:图像/ GIF; BASE64,R0lGODlhEgASAMQTANft99 / V + Ga44bHb8ITG52S44dXs9 + Z1 + UPX + YvK6WC24G + 944 / M6W28443L6dnu + Ge54v / + / l614P /// wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5 / VFID / DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7style =display:inline; width:12px; height:12px; />
< span style =vertical-align:top>显示跟踪< / span>
< / a>]
< div class =hidden> {{dump(query.trace)}}< / div>
< / div>
{%endif%}
< / td>
< / tr>
{%endfor%}
< / tbody>
< / table>
{%endif%}
{%endfor%}

< h2>数据库连接< / h2>

{%如果collector.connections%}
{%包含WebProfilerBundle:Profiler:table.html.twig与{data:collector.connections}仅%}
{ %else%}
< p>
< em>无连接。< / em>
< / p>
{%endif%}

< h2>实体经理< / h2>

{%如果collector.managers%}
{%包含WebProfilerBundle:Profiler:table.html.twig与{data:collector.managers}仅%}
{ %else%}
< p>
< em>没有实体管理员。< / em>
< / p>
{%endif%}

< h2>二级缓存< / h2>

{%if collector.cacheCounts%}
{%include'WebProfilerBundle:Profiler:table.html.twig'with {data:collector.cacheCounts} only%}

{%if collector.cacheRegions.hits%}
< h3>缓存命中数< / h3>
{%include'WebProfilerBundle:Profiler:table.html.twig'with {data:collector.cacheRegions.hits} only%}
{%endif%}

{%如果collector.cacheRegions.misses%}
< h3>高速缓存未命中数< / h3>
{%include'WebProfilerBundle:Profiler:table.html.twig'with {data:collector.cacheRegions.misses} only%}
{%endif%}

{%如果collector.cacheRegions.puts%}
< h3>缓存放置数量< / h3>
{%include'WebProfilerBundle:Profiler:table.html.twig'with {data:collector.cacheRegions.puts} only%}
{%endif%}
{%else%}
< p>
< em>无缓存。< / em>
< / p>
{%endif%}

< h2>映射< / h2>

{%为管理员,collect.entities%中的类}
< h3>管理员< em> {{manager}}< / em>< / h3>
{%如果类为空%}
< p>< em>没有加载的实体< / em>< / p>
{%else%}
< table>
< thead>
< tr>
< th scope =col> Class< / th>
< th scope =col>映射错误< / th>
< / tr>
< / thead>
< tbody>
{%类中的类%}
< tr>
< td> {{class}}< / td>
< td>
{%如果collector.mappingErrors [manager] [class]定义为%}
< ul>
{%for collector.mappingErrors [manager] [class]%}
< li> {{error}}< / li>
{%endfor%}
< / ul>
{%else%}
有效
{%endif%}
< / td>
< / tr>
{%endfor%}
< / tbody>
< / table>
{%endif%}
{%endfor%}

< script type =text / javascript> //<![CDATA [
功能说明(link){
use strict;

var imgs = link.children,
target = link.getAttribute('data-target-id');

Sfjs.toggle(target,imgs [0],imgs [1])$ ​​b $ b .load(
target,
link.href,
null ,
函数(xhr,el){
el.innerHTML ='加载详细信息时出错;
Sfjs.removeClass(el,'loading');
}
);

返回false;
}

函数expandAllQueries(button){
var queries = document.getElementsByClassName('query-section'),
i = queries.length,
action = button.getAttribute('data-action');

if(action =='expand'){
button.getElementsByClassName('btn-bg')[0] .innerHTML ='折叠所有查询';

while(i--){
if(queries [i] .getAttribute('data-state')=='collapsed'){
expandQuery(queries [ ]);
}
}
} else {
button.getElementsByClassName('btn-bg')[0] .innerHTML ='展开所有查询';

while(i--){
if(queries [i] .getAttribute('data-state')=='expanded'){
expandQuery(queries [ ]);
}
}
}

button.setAttribute('data-action',action =='expand'?'collapse':'expand');
}

函数expandQuery(link){
var sections = link.children,
target = link.getAttribute('data-target-id'),
targetId = target.replace('code',''),
queriesParameters = document.getElementById('original-query'+ targetId);

if(queriesParameters.style.display!='none'){
queriesParameters.style.display ='none';
document.getElementById('small'+ target).style.display ='inline';
document.getElementById('expandParams'+ targetId).innerHTML ='显示可运行的查询';
}

if(document.getElementById('small'+ target).style.display!='none'){
document.getElementById('small'+ target) .style.display ='none';
document.getElementById(target).style.display ='inline';

sections [0] .style.display ='none';
sections [1] .style.display ='inline';
sections [2] .style.display ='inline';

link.setAttribute('data-state','expanded');
} else {
document.getElementById('small'+ target).style.display ='inline';
document.getElementById(target).style.display ='none';

sections [0] .style.display ='inline';
sections [1] .style.display ='none';
sections [2] .style.display ='none';

link.setAttribute('data-state','collapsed');
}

return false;
}

函数toggleRunnableQuery(target){
var targetId = target.getAttribute('target-data-id')。replace('original-query','') ,
targetElement = document.getElementById(target.getAttribute('target-data-id')),
elem;

if(targetElement.style.display!='block'){
targetElement.style.display ='block';
target.innerHTML ='隐藏可运行查询';

document.getElementById('smallcode'+ targetId).style.display ='none';
document.getElementById('code'+ targetId).style.display ='none';

elem = document.getElementById('code'+ targetId).parentElement.children [0];

elem.children [0] .style.display ='inline';
elem.children [1] .style.display ='none';
elem.children [2] .style.display ='none';

} else {
targetElement.style.display ='none';
target.innerHTML ='显示可运行的查询';

document.getElementById('smallcode'+ targetId).style.display ='inline';
}
}

函数sortTable(header,column,targetId){
use strict;

var direction = parseInt(header.getAttribute('data-sort-direction'))|| 1,
items = [],
target = document.getElementById(targetId),
rows = target.children,
headers = header.parentElement.children,
i ; (i = 0; i< rows.length; ++ i){
items.push(rows [i]);


}

for(i = 0; i< headers.length; ++ i){
headers [i] .removeAttribute('data-sort-direction') ;
if(headers [i] .children.length> 0){
headers [i] .children [0] .innerHTML ='';
}
}

header.setAttribute('data-sort-direction',(-1 * direction).toString());
header.children [0] .innerHTML = direction> 0? '&#9650;':'&#9660;';

items.sort(function(a,b){
return direction *(parseFloat(a.children [column] .innerHTML) - parseFloat(b.children [column] .innerHTML) );
}); (i = 0; i< items.length; ++ i){
Sfjs.removeClass(items [i],i%2?'even':'odd' );
Sfjs.addClass(items [i],i%2?'odd':'even');
target.appendChild(items [i]);
}
}

//]]>< / script>

< style>
h3 {
margin-bottom:0px;
}

代码{
显示:无;
}

代码前{
padding:5px;
}
< / style>
{%endblock%}

接下来编辑供应商/原则/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php 文件



并更改startQuery方法如下:

  / ** 
* {@inheritdoc}
* /
public function startQuery($ sql,array $ params = null,array $ types = null)
{
if($ this-> enabled){
$ this-> start = microtime(true);
$ this-> queries [++ $ this-> currentQuery] = array('sql'=> $ sql,'params'=> $ params,'types'=> $ types, 'executionMS'=> 0,'trace'=> debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
}
}

我还没有找到如何做更多有效的变化,所以这里的每个命题都会非常好!
谢谢!

解决方案

所有DoctrineBundle类都配置为: https://github.com/doctrine/DoctrineBundle/blob/master/Resources/config/dbal.xml



你可以用你自己的实现来覆盖doctrine.dbal.logger.profiling.class:

 #app / config / config.yml 
参数:
doctrine.dbal.logger.profiling.class:Acme\HelloBundle\Logging\MyDebugStack

在你的课上:

 命名空间Acme\HelloBundle\Logging; 

使用Doctrine\DBAL\Logging\DebugStack;

class MyDebugStack扩展DebugStack
{
// ...
}

另外,请阅读有关捆绑覆盖的部分: http://symfony.com/doc/current/cookbook/bundles/override.html


In order to better manage how I was making my database calls using Doctrine, I investigated how I could add the php debug_backtrace to the symfony doctrine db collector.

I managed to identify the modifications I had to make but I did not yet found a good way to override the DebugStack class (apart from overriding the vendor class).

the class is located here :

vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php

For those who are interested, here is the result :

To do this, you need to :

Override the vendor/doctrine/doctrine-bundle/Resources/views/Collector/db.html.twig file

Copy this file to app\resources\DoctrineBundle\views\Collector\db.html.twig

You'll see my modifications below the two ====MODIFIED=== comments :

{% extends app.request.isXmlHttpRequest ? 'WebProfilerBundle:Profiler:ajax_layout.html.twig' : 'WebProfilerBundle:Profiler:layout.html.twig' %}

{% block toolbar %}
    {% set icon %}
        <img width="20" height="28" alt="Database" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAcCAYAAABh2p9gAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQRJREFUeNpi/P//PwM1ARMDlcGogZQDlpMnT7pxc3NbA9nhQKxOpL5rQLwJiPeBsI6Ozl+YBOOOHTv+AOllQNwtLS39F2owKYZ/gRq8G4i3ggxEToggWzvc3d2Pk+1lNL4fFAs6ODi8JzdS7mMRVyDVoAMHDsANdAPiOCC+jCQvQKqBQB/BDbwBxK5AHA3E/kB8nKJkA8TMQBwLxaBIKQbi70AvTADSBiSadwFXpCikpKQU8PDwkGTaly9fHFigkaKIJid4584dkiMFFI6jkTJII0WVmpHCAixZQEXWYhDeuXMnyLsVlEQKI45qFBQZ8eRECi4DBaAlDqle/8A48ip6gAADANdQY88Uc0oGAAAAAElFTkSuQmCC" />
        <span class="sf-toolbar-status{% if 50 < collector.querycount %} sf-toolbar-status-yellow{% endif %}">{{ collector.querycount }}</span>
        {% if collector.querycount > 0 %}
            <span class="sf-toolbar-info-piece-additional-detail">in {{ '%0.2f'|format(collector.time * 1000) }} ms</span>
        {% endif %}
        {% if collector.invalidEntityCount > 0 %}
            <span class="sf-toolbar-info-piece-additional sf-toolbar-status sf-toolbar-status-red">{{ collector.invalidEntityCount }}</span>
        {% endif %}
        {% if collector.cacheEnabled %}
            <span class="sf-toolbar-info-piece-additional sf-toolbar-status sf-toolbar-status-green" title="Second level cache enabled">2l cache</span>
        {% endif %}
    {% endset %}
    {% set text %}
        <div class="sf-toolbar-info-piece">
            <b>DB Queries</b>
            <span>{{ collector.querycount }}</span>
        </div>
        <div class="sf-toolbar-info-piece">
            <b>Query time</b>
            <span>{{ '%0.2f'|format(collector.time * 1000) }} ms</span>
        </div>
        <div class="sf-toolbar-info-piece">
            <b>Invalid entities</b>
            <span class="sf-toolbar-status sf-toolbar-status-{{ collector.invalidEntityCount > 0 ? 'red' : 'green' }}">{{ collector.invalidEntityCount }}</span>
        </div>
        {% if collector.cacheEnabled %}
            <div class="sf-toolbar-info-piece">
                <b>Cache hits</b>
                <span class="sf-toolbar-status sf-toolbar-status-green">{{ collector.cacheHitsCount }}</span>
            </div>
            <div class="sf-toolbar-info-piece">
                <b>Cache misses</b>
                <span class="sf-toolbar-status sf-toolbar-status-{{ collector.cacheMissesCount > 0 ? 'yellow' : 'green' }}">{{ collector.cacheMissesCount }}</span>
            </div>
            <div class="sf-toolbar-info-piece">
                <b>Cache puts</b>
                <span class="sf-toolbar-status sf-toolbar-status-{{ collector.cachePutsCount > 0 ? 'yellow' : 'green' }}">{{ collector.cachePutsCount }}</span>
            </div>
        {% endif %}
    {% endset %}
    {% include 'WebProfilerBundle:Profiler:toolbar_item.html.twig' with { 'link': profiler_url } %}
{% endblock %}

{% block menu %}
<span class="label">
    <span class="icon"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAYAAAB/E6/TAAABLUlEQVR42u3TP0vDQBiA8UK/gDiLzi0IhU4OEunk5OQUAhGSOBUCzqWfIKSzX8DRySF0URCcMjWLIJjFD9Cpk/D6HITecEPUuzhIAz8CIdyTP/f2iqI4qaqqDx8l5Ic2uIeP/bquezCokOAFF+oCN3t4gPzSEjc4NEPaCldQbzjELTYW0RJzHDchwwem+ons6ZBpLSJ7nueJC22h0V+FzmwWV0ee59vQNV67CGVZJmEYbkNjfpY6X6I0Qo4/3RMmTdDDspuQVsJvgkP3IdMbIkIjLPBoadG2646iKJI0Ta2wxm6OdnP0/Tk6DYJgHcfxpw21RtscDTDDnaVZ26474GkkSRIrrPEv5sgMTfHe+cA2O6wPH6vOBpYQNALneHb96XTEDI6dzpEZ0VzO0Rf3pP5LMLI4tAAAAABJRU5ErkJggg==" alt="" /></span>
    <strong>Doctrine</strong>
    <span class="count">
        <span>{{ collector.querycount }}</span>
        <span>{{ '%0.0f'|format(collector.time * 1000) }} ms</span>
    </span>
</span>
{% endblock %}

{% block panel %}
    {% if 'explain' == page %}
        {{ render(controller('DoctrineBundle:Profiler:explain', {
            'token': token,
            'panel': 'db',
            'connectionName': app.request.query.get('connection'),
            'query': app.request.query.get('query')
        })) }}
    {% else %}
        {{ block('queries') }}
    {% endif %}
{% endblock %}

{% block queries %}
    <h2>Queries</h2>

    {# =========================================       MODIFIED        ===============================#}
    <script src="{{ asset('vendor/jquery/jquery-2.1.1.min.js') }}"></script>
    <style rel="stylesheet">
        .hidden {display: none;}
    </style>
    <script>
        $(function(){
            $('.trace').on('click', function(e){
                e.preventDefault();
                $(this).next().toggleClass('hidden');
            });
        });
    </script>

    {% for connection, queries in collector.queries %}
        <h3>Connection <em>{{ connection }}</em></h3>
        {% if queries is empty %}
            <p>
                <em>No queries.</em>
            </p>
        {% else %}
            <p>
                <button type="button" class="sf-button" onclick="expandAllQueries(this);" data-action="expand">
                    <span class="border-l">
                        <span class="border-r">
                            <span class="btn-bg">Expand all queries</span>
                        </span>
                    </span>
                </button>
            </p>
            <table class="alt" id="queriesPlaceholder-{{ loop.index }}">
                <thead>
                    <tr>
                        <th onclick="javascript:sortTable(this, 0, 'queries-{{ loop.index }}')" data-sort-direction="-1" style="cursor: pointer;">#<span>&#9650;</span></th>
                        <th onclick="javascript:sortTable(this, 1, 'queries-{{ loop.index }}')" style="cursor: pointer;">Time<span></span></th>
                        <th style="width: 100%;">Info</th>
                    </tr>
                </thead>
                <tbody id="queries-{{ loop.index }}">
                {% for i, query in queries %}
                    <tr id="queryNo-{{ i }}-{{ loop.parent.loop.index }}" class="{{ cycle(['odd', 'even'], i) }}">
                        <td>{{ loop.index }}</td>
                        <td>{{ '%0.2f'|format(query.executionMS * 1000) }}&nbsp;ms</td>
                        <td>
                            <div class="query-section" data-state="collapsed" onclick="return expandQuery(this);" title="Expand query" data-target-id="code-{{ i }}-{{ loop.parent.loop.index }}" style="cursor: pointer;">
                                <img alt="+" src="data:image/gif;base64,R0lGODlhEgASAMQTANft99/v+Ga44bHb8ITG52S44dXs9+z1+uPx+YvK6WC24G+944/M6W28443L6dnu+Ge54v/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5/vFID/DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7" style="display: inline;" />
                                <img alt="-" src="data:image/gif;base64,R0lGODlhEgASAMQSANft94TG57Hb8GS44ez1+mC24IvK6ePx+Wa44dXs92+942e54o3L6W2844/M6dnu+P/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABIALAAAAAASABIAQAVCoCQBTBOd6Kk4gJhGBCTPxysJb44K0qD/ER/wlxjmisZkMqBEBW5NHrMZmVKvv9hMVsO+hE0EoNAstEYGxG9heIhCADs=" style="display: none;" />
                                <span style="display: none">Shrink query</span>
                                <span id="smallcode-{{ i }}-{{ loop.parent.loop.index }}">
                                    {{ query.sql|doctrine_minify_query|raw }}
                                </span>
                            </div>
                            <code id="code-{{ i }}-{{ loop.parent.loop.index }}">
                                {{ query.sql|doctrine_pretty_query(i, loop.parent.loop.index)|raw }}
                            </code>
                            <span id="original-query-{{ i }}-{{ loop.parent.loop.index }}" style="display: none;">
                                {{ query.sql|doctrine_replace_query_parameters(query.params)|raw }}
                            </span>
                            <small>
                                <strong>Parameters</strong>: {{ query.params|yaml_encode }} <br />
                                [<span id="expandParams-{{ i }}-{{ loop.parent.loop.index }}" onclick="javascript:toggleRunnableQuery(this);" target-data-id="original-query-{{ i }}-{{ loop.parent.loop.index }}" style="cursor: pointer;">Display runnable query</span>]<br/>
                            </small>

                            {% if query.explainable %}
                                [<a href="{{ path('_profiler', {'panel': 'db', 'token': token, 'page': 'explain', 'connection': connection, 'query': i}) }}" onclick="return explain(this);" style="text-decoration: none;" title="Explains the query" data-target-id="explain-{{ i }}-{{ loop.parent.loop.index }}" >
                                    <img alt="+" src="data:image/gif;base64,R0lGODlhEgASAMQTANft99/v+Ga44bHb8ITG52S44dXs9+z1+uPx+YvK6WC24G+944/M6W28443L6dnu+Ge54v/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5/vFID/DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7" style="display: inline; width: 12px; height: 12px;" />
                                    <img alt="-" src="data:image/gif;base64,R0lGODlhEgASAMQSANft94TG57Hb8GS44ez1+mC24IvK6ePx+Wa44dXs92+942e54o3L6W2844/M6dnu+P/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABIALAAAAAASABIAQAVCoCQBTBOd6Kk4gJhGBCTPxysJb44K0qD/ER/wlxjmisZkMqBEBW5NHrMZmVKvv9hMVsO+hE0EoNAstEYGxG9heIhCADs=" style="display: none; width: 12px; height: 12px;" />
                                    <span style="vertical-align:top">Explain query</span>
                                </a>]
                            {% else %}
                                This query cannot be explained
                            {% endif %}

                            {% if query.explainable %}
                                <div id="explain-{{ i }}-{{ loop.parent.loop.index }}" class="loading"></div>
                            {% endif %}

                            {# =========================================       MODIFIED        ===============================#}
                            {% if query.trace is defined %}
                                <div>
                                    [<a href="#/" style="text-decoration: none;" title="Show the trace" class="trace">
                                        <img alt="+" src="data:image/gif;base64,R0lGODlhEgASAMQTANft99/v+Ga44bHb8ITG52S44dXs9+z1+uPx+YvK6WC24G+944/M6W28443L6dnu+Ge54v/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5/vFID/DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7" style="display: inline; width: 12px; height: 12px;" />
                                        <span style="vertical-align:top">Show the trace</span>
                                    </a>]
                                    <div class="hidden">{{ dump(query.trace) }}</div>
                                </div>
                            {% endif %}
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        {% endif %}
    {% endfor %}

    <h2>Database Connections</h2>

    {% if collector.connections %}
        {% include 'WebProfilerBundle:Profiler:table.html.twig' with {data: collector.connections} only %}
    {% else %}
        <p>
            <em>No connections.</em>
        </p>
    {% endif %}

    <h2>Entity Managers</h2>

    {% if collector.managers %}
        {% include 'WebProfilerBundle:Profiler:table.html.twig' with {data: collector.managers} only %}
    {% else %}
        <p>
            <em>No entity managers.</em>
        </p>
    {% endif %}

    <h2>Second Level Cache</h2>

    {% if collector.cacheCounts %}
        {% include 'WebProfilerBundle:Profiler:table.html.twig' with {data: collector.cacheCounts} only %}

        {% if collector.cacheRegions.hits %}
            <h3>Number of cache hits</h3>
            {% include 'WebProfilerBundle:Profiler:table.html.twig' with {data: collector.cacheRegions.hits} only %}
        {% endif %}

        {% if collector.cacheRegions.misses %}
            <h3>Number of cache misses</h3>
            {% include 'WebProfilerBundle:Profiler:table.html.twig' with {data: collector.cacheRegions.misses} only %}
        {% endif %}

        {% if collector.cacheRegions.puts %}
            <h3>Number of cache puts</h3>
            {% include 'WebProfilerBundle:Profiler:table.html.twig' with {data: collector.cacheRegions.puts} only %}
        {% endif %}
    {% else %}
        <p>
            <em>No cache.</em>
        </p>
    {% endif %}

    <h2>Mapping</h2>

    {% for manager, classes in collector.entities %}
        <h3>Manager <em>{{ manager }}</em></h3>
        {% if classes is empty %}
            <p><em>No loaded entities.</em></p>
        {% else %}
            <table>
                <thead>
                <tr>
                    <th scope="col">Class</th>
                    <th scope="col">Mapping errors</th>
                </tr>
                </thead>
                <tbody>
                {% for class in classes %}
                    <tr>
                        <td>{{ class }}</td>
                        <td>
                            {% if collector.mappingErrors[manager][class] is defined %}
                                <ul>
                                    {% for error in collector.mappingErrors[manager][class] %}
                                        <li>{{ error }}</li>
                                    {% endfor %}
                                </ul>
                            {% else %}
                                Valid
                            {% endif %}
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        {% endif %}
    {% endfor %}

    <script type="text/javascript">//<![CDATA[
        function explain(link) {
            "use strict";

            var imgs = link.children,
                target = link.getAttribute('data-target-id');

            Sfjs.toggle(target, imgs[0], imgs[1])
                .load(
                    target,
                    link.href,
                    null,
                    function(xhr, el) {
                        el.innerHTML = 'An error occurred while loading the details';
                        Sfjs.removeClass(el, 'loading');
                    }
                );

            return false;
        }

        function expandAllQueries(button) {
            var queries = document.getElementsByClassName('query-section'),
                i = queries.length,
                action = button.getAttribute('data-action');

            if (action == 'expand') {
                button.getElementsByClassName('btn-bg')[0].innerHTML = 'Collapse all queries';

                while (i--) {
                    if (queries[i].getAttribute('data-state') == 'collapsed') {
                        expandQuery(queries[i]);
                    }
                }
            } else {
                button.getElementsByClassName('btn-bg')[0].innerHTML = 'Expand all queries';

                while (i--) {
                    if (queries[i].getAttribute('data-state') == 'expanded') {
                        expandQuery(queries[i]);
                    }
                }
            }

            button.setAttribute('data-action', action == 'expand' ? 'collapse' : 'expand');
        }

        function expandQuery(link) {
            var sections = link.children,
                target = link.getAttribute('data-target-id'),
                targetId = target.replace('code', ''),
                queriesParameters = document.getElementById('original-query' + targetId);

            if (queriesParameters.style.display != 'none') {
                queriesParameters.style.display = 'none';
                document.getElementById('small' + target).style.display = 'inline';
                document.getElementById('expandParams' + targetId).innerHTML = 'Display runnable query';
            }

            if (document.getElementById('small' + target).style.display != 'none') {
                document.getElementById('small' + target).style.display = 'none';
                document.getElementById(target).style.display = 'inline';

                sections[0].style.display = 'none';
                sections[1].style.display = 'inline';
                sections[2].style.display = 'inline';

                link.setAttribute('data-state', 'expanded');
            } else {
                document.getElementById('small' + target).style.display = 'inline';
                document.getElementById(target).style.display = 'none';

                sections[0].style.display = 'inline';
                sections[1].style.display = 'none';
                sections[2].style.display = 'none';

                link.setAttribute('data-state', 'collapsed');
            }

            return false;
        }

        function toggleRunnableQuery(target) {
            var targetId = target.getAttribute('target-data-id').replace('original-query', ''),
                targetElement = document.getElementById(target.getAttribute('target-data-id')),
                elem;

            if (targetElement.style.display != 'block') {
                targetElement.style.display = 'block';
                target.innerHTML = 'Hide runnable query';

                document.getElementById('smallcode' + targetId).style.display = 'none';
                document.getElementById('code' + targetId).style.display = 'none';

                elem = document.getElementById('code' + targetId).parentElement.children[0];

                elem.children[0].style.display = 'inline';
                elem.children[1].style.display = 'none';
                elem.children[2].style.display = 'none';

            } else {
                targetElement.style.display = 'none';
                target.innerHTML = 'Display runnable query';

                document.getElementById('smallcode' + targetId).style.display = 'inline';
            }
        }

        function sortTable(header, column, targetId) {
            "use strict";

            var direction = parseInt(header.getAttribute('data-sort-direction')) || 1,
                items = [],
                target = document.getElementById(targetId),
                rows = target.children,
                headers = header.parentElement.children,
                i;

            for (i = 0; i < rows.length; ++i) {
                items.push(rows[i]);
            }

            for (i = 0; i < headers.length; ++i) {
                headers[i].removeAttribute('data-sort-direction');
                if (headers[i].children.length > 0) {
                    headers[i].children[0].innerHTML = '';
                }
            }

            header.setAttribute('data-sort-direction', (-1*direction).toString());
            header.children[0].innerHTML = direction > 0 ? '&#9650;' : '&#9660;';

            items.sort(function(a, b) {
                return direction*(parseFloat(a.children[column].innerHTML) - parseFloat(b.children[column].innerHTML));
            });

            for (i = 0; i < items.length; ++i) {
                Sfjs.removeClass(items[i], i % 2 ? 'even' : 'odd');
                Sfjs.addClass(items[i], i % 2 ? 'odd' : 'even');
                target.appendChild(items[i]);
            }
        }

    //]]></script>

    <style>
        h3 {
            margin-bottom: 0px;
        }

        code {
            display: none;
        }

        code pre {
            padding: 5px;
        }
    </style>
{% endblock %}

Next edit the vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php file

and change the startQuery method as follows :

/**
 * {@inheritdoc}
 */
public function startQuery($sql, array $params = null, array $types = null)
{
    if ($this->enabled) {
        $this->start = microtime(true);
        $this->queries[++$this->currentQuery] = array('sql' => $sql, 'params' => $params, 'types' => $types, 'executionMS' => 0, 'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
    }
}

I've not yet found how to make a more efficient change, so every proposition here would be very nice ! Thanks !

解决方案

All DoctrineBundle classes are configured here: https://github.com/doctrine/DoctrineBundle/blob/master/Resources/config/dbal.xml

You could probably override "doctrine.dbal.logger.profiling.class" with your own implementation like this:

# app/config/config.yml
parameters:
    doctrine.dbal.logger.profiling.class: Acme\HelloBundle\Logging\MyDebugStack

And in your class:

namespace Acme\HelloBundle\Logging;

use Doctrine\DBAL\Logging\DebugStack;

class MyDebugStack extends DebugStack 
{
    //...
}

Also, read this section about bundle overriding: http://symfony.com/doc/current/cookbook/bundles/override.html

这篇关于Symfony2 / Doctrine2:如何覆盖在doctrine DataCollector中使用的DebugStack类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆