vscode-php-debug icon indicating copy to clipboard operation
vscode-php-debug copied to clipboard

Debugger does not stop in breakpoints in blade files.

Open jsantos42 opened this issue 10 months ago • 3 comments

Problem: Debugger does not stop in breakpoints in blade files.

PHPStorm can do this if you set the path to bladecache in Settings->PHP->Debug->Debug->Templates->Blade Debug

Is there a way to implement this? Or maybe my config is missing something:

return {
  "mfussenegger/nvim-dap",
  optional = true,
  opts = function()
    local dap = require("dap")
    local path = require("mason-registry").get_package("php-debug-adapter"):get_install_path()
    dap.adapters.php = {
      type = "executable",
      command = "node",
      args = { path .. "/extension/out/phpDebug.js" },
    }
    dap.configurations.php = {
      {
        name = "Debug",
        type = "php",
        request = "launch",
        port = 9003,
        pathMappings = {
          ["/usr/src/wordpress/wp-content"] = "${workspaceFolder}",
          ["/usr/src/wordpress"] = "${workspaceFolder}/.wordpress-src",
          ["/tmp/bladecache"] = "${workspaceFolder}/bladecache",
          ["/usr/src/wordpress/wp-config.php"] = "${workspaceFolder}/.docker/config/wp-config.php",
          -- ["/usr/src/wordpress/wp-content/bladecache"] = "${workspaceFolder}/bladecache",
        },
        xdebugSettings = { show_hidden = 1, max_children = 100, max_data = 1024, max_depth = 3 },
      },
    }
  end,
}

jsantos42 avatar Jan 29 '25 11:01 jsantos42

Hi. Path mappings aren't at a functional level to support this (probably). Derick is currently working on this inside Xdebug https://xdebug.org/funding/001-native-path-mapping

However, I would like to know what exactly is happening here. Would you be able to provide some logs? Next to xdebugSettings please add log = true (or 1, I'm not sure about LUA types...).

I'm interested in:

  • What is the exact filename you are setting the breakpoint in
  • What does this file (I'm assuming it's a blade template) get compiled to?
  • If you add the following code: where does the PHP execution stop?
@php
   xdebug_break();
@endphp

Thanks!

zobo avatar Jan 29 '25 13:01 zobo

@zobo I apologise for the huge delay, I must have read the email and forgot to answer. Anyway, answering your questions:

  1. I don't have anything in the logs except [58] [Config] WARN: Not setting up control socket with default value due to unavailable 'tsc' clock
  2. I'm guessing they get compiled to the bladecache directory.
  3. Adding
@php
   xdebug_break();
@endphp

alone didn't seem to make a difference. BUT after duplicating the dap.configurations.php config to an entry called dap.configurations.blade finally made it stop in a blade file. Funny enough:

  • adding the 'normal' breakpoints in blade files doesn't do anything, Xdebug still ignores them, but apparently stops in xdebug_break().
  • it doesn't stop "in the file", it stops in the cached file. So, for example, I had a breakpoint in themes/main/blade-templates/pages/faq.blade.php and it opened a new buffer on bladecache/017f1104941955f21742efba9c123d087cf4b5f3.php, where it stopped, in the correct line.

Do you think there's a way to make the DAP interpret the 'normal' breakpoints in blade templates as xdebug_break()? Is this something that must be done in this adapter or on DAP itself? In any case, I'd like to try and do it if you think it's feasible.

For reference, my nvim DAP config:

return {
  "mfussenegger/nvim-dap",
  optional = true,
  opts = function()
    local dap = require("dap")
    local path = require("mason-registry").get_package("php-debug-adapter"):get_install_path()
    dap.adapters.php = {
      type = "executable",
      command = "node",
      args = { path .. "/extension/out/phpDebug.js" },
    }
    dap.configurations.php = {
      {
        name = "Debug ",
        type = "php",
        request = "launch",
        port = 9003,
        -- this is needed for a remote app running in a container
        pathMappings = {
          ["/usr/src/wordpress/wp-content"] = "${workspaceFolder}",
          ["/usr/src/wordpress"] = "${workspaceFolder}/.wordpress-src",
          ["/tmp/bladecache"] = "${workspaceFolder}/bladecache",
          ["/usr/src/wordpress/wp-config.php"] = "${workspaceFolder}/.docker/config/wp-config.php",
        },
        skipFiles = {
          "**/wp-includes/**",
          "**/vendor/**",
        },
      },
    }
    dap.configurations.blade = {
      {
        name = "Debug",
        type = "php",
        request = "launch",
        port = 9003,
        -- this is needed for a remote app running in a container
        pathMappings = {
          ["/usr/src/wordpress/wp-content"] = "${workspaceFolder}",
          ["/usr/src/wordpress"] = "${workspaceFolder}/.wordpress-src",
          ["/tmp/bladecache"] = "${workspaceFolder}/bladecache",
          ["/usr/src/wordpress/wp-config.php"] = "${workspaceFolder}/.docker/config/wp-config.php",
        },
        skipFiles = {
          "**/wp-includes/**",
          "**/vendor/**",
        },
      },
    }
  end,
}

and my xdebug config:

zend_extension = xdebug
xdebug.client_port = 9003
xdebug.client_host = host.docker.internal
xdebug.log = /tmp/xdebug.log
xdebug.cli_color = 1
xdebug.mode = develop,debug
xdebug.start_upon_error = yes

On PHP 8.1.33 with Xdebug v3.4.5

jsantos42 avatar Oct 17 '25 14:10 jsantos42

Hi @jsantos42 thanks for the info and sorry for the late reply.

Not sure what's up with the configurations, they both should work as they look the same.

What I meant by log is something like this:

return {
  "mfussenegger/nvim-dap",
  optional = true,
  opts = function()
    local dap = require("dap")
    local path = require("mason-registry").get_package("php-debug-adapter"):get_install_path()
    dap.adapters.php = {
      type = "executable",
      command = "node",
      args = { path .. "/extension/out/phpDebug.js" },
    }
    dap.configurations.php = {
      {
        name = "Debug ",
        type = "php",
        request = "launch",
        port = 9003,
        -- this is needed for a remote app running in a container
        pathMappings = {
          ["/usr/src/wordpress/wp-content"] = "${workspaceFolder}",
          ["/usr/src/wordpress"] = "${workspaceFolder}/.wordpress-src",
          ["/tmp/bladecache"] = "${workspaceFolder}/bladecache",
          ["/usr/src/wordpress/wp-config.php"] = "${workspaceFolder}/.docker/config/wp-config.php",
        },
        skipFiles = {
          "**/wp-includes/**",
          "**/vendor/**",
        },
        log = 1,     <---- THIS HERE
      },
    }

Debug adapter uses the DAP OutputEvent to send messages to the client (nvim).

Anyway. First are you doing remote development or not. The pathMappings to suggest that. And if, what kind of (sftp, SMB...). Where is your working directory, where is PHP execution, where is you IDE and where your DAP adapter. I'm asking this, because I do not know if DAP and IDE have access to compiled Blade files.

Second, yes Blade files get compiled to PHP and that PHP is then executed. In order to set breakpoints DAP needs to know how to map themes/main/blade-templates/pages/faq.blade.php to bladecache/017f1104941955f21742efba9c123d087cf4b5f3.php. Also in these examples the front of the path is missing and I can't build a correct mental picture.

Now there are 2 other problems. First, the file of the compiled Blade file looks like a big hash. And I'm guessing it changes. If it changes, you can't make a valid path mapping for this to work.

Second, path mapping can only translate file paths, not the content of the file. So if you place a breakpoint on the first line of the Blade file, but that this gets compiled so, that the generated code is actually on the third line, this won't work.

Again, the only real solution will be to wait for https://xdebug.org/funding/001-native-path-mapping and support from Blade to generate Xdebug specific map files.

zobo avatar Oct 21 '25 13:10 zobo