DDEV and Magento 2
Local development and GitHub actions
Introduction
I would like to speak here about a tool that I discovered a few months ago: DDEV.
To summarize, DDEV makes it easier to set up a Docker stack for your PHP developments. I was surprised by how quickly it could be picked up, and I use it, among other things, for my Magento 2 developments.
I won't go into detail about everything that can be done with DDEV. There are a large number of resources (especially awesome-ddev) and its documentation seems clear enough to facilitate its installation and customization.
I simply prefer to share my experience here by evoking two types of tasks for which DDEV has simplified my life:
- install Magento 2 and develop modules locally
- set up GitHub actions to test several versions of Magento 2 and PHP in an automated way.
The first step is to install everything you need:
Step 1: Installations
Installing DDEV
The best way to install DDEV is to follow the official documentation. On a Linux distribution, you could run this type of command:
sudo apt install linuxbrew-wrapper
brew tap drud/ddev && brew install ddev
Preparing DDEV Magento 2 environment
The final structure of the project will look like below.:
m2-sources
│
│ (Magento 2 sources installed with composer)
│
└───.ddev
│ │
│ │ (DDEV configuration files)
│
└───my-own-modules (only if you want to test some of your module(s))
│
│
└───yourVendorName-yourModuleName
│
│ (Module sources)
To populate the above .ddev
folder, I will use here specific DDEV configurations.
It's, in fact, configurations that DDEV automatically generates when you tell it that you want to
work on a Magento 2 project, to which I added some DDEV files and commands. For example, I have
added docker-compose.yaml
files when I wanted to work with other Docker containers,
Varnish, PHPSTAN or Nginx configuration files for some very specific uses and I created commands
to simulate crons or run custom scripts.
For now, you could use my sources without trying to understand in detail, but the idea is that everyone should do according to their needs by adding their own DDEV files and commands. I will give below some more specific examples of custom commands.
So if you want to see what it looks like on your host:
- Create an empty
m2-sources
folder:
mkdir m2-sources
- In this folder, create an empty hidden
.ddev
folder and clone my GitHub repository:
mkdir m2-sources/.ddev && cd m2-sources/.ddev && git clone git@github.com:julienloizelet/ddev-m2.git ./
- In this example, we will install Magento 2.4.3 with PHP 7.4. To do this, copy a small configuration file:
cp .ddev/config_overrides/config.m243.yaml .ddev/config.m243.yaml
- Finally, launch DDEV
cd .ddev && ddev start
This should take some times on the first launch as this will download all necessary docker images. Later, it will be much faster.
If you are curious, you could then run a ddev describe
which will give you some information on the different Docker services.
Installing Magento 2
To install Magento 2 you will need your private and public Magento 2 keys. You will be asked for them during the installation with composer
.
DDEV has some basic commands that allow you to launch usual commands in the right docker container. For example,
ddev composer
runs composer
in the web
container where the sources are located.
So, to install Magento 2.4.3, you can do:
ddev composer create --repository=https://repo.magento.com/ magento/project-community-edition:2.4.3
Likewise, ddev magento
launches the CLI executable bin/magento
. So, to complete the installation, run:
ddev magento setup:install \
--base-url=https://m243.ddev.site \
--db-host=db \
--db-name=db \
--db-user=db \
--db-password=db \
--backend-frontname=admin \
--admin-firstname=admin \
--admin-lastname=admin \
--admin-email=admin@admin.com \
--admin-user=admin \
--admin-password=admin123 \
--language=en_US \
--currency=USD \
--timezone=America/Chicago \
--use-rewrites=1 \
--elasticsearch-host=elasticsearch
Magento 2 is now installed and operational.
For convenience purpose, I sometimes add commands like:
ddev magento config:set admin/security/password_is_forced 0
ddev magento config:set admin/security/password_lifetime 0
ddev magento module:disable Magento_TwoFactorAuth
ddev magento indexer:reindex
ddev magento c:c
Or, to add test data:
ddev magento setup:performance:generate-fixtures setup/performance-toolkit/profiles/ce/small.xml
The installations are complete. In the second step, I describe how I develop my modules locally:
Step 2: Local development of a module
Module sources
There are several ways to develop a module locally. Perhaps the easiest is to place your sources in
app/code
.
As far as I'm concerned, I prefer to modify the composer.json
of the project to add a repository
of type path
which point to the module sources:
mkdir -p m2-sources/my-own-modules/yourVendorName-yourModuleName
cd m2-sources/my-own-modules/yourVendorName-yourModuleName
git clone git@github.com:yourGitHubName/yourGitHubModule.git ./
ddev composer config repositories.yourVendorName-yourModuleName path my-own-modules/yourVendorName-yourModuleName/
ddev composer require yourComposerModuleName:@dev
ddev magento module:enable yourVendorName_yourModuleName
ddev magento setup:upgrade
ddev magento cache:flush
For the rest of this presentation, I will take as an example one of my modules called Okaeli_CategoryCode
. This one adds a code
attribute to the categories, but whatever. If you want to see what it looks like:
mkdir m2-sources/my-own-modules
mkdir m2-sources/my-own-modules/okaeli-category-code
cd m2-sources/my-own-modules/okaeli-category-code
git clone git@github.com:julienloizelet/magento2-category-code.git ./
ddev composer config repositories.okaeli-category-code path my-own-modules/okaeli-category-code/
ddev composer require okaeli/magento2-category-code:@dev
ddev magento module:enable Okaeli_CategoryCode
ddev magento setup:upgrade
ddev magento cache:flush
Static and unit tests
As mentioned above, one of the strengths of DDEV is that it allows you to add your own commands. I was thus able to define the phpcs, phpmd and phpstan commands which launch the tools of the same name:
- PHP Code Sniffer:
ddev phpcs my-own-modules/yourVendorName-yourModuleName
- PHP Mess Detector:
ddev phpmd my-own-modules/yourVendorName-yourModuleName
- PHP Stan:
ddev phpstan my-own-modules/yourVendorName-yourModuleName
If you have cloned the example module Okaeli_CategoryCode
in m2-sources/my-own-modules/okaeli-category-code
,
just replace
yourVendorName-yourModuleName
by okaeli-category-code
.
I also added a command to launch PHPUNIT:
ddev phpunit my-own-modules/yourVendorName-yourModuleName/Test/Unit
Sorry, the example module does not have unit tests :).
More tests: Cron and Varnish
If you want to see how I used DDEV to test crons and Varnish, you can watch here.
We have just seen how to test a module locally. The implementation of GitHub actions results directly from this way of doing:
Step 3: Implementing GitHub actions
I started using GitHub actions at the same time as DDEV. It was while creating the DDEV commands that I realized that it would be "easy" to launch them in a GitHub action. And I found that it also saves time: the commands that I create locally are directly applicable in my GitHub actions.
This is why the GitHub action I use to run the static tests (PHPCS, PHPMD and PHPSTAN) follows precisely the steps that I have just described above:
- we install DDEV
- we install Magento with DDEV
- we install a module with DDEV
- we launch tests with DDEV
The main difference is that we can play on the strategy.matrix
entry of the yaml
action file to test several
versions of Magento and PHP at the same time.
Here is what it looks like for the example module:
Small bonus if you have held up until then: these static and Varnish tests are close to those performed for the
technical review during a module submission to the marketplace (see here and here).
If you have a module to submit, it might save you from a failed
on this step.
Conclusion
This presentation is a use case and only covers a small part of DDEV's possibilities. I hope you find it useful if you ever want to give this tool a chance.