barryvdh / laravel-debugbar

Debugbar for Laravel (Integrates PHP Debug Bar)
MIT License
16.57k stars 1.53k forks source link

Ability to add a custom stacktrace parsing method #1585

Open OzanKurt opened 3 months ago

OzanKurt commented 3 months ago

Hello there,

I use https://github.com/yajra/laravel-datatables package in almost all of my projects.

I currently have a problem of seeing the source of the queries inside my DataTable classes.

For example:

I have a query builder setup inside my UsersDataTable.

    public function query()
    {
        return User::query();
    }

Since this function only starts to bulid the query it doesn't show up in debug_backtrace().

For this I've added a solution which allows me to check the "query sender" object and modify how the $frame was filled.

I've added simple static method to add my custom callables to QueryCollector, in there I can modify and return the $frame as I wish in case the $trace['object'] is matching my first parameter $objectType.

Here is an example DataTable::class query tracer.

QueryCollector::addCustomFrameParser(DataTable::class, function (object $frame, array $trace) {
    // Remove the 'App\' prefix from the namespace
    $relativeNamespace = str_replace('App\\', '', $trace['object']::class);

    // Convert namespace to a directory path
    $directoryPath = str_replace('\\', DIRECTORY_SEPARATOR, $relativeNamespace);
    $filePath = app_path($directoryPath) . '.php';

    // Get the file path inside the project from the class object
    $frame->file = $filePath;

    return $frame;
});

After I add this to my AppServiceProvider, I can simply see the change inside my "Query" tab.

Before: image

After: image

This way I can simply tell where I built the query and continue debugging/development.

parallels999 commented 3 months ago

Did you try adding PATH_TO_FILE/DataTablesController.php to options.db.backtrace_exclude_paths? I have a bridge query builder, and I had a similar problem, I added the file_path to the backtrace_exclude_paths and I already got the correct file

https://github.com/barryvdh/laravel-debugbar/blob/03448e59739181179697dd996f581404db4ce7c5/config/debugbar.php#L213

OzanKurt commented 3 months ago

Yes I tried, but since the query is NOT actually sent from the UsersDataTable PHP's debug_backtrace() only detects the call from: DataTablesController.php

Also here is how mine looks like usually:

'backtrace_exclude_paths' => [
    '/vendor/yajra/laravel-datatables',
    '/vendor/staudenmeir',
],
PaolaRuby commented 3 months ago

Post Before\After with backtrace image Maybe there could be a simpler way

OzanKurt commented 3 months ago

Before: image

After: image

PaolaRuby commented 3 months ago

extends UsersDataTable some yajra class?? or uses some yajra trait?

OzanKurt commented 3 months ago

It extends the DataTable class from the package.

PaolaRuby commented 3 months ago

I think it could be made more native, maybe some "demo minimal app" to find another approach?

OzanKurt commented 3 months ago

I can make a demo next week, the change is actually very minimal anyway.

OzanKurt commented 3 months ago

I actually already pushed a demo to GitHub.

https://github.com/OzanKurt/debugbar-demo

You can simply pull and run with php artisan serve.

After you install the app you can simply open these two pages:

http://127.0.0.1:8000/?custom_parsing=true http://127.0.0.1:8000/?custom_parsing=false

replace the contents of QueryCollector and check it out.

erikn69 commented 3 months ago

This removes a step from the trace, I'm going to try another approach Try #1588

OzanKurt commented 3 months ago

So you suggest adding an extra source to the trace instead of modifying its file...

I'm fine with that approach as well.

One thing to add maybe would be the custom source parsing:

So instead of

if (($trace['class'] ?? null) == 'Yajra\DataTables\Services\DataTable') {

looping through an array of customs would be nicer

foreach (static::$customSourceParsers as $objectType => $customSourceParser) {
    if (isset($trace['object']) && is_a($trace['object'], $objectType)) {
erikn69 commented 3 months ago

QueryCollector::addCustomFrameParser(DataTable::class, function (object $frame, array $trace) { // Remove the 'App\' prefix from the namespace $relativeNamespace = str_replace('App\', '', $trace['object']::class);

I try to avoid that, not everyone has the knowledge to do that customization, and not all cases can be solved in that way the way I add it would be ready to use but @barryvdh decides

OzanKurt commented 3 months ago

Why not add both, so people with the knowledge to customize can do it without needing a PR process.

barryvdh commented 3 months ago

I'm not really sure about this, not seeing this in my own datatables. Don't want to complicate the backtrace too much.