Skip to content

Instantly share code, notes, and snippets.

@quentint
Last active April 27, 2023 21:18
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quentint/6331aa9a75313ed955b2ea20d33557af to your computer and use it in GitHub Desktop.
Save quentint/6331aa9a75313ed955b2ea20d33557af to your computer and use it in GitHub Desktop.
Lando + PHPStorm/IntelliJ IDEA + PHPUnit

Lando + PHPStorm/IntelliJ IDEA + PHPUnit

Context

This gist is a follow-up to this Lando issue, updated for Docker Composer and Windows (but might also help macOS and Linux users).

Steps

Setup Docker

  1. Open File | Settings | Build, Execution, Deployment | Docker
  2. Click on the top-left "+"
  3. Case a: If you have (and want to use) Docker for Windows: choose "Docker for Windows"
  4. Case b (theorical, because unfortunately I could not get it to work): If your Lando instance is in WSL:
    1. Choose "WSL" and your Linux distribution
    2. Add one or more path mappings (in my case mapping /home/quentint to \\wsl$\Ubuntu\home\quentint was enough because my projects are stored in WSL's home directory)

PHP CLI Interpreter

  1. Open File | Settings | Languages & Frameworks | PHP

  1. Click on the three dots on the "CLI Interpreter" line
  2. Click on the top-left "+" and create CLI Interpreter "From Docker, Vagrant, VM, WSL, Remote..."

  1. Choose "Docker Compose"

  1. Click on the "Configuration files" folder icon
  2. Click on the top-right "+"

  1. Select all YAML files in C:\Users\[user]\.lando\compose\[project]
  2. Select "appserver" in the Service dropdown
  3. Click OK to close the "Configure Remote PHP Interpreter" window
  4. Choose "Connect to an existing container" in the "Lifecycle" section

  1. Click OK to close the "CLI Interpreters" window
  2. Click on the directory icon of the "Path mappings" section
  3. Add a local path mapping your project root to /app and click OK to confirm

PHPUnit

  1. Open File | Settings | Languages & Frameworks | PHP | Test Frameworks
  2. Click the top-left "+" to add a test framework
  3. Choose "PHPUnit by Remote Interpreter"
  4. Choose your newly created interpreter and click OK to close the window

When using Composer (you should)

  1. Choose "Use Composer autoloader"
  2. Set "Path to script" to /app/vendor/autoload.php

When using Symfony

  1. If not already there, create phpunit.xml.dist at the root of your project
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" colors="true"
         bootstrap="tests/bootstrap.php">
    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">src</directory>
        </include>
    </coverage>
    <php>
        <ini name="error_reporting" value="-1"/>
        <server name="APP_ENV" value="test" force="true"/>
        <server name="SHELL_VERBOSITY" value="-1"/>
    </php>
    <testsuites>
        <testsuite name="Project Test Suite">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
    <!-- Run `composer require symfony/phpunit-bridge` before enabling this extension -->
    <!--
      <listeners>
          <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
      </listeners>
      -->
    <!-- Run `composer require symfony/panther` before enabling this extension -->
    <!--
      <extensions>
          <extension class="Symfony\Component\Panther\ServerExtension" />
      </extensions>
      -->
</phpunit>
  1. If not present, add KERNEL_CLASS='App\Kernel' to your .env.test file
  2. Open previous settings (File | Settings | Languages & Frameworks | PHP | Test Frameworks)
  3. Check "Default configuration file"
  4. Set path to /app/phpunit.xml.dist

Add Xdebug support

See this comment for detailed steps.

Run tests 😊

@DuaelFr
Copy link

DuaelFr commented Mar 4, 2022

Thanks a lot for this walk-through! I would never have succeeded without it :)

I would be great to add an optional section talking about supporting xdebug for coverage. There was a comment on the lando issue to explain how. Maybe you could integrate it there?

@quentint
Copy link
Author

quentint commented Mar 8, 2022

Hey 🙂 I've simply added a section and a link to the comment, which I think should be enough.
Thanks!

@DuaelFr
Copy link

DuaelFr commented Mar 8, 2022

Great! Thanks :)

@nicomollet
Copy link

nicomollet commented May 31, 2022

Works great. Thank you.

You can also add instructions for Codeception.

Codeception

  1. Open File | Settings | Languages & Frameworks | PHP | Test Frameworks
  2. Click the top-left "+" to add a test framework
  3. Choose "Codeception by Remote Interpreter"
  4. Set "Path to Codeception executable" to /app/vendor/codeception/codeception/codecept (it can't be /app/vendor/bin/codecept for some reason, see https://intellij-support.jetbrains.com/hc/en-us/community/posts/360004361299-phpStorm-failed-to-run-Codeception-remote-using-Docker)

@GuyPaddock
Copy link

GuyPaddock commented Mar 22, 2023

When trying to debug PHPUnit tests with this configuration, PHPUnit kept failing with an error that it could not load /opt/project/vendor/autoload.php even though /opt/project did not appear anywhere in my settings. I ended up having to search and replace /opt/project to /app in the .idea folder.

This included changing .idea/php-docker-settings.xml, which originally appeared as follows:

<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="PhpDockerContainerSettings">
    <list>
      <map>
        <entry key="312016b0-ac5c-40d6-92f1-2d0c952038ef">
          <value>
            <DockerContainerSettings>
              <option name="version" value="1" />
              <option name="volumeBindings">
                <list>
                  <DockerVolumeBindingImpl>
                    <!-- The next line had to change to reflect '/app' -->
                    <option name="containerPath" value="/opt/project" />
                    <option name="hostPath" value="$PROJECT_DIR$" />
                  </DockerVolumeBindingImpl>
                </list>
              </option>
            </DockerContainerSettings>
          </value>
        </entry>
      </map>
    </list>
  </component>
</project>

And then .idea/php.xml originally appeared as follows:

<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <!-- Omitted -->
  <component name="PhpInterpreters">
      <interpreter id="38209bc7-af9e-45d2-b3f4-23743b814c3d" name="Docker (Lando)" home="docker-compose://DATA" debugger_id="php.debugger.XDebug">
        <!-- DOCKER_REMOTE_PROJECT_PATH had to be updated to reflect '/app'. -->
        <remote_data INTERPRETER_PATH="php" HELPERS_PATH="/opt/.phpstorm_helpers" INITIALIZED="false" 
           VALID="true" RUN_AS_ROOT_VIA_SUDO="false" DOCKER_ACCOUNT_NAME="Docker for Windows"
           DOCKER_COMPOSE_SERVICE_NAME="appserver" 
           DOCKER_REMOTE_PROJECT_PATH="/opt/project">
          <!-- Omitted -->
        </remote_data>
      </interpreter>
    </interpreters>
  </component>
  <!-- Omitted -->
</project>

You'll need to fix-up .idea/php.xml again any time you modify the "Configuration files" setting for the Docker Compose CLI interpreter configuration.

@SlimDeluxe
Copy link

Trying this in PhpStorm on Linux for a project with this landofile:

name: dpd-php-sdk
services:
  appserver:
    type: php:8.1
    via: cli
    webroot: .
    xdebug: "debug,coverage,develop"
tooling:
  php:
    service: appserver
  composer:
    service: appserver
  phpunit:
    service: appserver
    description: Run PHPUnit tests
    cmd: "/app/vendor/bin/phpunit"

... and the "Service" field is never populated with "appserver" for me to select. YML file selection is this:

image

I tried shuffling the order of the files but could not get it to work, it's always showing the loading spinner 😞

image

@quentint
Copy link
Author

@SlimDeluxe: Looks like an issue that'd need to be reported to JetBrains 😉

@SlimDeluxe
Copy link

@quentint maybe, but I'll try a plain docker-compose.yml setup (without Lando) first.

@GuyPaddock
Copy link

Unrelated to your issue @SlimDeluxe, but something I wanted to repost here: I got this to work in IntelliJ but my teammates running PhpStorm couldn't get it to work. Eventually, it turned out that it worked by chance for me because I had the Python plugin for IntelliJ installed, and a side effect of the Python plugin is that it remaps Windows paths into WSL paths when launching commands. PhpStorm doesn't have a Python plugin so this isn't an acceptable workaround there.

More here:
https://youtrack.jetbrains.com/issue/WI-71929

@quentint
Copy link
Author

Hmm, I am now running PhpStorm (without Python plugin) and it works pretty well 😉

@mortona42
Copy link

I'm able to run Unit and Kernel tests, but Functional tests are having issues with accessing urls and file permissions. I'm not sure how to configure PHPStorm to connect to the existing lando instance. When I select exec to run the existing container, it says the input device is not a TTY.

@quentint
Copy link
Author

@mortona42: I just published this gist with details that might be helpful to you: https://gist.github.com/quentint/265404e9fd9a6ada2893639006c0865b

@mortona42
Copy link

In PHPStorm, I had to enable the Docker Compose V2 option in the Docker tool settings, that fixed the TTY message.
Setting the test runner compose command to exec -u www-data fixed the file permission issue.

@SlimDeluxe
Copy link

Great success! 😄
It works for me now. I wish I could tell you what the problem was, but I don't know. In the meantime, my Linux kernel, Docker, PhpStorm etc. were updated. Maybe one of those was the problem. Anyway, the above approach works now and I am able to select appserver in the Service dropdown.

Also thanks to @mortona42 , the file permission problem is gone. To my surprise, it was not enough that the test ran through docker compose. The file created was still owned by root.
To recap: if you set up your test runner like this...

image

... any file created during testing will be owned by your (host) user and not root. The same way it works if you run lando phpunit.

The last problem is that PhpStorm tries to create the Clover XML in a dir that does not exist.

Generating code coverage report in Clover XML format ... failed [00:00.008]
Directory "/opt/phpstorm-coverage" could not be created

As you can see in the above screenshot, I tried setting a path for the XML report, but it's just ignored and PhpStorm appends another one with the problematic path.

image

I can't find any option how to properly set this path. 😏

@mortona42
Copy link

Path mappings are in the docker server settings:
Screenshot from 2023-04-27 10-50-24

@SlimDeluxe
Copy link

Isn't that path already mapped by Lando?
Trying this more portable solution from PhpStorm forums, I added it in service volumes like this and it works.

services:
  appserver:
    type: php:8.1
    via: cli
    webroot: .
    xdebug: "debug,coverage,develop"
    volumes:
      # Add directory for PhpStorm coverage XML report
      - ./build/coverage/xml/:/opt/phpstorm-coverage/

However it's strange that I see it as empty on the host, while files are present in the container.

image

It goes to show that I am still a Docker newb 😅

@mortona42
Copy link

I haven't tried to use coverage so I'm not sure if that's a hardcoded path or something. I was seeing /opt paths in the command phpstorm was running if I didn't set the path mapping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment