Sync vendor files to DDEV from PHPStorm

When using DDEV with Mutagen for a PHP project, you typically exclude the vendor folder from synchronization for performance reasons. It’s a good practice, but it creates a problem: how do you quickly modify a vendor file for debugging without having to use Vim inside the container?

The problem

On my project, I use DDEV with Mutagen. To avoid long synchronization times, the vendor folder is not tracked by Mutagen. However, I regularly need to modify vendor files for debugging: adding dump() calls, tracing code execution, or testing temporary changes.

Until now, I had to open a terminal, enter the container with ddev ssh, edit the file with Vim, then save and quit. It’s tedious, especially when going back and forth between code and debugging. The ideal would be to modify the file directly in PHPStorm and have the change automatically reflected in the container.

The solution: File Watcher in PHPStorm

PHPStorm offers a feature called File Watchers that allows you to automatically execute a command when a file is modified. We’ll use it to synchronize vendor files to the DDEV container.

Make sure vendor is indexed

By default, PHPStorm excludes the vendor folder from indexing. Excluded files don’t appear in scope configuration and cannot trigger a File Watcher.

To check and fix this, open File → Project Structure (or Cmd + ; on Mac). In the Modules tab, verify that the vendor folder is not marked in orange (Excluded). If it is, click on it and remove the exclusion. Alternatively, you can right-click on the vendor folder in the project tree → Mark Directory asNot Excluded.

Create a scope for vendor

We don’t want the File Watcher to trigger for all project files, only for those in vendor. For this, we create a custom scope.

Go to Settings → Appearance & Behavior → Scopes, then click + to create a new scope. Name it Vendor and in the pattern field, enter: file:vendor//*.

Configure the File Watcher

Now let’s create the File Watcher that will synchronize files. Go to Settings → Tools → File Watchers, click + and choose <custom>.

Give it a name like Sync vendor to DDEV. For File type, select PHP. For Scope, choose the Vendor scope created earlier.

In Program, enter /bin/bash. In Arguments, enter the following command:

-c "sleep 0.1 && cat '$FilePathRelativeToProjectRoot$' | ddev exec tee $FilePathRelativeToProjectRoot$ > /dev/null"

Finally, in Working directory, enter $ProjectFileDir$.

Configure advanced options

In the Advanced Options section of the File Watcher, it’s important to uncheck “Auto-save edited files to trigger the watcher” and “Trigger the watcher on external changes”. However, check “Trigger the watcher regardless of syntax errors”. These options prevent unwanted triggers and allow synchronization even if the file contains syntax errors, which is common during debugging.

Command explanation

Let’s break down the command used:

-c "sleep 0.1 && cat '$FilePathRelativeToProjectRoot$' | ddev exec tee $FilePathRelativeToProjectRoot$ > /dev/null"

The sleep 0.1 waits 100ms before executing the command. This is crucial because PHPStorm triggers the watcher while the file is being saved. Without this delay, the file might be empty or partially written, causing a race condition.

Then, cat '$FilePathRelativeToProjectRoot$' reads the content of the modified file. The PHPStorm variable $FilePathRelativeToProjectRoot$ provides the relative path, for example vendor/symfony/http-kernel/HttpKernel.php.

The content is then piped to ddev exec tee $FilePathRelativeToProjectRoot$. The tee command executed in the DDEV container writes the content received on stdin to the specified file. The > /dev/null at the end suppresses the standard output of tee to avoid cluttering the console.

The 100ms delay: solving the race condition

Without the sleep 0.1, I was getting empty files in the container. The problem comes from the fact that PHPStorm triggers the File Watcher when it starts writing the file to disk, not when the write is complete.

A 100ms delay turned out to be the right compromise: long enough for the file to be completely written, short enough not to slow down the workflow.

Debugging issues

If synchronization doesn’t work, PHPStorm displays a console with command errors. This helps you quickly understand what went wrong: incorrect path, permission issues, container not running, etc.

You can also test the command manually in a terminal to verify it works:

cat 'vendor/symfony/http-kernel/HttpKernel.php' | ddev exec tee vendor/symfony/http-kernel/HttpKernel.php > /dev/null

Conclusion

This solution allows you to keep the performance benefits of excluding vendor from Mutagen while having a smooth debugging workflow. You edit the file in PHPStorm with all IDE features (syntax highlighting, autocompletion, navigation), save it, and the change is instantly available in the container.

No more juggling between the IDE and Vim in the terminal!


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *