{"id":16625,"date":"2019-09-03T08:41:59","date_gmt":"2019-09-03T08:41:59","guid":{"rendered":"https:\/\/www.mautic.org\/local-mautic-development-with-ddev\/"},"modified":"2024-12-18T11:49:40","modified_gmt":"2024-12-18T11:49:40","slug":"local-mautic-development-with-ddev","status":"publish","type":"post","link":"https:\/\/mautic.org\/blog\/local-mautic-development-with-ddev","title":{"rendered":"Local Mautic development with DDEV"},"content":{"rendered":"\r\n<p><a href=\"https:\/\/github.com\/drud\/ddev\" target=\"_blank\" rel=\"noopener\">DDEV<\/a> is an OS agnostic wrapper for Docker that makes it easy to set up PHP projects on your local machine. DDEV aims to make Docker simple and accessible to everyone. Even better, DDEV is entirely open source.<\/p>\r\n\r\n\r\n<p>In this guide we will show you how to set up a local development environment for Mautic, using DDEV.<\/p>\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Installing Docker and DDEV<\/h2>\r\n\r\n\r\n<p>Before we can get started you will need to install Docker and Docker Compose. You can find documentation on how to correctly do this <a href=\"https:\/\/ddev.readthedocs.io\/en\/stable\/users\/docker_installation\/\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\r\n\r\n\r\n<p>Once those are installed we can continue with installing DDEV. You can find installation instructions for Linux, MacOS and Windows <a href=\"https:\/\/ddev.readthedocs.io\/en\/stable\/#installation\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Installing Mautic<\/h2>\r\n\r\n\r\n<p>Clone the Mautic repository into a folder of your choice. Once that is done make sure to install the Composer dependencies with composer install.<\/p>\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Starting DDEV and configuring Mautic<\/h2>\r\n\r\n\r\n<p>Use the command line and navigate to the root of your Mautic installation.\u00a0Once there, run\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev config<\/pre>\r\n\r\n\r\n<p>It will ask you for a project name &#8211; you can leave it at the default, or give it a custom name. This is really up to you. For the purposes of this example, we will name this project mautic.<\/p>\r\n\r\n\r\n<p>Next it will ask for the docroot of the project.<\/p>\r\n\r\n\r\n<p>Since the index.php of Mautic is located in the root folder of the project, we can just go with the default value. Simply press enter.<\/p>\r\n\r\n\r\n<p>After this it will ask for the project type. Enter php and hit enter again.<\/p>\r\n\r\n\r\n<p>Everything should now be configured. We just need to change one more thing! Go to .ddev\/config.yaml and you&#8217;ll find something similar to:<\/p>\r\n\r\n<pre>\r\n<code>APIVersion: v1.13.1\r\nname: demodir\r\ntype: php\r\ndocroot: \"\"\r\nphp_version: \"7.3\"\r\nwebserver_type: nginx-fpm\r\nrouter_http_port: \"80\"\r\nrouter_https_port: \"443\"\r\nxdebug_enabled: false\r\nadditional_hostnames: []\r\nadditional_fqdns: []\r\nnfs_mount_enabled: false\r\nprovider: default\r\nuse_dns_when_possible: true\r\ntimezone: \"\"<\/code><\/pre>\r\n\r\n\r\n<p>&#8230; change the webserver type to\u00a0the following:<\/p>\r\n\r\n<pre>\r\n<code>webserver_type: apache-fpm<\/code><\/pre>\r\n\r\n<p>&#8230; add the following row (<strong>make sure to replace 7.3 with whichever PHP version you&#8217;re using!<\/strong>):<\/p>\r\n\r\n<pre>\r\n<code>webimage_extra_packages: [php7.3-imap]<\/code><\/pre>\r\n\r\n<p>&#8230; and change the timezone to whichever timezone you&#8217;re in, for example:<\/p>\r\n\r\n<pre>\r\n<code>timezone: \"Europe\/Amsterdam\"<\/code><\/pre>\r\n\r\n<p>&#8230; you&#8217;ll have the following config.yaml file then:<\/p>\r\n\r\n<pre>\r\n<code>APIVersion: v1.13.1\r\nname: mautic\r\ntype: php\r\ndocroot: \"\"\r\nphp_version: \"7.3\"\r\nwebserver_type: apache-cgi\r\nrouter_http_port: \"80\"\r\nrouter_https_port: \"443\"\r\nxdebug_enabled: false\r\nadditional_hostnames: []\r\nadditional_fqdns: []\r\nnfs_mount_enabled: false\r\nprovider: default\r\nuse_dns_when_possible: true\r\ntimezone: \"Europe\/Amsterdam\"\r\nwebimage_extra_packages: [php7.3-imap]<\/code><\/pre>\r\n\r\n<p><em>Note: if you have Apache2 or nginx installed, and they are currently using port 80, ensure that you shut them down or change their ports before starting the DDEV instance. If you do not follow this step, starting will fail with an error message telling you that port 80 is already in use.<\/em><\/p>\r\n\r\n\r\n<p>You can start DDEV by running\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev start\u00a0<\/pre>\r\n\r\n\r\n<p>on the command line.\u00a0<\/p>\r\n\r\n\r\n<p>If this is your first DDEV instance this can take a bit of time to initialise, as it will need to pull all the containers.\u00a0<\/p>\r\n\r\n<p><strong>If you cloned Mautic from GitHub, you need to run composer install in order to get started. Run<\/strong><\/p>\r\n\r\n<pre>\r\nddev ssh\r\ncomposer install<\/pre>\r\n\r\n<p><strong>&#8230; and you should be good to go.<\/strong><\/p>\r\n\r\n\r\n<p>Once started you will find your project at mautic.ddev.site (in case you used a different project name it will be yourprojectname.ddev.site).<\/p>\r\n\r\n\r\n<p>Navigating there in the browser should bring up the Mautic installation. Make sure that during the installation you use the following settings:<\/p>\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n\t<li>Database port: 3306<\/li>\r\n\t<li>Database host: db<\/li>\r\n\t<li>Database name: db<\/li>\r\n\t<li>Database user: db<\/li>\r\n\t<li>Database password: db<\/li>\r\n<\/ul>\r\n\r\n\r\n<p>You can now finish the installation process. Your local Mautic instance should be up and running!<\/p>\r\n\r\n\r\n<p>To stop the containers, simply run\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev stop\u00a0<\/pre>\r\n\r\n\r\n<p>on the command line.<\/p>\r\n\r\n<h2>Opening Mautic&#8217;s development environment (index_dev.php)<\/h2>\r\n\r\n<p>Mautic has a development environment (index_dev.php) which shows a profiler toolbar at the bottom, shows more error details, and caches less (so you have to clear your cache less often).\u00a0<\/p>\r\n\r\n<p>The only\u00a0<strong>downside<\/strong>\u00a0is that the development environment is designed to work on\u00a0<strong>localhost<\/strong>\u00a0only. Since DDEV uses Docker, which has a slightly different networking stack, we need to make a small change in the code to get index_dev.php to work on DDEV.<\/p>\r\n\r\n<p>Open app\/middlewares\/Dev\/IpRestrictMiddleware.php and replace this code snippet:<\/p>\r\n\r\n<pre>\r\n<code class=\"language-php\">    \/**\r\n     * This check prevents access to debug front controllers\r\n     * that are deployed by accident to production servers.\r\n     *\r\n     * {@inheritdoc}\r\n     *\/\r\n    public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)\r\n    {\r\n        if (in_array($request->getClientIp(), $this->allowedIps)) {\r\n            return $this->app->handle($request, $type, $catch);\r\n        }\r\n\r\n        return new Response('You are not allowed to access this file.', 403);\r\n    }<\/code><\/pre>\r\n\r\n<p>&#8230; with this one:<\/p>\r\n\r\n<pre>\r\n<code class=\"language-php\">\/**\r\n     * This check prevents access to debug front controllers\r\n     * that are deployed by accident to production servers.\r\n     *\r\n     * {@inheritdoc}\r\n     *\/\r\n    public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)\r\n    {\r\n        return $this->app->handle($request, $type, $catch);\r\n    }<\/code><\/pre>\r\n\r\n<p>\u00a0That way, we bypass the IP restriction middleware (otherwise you&#8217;ll get an error &#8220;You are not allowed to access this file&#8221; when trying to access index_dev.php).<\/p>\r\n\r\n<p>Now you should be able to open index_dev.php in your DDEV environment<\/p>\r\n\r\n<img fetchpriority=\"high\" decoding=\"async\" class=\" size-full wp-image-14742\" src=\"https:\/\/www.mautic.org\/wp-content\/uploads\/2019\/09\/mautic-profiler.png\" alt=\"Mautic profiler bar Symfony\" title=\"\" width=\"2732\" height=\"1580\" srcset=\"https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mautic-profiler.png 2732w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mautic-profiler-300x173.png 300w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mautic-profiler-1024x592.png 1024w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mautic-profiler-768x444.png 768w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mautic-profiler-1536x888.png 1536w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mautic-profiler-2048x1184.png 2048w\" sizes=\"(max-width: 2732px) 100vw, 2732px\" \/>\r\n\r\n<h2>Running Mautic CLI commands in DDEV<\/h2>\r\n\r\n<p>You can run <a href=\"https:\/\/docs.mautic.org\/en\/troubleshooting\/command-line-tools-cli\">Mautic CLI commands<\/a> (like clearing cache) as follows:<\/p>\r\n\r\n<pre>\r\nddev ssh<\/pre>\r\n\r\n<p>Then you can run <a href=\"https:\/\/docs.mautic.org\/en\/troubleshooting\/command-line-tools-cli\">CLI commands<\/a>, for example:<\/p>\r\n\r\n<pre>\r\nbin\/console cache:clear --env=dev\r\nbin\/console mautic:campaigns:update\r\netc.<\/pre>\r\n\r\n<h2>Using MailHog to catch emails in DDEV<\/h2>\r\n\r\n<p><em>(update: MailHog is no longer available as an option)<\/em><\/p>\r\n\r\n<p>Run<\/p>\r\n\r\n<pre>\r\nddev describe<\/pre>\r\n\r\n<p>And it&#8217;ll show you the following at the bottom (example):<\/p>\r\n\r\n<pre>\r\n<code class=\"language-bash\">Other Services\r\n--------------\r\nMailHog:        http:\/\/mautic.ddev.site:8025\r\nphpMyAdmin:     http:\/\/mautic.ddev.site:8036<\/code><\/pre>\r\n\r\n\r\n<p>You can use MailHog to catch all emails sent by Mautic (without having to use an SMTP server). In your Mautic email configuration, go to Email Settings and select &#8220;Other SMTP server&#8221;, then enter &#8220;localhost&#8221; and use port 1025. All emails will end up in MailHog.<br \/>\r\n<br \/>\r\n\u00a0<\/p>\r\n\r\n<img decoding=\"async\" class=\" size-full wp-image-14743\" src=\"https:\/\/www.mautic.org\/wp-content\/uploads\/2019\/09\/ddev-SMTP.png\" alt=\"DDEV Mautic Mailhog configuration\" title=\"\" width=\"2666\" height=\"1154\" srcset=\"https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/ddev-SMTP.png 2666w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/ddev-SMTP-300x130.png 300w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/ddev-SMTP-1024x443.png 1024w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/ddev-SMTP-768x332.png 768w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/ddev-SMTP-1536x665.png 1536w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/ddev-SMTP-2048x886.png 2048w\" sizes=\"(max-width: 2666px) 100vw, 2666px\" \/>\r\n\r\n<img decoding=\"async\" class=\" size-full wp-image-14744\" src=\"https:\/\/www.mautic.org\/wp-content\/uploads\/2019\/09\/mailhog.png\" alt=\"Mailhog DDEV Mautic\" title=\"\" width=\"2726\" height=\"1019\" srcset=\"https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mailhog.png 2726w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mailhog-300x112.png 300w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mailhog-1024x383.png 1024w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mailhog-768x287.png 768w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mailhog-1536x574.png 1536w, https:\/\/mautic.org\/wp-content\/uploads\/2019\/09\/mailhog-2048x766.png 2048w\" sizes=\"(max-width: 2726px) 100vw, 2726px\" \/>\r\n\r\n<h2 class=\"wp-block-heading\">Further useful DDEV tips and tricks<\/h2>\r\n\r\n\r\n<p>Here you can find some other useful things you might need later along the way.<\/p>\r\n\r\n\r\n<h3 class=\"wp-block-heading\">SSH into the container<\/h3>\r\n\r\n\r\n<p>To SSH in to the web container, simply use\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev ssh\u00a0<\/pre>\r\n\r\n\r\n<p>on the command line.\u00a0<\/p>\r\n\r\n\r\n<p>If you wish to directly execute a command inside the container without going in with ssh first you can use\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev exec yourcommandhere<\/pre>\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Using Xdebug<\/h3>\r\n\r\n\r\n<p>You can use\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev exec enable_xdebug<\/pre>\r\n\r\n\r\n<p>and\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev exec disable_xdebug<\/pre>\r\n\r\n\r\n<p>respectively to turn Xdebug on and off.<\/p>\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Changing PHP versions<\/h3>\r\n\r\n\r\n<p>Navigate to .ddev\/config.yaml and edit the parameter called php_version. Once that is saved, run\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev restart<\/pre>\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Using additional PHP modules<\/h3>\r\n\r\n\r\n<p>Once DDEV has been set up, you can find its configuration in the .ddev folder.\u00a0<\/p>\r\n\r\n\r\n<p>If you need an extra PHP modules enabled such as IMAP for example, you can add it doing the following:<\/p>\r\n\r\n\r\n<p>Navigate to .ddev\/config.yaml\u00a0and find the following row:<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nwebimage_extra_packages: [php7.3-imap]\r\n<\/pre>\r\n\r\n<p>So, if you want to add the php-imap\u00a0package, you would add the package as above. You can add additional packages by comma-separating them.\u00a0<\/p>\r\n\r\n\r\n<p>Now save this file and restart your DDEV instance by running\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev restart<\/pre>\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Using PHPMyAdmin<\/h3>\r\n\r\n\r\n<p>A DDEV instance comes with PHPMyAdmin by default. To find out the location of the PHPMyAdmin instance of the current project, use\u00a0<\/p>\r\n\r\n\r\n<pre class=\"wp-block-preformatted\">\r\nddev describe<\/pre>\r\n\r\n\r\n<p>This will give you a lot of information about your containers, including the URL to the PHPMyAdmin instance.<\/p>\r\n\r\n<h3>Running PHPUNIT tests<\/h3>\r\n\r\n<p>In Mautic 5, you need to create .env.test.local file that will configure the test environment. Here is the content of this file:<\/p>\r\n\r\n<pre>\r\n# .env.test.local\r\nDB_HOST=db\r\nDB_PORT=3306\r\nDB_NAME=test\r\nDB_USER=db\r\nDB_PASSWD=db\r\nMAUTIC_DB_PREFIX=\r\nMAUTIC_TABLE_PREFIX=\r\nMAUTIC_ENV=test\r\nMAUTIC_ADMIN_USERNAME=admin\r\nMAUTIC_ADMIN_PASSWORD=Maut1cR0cks!\r\n<\/pre>\r\n\r\n<p>Make sure that the database with name &#8220;test&#8221; exists. You can add a prefix if you want.<\/p>\r\n\r\n<p>Then run the tests with:<\/p>\r\n\r\n<pre>\r\ncomposer test<\/pre>\r\n\r\n<p>or if you want to run a specific test then you can filter for it:<\/p>\r\n\r\n<pre>\r\ncomposer test -- --filter specificTest<\/pre>\r\n","protected":false},"excerpt":{"rendered":"<p>DDEV is an OS agnostic wrapper for Docker. Learn how to set up a local Mautic development environment using DDEV in this community blog article.<\/p>\n","protected":false},"author":52,"featured_media":16102,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"publish_to_discourse":"","publish_post_category":"13","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"34507","discourse_permalink":"https:\/\/forum.mautic.org\/t\/local-mautic-development-with-ddev\/11059","wpdc_publishing_response":"","wpdc_publishing_error":"","footnotes":""},"categories":[1494,1495],"tags":[843,847],"class_list":["post-16625","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-for-developers","category-for-integrators","tag-ddev","tag-development"],"acf":[],"_links":{"self":[{"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/posts\/16625","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/users\/52"}],"replies":[{"embeddable":true,"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/comments?post=16625"}],"version-history":[{"count":1,"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/posts\/16625\/revisions"}],"predecessor-version":[{"id":17089,"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/posts\/16625\/revisions\/17089"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/media\/16102"}],"wp:attachment":[{"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/media?parent=16625"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/categories?post=16625"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mautic.org\/wp-json\/wp\/v2\/tags?post=16625"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}