<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:og="http://ogp.me/ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:schema="http://schema.org/" xmlns:sioc="http://rdfs.org/sioc/ns#" xmlns:sioct="http://rdfs.org/sioc/types#" xmlns:skos="http://www.w3.org/2004/02/skos/core#" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" version="2.0" xml:base="http://badzilla.co.uk/">
  <channel>
    <title>Drupal</title>
    <link>http://badzilla.co.uk/</link>
    <description/>
    <language>en</language>
    
    <item>
  <title>Hosting Drupal 9 on AWS Fargate Part 2: Bitbucket Pipeline</title>
  <link>http://badzilla.co.uk/hosting-drupal-9-aws-fargate-part-2-bitbucket-pipeline</link>
  <description>
&lt;span&gt;Hosting Drupal 9 on AWS Fargate Part 2: Bitbucket Pipeline&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sun, 17/10/2021 - 09:31&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Introduction&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;In the first instalment of this sequence of blogs we talked about how imperative it is to create an industrial strength local dev environment when AWS Fargate is your target deployment platform. In this blog we discuss something equally important - the deploy and build process. This needs to be automated for Drupal since security patches are issued on a weekly basis by the Drupal Security Group, and an automated solution is the only way to keep on top of these updates.&lt;/p&gt;
&lt;p&gt;Over the last two years I have become accustomed  to using Atlassian's Bitbucket Pipelines, and I am really liking this CI/CD delivery mechanism. It is particularly suited to containerised solutions since the pipeline itself runs in a Docker container, and often times the solution Docker image can be used for the build process - case in point this project! This tutorial will show how the official Drupal PHP Docker container can be used as the pipeline for delivering Drupal 9 projects to AWS Fargate. Let's see how!&lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Bitbucket Pipeline&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-10/Pipeline.jpeg?itok=JFTezBU3 202w, https://assets.badzilla.co.uk/styles/max_650x650/s3/2021-10/Pipeline.jpeg?itok=lB6wJnbM 404w, https://assets.badzilla.co.uk/styles/max_1300x1300/s3/2021-10/Pipeline.jpeg?itok=ICDrDamw 808w, https://assets.badzilla.co.uk/styles/max_2600x2600/s3/2021-10/Pipeline.jpeg?itok=0UNx4Vgp 1616w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-10/Pipeline.jpeg?itok=JFTezBU3" alt="Pipeline" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The diagram above shows the basic steps the pipeline follows. Let's have a look at these in turn with narrative and then see how that transposes into the Pipeline code.A few trivial housekeeping activities have been omitted from the diagram for clarity but will be discussed when we look at the code. &lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Since my Badzilla blog is a hobby project, I don't have multiple environments, and merge all new features into the git master branch. Any merge into master triggers the build process. Commercial pipelines tend to trigger builds on feature branch commits too which may be a consideration depending upon your circumstances.&lt;/li&gt;
	&lt;li&gt;I've already mentioned that the Docker image selected for the pipeline will be the official Drupal / PHP release - and thus contains &lt;em&gt;composer&lt;/em&gt; which is used to build out the codebase.&lt;/li&gt;
	&lt;li&gt;Once the codebase has been built the testing can be undertaken. I have identified two parallel steps in the pipeline - &lt;a href="http://badzilla.co.uk/aws-fargate-automated-testing-cucumber-gherkin-java-maven-selenium-grid-hub-and-chrome-and-firefox"&gt;automated testing&lt;/a&gt; and &lt;a href="http://badzilla.co.uk/aws-fargate-static-analysis-php"&gt;static testing&lt;/a&gt;. I have covered the configuration for these in earlier blogs - so click through for further reading. &lt;/li&gt;
	&lt;li&gt;The next steps involve building the two Docker image artefacts we need for our Fargate bundles - the PHP / FPM / Codebase image, and the NGINX Web Server image. The latter is required since we need to load a configuration for Drupal 9 and for serving the S3 / CloudFront assets. &lt;/li&gt;
	&lt;li&gt;The artefacts are pushed into AWS ECR after being tagged &lt;em&gt;latest&lt;/em&gt;. &lt;/li&gt;
	&lt;li&gt;We are now ready to deploy the images to our ECS Cluster - but before we do this, we provide the opportunity to run any pre-deploy hooks. This would typically be activities such as &lt;em&gt;drush&lt;/em&gt; putting the web app into maintenance mode to prevent public access during updates.&lt;/li&gt;
	&lt;li&gt;One the pre-deploy scripts have completed, the deploy script is invoked. This forces an ECS service update on the cluster. The script loops to determine whether the update fails or completes, and upon a successful completion will move onto the final step. &lt;/li&gt;
	&lt;li&gt;The post-deploy scripts are now run. These would be further &lt;em&gt;drush&lt;/em&gt; commands to update the database schema for example, and to remove the maintenance mode flag. &lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Pipeline Code&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The pipeline code is saved in &lt;strong&gt;bitbucket-pipelines.yml&lt;/strong&gt; and is show below.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;image:
  name: drupal:9.2.6-php7.4-fpm
 
clone:
  depth: full
 
definitions:
  services:
    docker:
      memory: &lt;span style="color: #000000;"&gt;2048&lt;/span&gt;
 
  steps:
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;build-environment
        name: Build Environment
        script:
          &lt;span style="color: #666666; font-style: italic;"&gt;# Install git &amp; unzip for composer&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get update&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;git&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# Install dependencies&lt;/span&gt;
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; &lt;span style="color: #007800;"&gt;COMPOSER_ALLOW_SUPERUSER&lt;/span&gt;=&lt;span style="color: #000000;"&gt;1&lt;/span&gt;
          - composer &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# Copy project settings file in place&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;cp&lt;/span&gt; storage&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;settings.php web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;settings.php
          &lt;span style="color: #666666; font-style: italic;"&gt;# Remove all non-essential dirs and files from top level directory&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rf&lt;/span&gt; assets backup databases .git
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; Makefile README.md docker-compose.yml composer.json composer.lock .env .csslintrc .eslintignore .eslintrc.json
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; .gitignore
          &lt;span style="color: #666666; font-style: italic;"&gt;# Add the bind mount VOLUME so in Fargate the nginx container can do a VOLUME_FROM and load /opt/drupal docroot&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# from the core-drupal container&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-i&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'/^FROM.*/a VOLUME ["/opt/drupal"]'&lt;/span&gt; Dockerfile &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;dev&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;null &lt;span style="color: #000000;"&gt;2&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;
        caches:
          - composer
        artifacts:
          - &lt;span style="color: #ff0000;"&gt;'**'&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Automated Tests placeholder&lt;/span&gt;
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;automated-tests
        name: Automated Tests
        script:
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Add automated tests here"&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Static Analysis tests placeholder&lt;/span&gt;
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;static-tests
        name: Static Analysis Tests
        script:
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Add static analysis here"&lt;/span&gt;
 
pipelines:
  &lt;span style="color: #666666; font-style: italic;"&gt;# Run when code is merged / pushed into specific branches.&lt;/span&gt;
  branches:
    master:
      - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;build-environment
 
      - parallel:
          - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;automated-tests
          - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;static-tests
 
      - step:
          name: Build &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt; Deploy
          deployment: AWS Prod
          script:
            &lt;span style="color: #666666; font-style: italic;"&gt;# Install AWS CLI&lt;/span&gt;
            - apt update &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt; jq &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; python3 python-dev python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev python-pip
            - curl &lt;span style="color: #ff0000;"&gt;"https://s3.amazonaws.com/aws-cli/awscli-bundle-1.18.200.zip"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-o&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"awscli-bundle.zip"&lt;/span&gt;
            - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; awscli-bundle.zip
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;awscli-bundle&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-b&lt;/span&gt; ~&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;aws
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; &lt;span style="color: #007800;"&gt;PATH&lt;/span&gt;=~&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin:&lt;span style="color: #007800;"&gt;$PATH&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Build the codebase + FPM&lt;/span&gt;
            - docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; badzilla-core-drupal .
            &lt;span style="color: #666666; font-style: italic;"&gt;# Authenticate with ECR&lt;/span&gt;
            - aws configure &lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; aws_access_key_id &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_ACCESS_KEY}&lt;/span&gt;"&lt;/span&gt;
            - aws configure &lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; aws_secret_access_key &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_SECRET_KEY}&lt;/span&gt;"&lt;/span&gt;
            - aws ecr get-login &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/^.*-p \(.*\)\s\-\e.*$/\1/'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;  docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;login&lt;/span&gt; &lt;span style="color: #660033;"&gt;--password-stdin&lt;/span&gt; &lt;span style="color: #660033;"&gt;-u&lt;/span&gt; AWS &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Tag and push to the repo&lt;/span&gt;
            - docker tag badzilla-core-drupal:latest &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            - docker push &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# NGINX_DRUPAL_REPO_URL&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;fargate
            - docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; badzilla-nginx-drupal .
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
            &lt;span style="color: #666666; font-style: italic;"&gt;# Authenticate with ECR&lt;/span&gt;
            - aws ecr get-login &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/^.*-p \(.*\)\s\-\e.*$/\1/'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;  docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;login&lt;/span&gt; &lt;span style="color: #660033;"&gt;--password-stdin&lt;/span&gt; &lt;span style="color: #660033;"&gt;-u&lt;/span&gt; AWS &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Tag and push to the repo&lt;/span&gt;
            - docker tag badzilla-nginx-drupal:latest &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            - docker push &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Pre deploy Drush Commands&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; deploy-scripts
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-parser.sh ..&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;webhooks&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;pre-deploy&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
            &lt;span style="color: #666666; font-style: italic;"&gt;# Deploy script&lt;/span&gt;
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-scripts&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;ecs-service-deploy.sh
            &lt;span style="color: #666666; font-style: italic;"&gt;# Post deploy Drush Commands&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; deploy-scripts
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-parser.sh ..&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;webhooks&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;post-deploy&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
          services:
            - docker
          caches:
            - docker&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Now let's inspect the code per section. Firstly the declaration of the Docker image to use for the pipeline. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;image:
  name: drupal:9.2.6-php7.4-fpm&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
You'll note that I'm using the same image as I used for my development environment with one small change. In the pipeline I have abandoned the use of the ultra lightweight Alpine image - the image being used is standard Ubuntu. Why so? Firstly there is less necessity for keeping the image small since Atlassian don't charge for storage of the image, and secondly I will want to add additional Linux packages to this image for the pipeline process, and thus I want to use a package manager I am familiar with - &lt;em&gt;apt&lt;/em&gt;.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;clone:
  depth: full
 
definitions:
  services:
    docker:
      memory: &lt;span style="color: #000000;"&gt;2048&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Here I'm saying I want a full clone of the repository in the pipeline. This is a little unnecessary and causes an overhead. In the future I will consider a more shallow clone for greater performance. The Docker memory setting should provide enough headroom for Drupal builds.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;  steps:
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;build-environment
        name: Build Environment
        script:
          &lt;span style="color: #666666; font-style: italic;"&gt;# Install git &amp; unzip for composer&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get update&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;git&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# Install dependencies&lt;/span&gt;
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; &lt;span style="color: #007800;"&gt;COMPOSER_ALLOW_SUPERUSER&lt;/span&gt;=&lt;span style="color: #000000;"&gt;1&lt;/span&gt;
          - composer &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Steps are defined in the pipeline that are invoked later in the script. This step &lt;em&gt;&amp;build-environment&lt;/em&gt; will build out the environment by installing the packages I will need and then running &lt;em&gt;composer install&lt;/em&gt; to build out the codebase.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;          &lt;span style="color: #666666; font-style: italic;"&gt;# Copy project settings file in place&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;cp&lt;/span&gt; storage&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;settings.php web&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;settings.php
          &lt;span style="color: #666666; font-style: italic;"&gt;# Remove all non-essential dirs and files from top level directory&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rf&lt;/span&gt; assets backup databases .git
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; Makefile README.md docker-compose.yml composer.json composer.lock .env .csslintrc .eslintignore .eslintrc.json
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;rm&lt;/span&gt; .gitignore&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Every Drupal site needs a &lt;em&gt;settings.php&lt;/em&gt; file. I decided to have mine saved in the repository in the directory &lt;em&gt;storage&lt;/em&gt; since there is no confidential data. All settings use environmental variables. Your mileage may vary here - other strategies are possible for injecting the &lt;em&gt;settings.php&lt;/em&gt; into the build. &lt;br /&gt;&lt;br /&gt;
I then delete files and directories from the build which won't be needed in a production environment.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;          &lt;span style="color: #666666; font-style: italic;"&gt;# Add the bind mount VOLUME so in Fargate the nginx container can do a VOLUME_FROM and load /opt/drupal docroot&lt;/span&gt;
          &lt;span style="color: #666666; font-style: italic;"&gt;# from the core-drupal container&lt;/span&gt;
          - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-i&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'/^FROM.*/a VOLUME ["/opt/drupal"]'&lt;/span&gt; Dockerfile &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;dev&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;null &lt;span style="color: #000000;"&gt;2&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
This snippet is a kludge to fix a difference between the local environment &lt;em&gt;docker-compose&lt;/em&gt; and the production Fargate Task Definition. Fargate shared volumes use &lt;em&gt;bind mounts&lt;/em&gt; which are created by initially using the &lt;em&gt;VOLUME&lt;/em&gt; instruction in the &lt;em&gt;Dockerfile&lt;/em&gt; and settings in the Task Definition (to be discussed in a later blog). Here I use interactive &lt;em&gt;sed&lt;/em&gt; to inject the &lt;em&gt;VOLUME&lt;/em&gt; into the &lt;em&gt;Dockerfile&lt;/em&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;        caches:
          - composer
        artifacts:
          - &lt;span style="color: #ff0000;"&gt;'**'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Closing the build step I ensure that Docker is cached to save time next time the pipeline is invoked and the artifact (American spelling) setting tells the pipeline to save the all my work in that pipeline step for steps that follow it.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;    &lt;span style="color: #666666; font-style: italic;"&gt;# Automated Tests placeholder&lt;/span&gt;
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;automated-tests
        name: Automated Tests
        script:
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Add automated tests here"&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Static Analysis tests placeholder&lt;/span&gt;
    - step: &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt;static-tests
        name: Static Analysis Tests
        script:
          - &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Add static analysis here"&lt;/span&gt;
 
pipelines:
  &lt;span style="color: #666666; font-style: italic;"&gt;# Run when code is merged / pushed into specific branches.&lt;/span&gt;
  branches:
    master:
      - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;build-environment
 
      - parallel:
          - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;automated-tests
          - step: &lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;static-tests&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Here I have defined the testing steps (both of which are currently placeholders), and then started the 'implementation' section of the code. The steps will be invoked on the master branch, initially the build and then the the two testing steps in parallel.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;      - step:
          name: Build &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&lt;/span&gt; Deploy
          deployment: AWS Prod
          script:
            &lt;span style="color: #666666; font-style: italic;"&gt;# Install AWS CLI&lt;/span&gt;
            - apt update &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;apt-get install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-y&lt;/span&gt; jq &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; python3 python-dev python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev python-pip
            - curl &lt;span style="color: #ff0000;"&gt;"https://s3.amazonaws.com/aws-cli/awscli-bundle-1.18.200.zip"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-o&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"awscli-bundle.zip"&lt;/span&gt;
            - &lt;span style="color: #c20cb9; font-weight: bold;"&gt;unzip&lt;/span&gt; awscli-bundle.zip
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;awscli-bundle&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-b&lt;/span&gt; ~&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;aws
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; &lt;span style="color: #007800;"&gt;PATH&lt;/span&gt;=~&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;bin:&lt;span style="color: #007800;"&gt;$PATH&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Once testing has completed successfully we commence the inline deploy step. We are going to need the AWS CLI installing here since the CLI is necessary to issue the correct sequence of commands to AWS to commit and deploy. &lt;br /&gt;&lt;br /&gt;
Note I am also installing the amazing utility &lt;em&gt;jq&lt;/em&gt; - a JSON query language utility. This is imperative for inspecting the output of the CLI commands since their responses are sent in JSON format.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;            &lt;span style="color: #666666; font-style: italic;"&gt;# Build the codebase + FPM&lt;/span&gt;
            - docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; badzilla-core-drupal .
            &lt;span style="color: #666666; font-style: italic;"&gt;# Authenticate with ECR&lt;/span&gt;
            - aws configure &lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; aws_access_key_id &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_ACCESS_KEY}&lt;/span&gt;"&lt;/span&gt;
            - aws configure &lt;span style="color: #000000; font-weight: bold;"&gt;set&lt;/span&gt; aws_secret_access_key &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_SECRET_KEY}&lt;/span&gt;"&lt;/span&gt;
            - aws ecr get-login &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/^.*-p \(.*\)\s\-\e.*$/\1/'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;  docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;login&lt;/span&gt; &lt;span style="color: #660033;"&gt;--password-stdin&lt;/span&gt; &lt;span style="color: #660033;"&gt;-u&lt;/span&gt; AWS &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Tag and push to the repo&lt;/span&gt;
            - docker tag badzilla-core-drupal:latest &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            - docker push &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${CORE_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Now I've got all I need installed I can build the Docker image artefacts. Firstly I build out the Drupal codebase image which also contains PHP and FPM. I then authenticate with AWS ECR where I will push the artefact once its been tagged.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;            &lt;span style="color: #666666; font-style: italic;"&gt;# NGINX_DRUPAL_REPO_URL&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;fargate
            - docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; badzilla-nginx-drupal .
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
            &lt;span style="color: #666666; font-style: italic;"&gt;# Authenticate with ECR&lt;/span&gt;
            - aws ecr get-login &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/^.*-p \(.*\)\s\-\e.*$/\1/'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;  docker &lt;span style="color: #c20cb9; font-weight: bold;"&gt;login&lt;/span&gt; &lt;span style="color: #660033;"&gt;--password-stdin&lt;/span&gt; &lt;span style="color: #660033;"&gt;-u&lt;/span&gt; AWS &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            &lt;span style="color: #666666; font-style: italic;"&gt;# Tag and push to the repo&lt;/span&gt;
            - docker tag badzilla-nginx-drupal:latest &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;
            - docker push &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NGINX_DRUPAL_REPO_URL}&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
I now repeat the process for the NGINX web server Docker image. Note I have the configuration for this in my codebase repo under the directory &lt;em&gt;docker/nginx/fargate&lt;/em&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;            &lt;span style="color: #666666; font-style: italic;"&gt;# Pre deploy Drush Commands&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; deploy-scripts
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-parser.sh ..&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;webhooks&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;pre-deploy&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -
            &lt;span style="color: #666666; font-style: italic;"&gt;# Deploy script&lt;/span&gt;
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-scripts&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;ecs-service-deploy.sh
            &lt;span style="color: #666666; font-style: italic;"&gt;# Post deploy Drush Commands&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; deploy-scripts
            - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;deploy-parser.sh ..&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;webhooks&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;post-deploy&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
            - &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; -&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
This is the fun part! I now run the deploy shell scripts which are listed with narratives later in the blog. Firstly I run the pre-deploy commands, then the deploy commands and the post-deploy commands. All will be revealed...&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;          services:
            - docker
          caches:
            - docker&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
To use Docker commands in a pipeline, you need to list &lt;em&gt;Docker&lt;/em&gt; under the &lt;em&gt;services&lt;/em&gt; setting. Installing Docker in the pipeline itself and then invoking it will not work! I tried and failed! Note I am also using caching for greater performance.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Repository Environmental Variables&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=EYhOiCH9 126w, https://assets.badzilla.co.uk/styles/max_650x650/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=SINiOcxN 252w, https://assets.badzilla.co.uk/styles/max_1300x1300/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=7E76dh4f 505w, https://assets.badzilla.co.uk/styles/max_2600x2600/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=YYfDNJB3 536w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-10/Screenshot%202021-10-17%20at%2013.48.33.png?itok=EYhOiCH9" alt="Env Vars" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The pipeline and the shell scripts heavily use environmental variables that are set in the repository in Bitbucket. Their names are self-evident and listed in their entirety above. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Pre- and Post-deploy shell script&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The pre- and post-deploy shell script is defined below. Currently it only works on &lt;em&gt;drush&lt;/em&gt; commands but could be extended to include shell scripts easily enough. The idea is it scans the directory passed as a parameter and it looks for lines in any file that starts with the word &lt;em&gt;drush&lt;/em&gt;. It then takes the runtime arguments of that &lt;em&gt;drush&lt;/em&gt; command and converts it into a Docker &lt;em&gt;cmd&lt;/em&gt; syntax. Once that is done the command is executed as a Fargate task using the codebase image with parameter overrides. This task runs to completion and exits. The status of the command can be captured and reported back to the pipeline. Obviously this isn't as quick as running a &lt;em&gt;drush&lt;/em&gt; command in a terminal shell since the Fargate task needs to be provisioned which takes time. It is however a fiendish way of reusing an existing Docker image since the official Drupal Docker image already contains the &lt;em&gt;drush&lt;/em&gt; command. &lt;br /&gt;&lt;strong&gt;deploy-scripts/deploy-parser.sh&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Parse the passed files and issue commands in accordance.&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# Currently only supports drush commands.&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# This can be expanded out to other shell scripts.&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Output directory to be parsed&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Directory: $1 to be parsed"&lt;/span&gt;
 
set_network_configuration&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
&lt;span style="color: #007800;"&gt;NETWORK&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
    {
        "awsvpcConfiguration":
            {
                "subnets": [
                    $1,
                    $2
                ],
                "securityGroups": [
                    $3
                ],
                "assignPublicIp": "ENABLED"
            }
    }
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${NETWORK}&lt;/span&gt;"&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
 
 
set_overrides_command&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
&lt;span style="color: #007800;"&gt;OVERRIDES&lt;/span&gt;=$&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; &lt;span style="color: #cc0000; font-style: italic;"&gt;&lt;&lt;EOF
	{
		"containerOverrides": [
		    {
		        "name": $1,
		        "command": [
		            $2
		        ]
		    }
		]
	}
EOF&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${OVERRIDES}&lt;/span&gt;"&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Process each line in a selected file&lt;/span&gt;
parse_line&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# All lines to be processed must start with the word drush to be considered&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# This grep / sed combination will turn the drush command into docker cmd syntax&lt;/span&gt;
    &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #660033;"&gt;-e&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"^drush"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${1}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;while&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;read&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; line ; &lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
        &lt;span style="color: #007800;"&gt;cmd&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #007800;"&gt;$line&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/[^ ][^ ]*/"&amp;"/g'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/\s+/,/g'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; &lt;span style="color: #660033;"&gt;-r&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'s/drush/vendor\/bin\/drush/'&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
        &lt;span style="color: #666666; font-style: italic;"&gt;# @BUG with quoting in dotenv and how I load into environment. Appears to add newlines making it difficult to add quotes later.&lt;/span&gt;
        &lt;span style="color: #666666; font-style: italic;"&gt;# So already added quotes for $CORE_TASK_DEFINITION_NAME in .env file but need the unquoted version in&lt;/span&gt;
        &lt;span style="color: #666666; font-style: italic;"&gt;# --task-definition flag so unquote here&lt;/span&gt;
        &lt;span style="color: #007800;"&gt;TASK_DEF_UNQUOTE&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #800000;"&gt;${CORE_TASK_DEFINITION_NAME}&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sed&lt;/span&gt; s&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;\"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;//&lt;/span&gt;g&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
        &lt;span style="color: #666666; font-style: italic;"&gt;# Now execute the command to start the container with the drush cmd&lt;/span&gt;
        &lt;span style="color: #007800;"&gt;FARGATE_TASK&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs run-task \
            &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_CLUSTER_NAME}&lt;/span&gt;"&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--task-definition&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${TASK_DEF_UNQUOTE}&lt;/span&gt;"&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--network-configuration&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(set_network_configuration  ${ECS_SUBNET_1} ${ECS_SUBNET_2}  ${ECS_SECURITY_GROUP})&lt;/span&gt;"&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--launch-type&lt;/span&gt; FARGATE \
            &lt;span style="color: #660033;"&gt;--platform-version&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'1.4.0'&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_DEFAULT_REGION}&lt;/span&gt;"&lt;/span&gt; \
            &lt;span style="color: #660033;"&gt;--overrides&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(set_overrides_command ${CORE_TASK_DEFINITION_NAME} ${cmd})&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .tasks&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.taskArn -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
        &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;!&lt;/span&gt;= &lt;span style="color: #000000;"&gt;0&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Fargate Run Task Failed."&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #007800;"&gt;$?&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;elif&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt;  &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_TASK}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Unspecified Fargate Run Task Failure."&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;else&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Cmd run is &lt;span style="color: #007800;"&gt;${cmd}&lt;/span&gt;"&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
        &lt;span style="color: #666666; font-style: italic;"&gt;# Loop round to check on the status of the task. Can't run in parallel so have to wait for each task to finish&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;while&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;true&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
            &lt;span style="color: #007800;"&gt;FARGATE_STATUS&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs describe-tasks &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_CLUSTER_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tasks&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_TASK}&lt;/span&gt;"&lt;/span&gt;  &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .tasks&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.lastStatus -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
            &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #660033;"&gt;-z&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_STATUS}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
                &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Unspecified Fargate Describe Task Failure."&lt;/span&gt;
                &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
            &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_STATUS}&lt;/span&gt;"&lt;/span&gt;
 
            &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_STATUS}&lt;/span&gt;"&lt;/span&gt; == &lt;span style="color: #ff0000;"&gt;"STOPPED"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;||&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${FARGATE_STATUS}&lt;/span&gt;"&lt;/span&gt; == &lt;span style="color: #ff0000;"&gt;"DEPROVISIONING"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
                  &lt;span style="color: #7a0874; font-weight: bold;"&gt;break&lt;/span&gt;
            &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
            &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;20&lt;/span&gt;
        &lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;
 
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Drush command completed"&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get a list of all the files in the directory and process&lt;/span&gt;
parse_directory&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# loop though all the files in the directory&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;in&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${1}&lt;/span&gt;"&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;/*&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
        &lt;span style="color: #007800;"&gt;base&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(basename ${file})&lt;/span&gt;"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${base}&lt;/span&gt; being parsed"&lt;/span&gt;
        parse_line &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${file}&lt;/span&gt;"&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
parse_directory &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${1}&lt;/span&gt;"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;ECS Deploy Script&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The main ECS deploy shell script uses AWS CLI &lt;em&gt;ecs update-service &lt;/em&gt; to force a new deployment. This means that when the Fargate bundles are recycling any new codebase and NGINX Docker image will be used from AWS ECR. The process can take a few minutes so I have added a loop facility which uses AWS CLI &lt;em&gt;ecs describe-services&lt;/em&gt; to capture the current deployment status and act accordingly. Note I am using the previously mentioned &lt;em&gt;jq&lt;/em&gt; utility to interrogate the long JSON response from the CLI and whittle it down to the status field which should contain the word "COMPLETED" or "FAILED" or "IN_PROGRESS".&lt;br /&gt;&lt;strong&gt;deploy-scripts/ecs-service-deploy.sh&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#!/bin/bash&lt;/span&gt;
 
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Use the aws cli to force deploy Fargate task running in ECS service&lt;/span&gt;
aws ecs update-service &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_CLUSTER_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--service&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_SERVICE_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--force-new-deployment&lt;/span&gt; &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_DEFAULT_REGION}&lt;/span&gt;"&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Give it a few seconds to take effect&lt;/span&gt;
&lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;5&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Get the deployment status by looping over the deployment&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# Try for a maximum of 20 minutes then give up. Chances are after 20 minutes of incomplete&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# deployment there is a problem in the task definition&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; i &lt;span style="color: #000000; font-weight: bold;"&gt;in&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #000000;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;6&lt;/span&gt; &lt;span style="color: #000000;"&gt;7&lt;/span&gt; &lt;span style="color: #000000;"&gt;8&lt;/span&gt; &lt;span style="color: #000000;"&gt;9&lt;/span&gt; &lt;span style="color: #000000;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;21&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;do&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${i}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;-eq&lt;/span&gt; &lt;span style="color: #000000;"&gt;21&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Timed out before could determine if deployment succeeded"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;1&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
    &lt;span style="color: #007800;"&gt;STATUS&lt;/span&gt;=&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;aws ecs describe-services &lt;span style="color: #660033;"&gt;--cluster&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_CLUSTER_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--services&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${ECS_SERVICE_NAME}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #660033;"&gt;--region&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AWS_DEFAULT_REGION}&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; jq .services&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.deployments&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;.rolloutState -r&lt;span style="color: #000000; font-weight: bold;"&gt;`&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Was it successful?&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${STATUS}&lt;/span&gt;"&lt;/span&gt; = &lt;span style="color: #ff0000;"&gt;"COMPLETED"&lt;/span&gt;  &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Deployment succeeded"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;0&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# Anything we need to be concerned about?&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;elif&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${STATUS}&lt;/span&gt;"&lt;/span&gt; = &lt;span style="color: #ff0000;"&gt;"FAILED"&lt;/span&gt;  &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Deployment failed"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;2&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# If still deploying echo this&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;elif&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${STATUS}&lt;/span&gt;"&lt;/span&gt; = &lt;span style="color: #ff0000;"&gt;"IN_PROGRESS"&lt;/span&gt;  &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;; &lt;span style="color: #000000; font-weight: bold;"&gt;then&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Deployment in progress"&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;else&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Unknown status "&lt;/span&gt;&lt;span style="color: #800000;"&gt;${STATUS}&lt;/span&gt;&lt;span style="color: #ff0000;"&gt;" so quitting"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;exit&lt;/span&gt; &lt;span style="color: #000000;"&gt;3&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;fi&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Wait a minute before retrying&lt;/span&gt;
    &lt;span style="color: #c20cb9; font-weight: bold;"&gt;sleep&lt;/span&gt; &lt;span style="color: #000000;"&gt;60&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;done&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Ad hoc Drush Commands&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The solution provides the capability to run &lt;em&gt;drush&lt;/em&gt; during the pre- and post-deploy scripts. But what about running &lt;em&gt;drush&lt;/em&gt; commands on an ad hoc basis from a remote laptop? This is often required by developers or devops and would be crucial for the management of a Drupal 9 website. Stay tuned for a future blog on how to achieve this! &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/taxonomy/term/121" hreflang="en"&gt;Drupal 9&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sun, 17 Oct 2021 08:31:46 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">182 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Hosting Drupal 9 on AWS Fargate Part 1: Local Development </title>
  <link>http://badzilla.co.uk/hosting-drupal-9-aws-fargate-part-1-local-development</link>
  <description>
&lt;span&gt;Hosting Drupal 9 on AWS Fargate Part 1: Local Development &lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sun, 19/09/2021 - 09:46&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Introduction&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Welcome to a series of blogs on hosting Drupal 9 (or legacy Drupal 8) sites on AWS Fargate. Fargate can now be considered a mature product, and provides a simple serverless containerised platform for hosting web apps. It offers considerable savings over traditional Virtual servers without, if configured correctly, loss of performance. Furthermore it offers greater simplicity of operation and setup then its AWS sibling offering ECS over EC2, and again a cost saving. &lt;/p&gt;

&lt;p&gt;The blogs in this series will cover important considerations such as the pipelines to deploy your codebase within Docker images, and their storage; set up of the Drupal S3FS module along with the CloudFront accelerator and S3 object store; auto scaling of the Fargate tasks; load testing your app to ensure you are fully optimised; and how to run your Drush commands in short living Fargate tasks. &lt;/p&gt;

&lt;p&gt;This first blog will cover your team's local environment and how its build will ensure your path to Fargate deploy is smooth, with as much reuse of the configuration in production as possible. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Objective&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-09/FargateServices_1.jpeg?itok=fq097hDo 325w, https://assets.badzilla.co.uk/styles/max_650x650/s3/2021-09/FargateServices_1.jpeg?itok=SeCQrttM 650w, https://assets.badzilla.co.uk/styles/max_1300x1300/s3/2021-09/FargateServices_1.jpeg?itok=vTdoq1tf 1300w, https://assets.badzilla.co.uk/styles/max_2600x2600/s3/2021-09/FargateServices_1.jpeg?itok=TaitKa6l 1581w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-09/FargateServices_1.jpeg?itok=fq097hDo" alt="Fargate Services and Tasks" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The objective is to stand up a Fargate task running as a service which will be the web app, and it will persist and auto scale. Also have Fargate tasks to run which will run Drush commands, stood up on a per Drush command basis, and terminating after each Drush command completes. The diagram above shows the Docker images requires to achieve our goal. &lt;/p&gt;
&lt;h3&gt;Drupal Core + FPM PHP + Codebase&lt;/h3&gt;
&lt;p&gt;The intention is to use the official Drupal FPM Docker image using Alpine, and be as up to date as possible with the versioning. Note that the Alpine build has been chosen since it's an extremely lightweight version of Linux, based on busybox which has a very small footprint. This comes at a price - those with Ubuntu experience will have to learn new commands. For instance Alpine uses the &lt;em&gt;apk&lt;/em&gt; package manager instead of &lt;em&gt;apt-get&lt;/em&gt;. The web app's codebase - ie all the configuration and custom modules and themes created by the dev team - will be copied into this image. &lt;/p&gt;
&lt;h3&gt;Drupal Core + FPM PHP + Codebase + Exec command&lt;/h3&gt;
&lt;p&gt;This will be the Fargate task to run one off Drush commands. Since the codebase will already contain Drush binaries in &lt;em&gt;vendor/bin/drush&lt;/em&gt;, it will be the same as the previously mentioned image. Notwithstanding this, it won't persist. It will use the Fargate equivalent of the Docker command to &lt;em&gt;exec&lt;/em&gt; a particular command and then quit. &lt;/p&gt;
&lt;h3&gt;Memcached&lt;/h3&gt;
&lt;p&gt;I have elected to run individual Memcached caching in each task running in the Web App service. Memcached will be used for caching the Drupal MySQL cache tables and for page caching for anonymous users. There is an alternative strategy to this - centralise the caching using for instance the AWS ElastiCache with Memcached product. Each task in the web service would have an endpoint to the same centralised ElastiCache instance. This would be the preferred option if your website is largely serving logged in traffic, and if you are running an eCommerce site with the users' baskets stored in Memcached. Since that doesn't apply to my own site, and I would like to keep costs down too, my feeling is having Memcached as part of the Fargate task is a better fit. &lt;/p&gt;
&lt;h3&gt;nginx&lt;/h3&gt;
&lt;p&gt;A web server is needed, and I've elected for &lt;em&gt;nginx&lt;/em&gt; although &lt;em&gt;Apache&lt;/em&gt; would also be a good choice. My rationale for selecting nginx is I would like to add the feature of nginx serving slightly stale cached pages when the origin is returning 5xx errors. This would give a seamless switch-over when a task becomes unhealthy - during the period AWS determines that a task is returning errors and has crossed the unhealthy threshold, nginx could still serve pages which would be less than 5 minutes old. The task would then be drained and removed from the pool with no problem noticeable to the end user. This will be the subject of a blog at a later date. &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Using a local Virtual Machine&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Those who know me well will know I am not an advocate of using my laptop's OS for development purposes. The reason being that with multiple clients and with multiple projects in each, my host OS would quickly become a mess of different development tooling and versions which could collide and could also generate inconsistencies with other devs in the team should say different versions of bin files end up in the $PATH. &lt;/p&gt;

&lt;p&gt;My ethos has always been &lt;em&gt;do not pollute your host OS! Always use VMs for development!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I have created my own VM for Docker based implementations. My belief is if the target deploy is using Docker containers then the local development environment should match this as much as is practicable. In fact it's impossible to match the ECS/Fargate environment exactly, but it is certainly possible to use Docker with &lt;em&gt;docker-compose&lt;/em&gt; to simulate closely what will be seen in prod. &lt;/p&gt;

&lt;p&gt;My VM can be found in GitHub by clicking on &lt;a href="https://github.com/sanddevil/dockervm"&gt;this link&lt;/a&gt;. It is a very lightweight VM and can be orchestrated easily using Vagrant and Ansible. PHP and MySQL are deliberately not included in the playbook since all development work will be undertaken by using Docker containers.&lt;/p&gt;

&lt;p&gt;All my localhost config examples in this blog will have come from using my DockerVM mentioned above. If you intend to follow this blog closely, you will need to install it, but read the instructions in the README.md carefully!&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Composer&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Once you've got a lightweight VM up and running (hopefully mine), and ssh'd into it, and cloned your repo, you will need to build out the dependencies using &lt;em&gt;composer install&lt;/em&gt;. So how do we go about this when there is no composer and no PHP in the VM? There are two choices:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Use the official Docker Composer image&lt;/li&gt;
	&lt;li&gt;Use the latest official Docker Drupal image (9.2.6-php7.4-fpm-alpine.3.14 at time of writing this blog)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I chose the official Docker Composer image purely because (a) there was more documentation on it readily available, and (b) I wasn't sure at the time whether the Drupal image bundled Composer. It does, and it will be used in the Bitbucket Pipeline later so you may want to select that instead for consistency, but if you do, you'll have to change my composer commands slightly.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Ok so let's build our composer image. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ docker run &lt;span style="color: #660033;"&gt;--rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;--interactive&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tty&lt;/span&gt; &lt;span style="color: #660033;"&gt;--volume&lt;/span&gt; &lt;span style="color: #007800;"&gt;$PWD&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;app composer &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; &lt;span style="color: #660033;"&gt;--ignore-platform-reqs&lt;/span&gt;
Unable to &lt;span style="color: #c20cb9; font-weight: bold;"&gt;find&lt;/span&gt; image &lt;span style="color: #ff0000;"&gt;'composer:latest'&lt;/span&gt; locally
latest: Pulling from library&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;composer
a0d0a0d46f8b: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
153eea49496a: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
11efd0df1fcb: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
b3f3214c344d: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
9abd2f85688c: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
83d85b95eb4c: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
923d73ddadfa: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
711b5c4b02a7: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
ee08fa481788: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
5f9f812bf61d: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
28b3ecec72d5: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
a5ffb14bc4f9: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
d92aff3e5aec: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
cd0274c84e75: Pull &lt;span style="color: #7a0874; font-weight: bold;"&gt;complete&lt;/span&gt; 
Digest: sha256:33d2c1d9fb7311cb8f215a8f52669894ef534292ac5d331347f929c27e317bb1
Status: Downloaded newer image &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; composer:latest
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; DrupalProject\composer\ScriptHandler::checkComposerVersion
Installing dependencies from lock &lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;including require-dev&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
Verifying lock &lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt; contents can be installed on current platform.
  - Downloading composer&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;installers &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;v2.0.1&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt;---- SNIPPED ----&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;
  - Copy &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;web-root&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;profiles&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;README.txt from assets&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;scaffold&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;profiles.README.txt
  - Copy &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;web-root&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;themes&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;README.txt from assets&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;scaffold&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;themes.README.txt
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; DrupalProject\composer\ScriptHandler::createRequiredFiles
Created a sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files directory with &lt;span style="color: #c20cb9; font-weight: bold;"&gt;chmod&lt;/span&gt; 0777&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Success! Note that there is a requirement to use the composer flag --ignore-platform-reqs since it expects ext-gd locally which obviously we don't have.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;docker-compose: Codebase + FPM&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;In preparation for creating a docker-compose file we'll need to build out an image containing the latest Drupal 9 Docker image + our codebase once composer install has been run.  This will need a Dockerfile, and we can add APCu caching in the Dockerfile for greater Drupal performance. I also noted that Memcached API library needs to be added to Dockerfile since it is my intention to connect to a Memcached server for cache management in the container bundle.  The Dockerfile is listed below. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;FROM drupal:9.2.6-php7.4-fpm-alpine3.14
 
&lt;span style="color: #666666; font-style: italic;"&gt;# Copy the artefact (on Bitbucket) or local files into the image&lt;/span&gt;
COPY .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;opt&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;drupal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.
 
&lt;span style="color: #666666; font-style: italic;"&gt;# PHP Memcached which needs the libmemcached API&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;# Bug in Apline - creates extensions in the wrong directory so add them in correct location&lt;/span&gt;
RUN apk add php7-igbinary php7-pecl-memcached libmemcached \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"extension=memcached.so"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf.d&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;docker-php-ext-memcached.ini \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"extension=igbinary.so"&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf.d&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;docker-php-ext-igbinary.ini \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;mv&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lib&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php7&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;memcached.so &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lib&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;extensions&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;no-debug-non-zts-&lt;span style="color: #000000;"&gt;20190902&lt;/span&gt; \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;mv&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lib&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php7&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;modules&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;igbinary.so &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;usr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;lib&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;php&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;extensions&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;no-debug-non-zts-&lt;span style="color: #000000;"&gt;20190902&lt;/span&gt;
 
&lt;span style="color: #666666; font-style: italic;"&gt;# APCu cache&lt;/span&gt;
RUN apk add &lt;span style="color: #660033;"&gt;--update&lt;/span&gt; &lt;span style="color: #660033;"&gt;--no-cache&lt;/span&gt; &lt;span style="color: #660033;"&gt;--virtual&lt;/span&gt; .build-dependencies &lt;span style="color: #007800;"&gt;$PHPIZE_DEPS&lt;/span&gt; \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; pecl &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; apcu \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker-php-ext-enable apcu \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; pecl clear-cache \
    &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; apk del .build-dependencies&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;docker-compose: nginx image&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;We will also need to build out an nginx image with the standard Drupal configuration. To do this I created a docker directory at the top level of the repo (i.e. a sibling of web directory) as such:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;tree&lt;/span&gt; docker
docker
├── core-drupal
├── memcached
└── nginx
    ├── fargate
    │   ├── default.conf
    │   ├── Dockerfile
    │   └── nginx.conf
    └── &lt;span style="color: #7a0874; font-weight: bold;"&gt;local&lt;/span&gt;
        ├── default.conf
        ├── Dockerfile
        └── nginx.conf
 
&lt;span style="color: #000000;"&gt;5&lt;/span&gt; directories, &lt;span style="color: #000000;"&gt;6&lt;/span&gt; files&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
You'll note that I have two sets of config files - one for AWS Fargate and one for local development. In fact the differences are minimal and will be discussed later. The local files are below&lt;br /&gt;
&lt;strong&gt;nginx.conf&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;user  nginx;
worker_processes  auto;
 
error_log  &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;log&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;error.log notice;
pid        &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;run&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx.pid;
 
 
events &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    worker_connections  &lt;span style="color: #000000;"&gt;1024&lt;/span&gt;;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
 
http &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    include       &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;mime.types;
    default_type  application&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;octet-stream;
 
    fastcgi_buffers &lt;span style="color: #000000;"&gt;16&lt;/span&gt; 16k;
    fastcgi_buffer_size 32k;
 
    log_format  main  &lt;span style="color: #ff0000;"&gt;'$remote_addr - $remote_user [$time_local] "$request" '&lt;/span&gt;
                      &lt;span style="color: #ff0000;"&gt;'$status $body_bytes_sent "$http_referer" '&lt;/span&gt;
                      &lt;span style="color: #ff0000;"&gt;'"$http_user_agent" "$http_x_forwarded_for"'&lt;/span&gt;;
 
    access_log  &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;var&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;log&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;access.log  main;
 
    sendfile        on;
    &lt;span style="color: #666666; font-style: italic;"&gt;#tcp_nopush     on;&lt;/span&gt;
 
    keepalive_timeout  &lt;span style="color: #000000;"&gt;65&lt;/span&gt;;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;#gzip  on;&lt;/span&gt;
 
    include &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf.d&lt;span style="color: #000000; font-weight: bold;"&gt;/*&lt;/span&gt;.conf;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;strong&gt;default.conf&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;  server &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    server_name badzilla-fargate.test;
    root &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;opt&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;drupal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;web; &lt;span style="color: #666666; font-style: italic;"&gt;## &lt;-- Your only path reference.&lt;/span&gt;
 
    location = &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;favicon.ico &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      log_not_found off;
      access_log off;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location = &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;robots.txt &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      allow all;
      log_not_found off;
      access_log off;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location ~ \..&lt;span style="color: #000000; font-weight: bold;"&gt;*/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;\.php$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;403&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location ~ ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*/&lt;/span&gt;private&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;403&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Block access to scripts in site files directory&lt;/span&gt;
    location ~ ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;sites&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;+&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;\.php$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      deny all;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Allow "Well-Known URIs" as per RFC 5785&lt;/span&gt;
    location ~&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt; ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.well-known&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      allow all;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Block access to "hidden" files and directories whose names begin with a&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# period. This includes directories used by version control systems such&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# as Subversion or Git to store control files.&lt;/span&gt;
    location ~ &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;^&lt;span style="color: #000000; font-weight: bold;"&gt;|/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;\. &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;403&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;# try_files $uri @rewrite; # For Drupal &lt;= 6&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;index.php?&lt;span style="color: #007800;"&gt;$query_string&lt;/span&gt;; &lt;span style="color: #666666; font-style: italic;"&gt;# For Drupal &gt;= 7&lt;/span&gt;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location &lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;rewrite &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;#rewrite ^/(.*)$ /index.php?q=$1; # For Drupal &lt;= 6&lt;/span&gt;
      rewrite ^ &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;index.php; &lt;span style="color: #666666; font-style: italic;"&gt;# For Drupal &gt;= 7&lt;/span&gt;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Don't allow direct access to PHP files in the vendor directory.&lt;/span&gt;
    location ~ &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;vendor&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;\.php$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      deny all;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;404&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Protect files and directories from prying eyes.&lt;/span&gt;
    location ~&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt; \.&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;engine&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;inc&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;module&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;profile&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;po&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;sh&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;sql&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;theme&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;twig&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;tpl&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;\.php&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;?&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;xtmpl&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;yml&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;~&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;\.sw&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;op&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;\.bak&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;\.orig&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;\.save&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;?$&lt;span style="color: #000000; font-weight: bold;"&gt;|/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;\.&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;?&lt;span style="color: #000000; font-weight: bold;"&gt;!&lt;/span&gt;well-known&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;Entries.&lt;span style="color: #000000; font-weight: bold;"&gt;*|&lt;/span&gt;Root&lt;span style="color: #000000; font-weight: bold;"&gt;|/&lt;/span&gt;&lt;span style="color: #666666; font-style: italic;"&gt;#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ {&lt;/span&gt;
      deny all;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;404&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# In Drupal 8, we must also match new paths where the '.php' appears in&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# the middle, such as update.php/selection. The rule we use is strict,&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# and only allows this pattern with the update.php front controller.&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# This allows legacy path aliases in the form of&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# blog/index.php/legacy-path to continue to route to Drupal nodes. If&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# you do not have any paths like that, then you might prefer to use a&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# laxer rule, such as:&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;#   location ~ \.php(/|$) {&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# The laxer rule will continue to work if Drupal uses this new URL&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# pattern with front controllers other than update.php in a future&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# release.&lt;/span&gt;
    location ~ &lt;span style="color: #ff0000;"&gt;'\.php$|^/update.php'&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      fastcgi_split_path_info ^&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;.+?\.php&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;|/&lt;/span&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;$;
      &lt;span style="color: #666666; font-style: italic;"&gt;# Ensure the php file exists. Mitigates CVE-2019-11043&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$fastcgi_script_name&lt;/span&gt; =&lt;span style="color: #000000;"&gt;404&lt;/span&gt;;
      &lt;span style="color: #666666; font-style: italic;"&gt;# Security note: If you're running a version of PHP older than the&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;# latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;# See http://serverfault.com/q/627903/94922 for details.&lt;/span&gt;
      include fastcgi_params;
      &lt;span style="color: #666666; font-style: italic;"&gt;# Block httpoxy attacks. See https://httpoxy.org/.&lt;/span&gt;
      fastcgi_param HTTP_PROXY &lt;span style="color: #ff0000;"&gt;""&lt;/span&gt;;
      fastcgi_param SCRIPT_FILENAME &lt;span style="color: #007800;"&gt;$document_root&lt;/span&gt;&lt;span style="color: #007800;"&gt;$fastcgi_script_name&lt;/span&gt;;
      fastcgi_param PATH_INFO &lt;span style="color: #007800;"&gt;$fastcgi_path_info&lt;/span&gt;;
      fastcgi_param QUERY_STRING &lt;span style="color: #007800;"&gt;$query_string&lt;/span&gt;;
      fastcgi_intercept_errors on;
      &lt;span style="color: #666666; font-style: italic;"&gt;# PHP 5 socket location.&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;#fastcgi_pass unix:/var/run/php5-fpm.sock;&lt;/span&gt;
      &lt;span style="color: #666666; font-style: italic;"&gt;# PHP 7 socket location.&lt;/span&gt;
&lt;span style="color: #666666; font-style: italic;"&gt;#      fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;&lt;/span&gt;
      fastcgi_pass fpm:&lt;span style="color: #000000;"&gt;9000&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# S3FS Module&lt;/span&gt;
    location ~ ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;s3&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;styles&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;rewrite;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    location ~&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt; \.&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;js&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;css&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;png&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;jpg&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;jpeg&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;gif&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;ico&lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt;svg&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;rewrite;
      expires max;
      log_not_found off;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Fighting with Styles? This little gem is amazing.&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# location ~ ^/sites/.*/files/imagecache/ { # For Drupal &lt;= 6&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;#location ~ ^/sites/.*/files/styles/ { # For Drupal &gt;= 7&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;#  try_files $uri @rewrite;&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;#}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Handle private files through Drupal. Private file's path can come&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# with a language prefix.&lt;/span&gt;
    location ~ ^&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;a-z\-&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;+&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;?&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;system&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt; &lt;span style="color: #666666; font-style: italic;"&gt;# For Drupal &gt;= 7&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;index.php?&lt;span style="color: #007800;"&gt;$query_string&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
 
    &lt;span style="color: #666666; font-style: italic;"&gt;# Enforce clean URLs&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# Removes index.php from urls like www.example.com/index.php/my-page --&gt; www.example.com/my-page&lt;/span&gt;
    &lt;span style="color: #666666; font-style: italic;"&gt;# Could be done with 301 for permanent or other redirect codes.&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #007800;"&gt;$request_uri&lt;/span&gt; ~&lt;span style="color: #000000; font-weight: bold;"&gt;*&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"^(.*/)index\.php/(.*)"&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;307&lt;/span&gt; &lt;span style="color: #007800;"&gt;$1&lt;/span&gt;&lt;span style="color: #007800;"&gt;$2&lt;/span&gt;;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;strong&gt;Dockerfile&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;FROM nginx:1.21.1-alpine
COPY .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default.conf &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;conf.d&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
COPY .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx.conf &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;etc&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Some commentary is required here. You'll see in the default.conf file there is a snippet:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;    &lt;span style="color: #666666; font-style: italic;"&gt;# S3FS Module&lt;/span&gt;
    location ~ ^&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;s3&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;files&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;styles&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      try_files &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;rewrite;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
This is because the assets are not served locally - they are stored in an AWS S3 bucket with the AWS CloudFront accelerator providing edge capabilities. I will provide a further blog at a later date on setting all this up but in essence, assets shouldn't be kept in individual Fargate tasks, so either an AWS S3 / CloudFront solution needs to be utilised or an AWS EFS drive. &lt;br /&gt;&lt;br /&gt;
Now let's see what the differences are between the local configuration and Fargate. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;diff&lt;/span&gt; docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;local&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default.conf docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;fargate&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;default.conf 
2c2
&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt;     server_name badzilla-fargate.test;
&lt;span style="color: #660033;"&gt;---&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     server_name badzilla.co.uk www.badzilla.co.uk;
4a5,&lt;span style="color: #000000;"&gt;10&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     &lt;span style="color: #666666; font-style: italic;"&gt;# User Agent ELB-HealthChecker sends no headers with the request so nginx by default will respond with a 400&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     &lt;span style="color: #666666; font-style: italic;"&gt;# Fix with this&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     location = &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;health &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;         &lt;span style="color: #7a0874; font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: #000000;"&gt;200&lt;/span&gt;;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;     &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; 
92c98
&lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt;       fastcgi_pass fpm:&lt;span style="color: #000000;"&gt;9000&lt;/span&gt;;
&lt;span style="color: #660033;"&gt;---&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;       fastcgi_pass 127.0.0.1:&lt;span style="color: #000000;"&gt;9000&lt;/span&gt;;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Ok there are three differences. The first is obvious - I am using different server names dependent on the environment. The second difference is the AWS health checking capability that I have included for Fargate but not needed locally. I use the Drupal health_check module by the way, but the problem resides with the AWS Application Load Balancer health check feature. It sends requests to nginx without headers which nginx doesn't like - and always replies with a 400 response. This snippet fixes that problem. The third difference relates to how Fargate handles Docker networking. It is much simplified and all containers in the Fargate task use 127.0.0.1 for communication. Locally I am using a label named &lt;strong&gt;fpm&lt;/strong&gt; for fastcgi_pass communication between nginx and FPM.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;docker-compose: MariaDB and Memcached&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The use of MariaDB is the most significant difference between the local environment and Fargate. Fargate connects to a MariaDB instance in AWS RDS, whilst the local MariaDB persists its data in the VM. I did consider using another RDS instance for local development, but that would require public access to the database which I wasn't keen to do for security reasons. In addition there is a cost implication which isn't viable for a hobby project like my blog. I am using the standard Docker images for both MariaDB and Memcached locally.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;docker-compose Configuration&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;strong&gt;docker-compose&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;version: &lt;span style="color: #ff0000;"&gt;"3"&lt;/span&gt;
 
services:
  mariadb:
    image: &lt;span style="color: #ff0000;"&gt;"mariadb:&lt;span style="color: #007800;"&gt;${MARIADB_VERSION}&lt;/span&gt;"&lt;/span&gt;
    restart: &lt;span style="color: #ff0000;"&gt;'always'&lt;/span&gt;
    container_name: mariadb-drupal
    volumes:
      - &lt;span style="color: #ff0000;"&gt;"/var/lib/mysql/data:&lt;span style="color: #007800;"&gt;${MARIADB_DATA_DIR}&lt;/span&gt;"&lt;/span&gt;
      - &lt;span style="color: #ff0000;"&gt;"/var/lib/mysql/logs:&lt;span style="color: #007800;"&gt;${MARIADB_LOG_DIR}&lt;/span&gt;"&lt;/span&gt;
      - &lt;span style="color: #ff0000;"&gt;"/var/docker/mariadb/conf:/etc/mysql"&lt;/span&gt;
    environment:
      MYSQL_ROOT_PASSWORD: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_ROOT_PASSWORD}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_DATABASE: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_DATABASE}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_USER: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_USER}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_PASSWORD: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_PASSWORD}&lt;/span&gt;"&lt;/span&gt;
  drupal:
    image: core-drupal:latest
    container_name: core-drupal
    depends_on:
      - mariadb
      - memcached
    volumes:
      - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;opt&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;drupal
    restart: &lt;span style="color: #ff0000;"&gt;'always'&lt;/span&gt;
    environment:
      MYSQL_DATABASE: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_DATABASE}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_USER: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_USER}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_PASSWORD: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_PASSWORD}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_HOSTNAME: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_HOSTNAME}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_NAMESPACE: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_NAMESPACE}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_DRIVER: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_DRIVER}&lt;/span&gt;"&lt;/span&gt;
      MYSQL_PORT: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${MYSQL_PORT}&lt;/span&gt;"&lt;/span&gt;
      AH_SITE_ENVIRONMENT: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${AH_SITE_ENVIRONMENT}&lt;/span&gt;"&lt;/span&gt;
      S3FS_ACCESS_KEY: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_ACCESS_KEY}&lt;/span&gt;"&lt;/span&gt;
      S3FS_SECRET_KEY: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_SECRET_KEY}&lt;/span&gt;"&lt;/span&gt;
      S3FS_BUCKET: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_BUCKET}&lt;/span&gt;"&lt;/span&gt;
      S3FS_AWS_REGION: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_AWS_REGION}&lt;/span&gt;"&lt;/span&gt;
      S3FS_CLOUDFRONT_CNAME: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_CLOUDFRONT_CNAME}&lt;/span&gt;"&lt;/span&gt;
      S3FS_USE_S3_PUBLIC: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_USE_S3_PUBLIC}&lt;/span&gt;"&lt;/span&gt;
      S3FS_USE_CNAME: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_USE_CNAME}&lt;/span&gt;"&lt;/span&gt;
      S3FS_USE_HTTPS: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_USE_HTTPS}&lt;/span&gt;"&lt;/span&gt;
      S3FS_TWIG_PATH: &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;${S3FS_TWIG_PATH}&lt;/span&gt;"&lt;/span&gt;
 
  nginx:
    image: nginx-drupal:latest
    container_name: nginx-drupal
    links:
      - drupal:fpm
    ports:
      - &lt;span style="color: #ff0000;"&gt;"80:80"&lt;/span&gt;
      - &lt;span style="color: #ff0000;"&gt;"443:443"&lt;/span&gt;
    depends_on:
      - drupal
    restart: &lt;span style="color: #ff0000;"&gt;'always'&lt;/span&gt;
    volumes:
      - .&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;opt&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;drupal
  memcached:
    image: memcached:alpine3.14
    restart: &lt;span style="color: #ff0000;"&gt;'always'&lt;/span&gt;
    container_name: memcached-drupal
    ports:
      - &lt;span style="color: #ff0000;"&gt;"11211:11211"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Note I have all my settings held in the environment. I also use the vlucas/phpdotenv composer dependency so these environmental variables are accessible in Drupal through a dot env file.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Shortcuts&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=ZK1WZKNL 325w, https://assets.badzilla.co.uk/styles/max_650x650/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=5u4dc1HE 650w, https://assets.badzilla.co.uk/styles/max_1300x1300/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=4Rdov1w4 1300w, https://assets.badzilla.co.uk/styles/max_2600x2600/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=9Jbps5Ok 1500w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/styles/max_325x325/s3/2021-09/Screenshot%202021-09-26%20at%2011.33.54-scaled.png?itok=ZK1WZKNL" alt="start-web" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Remembering commands to build the Docker images, gain command line access to MariaDB, importing and exporting databases etc is an exercise in tedium I'd rather avoid. I have built a make file with shortcuts although command line aliases could also have been used.&lt;br /&gt;
&lt;strong&gt;Makefile&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;.DEFAULT_GOAL := &lt;span style="color: #7a0874; font-weight: bold;"&gt;help&lt;/span&gt;
 
 
help:
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"See the README.md for available options"&lt;/span&gt;
 
exportdb: set-env
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Exporting the database"&lt;/span&gt;
	docker &lt;span style="color: #7a0874; font-weight: bold;"&gt;exec&lt;/span&gt; &lt;span style="color: #660033;"&gt;-i&lt;/span&gt; mariadb-drupal &lt;span style="color: #c20cb9; font-weight: bold;"&gt;bash&lt;/span&gt; &lt;span style="color: #660033;"&gt;-c&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'mysqldump -u $$MYSQL_USER -p$$MYSQL_PASSWORD $$MYSQL_DATABASE'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
importdb: set-env
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Importing the database"&lt;/span&gt;
	docker &lt;span style="color: #7a0874; font-weight: bold;"&gt;exec&lt;/span&gt; &lt;span style="color: #660033;"&gt;-i&lt;/span&gt; mariadb-drupal &lt;span style="color: #c20cb9; font-weight: bold;"&gt;bash&lt;/span&gt; &lt;span style="color: #660033;"&gt;-c&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'mysql -u $$MYSQL_USER -p$$MYSQL_PASSWORD $$MYSQL_DATABASE'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
 
core-drupal: set-env
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Building Drupal Core Docker from Official Image"&lt;/span&gt;
	docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; core-drupal .
 
composer-require:
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Composer require running"&lt;/span&gt;
	docker run &lt;span style="color: #660033;"&gt;--rm&lt;/span&gt; &lt;span style="color: #660033;"&gt;--interactive&lt;/span&gt; &lt;span style="color: #660033;"&gt;--tty&lt;/span&gt; &lt;span style="color: #660033;"&gt;--volume&lt;/span&gt; $&lt;span style="color: #007800;"&gt;$PWD&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;app  &lt;span style="color: #660033;"&gt;--volume&lt;/span&gt; $&lt;span style="color: #800000;"&gt;${COMPOSER_HOME:-$$HOME/.composer}&lt;/span&gt;:&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;tmp composer require &lt;span style="color: #ff0000;"&gt;"&lt;span style="color: #007800;"&gt;$(module)&lt;/span&gt;"&lt;/span&gt;  &lt;span style="color: #660033;"&gt;--ignore-platform-reqs&lt;/span&gt;
 
build-all: set-env
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Building all non-standard docker images ready for spinning up docker-compose"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; docker&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;nginx&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;local&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;&amp;&amp;&lt;/span&gt; docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; nginx-drupal .
	docker build &lt;span style="color: #660033;"&gt;-t&lt;/span&gt; core-drupal .
 
start-web: set-env
	docker-compose up
 
stop-web:
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Stopping the web app gracefully. Please wait"&lt;/span&gt;
	docker-compose down
 
set-env:
	&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;echo&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"Setting the env variables"&lt;/span&gt;
	&lt;span style="color: #7a0874; font-weight: bold;"&gt;export&lt;/span&gt; $&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;cat&lt;/span&gt; .env &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #660033;"&gt;-v&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'^#'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'\S'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;tr&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'\r'&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;'\0'&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;xargs&lt;/span&gt; &lt;span style="color: #660033;"&gt;-0&lt;/span&gt; -n1&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
So for instance should I want to build the codebase and nginx Docker images I would simply type:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt; build-all&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
To add a new module using composer, the syntax would be:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt; composer-require &lt;span style="color: #007800;"&gt;module&lt;/span&gt;=drupal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;module_name&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Note the requirement to use key=value for parameter substitution in make. Similarly to import a database dump it would be:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt; importdb &lt;span style="color: #007800;"&gt;file&lt;/span&gt;=mydump.sql&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Not included in the make commands because of its interactive nature, to gain access to MariaDB do:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;docker &lt;span style="color: #7a0874; font-weight: bold;"&gt;exec&lt;/span&gt; &lt;span style="color: #660033;"&gt;-it&lt;/span&gt; mariadb-drupal mysql &lt;span style="color: #660033;"&gt;-uusername&lt;/span&gt; &lt;span style="color: #660033;"&gt;-ppassword&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Finally when you do:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #c20cb9; font-weight: bold;"&gt;make&lt;/span&gt; start-web&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
you should see output similar to the screenshot above!&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Drush&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;It's important to have Drush available in your local environment. To achieve this, ensure that drush is a dependency requirement in your composer.json file. If not add it using my shortcut mentioned earlier. This will place drush in path /opt/drupal/vendor/bin inside the drupal-core container which obviously must be running for it to work. Exec-ing a command from the VM command line and escaping it correctly is hard work - so to save you the heartache I've created a shell function in my VM to make light work of it. If you are not using my VM, add this to the bottom of your &lt;strong&gt;/etc/bash.bashrc&lt;/strong&gt; file. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;drush&lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
  &lt;span style="color: #007800;"&gt;PARAMS&lt;/span&gt;=$&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;
  &lt;span style="color: #007800;"&gt;CONTAINER&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"core-drupal"&lt;/span&gt;
  &lt;span style="color: #007800;"&gt;CMD&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"sh -c &lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;/opt/drupal/vendor/bin/drush &lt;span style="color: #007800;"&gt;${PARAMS}&lt;/span&gt;&lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;"&lt;/span&gt;
  &lt;span style="color: #007800;"&gt;DCMD&lt;/span&gt;=&lt;span style="color: #ff0000;"&gt;"docker exec -it &lt;span style="color: #007800;"&gt;$CONTAINER&lt;/span&gt; &lt;span style="color: #007800;"&gt;$CMD&lt;/span&gt;"&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;eval&lt;/span&gt; &lt;span style="color: #007800;"&gt;$DCMD&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Now any Drush command is available to you (when the container is running!)
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;drush cr
 &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;success&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; Cache rebuild complete.&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/taxonomy/term/121" hreflang="en"&gt;Drupal 9&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sun, 19 Sep 2021 08:46:14 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">181 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>AWS Fargate: CI/CD Architecture for Drupal and PHP Frameworks</title>
  <link>http://badzilla.co.uk/aws-fargate-cicd-architecture-drupal-and-php-frameworks</link>
  <description>
&lt;span&gt;AWS Fargate: CI/CD Architecture for Drupal and PHP Frameworks&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sat, 04/01/2020 - 13:45&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Introduction&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;AWS Fargate is a compute engine for Amazon ECS which allows the running of Docker containers without having to provision and manage the underlying EC2 servers. This makes the standing up of Docker bundles immeasurably easier, and thankfully that ease comes with very few limitations. It is often considered the Docker equivalent of AWS Lambda. &lt;/p&gt;

&lt;p&gt;Fargate's ease of use and convenience makes it a natural fit for CI/CD architecture. Apps can be defined as Fargate tasks which are analogous to Docker Bundles, and pipeline stages can be engineered to perform standard activities such as build, automated testing, static analysis, dev playground, and deploy. &lt;/p&gt;

&lt;p&gt;This architecture statement explains how this can be applied to the world of PHP frameworks and Drupal CMS. With a little imagination, and a few tweaks to the ecosystem and Fargate tasks, and the architecture would be valid for other high level languages and frameworks.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Pipeline Stages&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/CI-CD%20Stages.png?itok=gY0r9mcr 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2020-01/CI-CD%20Stages.png?itok=QMs76Kfz 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2020-01/CI-CD%20Stages.png?itok=PPI9yW8U 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2020-01/CI-CD%20Stages.png?itok=WHPePVns 1580w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/CI-CD%20Stages.png?itok=gY0r9mcr" alt="CI/CD Stages" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Before we get into the physical AWS ecosystem, it's worth discussing what we are trying to achieve. I have identified the four main stages in the pipeline in the diagram above. There will be two entry points into the build stage: it will be either automated on a git pull request creation and approval, but also a manual invocation is possible for times when a dev or QA wants to check progress on a feature after a commit but before a PR is created. In PHP frameworks and Drupal 8+ codebases, it is customary to use the dependency management tool &lt;em&gt;composer&lt;/em&gt; which obviates the need to check into vcs contributed plugins and modules. The build stage will also compile the front end themes and JavaScript and minify / uglify at the same - therefore production ready CSS and JS should not be committed into vcs by developers. Once the codebase has been built, it will be copied into a PHP/Apache Docker image and pushed into the AWS ECR repository for later use. &lt;/p&gt;

&lt;p&gt;The automated testing will cover both functional BDD and unit TDD testing against the codebase image that has just been built. Writing TDD against the largely procedural Drupal 7 was onerous and challenging and therefore overlooked in the main. Thankfully Drupal 8 is OOP which makes writing back-end tests with PHPUnit much more straightforward. &lt;/p&gt;

&lt;p&gt;The static analysis will check for code quality, vulnerability, smell, copy and paste detection, and basic lint type checking. &lt;/p&gt;

&lt;p&gt;The deploy step can mean different things to different people. Deployment can mean pushing your built codebase to the production server, or it can mean simply creating a semantic versioning tag, and pushing the codebase artefact to an upstream repository, ready for a manual deployment to prod by Ops staff. I have opted for the latter interpretation in this instance.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;CI/CD Ecosystem&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/FargateEcoSystem.png?itok=CxZMMUbk 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2020-01/FargateEcoSystem.png?itok=XlOMVQn6 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2020-01/FargateEcoSystem.png?itok=4cI6vzBk 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2020-01/FargateEcoSystem.png?itok=soBHoax5 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/FargateEcoSystem.png?itok=CxZMMUbk" alt="Ecosystem" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The physical ecosystem is described below and shown in diagrammatic form above. Whilst on first glance this may appear quite complex, in fact it is largely self-evident with a little explanation. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jenkins&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Jenkins will be the automation tool since it is ubiquitous across the industry and there is a great deal of expertise in the market place. Jenkins has pipeline capability, and new projects should elect to use the Groovy-based declarative scripting DSL. This allows stages to run in parallel, and thus once the build stage is completed, automated testing and static analysis can be concurrent. In addition I propose the standing up of a 'persisting playground' - the built feature branch of the web app with a DNS qualified relevant url which can be shared between devs, QA, and stakeholders. This would be useful for troubleshooting, demonstrations of progress, show and tells etc., and would be torn down at close of business to reduce costs. My tutorial &lt;a href="http://badzilla.co.uk/create-arbitrary-subdomains-aws-fargate-tasks-using-aws-cli"&gt;here&lt;/a&gt; shows how a friendly branch specific url can be created and propagated by AWS Route 53 within 60 seconds. &lt;/p&gt;

&lt;p&gt;The Jenkins pipeline script is responsible for control flow only; all the actual 'doing' activities, such as building the codebase Docker image on the fly and committing it to ECR, is undertaken by shell scripts spawned from the pipeline. This means the power of AWS CLI can be leveraged to undertake all AWS specific tasks. &lt;/p&gt;

&lt;p&gt;The flow of the pipeline will vary depending upon the digital team's needs. I have elected for the following:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;On PR Creation, run build, automated testing, static analysis, persisting playground&lt;/li&gt;
	&lt;li&gt;On PR Approval, run build, automation testing (and fail the pipeline if testing fails), deploy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obviously you may have different requirements here such as building on each feature branch commit, but the re-configuration effort will be minimal regardless. Adding conditions on the Jenkins pipeline stages is trivial. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS ECR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The PHP-Apache Docker image is a starting point for creating an image that will include the feature branch built by Jenkins. Detailed instructions on how to achieve this are covered i&lt;a href="http://badzilla.co.uk/programmatically-create-aws-ecr-repository-and-commit-docker-image-ecr"&gt;n my earlier blog&lt;/a&gt;, and once the image is created it is committed to ECR. When a Fargate task is run, it must first be provisioned by fetching all the Docker images it needs, and having the codebase + Apache/PHP local to AWS will improve start-up. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Fargate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Jenkins will run up to three concurrent AWS Fargate tasks - a task which includes all the Docker containers to run the automated tests, a task that has the static analysis containers, and the basic web app containers for the persisting playground which will contain Apache+PHP along with probably Memcached or Redis, and any other products and services required by your web app. More on the AWS Fargate task definitions later. &lt;/p&gt;

&lt;p&gt;The automated tests and the static analysis run to conclusion and automatically die once their entry point scripts have run. The persisting playground will run Apache in the foreground to prevent termination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS RDS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is impractical to import db dumps into Fargate tasks, so all Fargate tasks will use one shared database resource. Obviously sharing a database can feasibly lead to schema inconsistencies when different schema changes are being developed on different feature branches. In Drupal these are implemented by &lt;em&gt;drush updatedb &lt;/em&gt;and in PHP frameworks there is always specific command line tooling to perform database migrations. To mitigate against schema inconsistencies, there would need to be communication between developers, and the facility to reset the database to a known develop branch datum with a Jenkins job. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS S3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An export of the develop branch database should be held locally in AWS S3 to facilitate quick import into RDS as required, and updated nightly. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS S3 &amp; AWS Cloudfront&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;File assets such as jpg and png images are normally held in &lt;em&gt;/sites/{default|domain name}/files&lt;/em&gt; in Drupal but are not committed to vcs. These need to be synced from the host's server nightly into S3, and for greater performance the use of Cloudfront acceleration is recommended. Configuration changes will be required in the Drupal or PHP framework codebase to point to the Cloudfront endpoints. Drupal will require the use of the Storage API module or the S3 File System module. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS CloudWatch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fargate integrates with CloudWatch easily, and output from each Docker container in the Fargate task definition will send stdout and stderr to a CloudWatch log group. This is imperative not just for troubleshooting, but also to determine the automated test results. By parsing the logs, a full test output can be created. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slack Integration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is desirable for the CI/CD pipeline to be hands-free, i.e. Jenkins login not required unless a manual pipeline invocation is necessary. To achieve this goal, Slack integration is required with job statuses being sent to dedicated Slack channels, and output from the test results also sent through Slack. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Existing Host&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Of course to seed RDS and the file asset S3, we need to get database exports and assets from our existing host. Exactly how to achieve this will vary dependent upon the host. If possible, a slave Jenkins can execute remote jobs on the host to upload the db exports and file assets to RDS and S3 respectively, and that is how I have drawn my diagram. If this is not possible, a combination of scp and rsync will suffice. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Fargate Task Definitions&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/Fargate%20Docker.png?itok=jOoDKprr 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2020-01/Fargate%20Docker.png?itok=sZJoL3eU 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2020-01/Fargate%20Docker.png?itok=wV7fKMmL 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2020-01/Fargate%20Docker.png?itok=Vpzxkv5i 1330w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2020-01/Fargate%20Docker.png?itok=jOoDKprr" alt="Fargate Docker Containers" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Fargate tasks can be defined in the AWS Console, but I've already identified that AWS CLI is the tool of choice for programmatic creation. The CLI requires the container definitions in JSON format, and for the pipeline discussed above there would be three Fargate definitions per feature branch. The first is the standard web app which would typically have the PHP/Apache container with the codebase copied into it during a &lt;em&gt;docker build&lt;/em&gt; command. The second is the automated testing stack which includes Maven (which has the Java runtime bundled) along with Selenium grid and two nodes: Firefox and Chrome. I spoke about this Fargate task at length in an earlier blog &lt;a href="http://badzilla.co.uk/aws-fargate-automated-testing-cucumber-gherkin-java-maven-selenium-grid-hub-and-chrome-and-firefox"&gt;here&lt;/a&gt;. The third definition is for static analysis and I am suggesting the excellent jakzal/phpqa repository for this. &lt;/p&gt;

&lt;p&gt;The three tasks would be defined and then run within the Jenkins pipeline. It must be noted that once the tasks have been run they should be immediately deleted from AWS ECR. Storage in ECR is costed, and in the unlikely event of the tasks being required at a later date, they can always be recreated by invoking the pipeline again manually and selecting the feature branch from a drop down list. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;The use of Drupal Drush&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Fargate is a black box, without access to the underlying EC2 infrastructure, and therefore it is not possible to ssh into EC2 and then perform a &lt;em&gt;docker exec &lt;/em&gt;command. Furthermore drush aliases require an ssh daemon running on the target alias to be able to execute remote commands from say a developer working on premises. So how can we run the normal set of everyday drush commands such as to apply schema changes, apply features, split the configuration, flush the caches etc?&lt;/p&gt;

&lt;p&gt;Ok so we have PHP installed on Jenkins since we have to run &lt;em&gt;composer install&lt;/em&gt; in the build stage. We also have an RDS instance with the database. We therefore have what we need to bootstrap Drupal - which is a requirement of drush. &lt;/p&gt;

&lt;p&gt;Therefore all drush commands should be run on Jenkins during the build stage. These commands should be listed in a sibling directory to the codebase's &lt;em&gt;docroot&lt;/em&gt; or &lt;em&gt;web&lt;/em&gt; directory, in say &lt;em&gt;devops_hooks&lt;/em&gt; or some such. As part of the Jenkins build stage, the existence of directory &lt;em&gt;devops_hooks &lt;/em&gt;will be checked, and all shell scripts within it will be run.  &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/aws" hreflang="en"&gt;AWS&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/awscli" hreflang="en"&gt;AWS CLI&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/devops" hreflang="en"&gt;devops&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sat, 04 Jan 2020 13:45:57 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">175 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Drupal 8 as a Static Site: Drupal 8 Contact Form Thank You Page</title>
  <link>http://badzilla.co.uk/drupal-8-static-site-drupal-8-contact-form-thank-you-page</link>
  <description>
&lt;span&gt;Drupal 8 as a Static Site: Drupal 8 Contact Form Thank You Page&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sat, 04/05/2019 - 14:50&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Architecture&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Our previous two tutorials on the Drupal 8 as a static site covered the Contact Form and the journey through the action to AWS Lambda to process the form and send an email. Now the final part of the contact form journey - returning back to the static site and showing a Thank You page. &lt;/p&gt;

&lt;p&gt;In fact in this tutorial the Thank You path will actually be the same path with the contact form on it - so we return to the starting point, but we want to show a message back to the user to thank them for filling out the form. The notification back to the user will have to be JavaScript obviously since we have no backend language functionality.&lt;/p&gt;

&lt;p&gt;If you remember the redirect back to the static site from AWS uses a HTTP code of 307. This code matches in the incoming HTTP request with the redirect. So since in our case the form was POSTed, then the redirect will also be POSTed back to the static site. This is both a blessing and a curse as we'll see. &lt;/p&gt;

&lt;p&gt;Common wisdom says that JavaScript can neither detect whether an incoming request is POSTed or GETed, nor retrieve any of the POSTed data. That is theoretically true, but there are always workarounds of course :) :) &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Adding the JavaScript&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;This is very similar to our earlier tutorial on how to add the Elasticsearch JavaScript client. So I won't dwell too much on this. Firstly we need to extend our template_preprocess_page function to add our thank-you JS library. This is the second section of code below, underneath the elasticsearch part&lt;br /&gt;&lt;br /&gt;
&lt;strong&gt;{themename}.theme&lt;/strong&gt; - in my case the custom theme is called beezee8. 
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;function &lt;/span&gt;&lt;span style="color: #0000BB"&gt;beezee8_preprocess_page&lt;/span&gt;&lt;span style="color: #007700"&gt;(&amp;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$variables&lt;/span&gt;&lt;span style="color: #007700"&gt;) {&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #FF8000"&gt;// If we are on the search page, load the JS search client api&lt;br /&gt;    // and our implementation to Elasticsearch&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #007700"&gt;if (\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Drupal&lt;/span&gt;&lt;span style="color: #007700"&gt;::&lt;/span&gt;&lt;span style="color: #0000BB"&gt;routeMatch&lt;/span&gt;&lt;span style="color: #007700"&gt;()-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;getRouteName&lt;/span&gt;&lt;span style="color: #007700"&gt;() == &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'search.view_node_search'&lt;/span&gt;&lt;span style="color: #007700"&gt;) {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$variables&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#attached'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'library'&lt;/span&gt;&lt;span style="color: #007700"&gt;][] = &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'beezee8/elastic-library'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #FF8000"&gt;// If we are on the contact form page, load the JS to show thank you message&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #007700"&gt;if (\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Drupal&lt;/span&gt;&lt;span style="color: #007700"&gt;::&lt;/span&gt;&lt;span style="color: #0000BB"&gt;request&lt;/span&gt;&lt;span style="color: #007700"&gt;()-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;getRequestUri&lt;/span&gt;&lt;span style="color: #007700"&gt;() == &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'/about'&lt;/span&gt;&lt;span style="color: #007700"&gt;) {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$variables&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#attached'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'library'&lt;/span&gt;&lt;span style="color: #007700"&gt;][] = &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'beezee8/thank-you-library'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
In the code above I get the current path alias and should that equal the '/about' page then I inject my JS library which is defined below.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Libraries file&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The libraries file now needs a further entry for our thank you JS. Again we already created an entry for elasticsearch so I am not going to go over this in too much detail. &lt;br /&gt;&lt;br /&gt;
&lt;strong&gt;{themename}.libraries.yml&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;global-styling:
  css:
    theme:
      css&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;style.css: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
elastic-library:
  js:
    js&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;elasticsearch-js&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;elasticsearch.min.js: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
    js&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;beezee&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;beezee_elastic.js: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
thank-you-library:
  js:
    js&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;beezee&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;beezee_thankyou.js: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;JavaScript Thank You&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Now here's the JavaScript. I did say that there is no way of knowing whether the HTTP request is GET or POST - well true, but we can deduce it. If we interrogate the referrer and it equals the current URL then we can make the assumption that the form has been POSTed, completed its round trip to AWS Lambda and back with a 307 code, and therefore we should show the thank you message. If you have a look at my code below you will see the conditional, and you will see the markup I inject into the page - it's classic Drupal 8 Bootstrap since that's how my theme is built. Your mileage here will obviously vary dependent upon your own theme.&lt;br /&gt;&lt;br /&gt;
&lt;strong&gt;{themename}_thankyou.js&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="javascript geshifilter-javascript" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000066; font-weight: bold;"&gt;function&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;$&lt;span style="color: #339933;"&gt;,&lt;/span&gt; Drupal&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
 
    &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; thank_once&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
    &lt;span style="color: #000066; font-weight: bold;"&gt;function&lt;/span&gt; BeezeeThankyou&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000066; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #339933;"&gt;!&lt;/span&gt;thank_once&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
            thank_once &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #003366; font-weight: bold;"&gt;true&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
            &lt;span style="color: #006600; font-style: italic;"&gt;// If we are arriving here from lambda which passes on the referrer from here&lt;/span&gt;
            &lt;span style="color: #006600; font-style: italic;"&gt;// then the form has been POSTed so show the thank you page&lt;/span&gt;
            &lt;span style="color: #000066; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;document.&lt;span style="color: #660066;"&gt;referrer&lt;/span&gt; &lt;span style="color: #339933;"&gt;==&lt;/span&gt; document.&lt;span style="color: #660066;"&gt;URL&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
 
                &lt;span style="color: #006600; font-style: italic;"&gt;// Markup to add the thankyou message&lt;/span&gt;
                &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; thanks &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #009900;"&gt;[&lt;/span&gt;
                    &lt;span style="color: #3366CC;"&gt;'&lt;div class="alert alert-success alert-dismissible" role="alert"&gt;'&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                    &lt;span style="color: #3366CC;"&gt;'&lt;button role="button" class="close" data-dismiss="alert" aria-label="Close"&gt;&lt;span aria-hidden="true"&gt;×&lt;/span&gt;&lt;/button&gt;'&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                    &lt;span style="color: #3366CC;"&gt;'&lt;h4 class="sr-only"&gt;Status message&lt;/h4&gt;'&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                    &lt;span style="color: #3366CC;"&gt;'Thank you for contacting me. I will be in touch.'&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                    &lt;span style="color: #3366CC;"&gt;'&lt;/div&gt;'&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
                &lt;span style="color: #006600; font-style: italic;"&gt;// Inject the markup&lt;/span&gt;
                $&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;'.region-highlighted'&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #660066;"&gt;append&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;thanks.&lt;span style="color: #660066;"&gt;join&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;''&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
    Drupal.&lt;span style="color: #660066;"&gt;behaviors&lt;/span&gt;.&lt;span style="color: #660066;"&gt;beezee_thankyou&lt;/span&gt; &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        attach&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;function&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;context&lt;span style="color: #339933;"&gt;,&lt;/span&gt; settings&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
            BeezeeThankyou&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;jQuery&lt;span style="color: #339933;"&gt;,&lt;/span&gt; Drupal&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;nginx Server Configuration&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-05/Screenshot%202019-05-04%20at%2014.20.54.png?itok=6tpIS5Ha 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-05/Screenshot%202019-05-04%20at%2014.20.54.png?itok=ob3PdIWy 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-05/Screenshot%202019-05-04%20at%2014.20.54.png?itok=HXKYNHSr 1232w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-05/Screenshot%202019-05-04%20at%2014.20.54.png?itok=6tpIS5Ha" alt="nginx error" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;If we try our form now (or at least if I do since I'm using nginx) - we will get an nginx &lt;strong&gt;405 Not Allowed&lt;/strong&gt; error. Remember I said the POST could be a blessing and a curse? The error is because by default nginx will not allow a POST to a static page. Thankfully there is a workaround. Locate the server configuration for your particular virtual host, and edit it by adding the following line into the &lt;strong&gt;server&lt;/strong&gt; section. &lt;br /&gt;&lt;br /&gt;
&lt;strong&gt;{VM name}.conf&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;server &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
.
.
.
      error_page  &lt;span style="color: #000000;"&gt;405&lt;/span&gt;     =&lt;span style="color: #000000;"&gt;200&lt;/span&gt; &lt;span style="color: #007800;"&gt;$uri&lt;/span&gt;;
.
.&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Form submission&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-05/Screenshot%202019-05-04%20at%2015.36.57.png?itok=0_8Bbaz8 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-05/Screenshot%202019-05-04%20at%2015.36.57.png?itok=k1HGEgk5 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-05/Screenshot%202019-05-04%20at%2015.36.57.png?itok=InG6NxCW 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-05/Screenshot%202019-05-04%20at%2015.36.57.png?itok=xNGfoh3u 2518w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-05/Screenshot%202019-05-04%20at%2015.36.57.png?itok=0_8Bbaz8" alt="form submission" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Ok we should now be good to go. Submit the form and it should do the round trip from static site to AWS Lambda back to static site and an email arriving in your inbox! &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;An even better solution? &lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-05/Screenshot%202019-05-04%20at%2012.22.24.png?itok=gRLJM0fM 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-05/Screenshot%202019-05-04%20at%2012.22.24.png?itok=ZCyJqk5L 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-05/Screenshot%202019-05-04%20at%2012.22.24.png?itok=iJlZV3ZA 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-05/Screenshot%202019-05-04%20at%2012.22.24.png?itok=U51-2amo 2494w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-05/Screenshot%202019-05-04%20at%2012.22.24.png?itok=gRLJM0fM" alt="alternative solution" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;If you look carefully above you will see a placeholder in the thank you message. So am I saying it is possible to retrieve the POSTed data and insert the name into the placeholder? Sort of. There is a JS library called &lt;a href="https://github.com/ssut/jQuery-PostCapture"&gt;jQuery-PostCapture&lt;/a&gt; which can achieve this. It works by capturing the POSTed data when the form is initially submitted. This copy of the data is stored either as a cookie or in the browser's local storage. Once the trip to AWS Lambda is completed, this data can be fetched from the cookie or local storage - so the data isn't fetched from the actual POST itself. &lt;/p&gt;

&lt;p&gt;The problem I've got with this is neither a cookie nor local storage is secure. However if you feel that the gains (being able to customise a message on the thank you page) is worth the security risk, then give it a shot! &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/static-site" hreflang="en"&gt;Static Site&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal8" hreflang="en"&gt;Drupal 8&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/development" hreflang="en"&gt;Development&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/js" hreflang="en"&gt;JavaScript&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sat, 04 May 2019 13:50:36 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">167 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Drupal 8 as a Static Site: AWS API Gateway, Lambda and SES Form Processing</title>
  <link>http://badzilla.co.uk/drupal-8-static-site-aws-api-gateway-lambda-and-ses-form-processing</link>
  <description>
&lt;span&gt;Drupal 8 as a Static Site: AWS API Gateway, Lambda and SES Form Processing&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Wed, 02/01/2019 - 10:38&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Serverless Installation&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The intention is to build our AWS ecosystem using the &lt;a href="https://serverless.com/"&gt;serverless&lt;/a&gt; product. This will enable us to configure our AWS provisioning in a YML file which is then translated into AWS CloudFormation orchestration. In the same codebase our PHP Lambda function can be built out. It isn't my intention to provide heavy documentation here since the Contact Form architecture was &lt;a href="http://badzilla.co.uk/drupal-8-static-site-contact-form-architecture"&gt;defined in an earlier blog&lt;/a&gt;, and I have previously written &lt;a href="http://badzilla.co.uk/real-world-php-lambda-app"&gt;many articles on the serverless / lambda / API Gateway&lt;/a&gt; combination of technologies to deliver HTTP content and handle form POSTs. &lt;/p&gt;
&lt;p&gt;Notwithstanding this, I will of course document points of interest along the way so it all makes sense! &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The first step is to install &lt;strong&gt;serverless&lt;/strong&gt; on your system. A dependency is node, so if you don't have that then please follow tutorials elsewhere on the Internet before executing the command below to install globally serverless.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #666666;"&gt;$ &lt;/span&gt;npm &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; serverless &lt;span style="color: #660033;"&gt;-g&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
We will be using Andy Raines' excellent PHP for AWS Lambda via Serverless Framework repo as our stating point. Issuing the following command will install our PHP serverless project into a directory called  d8-contact-form.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ serverless &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; &lt;span style="color: #660033;"&gt;--url&lt;/span&gt; https:&lt;span style="color: #000000; font-weight: bold;"&gt;//&lt;/span&gt;github.com&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;araines&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;serverless-php &lt;span style="color: #660033;"&gt;-n&lt;/span&gt; d8-contact-form
Serverless: Downloading and installing &lt;span style="color: #ff0000;"&gt;"serverless-php"&lt;/span&gt;...
Serverless: Successfully installed &lt;span style="color: #ff0000;"&gt;"d8-contact-form"&lt;/span&gt; &lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
We then cd into the directory and list. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #7a0874; font-weight: bold;"&gt;cd&lt;/span&gt; d8-contact-form&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;
$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;ls&lt;/span&gt; &lt;span style="color: #660033;"&gt;-las&lt;/span&gt;
total &lt;span style="color: #000000;"&gt;48&lt;/span&gt;
&lt;span style="color: #000000;"&gt;0&lt;/span&gt; drwxrwxr-x &lt;span style="color: #000000;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  &lt;span style="color: #000000;"&gt;512&lt;/span&gt; Jan  &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt;:&lt;span style="color: #000000;"&gt;14&lt;/span&gt; .
&lt;span style="color: #000000;"&gt;0&lt;/span&gt; drwxr-xr-x &lt;span style="color: #000000;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  &lt;span style="color: #000000;"&gt;448&lt;/span&gt; Jan  &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt;:&lt;span style="color: #000000;"&gt;14&lt;/span&gt; ..
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rwxr-xr-x&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  &lt;span style="color: #000000;"&gt;660&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; buildphp.sh
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  &lt;span style="color: #000000;"&gt;569&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; CHANGELOG.md
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  &lt;span style="color: #000000;"&gt;430&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; composer.json
&lt;span style="color: #000000;"&gt;0&lt;/span&gt; drwxrwxr-x  &lt;span style="color: #000000;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout   &lt;span style="color: #000000;"&gt;96&lt;/span&gt; Jan  &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt;:&lt;span style="color: #000000;"&gt;14&lt;/span&gt; config
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout &lt;span style="color: #000000;"&gt;1011&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; dockerfile.buildphp
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout   &lt;span style="color: #000000;"&gt;40&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; .gitattributes
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  &lt;span style="color: #000000;"&gt;120&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; .gitignore
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout &lt;span style="color: #000000;"&gt;1330&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; handler.js
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  &lt;span style="color: #000000;"&gt;829&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; handler.php
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout &lt;span style="color: #000000;"&gt;1103&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; LICENSE
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rwxr-xr-x&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  &lt;span style="color: #000000;"&gt;133&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; php
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout &lt;span style="color: #000000;"&gt;3705&lt;/span&gt; Feb &lt;span style="color: #000000;"&gt;14&lt;/span&gt;  &lt;span style="color: #000000;"&gt;2018&lt;/span&gt; README.md
&lt;span style="color: #000000;"&gt;4&lt;/span&gt; &lt;span style="color: #660033;"&gt;-rw-r--r--&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout &lt;span style="color: #000000;"&gt;3008&lt;/span&gt; Jan  &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt;:&lt;span style="color: #000000;"&gt;14&lt;/span&gt; serverless.yml
&lt;span style="color: #000000;"&gt;0&lt;/span&gt; drwxrwxr-x  &lt;span style="color: #000000;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  &lt;span style="color: #000000;"&gt;160&lt;/span&gt; Jan  &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt;:&lt;span style="color: #000000;"&gt;14&lt;/span&gt; src&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Since I don't have Git LFS installed, the PHP executable hasn't been downloaded from the repo correctly. I will download this manually, and add it to the directory. Once completed, we can see it there with:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;ls&lt;/span&gt; &lt;span style="color: #660033;"&gt;-lash&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;" php"&lt;/span&gt;
 27M &lt;span style="color: #660033;"&gt;-rwxr-xr-x&lt;/span&gt;  &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;501&lt;/span&gt; dialout  27M Jan  &lt;span style="color: #000000;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;11&lt;/span&gt;:&lt;span style="color: #000000;"&gt;22&lt;/span&gt; php&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Now we need to install the PHP dependencies using composer. This does have a dependency on PHP 7.1. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ composer &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt; &lt;span style="color: #660033;"&gt;-o&lt;/span&gt; &lt;span style="color: #660033;"&gt;--no-dev&lt;/span&gt;
You are running composer with xdebug enabled. This has a major impact on runtime performance. See https:&lt;span style="color: #000000; font-weight: bold;"&gt;//&lt;/span&gt;getcomposer.org&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;xdebug
Loading composer repositories with package information
Updating dependencies
Package operations: &lt;span style="color: #000000;"&gt;9&lt;/span&gt; installs, &lt;span style="color: #000000;"&gt;0&lt;/span&gt; updates, &lt;span style="color: #000000;"&gt;0&lt;/span&gt; removals
  - Installing psr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;log &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;1.1.0&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Downloading &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;         
  - Installing monolog&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;monolog &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;1.24.0&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Downloading &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;         
  - Installing symfony&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;polyfill-ctype &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;v1.10.0&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Loading from cache
  - Installing symfony&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;filesystem &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;v4.2.1&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Downloading &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;         
  - Installing symfony&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;config &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;v4.2.1&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Downloading &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;         
  - Installing symfony&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;contracts &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;v1.0.2&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Downloading &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;         
  - Installing psr&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;container &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;1.0.0&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Loading from cache
  - Installing symfony&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;dependency-injection &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;v4.2.1&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Downloading &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;         
  - Installing symfony&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;yaml &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;v4.2.1&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Downloading &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;         
Writing lock &lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt;
Generating optimized autoload files&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Any Raines' code comes with a very basic Lambda function called &lt;strong&gt;hello&lt;/strong&gt;. To prove the environment is working correctly, we should invoke it locally (no need for deploying to AWS yet) and if everything is correct, it'll look like this:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ serverless invoke &lt;span style="color: #7a0874; font-weight: bold;"&gt;local&lt;/span&gt; &lt;span style="color: #660033;"&gt;-f&lt;/span&gt; hello
Got event &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    &lt;span style="color: #ff0000;"&gt;"statusCode"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;200&lt;/span&gt;,
    &lt;span style="color: #ff0000;"&gt;"body"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"Go Serverless v1.0! Your function executed successfully!"&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
In an &lt;a href="http://badzilla.co.uk/running-php-amazon-lambda-serverless"&gt;earlier blog&lt;/a&gt; I replaced the references of &lt;strong&gt;Hello&lt;/strong&gt; with &lt;strong&gt;demo&lt;/strong&gt;. I have changed it to &lt;strong&gt;D8ContactForm&lt;/strong&gt; for the contact form. By deploying the code to AWS, and submitting the contact form, you will see the same screenshot as shown at the end of the &lt;a href="http://badzilla.co.uk/drupal-8-static-site-drupal-8-contact-form"&gt;previous blog. &lt;/a&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;SES Validation of email address&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-03/Screenshot%202019-03-24%20at%2012.53.48.png?itok=VklpZIXH 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-03/Screenshot%202019-03-24%20at%2012.53.48.png?itok=w6rR8Bo2 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-03/Screenshot%202019-03-24%20at%2012.53.48.png?itok=Pt0JuZRW 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-03/Screenshot%202019-03-24%20at%2012.53.48.png?itok=wYgkoMN1 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-03/Screenshot%202019-03-24%20at%2012.53.48.png?itok=VklpZIXH" alt="Email address validation" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-03/Screenshot%202019-03-24%20at%2013.03.04-edited.png?itok=gDIdr5NA 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-03/Screenshot%202019-03-24%20at%2013.03.04-edited.png?itok=4U2cM8Hw 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-03/Screenshot%202019-03-24%20at%2013.03.04-edited.png?itok=Y1AhIOSK 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-03/Screenshot%202019-03-24%20at%2013.03.04-edited.png?itok=8YS9rsXw 2600w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-03/Screenshot%202019-03-24%20at%2013.03.04-edited.png?itok=gDIdr5NA" alt="Verification completed" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;To use the AWS SES service, your email address will need to be verified. This is easy - navigate to Simple Email Service and click on email addresses, then "Verify a new email address". Add the email address and a verification email message will be sent for you to click back and confirm the verification process. Once verified, you'll see the second screenshot above. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Serverless configuration&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The next step is to add the SES configuration to the &lt;strong&gt;serverless.yml&lt;/strong&gt; file. Add a custom area for your own variables - in this case the email address.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;custom:
  SENDER_EMAIL: xxxx&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;xxxxxxxx
  RECIPIENT_EMAIL: xxxx&lt;span style="color: #000000; font-weight: bold;"&gt;@&lt;/span&gt;xxxxxxxx&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
And add the SES config to the provider area so it looks like this in its entirety:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;provider:
  name: aws
  runtime: nodejs6.10
  stage: dev
  region: eu-west-&lt;span style="color: #000000;"&gt;1&lt;/span&gt;
  environment:
    SENDER: &lt;span style="color: #800000;"&gt;${self:custom.SENDER_EMAIL}&lt;/span&gt;
    RECIPIENT: &lt;span style="color: #800000;"&gt;${self:custom.RECIPIENT_EMAIL}&lt;/span&gt;
    DOMAIN: &lt;span style="color: #ff0000;"&gt;"*"&lt;/span&gt;
  iamRoleStatements:
    - Effect: &lt;span style="color: #ff0000;"&gt;"Allow"&lt;/span&gt;
      Action:
        - &lt;span style="color: #ff0000;"&gt;"ses:SendEmail"&lt;/span&gt;
      Resource: &lt;span style="color: #ff0000;"&gt;"*"&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Then deploy
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ sls deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Add AWS SDK to the codebase using composer&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The SDK will make it much easier to build out the SES interface code and can be installed to the codebase in the usual composer way
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ composer require aws&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;aws-sdk-php
You are running composer with xdebug enabled. This has a major impact on runtime performance. See https:&lt;span style="color: #000000; font-weight: bold;"&gt;//&lt;/span&gt;getcomposer.org&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;xdebug
Using version ^&lt;span style="color: #000000;"&gt;3.90&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; aws&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;aws-sdk-php
.&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;composer.json has been updated&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Add SDK PHP required libraries&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The AWS PHP SDK requires the &lt;strong&gt;filter and simplexml&lt;/strong&gt; libraries that aren't in the PHP executable we deploy to AWS by default. Thankfully there is a way of recompiling the PHP executable and I covered this in &lt;a href="http://badzilla.co.uk/recompiling-php-serverless-php-and-lambda"&gt;an earlier blog.&lt;/a&gt; So the tl;dr is &lt;ul&gt;
&lt;li&gt;Add the filter and simplexml libraries to dockerfile.buildphp&lt;/li&gt;
&lt;li&gt;Make a note of the php creation date and filesize.
&lt;/li&gt;&lt;li&gt;Make sure buildphp.sh is executable on the command line and run it.&lt;/li&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Add the Serverless and SDK handler code&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Now the AWS SDK is in the code base we can build out the functionality to integrate the SDK. Our first work is to ensure that the recipient and sender email addresses are available to the code. To achieve this, they were defined in the &lt;strong&gt;serverless.yml&lt;/strong&gt; in the environment section which can be picked up in &lt;strong&gt;handler.php&lt;/strong&gt; and assigned to the &lt;strong&gt;$event&lt;/strong&gt; array which is made available to the handler class. Add the following lines before the call to handle
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;$event&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'sender_email'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = &lt;/span&gt;&lt;span style="color: #0000BB"&gt;getenv&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'SENDER'&lt;/span&gt;&lt;span style="color: #007700"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$event&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'recipient_email'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = &lt;/span&gt;&lt;span style="color: #0000BB"&gt;getenv&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'RECIPIENT'&lt;/span&gt;&lt;span style="color: #007700"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
Now the handler itself. A few things to note. &lt;ul&gt;&lt;li&gt;I have added the necessary &lt;strong&gt;use&lt;/strong&gt; clauses to the AWS SDK client and the exception class&lt;/li&gt;&lt;li&gt;The protected &lt;strong&gt;$client_config&lt;/strong&gt; holds the configuration we have - but note that further down I am getting the credentials from the &lt;strong&gt;CredentialProvider&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;The recipients are an array and so it is possible if required to add multiples here.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;
&lt;strong&gt;D8ContactFormHandler.php&lt;/strong&gt;
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;br /&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;namespace &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Raines&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Serverless&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;br /&gt;require &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'vendor/autoload.php'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;br /&gt;use &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Aws&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Ses&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;SesClient&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;use &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Aws&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Exception&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;AwsException&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;br /&gt;class &lt;/span&gt;&lt;span style="color: #0000BB"&gt;D8ContactFormHandler &lt;/span&gt;&lt;span style="color: #007700"&gt;implements &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Handler&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;{&lt;br /&gt;    protected &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$client_config &lt;/span&gt;&lt;span style="color: #007700"&gt;= [&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'region' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'eu-west-1'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'version' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'2010-12-01'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'credentials.cache' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;TRUE&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'validation' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;FALSE&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;    ];&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #FF8000"&gt;/**&lt;br /&gt;     * {@inheritdoc}&lt;br /&gt;     */&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #007700"&gt;public function &lt;/span&gt;&lt;span style="color: #0000BB"&gt;handle&lt;/span&gt;&lt;span style="color: #007700"&gt;(array &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$event&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Context $context&lt;/span&gt;&lt;span style="color: #007700"&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$logger &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$context&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;getLogger&lt;/span&gt;&lt;span style="color: #007700"&gt;();&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #FF8000"&gt;// Comment out for debugging&lt;br /&gt;        //$logger-&gt;notice('Got event', $event);&lt;br /&gt;&lt;br /&gt;        // Set up AWS SDK&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$this&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;client_config&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'credentials'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = \&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Aws&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Credentials&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;CredentialProvider&lt;/span&gt;&lt;span style="color: #007700"&gt;::&lt;/span&gt;&lt;span style="color: #0000BB"&gt;env&lt;/span&gt;&lt;span style="color: #007700"&gt;();&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$SesClient &lt;/span&gt;&lt;span style="color: #007700"&gt;= new &lt;/span&gt;&lt;span style="color: #0000BB"&gt;SesClient&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$this&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;client_config&lt;/span&gt;&lt;span style="color: #007700"&gt;);&lt;br /&gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$sender_email &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$event&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'sender_email'&lt;/span&gt;&lt;span style="color: #007700"&gt;];&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$recipient_emails&lt;/span&gt;&lt;span style="color: #007700"&gt;[] = &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$event&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'recipient_email'&lt;/span&gt;&lt;span style="color: #007700"&gt;];&lt;br /&gt;&lt;br /&gt;        return [&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'statusCode' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;200&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'body' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Go Serverless v1.0! Your function executed successfully!'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;        ];&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Email generation&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Now we can insert the code to actually generate the email. All of this is self evident and really doesn't need further commentary from me. It should be inserted just before the return statement. &lt;br /&gt;
&lt;strong&gt;D8ContactFormHandler.php&lt;/strong&gt;
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #FF8000"&gt;// Process the submitted form.&lt;br /&gt;        // *TODO* This could do with more validation.&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields &lt;/span&gt;&lt;span style="color: #007700"&gt;= [];&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;parse_str&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$event&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'body'&lt;/span&gt;&lt;span style="color: #007700"&gt;], &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;);&lt;br /&gt;&lt;br /&gt;        if (!isset(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'name'&lt;/span&gt;&lt;span style="color: #007700"&gt;])) &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'name'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'{unknown name}'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;        if (!isset(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'mail'&lt;/span&gt;&lt;span style="color: #007700"&gt;])) &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'mail'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'{unknown email address}'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;        if (!isset(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'subject'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'value'&lt;/span&gt;&lt;span style="color: #007700"&gt;])) &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'subject'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'value'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'{unknown subject}'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;        if (!isset(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'message'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'value'&lt;/span&gt;&lt;span style="color: #007700"&gt;])) &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'message'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'value'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'{unknown message}'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$subject &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'[badzilla.co.uk website feedback] '&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'subject'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'value'&lt;/span&gt;&lt;span style="color: #007700"&gt;];&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$plaintext_body &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'From: '&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'name'&lt;/span&gt;&lt;span style="color: #007700"&gt;].&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'  '&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'mail'&lt;/span&gt;&lt;span style="color: #007700"&gt;].&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Subject: '&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'subject'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'value'&lt;/span&gt;&lt;span style="color: #007700"&gt;].&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;' Message: '&lt;/span&gt;&lt;span style="color: #007700"&gt;. &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'message'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'value'&lt;/span&gt;&lt;span style="color: #007700"&gt;];&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$html_body &lt;/span&gt;&lt;span style="color: #007700"&gt;=  &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'&lt;h1&gt;'&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'subject'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'value'&lt;/span&gt;&lt;span style="color: #007700"&gt;].&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'&lt;/h1&gt;'&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'&lt;h2&gt;'&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'From: '&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'name'&lt;/span&gt;&lt;span style="color: #007700"&gt;].&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'  &lt;a href="mailto:"'&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'mail'&lt;/span&gt;&lt;span style="color: #007700"&gt;].&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'"&gt;'&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'mail'&lt;/span&gt;&lt;span style="color: #007700"&gt;].&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'&lt;/a&gt;'&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'&lt;/h2&gt;'&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'&lt;p&gt;'&lt;/span&gt;&lt;span style="color: #007700"&gt;.&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$fields&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'message'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'value'&lt;/span&gt;&lt;span style="color: #007700"&gt;].&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'&lt;/p&gt;'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$char_set &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'UTF-8'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;br /&gt;        try {&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$result &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$SesClient&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;sendEmail&lt;/span&gt;&lt;span style="color: #007700"&gt;([&lt;br /&gt;                &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Destination' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;br /&gt;                    &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'ToAddresses' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$recipient_emails&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                ],&lt;br /&gt;                &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'ReplyToAddresses' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$sender_email&lt;/span&gt;&lt;span style="color: #007700"&gt;],&lt;br /&gt;                &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Source' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$sender_email&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Message' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;br /&gt;                    &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Body' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;br /&gt;                        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Html' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;br /&gt;                            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Charset' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$char_set&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Data' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$html_body&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                        ],&lt;br /&gt;                        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Text' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;br /&gt;                            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Charset' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$char_set&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Data' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$plaintext_body&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                        ],&lt;br /&gt;                    ],&lt;br /&gt;                    &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Subject' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;br /&gt;                        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Charset' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$char_set&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Data' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$subject&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                    ],&lt;br /&gt;                ],&lt;br /&gt;            ]);&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$messageId &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$result&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'MessageId'&lt;/span&gt;&lt;span style="color: #007700"&gt;];&lt;br /&gt;        } catch (&lt;/span&gt;&lt;span style="color: #0000BB"&gt;AwsException $e&lt;/span&gt;&lt;span style="color: #007700"&gt;) {&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #FF8000"&gt;// output error message if fails&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$logger&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;notice&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Message'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$e&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;getMessage&lt;/span&gt;&lt;span style="color: #007700"&gt;());&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$logger&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;notice&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'AWS Message'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$e&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;getAwsErrorMessage&lt;/span&gt;&lt;span style="color: #007700"&gt;());&lt;br /&gt;        }&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Redirect to thank you page&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Once we've sent the email we want to redirect back to our thank you page. This is done with a 307 code which preserves the original POSTed values so they can be used on the forwarded page. Our use will be to make the message personalised. I have decided that I would like my redirect back to my originating page, but of course you could customise it as you see fit. For my case, I use the Referer header. The code below replaces the existing return functionality.&lt;br /&gt;
&lt;strong&gt;D8 ContactFormHandler.php&lt;/strong&gt;
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #007700"&gt;return [&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'headers' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Location' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$event&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'headers'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Referer'&lt;/span&gt;&lt;span style="color: #007700"&gt;]],&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'statusCode' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;307&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;        ];&lt;br /&gt;&lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;codE&lt;/span&gt;&lt;span style="color: #007700"&gt;&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Debugging&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-03/Screenshot%202019-03-24%20at%2018.22.11.png?itok=LTjE38Bn 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-03/Screenshot%202019-03-24%20at%2018.22.11.png?itok=uyEGnya5 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-03/Screenshot%202019-03-24%20at%2018.22.11.png?itok=KbaNuSz5 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-03/Screenshot%202019-03-24%20at%2018.22.11.png?itok=BRx1-OBf 2552w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-03/Screenshot%202019-03-24%20at%2018.22.11.png?itok=LTjE38Bn" alt="CloudWatch" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;During the development process you will have to do multiple deploys and doubtless you will get numerous error responses from AWS. The best way of working these issues is to use CloudWatch, and a sample screenshot is shown above. The codebase has an excellent logging facility to check variables and these are written out to CloudWatch. Have a look at:&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;$logger&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;notice&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Got event'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$event&lt;/span&gt;&lt;span style="color: #007700"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
This can be amended for whatever you need to interrogate, but remember the second parameter must be an array.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Git Repository&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The entire codebase discussed here is at &lt;a href="https://github.com/sanddevil/serverless-php-contact-form"&gt;https://github.com/sanddevil/serverless-php-contact-form&lt;/a&gt; - if you wish to extend its functionality, please send me a pull request. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/static-site" hreflang="en"&gt;Static Site&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal8" hreflang="en"&gt;Drupal 8&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/development" hreflang="en"&gt;Development&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/serverless" hreflang="en"&gt;serverless&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/serverless-php" hreflang="en"&gt;serverless-php&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/lambda" hreflang="en"&gt;lambda&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Wed, 02 Jan 2019 10:38:46 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">164 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Drupal 8 as a Static Site: Drupal 8 Contact Form</title>
  <link>http://badzilla.co.uk/drupal-8-static-site-drupal-8-contact-form</link>
  <description>
&lt;span&gt;Drupal 8 as a Static Site: Drupal 8 Contact Form&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Mon, 31/12/2018 - 10:38&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Drupal Contact&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2010.41.48.png?itok=g7UCAwiw 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-12/Screenshot%202018-12-31%20at%2010.41.48.png?itok=fESRp_XM 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-12/Screenshot%202018-12-31%20at%2010.41.48.png?itok=2ZEMp22N 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2018-12/Screenshot%202018-12-31%20at%2010.41.48.png?itok=KH1K0fWP 2304w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2010.41.48.png?itok=g7UCAwiw" alt="Extend" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot_2018-12-31_at_11_08_53-edited.png?itok=s4ONl3xB 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-12/Screenshot_2018-12-31_at_11_08_53-edited.png?itok=Vh-HhXXk 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-12/Screenshot_2018-12-31_at_11_08_53-edited.png?itok=tV56yvb4 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2018-12/Screenshot_2018-12-31_at_11_08_53-edited.png?itok=eZdVPGL9 2004w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot_2018-12-31_at_11_08_53-edited.png?itok=s4ONl3xB" alt="Feedback" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2015.03.27.png?itok=pHkxHQJL 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-12/Screenshot%202018-12-31%20at%2015.03.27.png?itok=f1MqYlsn 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-12/Screenshot%202018-12-31%20at%2015.03.27.png?itok=BknQ62jT 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2018-12/Screenshot%202018-12-31%20at%2015.03.27.png?itok=g0ej4cfc 1990w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2015.03.27.png?itok=pHkxHQJL" alt="Display" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Drupal core comes with a Contact form, so the first step is to check it is already enabled by navigating to /admin/modules as per the first screenshot above. &lt;/p&gt;
&lt;p&gt;Next go to /admin/structure/contact and the default forms are listed including the Website Feedback form which is the one we will be using. See the second screenshot. &lt;/p&gt;
&lt;p&gt;The third screenshot shows the default fields. I've made two changes here. The form preview requires a Drupal backend so has been removed, and I've disabled the 'Send copy to sender' option since that could encourage spamming. &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Add contrib module Contact Block&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Since I want my contact form to be below my 'about' content on my /about route, I need the form to be available as a block. This can be achieved using the contrib module Contact Block and can be installed and enabled in the normal way. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ composer require drupal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;contact_block
Using version ^&lt;span style="color: #000000;"&gt;1.4&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; drupal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;contact_block
.&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;composer.json has been updated
Gathering patches &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; root package.
Loading composer repositories with package information
Updating dependencies &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;including require-dev&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;
Package operations: &lt;span style="color: #000000;"&gt;1&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;install&lt;/span&gt;, &lt;span style="color: #000000;"&gt;0&lt;/span&gt; updates, &lt;span style="color: #000000;"&gt;0&lt;/span&gt; removals
Gathering patches &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; root package.
Gathering patches &lt;span style="color: #000000; font-weight: bold;"&gt;for&lt;/span&gt; dependencies. This might take a minute.
  - Installing drupal&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;contact_block &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;1.4.0&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;: Downloading &lt;span style="color: #7a0874; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;%&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;)&lt;/span&gt;         
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; Drupal\Core\Composer\Composer::vendorTestCodeCleanup
Writing lock &lt;span style="color: #c20cb9; font-weight: bold;"&gt;file&lt;/span&gt;
Generating autoload files
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; Drupal\Core\Composer\Composer::preAutoloadDump
&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt; Drupal\Core\Composer\Composer::ensureHtaccess
$ drush en contact_block
 &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;success&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; Successfully enabled: contact_block&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Add contact form block to region&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2014.43.19.png?itok=X25q6yyr 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-12/Screenshot%202018-12-31%20at%2014.43.19.png?itok=EhmZLXPP 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-12/Screenshot%202018-12-31%20at%2014.43.19.png?itok=dpgd05YO 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2018-12/Screenshot%202018-12-31%20at%2014.43.19.png?itok=EjGDaXhf 1396w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2014.43.19.png?itok=X25q6yyr" alt="Add block" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2014.44.06.png?itok=cOcHH__W 295w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-12/Screenshot%202018-12-31%20at%2014.44.06.png?itok=Fp8pwjJY 590w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-12/Screenshot%202018-12-31%20at%2014.44.06.png?itok=JrP_77EW 1180w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2018-12/Screenshot%202018-12-31%20at%2014.44.06.png?itok=jC3cE-Tl 1392w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2014.44.06.png?itok=cOcHH__W" alt="Block settings" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2014.44.27.png?itok=NvZhm9BX 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-12/Screenshot%202018-12-31%20at%2014.44.27.png?itok=ILVQRXX5 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-12/Screenshot%202018-12-31%20at%2014.44.27.png?itok=8RBmyDlo 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2018-12/Screenshot%202018-12-31%20at%2014.44.27.png?itok=_ngrrHLk 1922w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-31%20at%2014.44.27.png?itok=NvZhm9BX" alt="Content Region" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Adding the content form block to a block region should be familiar to most people so I won't go into this in great detail. I have placed it in the content region (first screenshot) at /admin/structure/block, configured it with the title, path restrictions so it only appears on my /about route, and ensured the correct form is to be displayed (second screenshot). The third screenshot shows I have dragged the contact form block to be the final block in the content region.  &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;POST form to external URL&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Since it is not possible in the admin UI to add an external URL for the POST action, we will have to achieve this by a few lines of code. But where are we POSTing the form anyway? This is covered in the next blog, but in a nutshell the URL is autogenerated by AWS API Gateway during the CloudFormation orchestration. I won't go into the details now how that is achieved since it can be read later in this sequence, but here is the url we'll use. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ sls info &lt;span style="color: #000000; font-weight: bold;"&gt;|&lt;/span&gt; &lt;span style="color: #c20cb9; font-weight: bold;"&gt;grep&lt;/span&gt; POST
  POST - https:&lt;span style="color: #000000; font-weight: bold;"&gt;//&lt;/span&gt;djbbm406h0.execute-api.eu-west-&lt;span style="color: #000000;"&gt;2&lt;/span&gt;.amazonaws.com&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;dev&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
The easiest way of adding that url to the Drupal contact form would be to include it into settings.php and then use a template preprocess function to swap out the 'action' value in the form. &lt;br /&gt;
&lt;strong&gt;settings.php&lt;/strong&gt;
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;$config&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'aws:lambda'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'url'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'https://djbbm406h0.execute-api.eu-west-2.amazonaws.com/dev'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt; 
&lt;strong&gt;{themename}.theme&lt;/strong&gt;
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #FF8000"&gt;/**&lt;br /&gt; * @param $variables&lt;br /&gt; */&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;function &lt;/span&gt;&lt;span style="color: #0000BB"&gt;beezee8_preprocess_form&lt;/span&gt;&lt;span style="color: #007700"&gt;(&amp;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$variables&lt;/span&gt;&lt;span style="color: #007700"&gt;) {&lt;br /&gt;&lt;br /&gt;  &lt;/span&gt;&lt;span style="color: #FF8000"&gt;// find the contact form and add the lambda contact form action url&lt;br /&gt;  &lt;/span&gt;&lt;span style="color: #007700"&gt;if (&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$variables&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'attributes'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'id'&lt;/span&gt;&lt;span style="color: #007700"&gt;] == &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'contact-message-feedback-form'&lt;/span&gt;&lt;span style="color: #007700"&gt;) {&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$variables&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'attributes'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'action'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = \&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Drupal&lt;/span&gt;&lt;span style="color: #007700"&gt;::&lt;/span&gt;&lt;span style="color: #0000BB"&gt;config&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'aws:lambda'&lt;/span&gt;&lt;span style="color: #007700"&gt;)-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;get&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'url'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #0000BB"&gt;FALSE&lt;/span&gt;&lt;span style="color: #007700"&gt;);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Submission of the contact form&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-03/Screenshot%202019-03-24%20at%2011.06.26.png?itok=iSVtBIhS 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2019-03/Screenshot%202019-03-24%20at%2011.06.26.png?itok=WPksDgcB 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2019-03/Screenshot%202019-03-24%20at%2011.06.26.png?itok=jAkjc3KA 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2019-03/Screenshot%202019-03-24%20at%2011.06.26.png?itok=-np8CCd4 1384w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2019-03/Screenshot%202019-03-24%20at%2011.06.26.png?itok=iSVtBIhS" alt="Form submission" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Now the form will be submitted to AWS Lambda for onward processing, and ultimately, a redirect back with a thank you message. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/static-site" hreflang="en"&gt;Static Site&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal8" hreflang="en"&gt;Drupal 8&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/development" hreflang="en"&gt;Development&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Mon, 31 Dec 2018 10:38:02 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">163 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Drupal 8 as a Static Site: Contact Form Architecture</title>
  <link>http://badzilla.co.uk/drupal-8-static-site-contact-form-architecture</link>
  <description>
&lt;span&gt;Drupal 8 as a Static Site: Contact Form Architecture&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Wed, 26/12/2018 - 11:06&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;As I have already mentioned in this sequence of blogs, the intention is to use AWS products for my static site contact form. It's worthwhile explaining the proposed architecture and steps involved to implement such a solution. On the face of it, it may appear somewhat convoluted, but AWS provide a number of complementary products to achieve what we want, and the configuration can be saved in code so it is easy to reproduce. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Architecture&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Form%20Submission%20%281%29.jpg?itok=10FV-4E6 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-12/Form%20Submission%20%281%29.jpg?itok=KWSN4VeQ 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-12/Form%20Submission%20%281%29.jpg?itok=bO9_BzQz 960w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Form%20Submission%20%281%29.jpg?itok=10FV-4E6" alt="Architecture Diagram" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The above diagram shows the architecture of our contact form, and the flow through the form ecosystem. Let's have a look at the components. &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Webpage with Contact Form&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Drupal comes with a contact form in core, and therefore this is fairly straightforward, albeit with a couple of hurdles to jump. Firstly I would like to place my contact form on my &lt;a href="http://badzilla.co.uk/about"&gt;About Me&lt;/a&gt; page underneath my existing bio. To achieve this I need the form to be a block which will require the installation of a contrib module. In addition I want my form's action to POST the form data to an external URL which isn't supported in the core form - so that will need a solution too. &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;AWS API Gateway&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The form will be submitted for processing to AWS since we don't have a backend on our own static site - hence why the form needs an external URL for its action parameter. &lt;/p&gt;

&lt;p&gt;We will use AWS API Gateway which is a fully managed service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at any scale. This will give us access to AWS compute backend services to process our POSTed form. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;AWS Lambda Function&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;AWS Lambda is a FaaS (Function as a Service) compute service. It is excellent at running a snippet of code on demand once it's been triggered, for instance in our case by the contact form being POSTed.&lt;/p&gt;
&lt;p&gt;PHP isn't a supported Lambda language, but there are workarounds for this - as explained in my sequence of blogs &lt;a href="http://badzilla.co.uk/real-world-php-lambda-app"&gt;here&lt;/a&gt;. Using these workarounds, we will develop a PHP app to process the form, and in addition we will need the AWS PHP SDK to interface with AWS SES (Simple Email Service). &lt;/p&gt;
&lt;p&gt;The PHP code will reside in Amazon's S3 object storage, and we will use the &lt;a href="https://serverless.com/"&gt;serverless&lt;/a&gt; product along with the aws console to manage the deploy process. &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;AWS SES&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;AWS SES is a very cost effective method of sending marketing, notification and transactional emails. For the amount of usage a blog contact form would see, it's highly unlikely to go above the AWS free tier threshold. It is the perfect tool for sending the contact form contents onto my personal email account. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Inbox&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The objective is the form contents should arrive into my Gmail inbox for me to read and action if necessary. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Thank you page&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The last activity of the Lambda function is to redirect the submitted form back to the website's thank you page which will have to be constructed as part of this exercise. The redirect will be a 307 to preserve the POSTed parameters that can be parsed and injected into the thank you message with a few lines of JavaScript.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/static-site" hreflang="en"&gt;Static Site&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal8" hreflang="en"&gt;Drupal 8&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/lambda" hreflang="en"&gt;lambda&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Wed, 26 Dec 2018 11:06:18 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">162 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Drupal 8 as a Static Site: JavaScript Search Client</title>
  <link>http://badzilla.co.uk/drupal-8-static-site-javascript-search-client</link>
  <description>
&lt;span&gt;Drupal 8 as a Static Site: JavaScript Search Client&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sat, 15/12/2018 - 10:19&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;We now need to plug the Elasticsearch query that was built in &lt;a href="http://badzilla.co.uk/drupal-8-static-site-elasticsearch-query"&gt;the previous blog&lt;/a&gt; into a JavaScript client that has been loaded on the search page as described in another &lt;a href="http://badzilla.co.uk/drupal-8-static-site-search-architecture-and-drupal-configuration"&gt;earlier blog&lt;/a&gt;. So a few lines of JavaScript will be required here, and it will need to work on my three environments:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Sandbox Drupal site connecting to local Elasticsearch server.&lt;/li&gt;
	&lt;li&gt;Sandbox static site connecting to local Elasticsearch server.&lt;/li&gt;
	&lt;li&gt;Production static site connecting to production Elasticsearch server. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The JavaScript will use the elasticsearch.js API library which can be downloaded from &lt;a href="https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html"&gt;here&lt;/a&gt;. We need to make our theme aware of our JavaScript files and we only wanted them loading on the node search page route. Our JavaScript file will be called beezee_elastic.js, which is the name of my theme (beezee8) and elastic obviously.  &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Add the JavaScript to the Beezee theme&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Firstly we need an entry in our theme's info.yml file under the Libraries heading. &lt;br /&gt;
&lt;strong&gt;beezee8.info.yml&lt;/strong&gt;&lt;br /&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;libraries:
  - &lt;span style="color: #ff0000;"&gt;'beezee8/elastic-library'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Next we need to append to the libraries yml file the location of our JavaScript files - the Elastic API library and our own personal script. &lt;br /&gt;
&lt;strong&gt;beezee8.libraries.yml&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;elastic-library:
  js:
    js&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;elasticsearch-js&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;elasticsearch.min.js: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
    js&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;beezee&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;beezee_elastic.js: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt; &lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Obviously we then have to copy our JS files into the filesystem at those locations - for now I will have a placeholder empty file for beezee_elastic.js which we will flesh out later.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Load the JavaScript files on the search page only&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;There are a few ways of doing this, but my favourite is to use a preprocessor function in the {themename}.theme file. We can use hook_preprocess_page for this.&lt;br /&gt;
&lt;strong&gt;beezee8.theme&lt;/strong&gt;
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #FF8000"&gt;/**&lt;br /&gt; * @param $variables&lt;br /&gt; */&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;function &lt;/span&gt;&lt;span style="color: #0000BB"&gt;beezee8_preprocess_page&lt;/span&gt;&lt;span style="color: #007700"&gt;(&amp;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$variables&lt;/span&gt;&lt;span style="color: #007700"&gt;) {&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #FF8000"&gt;// If we are on the search page, load the JS search client api&lt;br /&gt;    // and our implementation to Elasticsearch&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #007700"&gt;if (\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Drupal&lt;/span&gt;&lt;span style="color: #007700"&gt;::&lt;/span&gt;&lt;span style="color: #0000BB"&gt;routeMatch&lt;/span&gt;&lt;span style="color: #007700"&gt;()-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;getRouteName&lt;/span&gt;&lt;span style="color: #007700"&gt;() == &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'search.view_node_search'&lt;/span&gt;&lt;span style="color: #007700"&gt;) {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$variables&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#attached'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'library'&lt;/span&gt;&lt;span style="color: #007700"&gt;][] = &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'beezee8/elastic-library'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;The JavaScript search client&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Ok so finally we are ready to build out our front end search client. Here we go!&lt;br /&gt;
&lt;strong&gt;beezee_elastic.js&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="javascript geshifilter-javascript" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000066; font-weight: bold;"&gt;function&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;$&lt;span style="color: #339933;"&gt;,&lt;/span&gt; Drupal&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
 
    &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; elastic_once&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
    &lt;span style="color: #000066; font-weight: bold;"&gt;function&lt;/span&gt; BeezeeElastic&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        &lt;span style="color: #000066; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #339933;"&gt;!&lt;/span&gt;elastic_once&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
            elastic_once &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #003366; font-weight: bold;"&gt;true&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
            &lt;span style="color: #006600; font-style: italic;"&gt;// Get the params from the url&lt;/span&gt;
            &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; pageURL &lt;span style="color: #339933;"&gt;=&lt;/span&gt; window.&lt;span style="color: #660066;"&gt;location&lt;/span&gt;.&lt;span style="color: #660066;"&gt;search&lt;/span&gt;.&lt;span style="color: #660066;"&gt;substring&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;1&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; URLVariables &lt;span style="color: #339933;"&gt;=&lt;/span&gt; pageURL.&lt;span style="color: #660066;"&gt;split&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;'&amp;'&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; keys&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            i &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;0&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            while &lt;span style="color: #009900;"&gt;(&lt;/span&gt;i &lt;span style="color: #339933;"&gt;&lt;&lt;/span&gt; URLVariables.&lt;span style="color: #660066;"&gt;length&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; ParameterName &lt;span style="color: #339933;"&gt;=&lt;/span&gt; URLVariables&lt;span style="color: #009900;"&gt;[&lt;/span&gt;i&lt;span style="color: #009900;"&gt;]&lt;/span&gt;.&lt;span style="color: #660066;"&gt;split&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;'='&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                &lt;span style="color: #000066; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;ParameterName&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;0&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt; &lt;span style="color: #339933;"&gt;==&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;'keys'&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                    keys &lt;span style="color: #339933;"&gt;=&lt;/span&gt; ParameterName&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;1&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                i&lt;span style="color: #339933;"&gt;++;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
            &lt;span style="color: #006600; font-style: italic;"&gt;// Did we get anything from the URL? If not bail, otherwise do the search.&lt;/span&gt;
            &lt;span style="color: #006600; font-style: italic;"&gt;// We shouldn't get to here so don't show a message to user.&lt;/span&gt;
            &lt;span style="color: #000066; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #339933;"&gt;!&lt;/span&gt;keys&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                console.&lt;span style="color: #660066;"&gt;log&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;'Invalid keys'&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                &lt;span style="color: #000066; font-weight: bold;"&gt;return&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
            &lt;span style="color: #006600; font-style: italic;"&gt;// Add the search key to the h1 selector&lt;/span&gt;
            $&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;"h1"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #660066;"&gt;append&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;Drupal.&lt;span style="color: #660066;"&gt;t&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;" for "&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; keys&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
            &lt;span style="color: #006600; font-style: italic;"&gt;// Endpoint defined during instantiation of API Client&lt;/span&gt;
            &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; client &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;new&lt;/span&gt; elasticsearch.&lt;span style="color: #660066;"&gt;Client&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                host&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;'http://meedjum.test:9200/'&lt;/span&gt; &lt;span style="color: #006600; font-style: italic;"&gt;/*,*/&lt;/span&gt;
                &lt;span style="color: #006600; font-style: italic;"&gt;/* log: 'trace' */&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
            client.&lt;span style="color: #660066;"&gt;search&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                index&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;'elasticsearch_index_badzilla_meedjum_staticcontent'&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                body&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                    query&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                        function_score&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                            query&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                                query_string&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                                    query&lt;span style="color: #339933;"&gt;:&lt;/span&gt; keys&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                                    fields&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;[&lt;/span&gt;
                                        &lt;span style="color: #3366CC;"&gt;"title"&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                                        &lt;span style="color: #3366CC;"&gt;"*body"&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                                        &lt;span style="color: #3366CC;"&gt;"term"&lt;/span&gt;
                                    &lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                                    default_operator&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"OR"&lt;/span&gt;
                                &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                            &lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                            functions&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;[&lt;/span&gt;
                                &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                                    linear&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                                        &lt;span style="color: #3366CC;"&gt;"created"&lt;/span&gt;&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                                            origin&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"now"&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                                            offset&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"365d"&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                                            scale&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"1460d"&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                                            decay&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;0.5&lt;/span&gt;
                                        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                                    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                                &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                            &lt;span style="color: #009900;"&gt;]&lt;/span&gt;
                        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                    highlight&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                        number_of_fragments&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;1&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                        pre_tags&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;"&lt;strong&gt;"&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                        post_tags&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;"&lt;/strong&gt;"&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                        fragment_size&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;400&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                        no_match_size&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;400&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                        phrase_limit&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;1&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                        fields&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                            &lt;span style="color: #3366CC;"&gt;"*body"&lt;/span&gt;&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;&lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                            &lt;span style="color: #3366CC;"&gt;"title"&lt;/span&gt;&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;&lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                            &lt;span style="color: #3366CC;"&gt;"term"&lt;/span&gt;&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;&lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt;
                    size&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;10&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #339933;"&gt;,&lt;/span&gt; response&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
            &lt;span style="color: #006600; font-style: italic;"&gt;/*
             Process the response from Elastic
             */&lt;/span&gt;
            &lt;span style="color: #000066; font-weight: bold;"&gt;function&lt;/span&gt; response&lt;span style="color: #009900;"&gt;(&lt;/span&gt;err&lt;span style="color: #339933;"&gt;,&lt;/span&gt; resp&lt;span style="color: #339933;"&gt;,&lt;/span&gt; status&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
 
                &lt;span style="color: #006600; font-style: italic;"&gt;// Are we logged in? If so our jQuery calls will be slightly different due to additional DOM stuff&lt;/span&gt;
                &lt;span style="color: #006600; font-style: italic;"&gt;// for non anonymous&lt;/span&gt;
                &lt;span style="color: #006600; font-style: italic;"&gt;// These are our targets for injecting the content on the page. Markup is Bootstrap 3&lt;/span&gt;
                &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; h1_find&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; h2_find&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                &lt;span style="color: #000066; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;$&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;".user-logged-in"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #660066;"&gt;length&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                    h1_find &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"h1 + nav:last-child"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                    h2_find &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"h1 + nav + h2:last-child"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;}&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;else&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                    h1_find &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"h1"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                    h2_find &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"h1 + h2:last-child"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
                &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; hits &lt;span style="color: #339933;"&gt;=&lt;/span&gt; resp.&lt;span style="color: #660066;"&gt;hits&lt;/span&gt;.&lt;span style="color: #660066;"&gt;hits&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
                &lt;span style="color: #000066; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;resp.&lt;span style="color: #660066;"&gt;hits&lt;/span&gt;.&lt;span style="color: #660066;"&gt;total&lt;/span&gt; &lt;span style="color: #339933;"&gt;==&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;0&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                    $&lt;span style="color: #009900;"&gt;(&lt;/span&gt;h1_find&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #660066;"&gt;after&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;"&lt;h3&gt;"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; Drupal.&lt;span style="color: #660066;"&gt;t&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;"Your search yielded no results."&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;/h3&gt;"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                &lt;span style="color: #000066; font-weight: bold;"&gt;else&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                    $&lt;span style="color: #009900;"&gt;(&lt;/span&gt;h1_find&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #660066;"&gt;after&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;"&lt;h2&gt;"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; Drupal.&lt;span style="color: #660066;"&gt;t&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;"Search results"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;/h2&gt;"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
                    &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; inject &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;ol&gt;"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                    $.&lt;span style="color: #660066;"&gt;each&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;hits&lt;span style="color: #339933;"&gt;,&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;function&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;key&lt;span style="color: #339933;"&gt;,&lt;/span&gt; value&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
 
                        &lt;span style="color: #006600; font-style: italic;"&gt;// Url, title and Body&lt;/span&gt;
                        &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; prefix &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;li&gt;&lt;h3&gt;"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                        &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; suffix &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;/li&gt;"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                        &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; title &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;a href=&lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; value._source.&lt;span style="color: #660066;"&gt;url&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;0&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;span style="color: #000099; font-weight: bold;"&gt;\"&lt;/span&gt;&gt;"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; value.&lt;span style="color: #660066;"&gt;highlight&lt;/span&gt;.&lt;span style="color: #660066;"&gt;title&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;0&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;/a&gt;&lt;/h3&gt;"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
                        &lt;span style="color: #006600; font-style: italic;"&gt;// do we have a book body or a paragraph body?&lt;/span&gt;
                        &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; body&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                        &lt;span style="color: #000066; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000066; font-weight: bold;"&gt;typeof&lt;/span&gt; value.&lt;span style="color: #660066;"&gt;highlight&lt;/span&gt;.&lt;span style="color: #660066;"&gt;blog_body&lt;/span&gt; &lt;span style="color: #339933;"&gt;!=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;'undefined'&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                            body &lt;span style="color: #339933;"&gt;=&lt;/span&gt; value.&lt;span style="color: #660066;"&gt;highlight&lt;/span&gt;.&lt;span style="color: #660066;"&gt;blog_body&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;0&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                        &lt;span style="color: #009900;"&gt;}&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;else&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                            body &lt;span style="color: #339933;"&gt;=&lt;/span&gt; value.&lt;span style="color: #660066;"&gt;highlight&lt;/span&gt;.&lt;span style="color: #660066;"&gt;body&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
                        body &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;p&gt;"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; body &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;/p&gt;"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
                        inject &lt;span style="color: #339933;"&gt;+=&lt;/span&gt; prefix &lt;span style="color: #339933;"&gt;+&lt;/span&gt; title &lt;span style="color: #339933;"&gt;+&lt;/span&gt; body &lt;span style="color: #339933;"&gt;+&lt;/span&gt; suffix&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
                        &lt;span style="color: #006600; font-style: italic;"&gt;// Add the tag&lt;/span&gt;
                        &lt;span style="color: #000066; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #000066; font-weight: bold;"&gt;typeof&lt;/span&gt; value.&lt;span style="color: #660066;"&gt;highlight&lt;/span&gt;.&lt;span style="color: #660066;"&gt;term&lt;/span&gt; &lt;span style="color: #339933;"&gt;!=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;'undefined'&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
                            inject &lt;span style="color: #339933;"&gt;+=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;p&gt;"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; Drupal.&lt;span style="color: #660066;"&gt;t&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;"Tag:"&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;" "&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; value.&lt;span style="color: #660066;"&gt;highlight&lt;/span&gt;.&lt;span style="color: #660066;"&gt;term&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;/p&gt;"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
                        &lt;span style="color: #006600; font-style: italic;"&gt;// Author and date&lt;/span&gt;
                        &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; gb_obj &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;new&lt;/span&gt; &lt;span style=""&gt;Date&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;value._source.&lt;span style="color: #660066;"&gt;created&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;0&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt; &lt;span style="color: #339933;"&gt;*&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;1000&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                        &lt;span style="color: #000066; font-weight: bold;"&gt;var&lt;/span&gt; gb_date &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;'0'&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; gb_obj.&lt;span style="color: #660066;"&gt;getDate&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #660066;"&gt;slice&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #339933;"&gt;-&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;2&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt;
                            &lt;span style="color: #3366CC;"&gt;"/"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #3366CC;"&gt;'0'&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;gb_obj.&lt;span style="color: #660066;"&gt;getMonth&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #CC0000;"&gt;1&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #660066;"&gt;slice&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #339933;"&gt;-&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;2&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt;
                            &lt;span style="color: #3366CC;"&gt;"/"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; gb_obj.&lt;span style="color: #660066;"&gt;getFullYear&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt;
                            &lt;span style="color: #3366CC;"&gt;" "&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"-"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&amp;nbsp"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt;
                            gb_obj.&lt;span style="color: #660066;"&gt;getHours&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;":"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt;
                            gb_obj.&lt;span style="color: #660066;"&gt;getMinutes&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
                        inject &lt;span style="color: #339933;"&gt;+=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;p&gt;"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; value._source.&lt;span style="color: #660066;"&gt;author&lt;/span&gt;&lt;span style="color: #009900;"&gt;[&lt;/span&gt;&lt;span style="color: #CC0000;"&gt;0&lt;/span&gt;&lt;span style="color: #009900;"&gt;]&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;" "&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"-"&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;" "&lt;/span&gt; &lt;span style="color: #339933;"&gt;+&lt;/span&gt; gb_date&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
 
                    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                    inject &lt;span style="color: #339933;"&gt;+=&lt;/span&gt; &lt;span style="color: #3366CC;"&gt;"&lt;/ol&gt;"&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                    $&lt;span style="color: #009900;"&gt;(&lt;/span&gt;h2_find&lt;span style="color: #009900;"&gt;)&lt;/span&gt;.&lt;span style="color: #660066;"&gt;after&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;inject&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
                &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
            &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
 
 
    Drupal.&lt;span style="color: #660066;"&gt;behaviors&lt;/span&gt;.&lt;span style="color: #660066;"&gt;beezee_elastic&lt;/span&gt; &lt;span style="color: #339933;"&gt;=&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
        attach&lt;span style="color: #339933;"&gt;:&lt;/span&gt; &lt;span style="color: #000066; font-weight: bold;"&gt;function&lt;/span&gt; &lt;span style="color: #009900;"&gt;(&lt;/span&gt;context&lt;span style="color: #339933;"&gt;,&lt;/span&gt; settings&lt;span style="color: #009900;"&gt;)&lt;/span&gt; &lt;span style="color: #009900;"&gt;{&lt;/span&gt;
            BeezeeElastic&lt;span style="color: #009900;"&gt;(&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
        &lt;span style="color: #009900;"&gt;}&lt;/span&gt;
    &lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;
&lt;span style="color: #009900;"&gt;}&lt;/span&gt;&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #009900;"&gt;(&lt;/span&gt;jQuery&lt;span style="color: #339933;"&gt;,&lt;/span&gt; Drupal&lt;span style="color: #009900;"&gt;)&lt;/span&gt;&lt;span style="color: #339933;"&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Code commentary&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;I'd like to think the code is self-explanatory, but here are a few words for additional clarification. &lt;/p&gt;
&lt;p&gt;The first block of code is processing the URL params. We are expecting the &lt;em&gt;?keys={search_phrase}&lt;/em&gt;. The search phrase needs to be injected into the Elasticsearch query later. &lt;/p&gt;
&lt;p&gt;The &lt;em&gt;client&lt;/em&gt; object is returned from me instantiating the Elasticsearch API. I needed a parameter of the Elasticsearch endpoint which is currently hardcoded. It will work for my two sandbox environments (Drupal and static) but not for production. I will have to come up with a solution to rewrite the endpoint during the deployment process!&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;client.search&lt;/em&gt; call is our query created earlier, and I have added the search term from the URL. The Elasticsearch API provides two mechanisms for this call - it can return a promise or invoke a callback. I opted for the latter. &lt;/p&gt;
&lt;p&gt;The &lt;em&gt;response&lt;/em&gt; function is the callback and it handles the Elastic response. My first task is to set the selectors where I will inject the results - note that the DOM is different whether I am logged into my sandbox Drupal or not - so my injection anchor points are different dependent upon this circumstance. &lt;/p&gt;
&lt;p&gt;I add the title, body text, tag, author and published date to my output, concatenating them together, and then inject them into the content area of the screen around ordered list tags. &lt;/p&gt;
&lt;p&gt;The next result is very similar visually to the default Drupal core search with the addition of my blog tags, although of course it can be styled differently if wanted. &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;The results&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-15%20at%2015.04.52.png?itok=ZnDNHXFC 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-12/Screenshot%202018-12-15%20at%2015.04.52.png?itok=w9IqdciG 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-12/Screenshot%202018-12-15%20at%2015.04.52.png?itok=WNHqHJYw 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2018-12/Screenshot%202018-12-15%20at%2015.04.52.png?itok=XruPF1MZ 1766w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-12/Screenshot%202018-12-15%20at%2015.04.52.png?itok=ZnDNHXFC" alt="results" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The script works well on both the Drupal and static sites in sandbox. The screenshot above shows a search on the word &lt;em&gt;nginx&lt;/em&gt;. At the moment I haven't built in a paginator, but that could come along later. &lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/static-site" hreflang="en"&gt;Static Site&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal8" hreflang="en"&gt;Drupal 8&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/js" hreflang="en"&gt;JavaScript&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sat, 15 Dec 2018 10:19:04 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">161 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Drupal 8 as a Static Site: Elasticsearch Query</title>
  <link>http://badzilla.co.uk/drupal-8-static-site-elasticsearch-query</link>
  <description>
&lt;span&gt;Drupal 8 as a Static Site: Elasticsearch Query&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Wed, 28/11/2018 - 14:35&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;The most fundamental part of the search is the query - this will determine which documents will be retrieved after a search. It must obviously reflect the search phrase input into the search form, and the results returned should be presented in an order of most relevant first. &lt;/p&gt;

&lt;p&gt;Elasticsearch is excellent at this - but it's crucial that the query reflects exactly what I want to achieve and it searches the correct fields. No two sites are the same and therefore no two search requirements are identical. I have decided that I want to search on the following:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Blog title&lt;/li&gt;
	&lt;li&gt;Blog body text (a custom defined Paragraph type)&lt;/li&gt;
	&lt;li&gt;Body text (only used with the book content type and not my regular blogs)&lt;/li&gt;
	&lt;li&gt;Technology vocabulary which I use to tag my blog&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each of these will be assigned a score during the search process and the results delivered back in high to low score order.&lt;/p&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Initial basic query&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Unless you re an expert in Elastsearch queries (I am definitely not that), you will need a useful tool with automatic syntax suggestions, and lo and behold Kibana is excellent at this. My first stab at the query is shown below, and it behaved pretty much to my expectations
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;GET &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;myindex&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;_search
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
  &lt;span style="color: #ff0000;"&gt;"query"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
        &lt;span style="color: #ff0000;"&gt;"query_string"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
           &lt;span style="color: #ff0000;"&gt;"query"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"Search phrase here"&lt;/span&gt;,
           &lt;span style="color: #ff0000;"&gt;"fields"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;
              &lt;span style="color: #ff0000;"&gt;"title"&lt;/span&gt;,
              &lt;span style="color: #ff0000;"&gt;"*body"&lt;/span&gt;,
              &lt;span style="color: #ff0000;"&gt;"term"&lt;/span&gt;
              &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;,
            &lt;span style="color: #ff0000;"&gt;"default_operator"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"or"&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;,
  &lt;span style="color: #ff0000;"&gt;"highlight"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
        &lt;span style="color: #ff0000;"&gt;"number_of_fragments"&lt;/span&gt; : &lt;span style="color: #000000;"&gt;1&lt;/span&gt;,
        &lt;span style="color: #ff0000;"&gt;"pre_tags"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;strong&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;,
        &lt;span style="color: #ff0000;"&gt;"post_tags"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;/strong&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;,
        &lt;span style="color: #ff0000;"&gt;"fragment_size"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;400&lt;/span&gt;,
        &lt;span style="color: #ff0000;"&gt;"no_match_size"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;400&lt;/span&gt;,
        &lt;span style="color: #ff0000;"&gt;"phrase_limit"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;1&lt;/span&gt;,        
        &lt;span style="color: #ff0000;"&gt;"fields"&lt;/span&gt; : &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
            &lt;span style="color: #ff0000;"&gt;"*body"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;,
            &lt;span style="color: #ff0000;"&gt;"title"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;,
            &lt;span style="color: #ff0000;"&gt;"term"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;,
  &lt;span style="color: #ff0000;"&gt;"size"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;10&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Some of this is self-explanatory, some less so. Let's cherry pick our explanations.&lt;br /&gt;
&lt;strong&gt;*body&lt;/strong&gt; - I have two fields which contain the word body and these can be searched using a wildcard.&lt;br /&gt;
&lt;strong&gt;highlight&lt;/strong&gt; - This is where I specify what I actually want to display back to the end user. The following parameters defined this. &lt;br /&gt;
&lt;strong&gt;number_of_fragments&lt;/strong&gt; - The maximum number of fragments to return.&lt;br /&gt;
&lt;strong&gt;pre_tags&lt;/strong&gt; and &lt;strong&gt;post_tags&lt;/strong&gt; - When the search term is found, we can specify what tags we want before and after. I chose &lt;strong&gt;strong&lt;/strong&gt; instead of the default &lt;strong&gt;em&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;fragment_size&lt;/strong&gt; - How many characters the snipped of the find will contain as a maximum, although it could be less depending upon how Elasticsearch's paragraph and line break algorithm interprets the result&lt;br /&gt;
&lt;strong&gt;no_match_size&lt;/strong&gt; - As above if there are no matches in a particular field. I still want to show the snippet so the user has got some context.&lt;br /&gt;
&lt;strong&gt;phrase_limit&lt;/strong&gt; - Controls the number of matching phrases in a document that are considered.&lt;br /&gt;&lt;br /&gt;
The major shortcoming of this query is it shows no favouritism towards the date the blog is published. Whether it was published yesterday or ten years ago, the score will be same.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Adding a date decay to favour more recent blogs&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-11/DateDecay.png?itok=hlw5y4c6 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-11/DateDecay.png?itok=g_CEfRV0 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-11/DateDecay.png?itok=9dtA-6wg 813w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-11/DateDecay.png?itok=hlw5y4c6" alt="Elasticsearch date decay" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Technical blogs are ephemeral and transitory. They tend to have a shelf life when they are very popular, but then their popularity will wane as time goes by. This can be due to a number of factors - such as the popularity of the subject of the blog, the technology written about evolving thus obsoleting the origin blog, and the subject of the blog becoming commonplace or covered more extensively in official documentation.&lt;/p&gt;
&lt;p&gt;Therefore we need a mechanism to favour newer blogs in our search that will be more relevant to our users. Elasticsearch has the &lt;strong&gt;decay&lt;/strong&gt; feature, and it supports three different mathematical formula. There is &lt;em&gt;gauss&lt;/em&gt;, &lt;em&gt;linear&lt;/em&gt; and &lt;em&gt;exp&lt;/em&gt;. I had a think here - I could use the default Gaussian approach and with some subtle parameter settings I think it would have done a good job. I could also have used Exponential, with the relatively shallow curve to present the passing of time. In the end I decided I liked a linear representation. &lt;/p&gt;
&lt;p&gt;My rationale is this: A blog will be totally relevant for about a year, then it will decay at a linear rate for a number of years, then it will hit the bottom. Sheer speculation drove me to use a total decay period of eight years although I concede this is somewhat arbitrary and probably sub-optimal. &lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;br /&gt;The syntax for representing this is a little arcane. Here we go:
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;&lt;span style="color: #ff0000;"&gt;"function_score"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
  &lt;span style="color: #ff0000;"&gt;"functions"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #ff0000;"&gt;"linear"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
        &lt;span style="color: #ff0000;"&gt;"created"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
          &lt;span style="color: #ff0000;"&gt;"origin"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"now"&lt;/span&gt;,
          &lt;span style="color: #ff0000;"&gt;"offset"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"365d"&lt;/span&gt;, 
          &lt;span style="color: #ff0000;"&gt;"scale"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"1460d"&lt;/span&gt;,
          &lt;span style="color: #ff0000;"&gt;"decay"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;0.5&lt;/span&gt;
          &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Here is the commentary:&lt;br /&gt;
&lt;strong&gt;created&lt;/strong&gt;  - This is the name of the date field for the date the content was published&lt;br /&gt;
&lt;strong&gt;origin&lt;/strong&gt; - The start point for our time span, which will always be anchored at the current date.&lt;br /&gt;
&lt;strong&gt;offset&lt;/strong&gt; - This is the initial flat spot at the top of the graph above. I am saying here - all documents in the first year will be scored equally from a date created perspective.&lt;br /&gt;
&lt;strong&gt;scale&lt;/strong&gt; - Defines the distance from origin + offset at which the computed score will equal decay parameter. &lt;br /&gt;
&lt;strong&gt;decay&lt;/strong&gt; - The decay parameter defines how documents are scored at the distance given at scale. So if you divide decay into scale you get the figure of 8 years.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;The complete query&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Adding the decay to the initial query means that they &lt;strong&gt;multiplied together&lt;/strong&gt; (inferred by default).
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;GET &lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;myindex&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;_search
&lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
 
  &lt;span style="color: #ff0000;"&gt;"query"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    &lt;span style="color: #ff0000;"&gt;"function_score"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #ff0000;"&gt;"query"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
        &lt;span style="color: #ff0000;"&gt;"query_string"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
          &lt;span style="color: #ff0000;"&gt;"query"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"Search phrase here"&lt;/span&gt;,
             &lt;span style="color: #ff0000;"&gt;"fields"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;
                &lt;span style="color: #ff0000;"&gt;"title"&lt;/span&gt;,
                &lt;span style="color: #ff0000;"&gt;"*body"&lt;/span&gt;,
                &lt;span style="color: #ff0000;"&gt;"term"&lt;/span&gt;   
             &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;,
             &lt;span style="color: #ff0000;"&gt;"default_operator"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"OR"&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;,
      &lt;span style="color: #ff0000;"&gt;"functions"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
          &lt;span style="color: #ff0000;"&gt;"linear"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
            &lt;span style="color: #ff0000;"&gt;"created"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
              &lt;span style="color: #ff0000;"&gt;"origin"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"now"&lt;/span&gt;,
              &lt;span style="color: #ff0000;"&gt;"offset"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"365d"&lt;/span&gt;, 
              &lt;span style="color: #ff0000;"&gt;"scale"&lt;/span&gt;: &lt;span style="color: #ff0000;"&gt;"1460d"&lt;/span&gt;,
              &lt;span style="color: #ff0000;"&gt;"decay"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;0.5&lt;/span&gt;
            &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
          &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
        &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
      &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;,
    &lt;span style="color: #ff0000;"&gt;"highlight"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
    &lt;span style="color: #ff0000;"&gt;"number_of_fragments"&lt;/span&gt; : &lt;span style="color: #000000;"&gt;1&lt;/span&gt;,
    &lt;span style="color: #ff0000;"&gt;"pre_tags"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;strong&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;,
    &lt;span style="color: #ff0000;"&gt;"post_tags"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;"&lt;/strong&gt;"&lt;/span&gt; &lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt;,
    &lt;span style="color: #ff0000;"&gt;"fragment_size"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;400&lt;/span&gt;,
    &lt;span style="color: #ff0000;"&gt;"no_match_size"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;400&lt;/span&gt;,
    &lt;span style="color: #ff0000;"&gt;"phrase_limit"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;1&lt;/span&gt;,        
    &lt;span style="color: #ff0000;"&gt;"fields"&lt;/span&gt; : &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;
      &lt;span style="color: #ff0000;"&gt;"*body"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;,
      &lt;span style="color: #ff0000;"&gt;"title"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;,
      &lt;span style="color: #ff0000;"&gt;"term"&lt;/span&gt;: &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
    &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;
  &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;,
  &lt;span style="color: #ff0000;"&gt;"size"&lt;/span&gt;: &lt;span style="color: #000000;"&gt;10&lt;/span&gt;
&lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/static-site" hreflang="en"&gt;Static Site&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal8" hreflang="en"&gt;Drupal 8&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Wed, 28 Nov 2018 14:35:57 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">160 at http://badzilla.co.uk</guid>
    </item>
<item>
  <title>Drupal 8 as a Static Site: Disable Core Search</title>
  <link>http://badzilla.co.uk/drupal-8-static-site-disable-core-search</link>
  <description>
&lt;span&gt;Drupal 8 as a Static Site: Disable Core Search&lt;/span&gt;

&lt;span&gt;&lt;span lang="" about="http://badzilla.co.uk/user/1" typeof="schema:Person" property="schema:name" datatype="" xml:lang=""&gt;nigel&lt;/span&gt;&lt;/span&gt;

&lt;span&gt;Sun, 18/11/2018 - 10:04&lt;/span&gt;

      &lt;div class="field field--name-field-heading-image-text field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;&lt;p&gt;Since the static site will not have access to the Drupal 8 Core Search facility, it can be removed by using the command &lt;em&gt;drush pm_uninstall search&lt;/em&gt; on the command line, or by visiting &lt;em&gt;admin/modules/uninstall.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The problem with that approach is core search also has the search form that appears as a block in the navbar on every page of my website. If I uninstall core search I lose the form at the same time. It is my desire to keep on using the search form despite having an Elasticsearch backend. The proposed Elasticsearch JavaScript client will be installed on the /search route which is where the core search form action is directed to. &lt;/p&gt;
&lt;p&gt;Okay, so feasibly I could uninstall the core search and do either:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a custom block with a search form that replicates (from an HTML frontend perspective) the core search form.&lt;/li&gt;
&lt;li&gt;Copy the generated markup from the core search form, and paste it into the page template.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I don't like either approach. I would prefer to keep the core search and stub it so it doesn't actually do any backend searching. That way I will have near identical functionality for both my sandbox static and sandbox Drupal sites. &lt;/p&gt;
&lt;p&gt;To stub the search I would have to alter the default search route and replace it with my own custom route with a controller that returns nothing.&lt;/p&gt;
&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Define the route subscriber config&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;The first step is to add to our custom module's services file.&lt;br /&gt;
&lt;strong&gt;badzilla_static.services.yml&lt;/strong&gt;
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;  &lt;span style="color: #000000; font-weight: bold;"&gt;&lt;&lt;/span&gt;-- previous entry snipped --&lt;span style="color: #000000; font-weight: bold;"&gt;&gt;&lt;/span&gt;
  badzilla.route_subscriber:
      class: Drupal\badzilla_static\Routing\RouteSubscriber
      tags:
        - &lt;span style="color: #7a0874; font-weight: bold;"&gt;{&lt;/span&gt; name: event_subscriber &lt;span style="color: #7a0874; font-weight: bold;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
We have now defined where our route subscriber lives. Let's create.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Route subscriber class&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;We need to create the directory structure and the file itself first.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;mkdir&lt;/span&gt;  src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;Routing
$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;touch&lt;/span&gt; src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;Routing&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;RouteSubscriber.php&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
And the file contents are: &lt;br /&gt;
&lt;strong&gt;RouteSubscriber.php&lt;/strong&gt;
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;br /&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #FF8000"&gt;/**&lt;br /&gt;* @file&lt;br /&gt;* Contains \Drupal\mymodule\Routing\RouteSubscriber.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;namespace &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Drupal&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;badzilla_static&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Routing&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;br /&gt;use &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Drupal&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Core&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Routing&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;RouteSubscriberBase&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;use &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Symfony&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Component&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Routing&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;RouteCollection&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #FF8000"&gt;/**&lt;br /&gt;* Listens to the dynamic route events.&lt;br /&gt;*/&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;class &lt;/span&gt;&lt;span style="color: #0000BB"&gt;RouteSubscriber &lt;/span&gt;&lt;span style="color: #007700"&gt;extends &lt;/span&gt;&lt;span style="color: #0000BB"&gt;RouteSubscriberBase &lt;/span&gt;&lt;span style="color: #007700"&gt;{&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #FF8000"&gt;/**&lt;br /&gt;    * {@inheritdoc}&lt;br /&gt;    */&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #007700"&gt;public function &lt;/span&gt;&lt;span style="color: #0000BB"&gt;alterRoutes&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;RouteCollection $collection&lt;/span&gt;&lt;span style="color: #007700"&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #FF8000"&gt;// Replace dynamically created "search.view_node_search" route's Controller with my own.&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #007700"&gt;if (&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$route &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$collection&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;get&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'search.view_node_search'&lt;/span&gt;&lt;span style="color: #007700"&gt;)) {&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$route&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;setDefault&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'_controller'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'\Drupal\badzilla_static\Controller\BadzillaStaticSearchController::view'&lt;/span&gt;&lt;span style="color: #007700"&gt;);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
Here I am replacing the built-in search module's controller with my own. Now let's build out my own do-nothing controller.&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Custom search controller&lt;/div&gt;
      
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;As previously, create the file structure.
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;mkdir&lt;/span&gt; src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;Controller
$ &lt;span style="color: #c20cb9; font-weight: bold;"&gt;touch&lt;/span&gt; src&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;Controller&lt;span style="color: #000000; font-weight: bold;"&gt;/&lt;/span&gt;BadzillaStaticSearchController.php&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Here's the controller in all its glory.&lt;br /&gt;
&lt;strong&gt;BadzillaStaticSearchController.php&lt;/strong&gt;
&lt;div class="codeblock geshifilter"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;namespace &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Drupal&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;badzilla_static&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Controller&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;br /&gt;use &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Drupal&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;search&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;SearchPageInterface&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;use &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Symfony&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Component&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;HttpFoundation&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Request&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;use &lt;/span&gt;&lt;span style="color: #0000BB"&gt;Drupal&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;search&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Controller&lt;/span&gt;&lt;span style="color: #007700"&gt;\&lt;/span&gt;&lt;span style="color: #0000BB"&gt;SearchController&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #FF8000"&gt;/**&lt;br /&gt; * Override the Route controller for search.&lt;br /&gt; */&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;class &lt;/span&gt;&lt;span style="color: #0000BB"&gt;BadzillaStaticSearchController &lt;/span&gt;&lt;span style="color: #007700"&gt;extends &lt;/span&gt;&lt;span style="color: #0000BB"&gt;SearchController &lt;/span&gt;&lt;span style="color: #007700"&gt;{&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #FF8000"&gt;/**&lt;br /&gt;     * {@inheritdoc}&lt;br /&gt;     */&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #007700"&gt;public function &lt;/span&gt;&lt;span style="color: #0000BB"&gt;view&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Request $request&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #0000BB"&gt;SearchPageInterface $entity&lt;/span&gt;&lt;span style="color: #007700"&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$build &lt;/span&gt;&lt;span style="color: #007700"&gt;= [];&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$plugin &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$entity&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;getPlugin&lt;/span&gt;&lt;span style="color: #007700"&gt;();&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$build&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#title'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$plugin&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;suggestedTitle&lt;/span&gt;&lt;span style="color: #007700"&gt;();&lt;br /&gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$results &lt;/span&gt;&lt;span style="color: #007700"&gt;= [];&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$build&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'search_results'&lt;/span&gt;&lt;span style="color: #007700"&gt;] = [&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#theme' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;br /&gt;                &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'item_list__search_results__' &lt;/span&gt;&lt;span style="color: #007700"&gt;. &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$plugin&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;getPluginId&lt;/span&gt;&lt;span style="color: #007700"&gt;(),&lt;br /&gt;                &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'item_list__search_results'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;            ],&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#items' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$results&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#empty' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;br /&gt;                &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#markup' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;''&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;            ],&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#list_type' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'ol'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'#context' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; [&lt;br /&gt;                &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'plugin' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$plugin&lt;/span&gt;&lt;span style="color: #007700"&gt;-&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;getPluginId&lt;/span&gt;&lt;span style="color: #007700"&gt;(),&lt;br /&gt;            ],&lt;br /&gt;        ];&lt;br /&gt;&lt;br /&gt;        return &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$build&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
The view function must return a render array, and so I have honoured the convention of the parent SearchController::view to large extent although obviously in my case there will always be no results returned. A useful stub!&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-heading-picture-text paragraph--view-mode--default"&gt;
          
            &lt;div class="field field--name-field-heading field--type-string field--label-hidden field--item"&gt;Clear Rebuild and Test&lt;/div&gt;
      
      &lt;div class="field field--name-field-blog-image field--type-image field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-11/Screenshot_2018-11-18_at_15_22_08-edited.png?itok=SkBm2FM6 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-11/Screenshot_2018-11-18_at_15_22_08-edited.png?itok=ckGbh1Np 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-11/Screenshot_2018-11-18_at_15_22_08-edited.png?itok=a925Zvff 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2018-11/Screenshot_2018-11-18_at_15_22_08-edited.png?itok=9SaizRUC 2314w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-11/Screenshot_2018-11-18_at_15_22_08-edited.png?itok=SkBm2FM6" alt="Seach1" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
              &lt;div class="field--item"&gt;    &lt;img srcset="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-11/Screenshot_2018-11-18_at_15_21_23-edited.png?itok=Hx9JuUhC 325w, https://assets.badzilla.co.uk/s3fs-public/styles/max_650x650/public/2018-11/Screenshot_2018-11-18_at_15_21_23-edited.png?itok=uFQLs4hF 650w, https://assets.badzilla.co.uk/s3fs-public/styles/max_1300x1300/public/2018-11/Screenshot_2018-11-18_at_15_21_23-edited.png?itok=MapWzEyf 1300w, https://assets.badzilla.co.uk/s3fs-public/styles/max_2600x2600/public/2018-11/Screenshot_2018-11-18_at_15_21_23-edited.png?itok=5giBsaDr 2312w" sizes="(min-width: 1290px) 1290px, 100vw" src="https://assets.badzilla.co.uk/s3fs-public/styles/max_325x325/public/2018-11/Screenshot_2018-11-18_at_15_21_23-edited.png?itok=Hx9JuUhC" alt="Search2" typeof="foaf:Image" class="img-responsive" /&gt;


&lt;/div&gt;
          &lt;/div&gt;
  
            &lt;div class="field field--name-field-blog-text field--type-text-long field--label-hidden field--item"&gt;Since we've added to our services yaml file we need to do the customary cache rebuild for our changes to take effect. 
&lt;div class="geshifilter"&gt;&lt;div class="bash geshifilter-bash" style="font-family:monospace;"&gt;&lt;pre style="font-family: monospace; font-weight: normal; font-style: normal"&gt;$ drush cr
 &lt;span style="color: #7a0874; font-weight: bold;"&gt;[&lt;/span&gt;success&lt;span style="color: #7a0874; font-weight: bold;"&gt;]&lt;/span&gt; Cache rebuild complete.&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
Next let's attempt a search on the dynamic and the static version of my sandbox Badzilla sites. The two screenshots above show that both the static and the dynamic version of the sandbox sites are correctly showing a blank search page. Next we have to plug in the client....&lt;/div&gt;
      
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
      &lt;div class="field field--name-field-blog-youtube field--type-entity-reference-revisions field--label-hidden field--items"&gt;
              &lt;div class="field--item"&gt;  &lt;div class="paragraph paragraph--type--blog-text-youtube paragraph--view-mode--default"&gt;
          
      &lt;/div&gt;
&lt;/div&gt;
          &lt;/div&gt;
  
  &lt;div class="field field--name-field-blog-terms field--type-entity-reference field--label-inline"&gt;
    &lt;div class="field--label"&gt;blog terms&lt;/div&gt;
          &lt;span class="field__items"&gt;
              &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/static-site" hreflang="en"&gt;Static Site&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal8" hreflang="en"&gt;Drupal 8&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/development" hreflang="en"&gt;Development&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/drupal" hreflang="en"&gt;Drupal&lt;/a&gt;&lt;/span&gt;
          &lt;span class="field--item"&gt;&lt;a href="http://badzilla.co.uk/php" hreflang="en"&gt;PHP&lt;/a&gt;&lt;/span&gt;
              &lt;/span&gt;
      &lt;/div&gt;
</description>
  <pubDate>Sun, 18 Nov 2018 10:04:27 +0000</pubDate>
    <dc:creator>nigel</dc:creator>
    <guid isPermaLink="false">159 at http://badzilla.co.uk</guid>
    </item>

  </channel>
</rss>
