The question I get asked most often when discussing my Lando development environment with other Drupal Web Developers is, “How do you setup Lando and PhpStorm to debug Drupal using Xdebug?” This blog post will help you do exactly that.
Before you start, you should have a Drupal website up-and-running in Lando. Even a freshly-installed, blank Drupal website will do.
Multistep popup form in Drupal 9.9. Configuration management in Drupal. Active, Sync configuration, transfer configurations from DEV to LIVE. This module allows to export PHPStorm Advanced Metadata in order to get autocomplete functionality and return type information for next calls: Drupal::service, ContainerInterface::get EntityTypeManager::getStorage Usage. In order to generate a metadata file inside Drupal root run a drush command: Drush 9 drush phpstorm-metadata:generate.
Once you finish, you will be able to use PhpStorm to:
- Debug Drupal 8 (and 7) in Lando: a Docker-based development environment
- Debug drush commands for Drupal in Lando
- Debug phpunit tests for Drupal in Lando
- because if you had just written your unit test before you wrote that snazzy method, like you were supposed to,…😉
Tested using:
- OSX
- v10.12.6
- v10.13.6
- PhpStorm v2018.2.2
- Xdebug v2.6.1
- Lando v3.0.0-beta.47
- Docker v18.06.1-ce-mac73 (26764)
- Drupal
- v8.6.0
- v7.59
- drush v8.1.17
- NOTE: drush 9 is currently NOT supported in PhpStorm
- phpunit
- v6.5.12 for Drupal 8
- v6.5.3 for Drupal 7
Prerequisites:
- PhpStorm is installed
- Xdebug is installed
- Lando is installed (includes Docker)
- Drupal is installed in Lando
- drush 8.x.x is installed
- NOTE: drush 9 is currently NOT supported in PhpStorm
- phpunit 6.5.x is installed
- Drupal 8: included with install
- Drupal 7: https://phpunit.de/manual/6.5/en/phpunit-book.html#installation
- You should be reasonably familiar with the command line, as well as with the above software.
Prepare your Drupal in Lando for PhpStorm:
Create a custom php.ini for your Drupal in Lando website:
In the root directory of your lando project, create a “config” directory.
- For example, on OSX this might be: ~/Sites/yourdrupal.lndo.site/config/
Inside this config directory, create a php.ini file with the following:
Edit the .lando.yml file for your Drupal in Lando website:
Add the following to the “config” key of the .lando.yml file, so that Lando will include your new php.ini.
Add the following to the “services” key of the .lando.yml file, so that Lando will include a PHP_IDE_CONFIG for PhpStorm.
Change “yourdrupal.lndo.site” above to match the domain name of your Drupal in Lando website.
Add the following to the “tooling” key of the .lando.yml file, so Lando will recognize “lando phpunit” commands.
If Drupal 8:
Change “web” above to match the webroot directory of your Drupal 8 in Lando website.
If Drupal 7:
Examples of complete Drupal 8 and Drupal 7 .lando.yml files:
A complete but basic Drupal 8 .lando.yml configured for PhpStorm would look like the following:
A complete but basic Drupal 7 .lando.yml configured for PhpStorm would look like the following:
In fact, you could use either of the above .lando.yml files as written, just to test things out. If you plan on spinning-up both of them on the same machine at the same time, though, change the value in “name:” and “PHP_IDE_CONFIG:” of at least one of them first. 😉
Rebuild your Drupal in Lando website in order to apply the new settings.
Create a new PhpStorm Project for your Drupal in Lando website:
Open PhpStorm and click on the following:
File > New Project from Existing Files
- Source Files are in a local directory, no Web server is yet configured
- Click on the “Next” button.
Mark as Project Root a directory to create the project in:
- Click on “Project Root”
- (in the top left window toolbar).
- Select your drupal root directory.
- For example, /Users/You/Sites/yourdrupal.lndo.site/web
- Click on the “Finish” button.
Enable Drupal Support:
After the project finishes indexing, the Event log window should be visible. If it isn’t, click on “Event log” in the bottom-right of the screen.
In the Event log window, enable the suggested items by clicking on them:
- Enable the Symfony Plugin with auto configuration now
- (may or may not be available)
- Enable Drupal Support, which should display the “Enable Drupal Integration” configuration window below.
Enable Drupal integration:
- Verify that “Enable Drupal integration” is checked.
- Drupal installation path: (Select your drupal root directory)
- For example, /Users/You/Sites/yourdrupal.lndo.site/web
- Verify that “Set up PHP | Include paths” is checked
- Version: 8
- (or whatever Drupal version you are using)
- OK
The above configurations can also be set at:
Phpstorm Drupal 9 Support
- PhpStorm > Preferences > Languages & Frameworks > PHP > Frameworks
If prompted by the Event log window, “Set Drupal-style formatting for this project”.
Configure your PhpStorm project:
Setup the PHP Interpreter for the project:
- PhpStorm > Preferences > Languages & Frameworks > PHP
- PHP language level: 7.1
- (or whatever PHP version your Drupal in Lando website uses).
- Click on the “…” icon to the right of the “CLI Interpreter” field.
In the window that opens,
- control+n
- (or click on the “+” icon at the top left of the pane).
- Select “From Docker…”
- Server: Docker
- Image Name: devwithlando/php:7.1-apache
- (or whatever PHP version your Drupal in Lando website uses)
- PHP interpreter path = php
- OK
- Apply
- OK
- Apply
Setup the PHP Server for the project:
- PhpStorm > Preferences > Languages & Frameworks > PHP > Servers
- Click on the “+” in the top left of the left pane.
- Name: yourdrupal.lndo.site
- (Change this to match the domain name of your Drupal in Lando website.)
- Host: yourdrupal.lndo.site
- (Change this to match the domain name of your Drupal in Lando website.)
- Port: 80
- (or whatever lando provided, if applicable)
- Debugger: Xdebug
- Enable: “Use path mappings”
Set the path mapping for the Drupal in Lando website’s root directory:
In the “File/Directory” column, highlight the (path to your Drupal root) row that is listed under the “Project files” folder, by clicking on it.
- For example, click on: /Users/You/Sites/yourdrupal.lndo.site/web
- Edit the “Absolute path on the server” field for the highlighted row.
- Click on the highlighted edit icon that is visible on the right of the same row.
- Type: /app/web
- Press the enter key to update the field.
- Apply
Set the path mapping for drush in Lando:
If Drupal 8:
In the “File/Directory” column, highlight the (path to your included drush) row that is listed the under the “Include path” folder, by clicking on it:
- For example, click on: /Users/You/Sites/yourdrupal.lndo.site/web/vendor/drush/drush
- Edit the “Absolute path on the server” field for the highlighted row.
- Click on the highlighted edit icon that is visible on the right of the same row.
- Type: /usr/local/bin/drush
- Press the enter key to update the field.
- Apply:
If Drupal 7:
In Terminal, add a symlink at your Drupal web root to your globally-installed drush
- For example, on OSX:
In PhpStorm, highlight your newly created “drush” symlink row that is listed the under the “Include path” folder, by clicking on it.
- Edit the “Absolute path on the server” field for the highlighted row.
- Click on the highlighted edit icon that is visible on the right of the same row.
- Type: /usr/local/bin/drush
- Press the enter key to update the field.
- Apply
Configure PhpStorm to debug browser-triggered events for your Drupal in Lando website:
- PhpStorm > Preferences > Languages & Frameworks > PHP > Debug
- External Connections
- Enable “Break at first line in PHP scripts”
- (to at least verify that the debug session is working)
- Max simultaneous connections = 19
- Press the tab key to update the field.
- Enable “Break at first line in PHP scripts”
- Apply
Configure PhpStorm to debug “lando drush” commands for your Drupal in Lando website
- PhpStorm > Preferences > Tools > Command Line Tool Support
- control+n
- (or click on the “+” icon on the left side of the main pane)
Phpstorm Drupal 9 Key
- Select “Custom tool” (not “Drush”) from the dropdown menu.
- We don’t select “Drush” here because the path to the Lando appserver’s drush must be entered manually.
- Visibility = project
- OK
- Set the path to the Lando appserver’s drush:
- /usr/local/bin/drush
- Alias: drush
- OK
- Show console in: tool window
- Apply
- OK
Test your Drupal in Lando PhpStorm Debugging Setup:
Start listening for PHP debug connections:
- command+shift+L in PhpStorm
In your web browser, reload your Drupal in Lando website. You do NOT need an Xdebug Helper browser extension for this to work. With the above settings, PhpStorm will automatically pause your website at:
- If Drupal 8: line 14 (“$autoloader) of index.php
- If Drupal 7: line 17 (“define”) of index.php
Note: PhpStorm did NOT automatically focus the PhpStorm application in your computer display. With the current PhpStorm settings, you have to switch to PhpStorm manually in order to see that it is pausing your website. We will change this setting in the next step.
fn+command+F2 to stop debugging but continue listening for PHP Debug Connections
To focus PhpStorm automatically when a breakpoint is set:
- PhpStorm > Preferences > Languages & Frameworks > PHP > Debug > External connections
- Uncheck “Break at first line in PHP scripts”.
- Apply
- OK
Test browser-triggered debugging:
If Drupal 8:
- Add a breakpoint at line 14 (“$autoloader”) of web/index.php
- Add a breakpoint at line 236 (“function user_load”) of web/core/modules/user/user.module
If Drupal 7:
- Add a breakpoint at line 19 (“require_once”) of web/index.php
- Add a breakpoint at line 365 (“function user_load”) of web/core/modules/user/user.module
In your web browser, navigate to yourdrupal.lndo.site/user/1
- Focus will switch to PhpStorm and catch at the breakpoint in index.php.
- fn+F9 to jump to the next breakpoint.
- PhpStorm will catch at the breakpoint in user.module.
- fn+command+F2 to stop debugging but continue listening for PHP Debug Connections
Test “lando drush” debugging:
In Terminal:
- PhpStorm will catch at the breakpoint that is still set for user.module in the example above.
- fn+command+F2 to stop debugging but continue listening for PHP Debug Connections
Test phpunit debugging:
If Drupal 8:
- Add a breakpoint at line 62 (“$this->password”) of web/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php
- Run a phpunit test in Terminal:
- Focus will switch to PhpStorm and catch at the breakpoint in PasswordHashingTest.php.
- fn+command+F2 to stop debugging but continue listening for PHP Debug Connections
- You may have to fn+command+F2 more than once
If Drupal 7:
- Enable the Testing module:
- Remove the breakpoint you set above at line 365 (“function user_load”) of web/core/modules/user/user.module
- Add a breakpoint at line 23 (“require_once”) of web/modules/simpletest/tests/password.test
- Run a phpunit test in Terminal:
- Focus will switch to PhpStorm and catch at the breakpoint in password.test
- fn+command+F2 to stop debugging but continue listening for PHP Debug Connections
- You may have to fn+command+F2 more than once
Happy Drupal in Lando debugging with PhpStorm!
Have your own tricks for Drupal debugging? Share your thoughts with us on Twitter, and subscribe to our newsletter for more content like this!
Skip to end of metadataGo to start of metadataPhpstorm Drupal 9 Free
PHP Inspections | Feature | WI-49520 | New inspection: Unnecessary double quotes |
PHP Interpreters | Bug | WI-56680 | Can't use Browse button for SSH PHP interpreter |
PHP Quality Tools | Bug | WI-56216 | PHPStan and Psalm stop on timeout too early |
Plugin: Drupal support | Exception | WI-56799 | NPE when generate drupal module for drupal 9 |
Plugin: PHPStan | Bug | WI-56623 | PHPStan error highlighting in editor starts with an offset |
Plugin: Psalm | Feature | WI-56040 | Support non-empty-list type |
Feature | WI-56045 | Support positive-int type | |
Feature | WI-56037 | Support iterable type | |
Feature | WI-55920 | Consider functions with no-return, never-return and never-returns as exit functions | |
Feature | WI-55914 | Support advanced callables | |
Bug | WI-55981 | Support non-empty-string | |
Bug | WI-56526 | array<class-string<>> is inferred as string instead of string[] | |
Bug | WI-56764 | Type of key depends on the value's type although it shouldn't in multi-dimensional array | |
Bug | WI-55922 | Type already exists in PHPDoc tag: Parametrized with different classes types are reported as identical | |
Core. IDE Settings | Task | IDEA-253638 | Add an API to prioritize configurables within a group in code style settings |
Core. IDE Settings. Sharing | Bug | IDEA-253846 | Can't set up IDE settings sync |
Core. Indexing | Task | IDEA-252012 | Group indexing diagnostics per project |
Core. Licensing | Bug | IDEA-254049 | License source is changed after the IDE restart |
Core. Plugin Management | Bug | IDEA-254029 | Issues after unloading Maven plugin by disabling it for project |
Core. Project Settings | Bug | IDEA-254157 | Sometimes VfsUtilCore.copyFile adds an extra bom to the new file |
Bug | IDEA-253040 | IDEA does not recognise a module, but it is present in modules.xml | |
Exception | IDEA-189132 | Throwable at com.intellij.openapi.roots.ui.configuration.ModulesConfigurator.getOrCreateModuleEditor | |
Exception | IDEA-253686 | It's not possible to create a new project at location which was used for another project | |
Core. Run. Targets | Feature | IDEA-251763 | Provide browsers from browsable targets to run configurations |
Bug | IDEA-253695 | Run Targets: rsync test connection asks for ssh server password, but it is provided | |
Bug | IDEA-248370 | Show an error when no runtime is configured | |
Bug | IDEA-253810 | Run targets. Docker. Creation via Settings: it doesn't take the set 'language runtime' and doesn't run container introspection | |
Bug | IDEA-253090 | Run Targets: Get Maven exception after choosing several targets in maven configuration | |
Bug | IDEA-253369 | Run Targets. Docker. Build args are ignored. | |
Bug | IDEA-252405 | Run Targets: Can't configure maven home for docker run target | |
Bug | IDEA-253797 | Docker. Run Targets. Copy a docker target action creates a new target without a name and doesn't copy language values | |
Bug | IDEA-253362 | Run Targets. Docker. Add validation for 'Run options' field as it for Docker run configs | |
Usability | IDEA-253274 | Run Targets: SSH: provide possibility to select the Maven home path on the remote machine using the path chooser | |
Usability | IDEA-253334 | Run Targets. RunConfigs->Manage targets. Add Apply button. | |
Cosmetics | IDEA-253693 | Run Targets: rsync connected message not visible in dark theme | |
Cosmetics | IDEA-254006 | Run Targets. Docker. Create via Settings: the 3d step name is present only as `3/3.` instead of `3/3. Configure Java` | |
Task | IDEA-252711 | Run Targets: targets should be project-level | |
Core. SSH | Bug | IDEA-253287 | SSH password requests are not cancellable. |
Editor | Feature | IDEA-252707 | Soft wrap in lightedit |
User Interface | Bug | IDEA-253839 | Big Sur: Custom alerts are invoked instead of native |
Bug | IDEA-252781 | Window titles are light in Darcula, when reopening IDEA with 2 projects | |
Cosmetics | IDEA-250519 | grammatical & typographic errors in notification | |
Task | IDEA-252636 | What's new in Editor | |
User Interface. Accessibility | Bug | IDEA-253342 | On `Settings | Appearance and Behavior | System Settings`, the NVDA screen reader doesn't speak the 'Database' when navigated to the 'Database:'s edit view by using tab |
Bug | IDEA-253340 | Two buttons in `Settings | Appearance & Behavior | Menus and Toolbars` are not spoken by NVDA screen reader | |
User Interface. Focus | Bug | IDEA-190158 | Typeahead timeout exception if same shortcut is assigned to multiple actions (Find and Find in Path, or similar case with Goto Class) |
Version Control | Bug | IDEA-252307 | Rebase modal no longer stores previously selected ref or options |
Bug | IDEA-231698 | Non-modal commit: Author field is not shown inline | |
Bug | IDEA-252549 | Double click on change in commit tab no longer shows inline diff window | |
Version Control. Git | Bug | IDEA-253313 | Can't commit staged deletion |
Usability | IDEA-253485 | Git Staging Area: Vertical scrollbar covers plus/minus icons | |
Usability | IDEA-251554 | Pull-dialog: suggests pulling from the last entered branch, instead from tracked branch | |
Version Control. GitHub | Bug | IDEA-243134 | Clone Dialog -> GitHub: Infinite wait if pressing 'Log In' with all fields empty |
Version Control. Log | Task | IDEA-252476 | Create color key for hovered line in the Log table |
DB Introspection | Bug | DBE-11870 | Problem refreshing DB connection on old SQL server databases |
Data Views | Bug | DBE-11839 | IDE windows/tab system freaks out when database results are dragged to new windows |
No subsystem | Bug | WEB-48044 | Create React component quick fix for qualified references shouldn't be available |
Performance | WEB-44334 | Minute-long freeze when starting to type inside large mixed php file | |
Exception | WEB-47780 | Throwable at com.intellij.psi.impl.SharedPsiElementImplUtil.getChildIndex | |
Build tools | Usability | WEB-36182 | webpack aliases are not resolved correctly when config is exported as function |
JavaScript | Bug | WEB-48031 | Go to usages (cmd/ctrl+click) doesn't work with enabled flow service |
JavaScript. Frameworks | Feature | WEB-46511 | Vue 3: Support <script setup> |
Feature | WEB-48010 | Import prettier rules with ESLint | |
Exception | WEB-47998 | 'Convert to visible line separators' causes 'nonempty text is not covered by block in #Vue #formatter' | |
JavaScript. Inspections | Bug | WEB-46999 | Common.js imports with require are not suggested in quick fixes |
TypeScript | Bug | WEB-44282 | Importing an external function that is only used as a variable's declaration is detected as unused |
Bug | WEB-47803 | Multiple candidates for the same type variable in contra-variant positions isn't inferred to an intersection type | |
Task | WEB-48001 | Remove options 'Use for projects without tsconfig.json' and 'Compile scope' in the TypeScript language server configuration | |
Exception | WEB-48034 | Code with Variadic tuple types causes an exception |