Nedokonalé zjišťování zdroje SQL dotazu
- kminekmatej
- Generous Backer | 38
Hola hej,
mám v Nette projekt, kde na vstupu používám Presenter, logiku následně
obstarávám v zanořených managerech. Manager pracuje s DB vrstvou a
pokládá dotazy. Výsledek vrátí zpět Presenteru a ten jej zobrazí jako
JSON (ano, api).
Když mi pak ale v následném běhu presenteru vypadne jiný Exception, tak mi správně vyleze laděnka s panelem SQL dotazů. Nicméně u každého SQL dotazu je jako zdroj uvedený soubor index.php, line 13 – což je run(). Laděnka totiž zjišťuje soubor, který vyvolal SQL příkaz takto:
nette\database\src\Bridges\DatabaseTracy\ConnectionPanel.php:68
$trace = $result instanceof \PDOException
? $result->getTrace()
: debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
foreach ($trace as $row) {
if (
(isset($row['file']) && is_file($row['file']) && !Tracy\Debugger::getBluescreen()->isCollapsed($row['file']))
&& ($row['class'] ?? '') !== self::class
&& !is_a($row['class'] ?? '', Connection::class, true)
) {
$source = [$row['file'], (int) $row['line']];
break;
}
}
Problematické je podle mě právě podmínka rozbalení:
!Tracy\Debugger::getBluescreen()->isCollapsed($row['file'])
.
Soubory, které proběhly v manageru předtím totiž nejsou v Tracy
rozbalené a tak jsou přeskočeny. Ve výsledku teď můj výpis příkazů
vypadá například takto:
SELECT `cs`
FROM `v_translation`
WHERE (`name` = 'A200') AND (`module` = 'core')
.../boost.kminet.eu/api/www/index.php:12
Funkce která zjišťuje zdrojový soubor je tedy nedokonalá. Napadají mne dvě možný řešení, jedno blbější než druhé:
- Najít každou „vnitřní“ Nette funkci, která se volá bezprostředně
po vyvolání dotazu. Tedy
fetch()
,fetchAll()
,update()
,insert()
,get()
apod. – a v každé z nich (pokud je zapnutý Debugger) si vyhodit backtrace a vzít jako source předchozí soubor. Ale u toho mi vadí mísení logiky balíčkůNette/Database
aNette/Tracy
. - Upravit detektor zdrojového souboru tak, aby byl nějak šikovnější. Úprava co mne napadla (a u mne funguje) je, že zdrojový soubor je první soubor v backtrace dump, který není součástí Nette namespace (to by samozřejmě nefungovalo pro dotazy ze samotného Nette. Vyvíjená aplikace by samozřejmě nesměla být v namespacu Nette. Má úprava:
if (
(isset($row['file']) && is_file($row['file']))
&& ($row['class'] ?? '') !== self::class
&& strpos($row['class'] ?? '', "Nette\\") === false
) {
$source = [$row['file'], (int) $row['line']];
break;
}
Jsem si téměř jist že řešení, které pomůže mne, naopak rozbije nějaké jiné usecasy, které teď prostě nevidím. Možná by to šlo nějak zkombinovat? Typu použij první řešení, pokud dojedeš až na index.php, použij druhé řešení. Díky za jakékoliv náměty v diskusi.
- kminekmatej
- Generous Backer | 38
Samotné volání je v souboru TranslationManager:93
:
return $db->fetchField($lang) ?: $key;
Jak tak studuji ten stacktrace, tak i ta má úprava není úplně dokonalá, neboť by vrátila Responder.php:112 (tedy o jeden trace dříve) – můžu ji o ten jeden upravit, ale je to spíš k diskusi.
Stacktrace:
[
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/utils\/src\/Utils\/Arrays.php",
"line":361,
"function":"logQuery",
"class":"Nette\\Bridges\\DatabaseTracy\\ConnectionPanel",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/database\/src\/Database\/Connection.php",
"line":193,
"function":"invoke",
"class":"Nette\\Utils\\Arrays",
"type":"::"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/database\/src\/Database\/Explorer.php",
"line":93,
"function":"query",
"class":"Nette\\Database\\Connection",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/database\/src\/Database\/Table\/Selection.php",
"line":597,
"function":"queryArgs",
"class":"Nette\\Database\\Explorer",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/database\/src\/Database\/Table\/Selection.php",
"line":547,
"function":"query",
"class":"Nette\\Database\\Table\\Selection",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/database\/src\/Database\/Table\/Selection.php",
"line":210,
"function":"execute",
"class":"Nette\\Database\\Table\\Selection",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/database\/src\/Database\/Table\/Selection.php",
"line":228,
"function":"fetch",
"class":"Nette\\Database\\Table\\Selection",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/boost.space\/translation\/manager\/TranslationManager.php",
"line":93,
"function":"fetchField",
"class":"Nette\\Database\\Table\\Selection",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/boost.space\/core\/manager\/Responder.php",
"line":112,
"function":"getByKey",
"class":"BoostSpace\\Module\\Translation\\Manager\\TranslationManager",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/boost.space\/core\/manager\/Responder.php",
"line":67,
"function":"composeMessage",
"class":"BoostSpace\\Core\\Manager\\Responder",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/boost.space\/core\/manager\/Responder.php",
"line":173,
"function":"respond",
"class":"BoostSpace\\Core\\Manager\\Responder",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/boost.space\/core\/presenters\/BaseRestPresenter.php",
"line":161,
"function":"A200_OK",
"class":"BoostSpace\\Core\\Manager\\Responder",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/boost.space\/user\/presenter\/DefaultPresenter.php",
"line":64,
"function":"respondOk",
"class":"BoostSpace\\Core\\Presenter\\BaseRestPresenter",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/boost.space\/user\/presenter\/DefaultPresenter.php",
"line":46,
"function":"requestGet",
"class":"BoostSpace\\Module\\User\\Presenter\\DefaultPresenter",
"type":"->"
},
{
"function":"actionDefault",
"class":"BoostSpace\\Module\\User\\Presenter\\DefaultPresenter",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/application\/src\/Application\/UI\/Component.php",
"line":102,
"function":"invokeArgs",
"class":"ReflectionMethod",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/application\/src\/Application\/UI\/Presenter.php",
"line":213,
"function":"tryCall",
"class":"Nette\\Application\\UI\\Component",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/application\/src\/Application\/Application.php",
"line":160,
"function":"run",
"class":"Nette\\Application\\UI\\Presenter",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/vendor\/nette\/application\/src\/Application\/Application.php",
"line":89,
"function":"processRequest",
"class":"Nette\\Application\\Application",
"type":"->"
},
{
"file":"\/var\/www\/vhosts\/kminet.eu\/subdomains\/boost.kminet.eu\/api\/www\/index.php",
"line":12,
"function":"run",
"class":"Nette\\Application\\Application",
"type":"->"
}
]
- David Grudl
- Nette Core | 8228
Asi by se mohlo do collapsePaths místo celého vendor zahrnout jen vendor/nette a vendor/tracy. Zkus master.
- kminekmatej
- Generous Backer | 38
David Grudl napsal(a):
Asi by se mohlo do collapsePaths místo celého vendor zahrnout jen vendor/nette a vendor/tracy. Zkus master.
Funguje to skvěle, dík! Takže celý problém byl vlastně způsoben tím že pracuji ve složce vendor