Skip to main content

PHP

Dagger can be used to perform common CI tasks - testing, containerizing, publishing and more - for any PHP application.

The following code sample demonstrates how these CI tasks can be encapsulated as Dagger Functions in a Dagger module. It assumes:

  • A PHP 8.2.x Web application with:
    • Composer for package management
    • PHPUnit for application testing
  • Credentials to publish the containerized application image to a registry

Bootstrap a new module:

dagger init --name=my-module --sdk=go

Update the generated dagger/main.go file with the following code:

package main

import (
"context"
"fmt"
)

type MyModule struct{}

// return container image with application source code and dependencies
func (m *MyModule) Build(source *Directory) *Container {
return dag.Container().
From("php:8.2-apache-buster").
WithExec([]string{"apt-get", "update"}).
WithExec([]string{"apt-get", "install", "--yes", "git-core", "zip", "curl"}).
WithExec([]string{"docker-php-ext-install", "pdo", "pdo_mysql", "mysqli"}).
WithExec([]string{"sh", "-c", "sed -ri -e 's!/var/www/html!/var/www/public!g' /etc/apache2/sites-available/*.conf"}).
WithExec([]string{"sh", "-c", "sed -ri -e 's!/var/www/!/var/www/public!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf"}).
WithExec([]string{"a2enmod", "rewrite"}).
WithExec([]string{"sh", "-c", "curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer"}).
WithDirectory("/var/www", source.WithoutDirectory("dagger"), ContainerWithDirectoryOpts{
Owner: "www-data",
}).
WithWorkdir("/var/www").
WithExec([]string{"chmod", "-R", "775", "/var/www"}).
WithMountedCache("/root/.composer", dag.CacheVolume("composer-cache")).
WithMountedCache("/var/www/vendor", dag.CacheVolume("composer-vendor-cache")).
WithExec([]string{"composer", "install"})
}

// return result of unit tests
func (m *MyModule) Test(ctx context.Context, source *Directory) (string, error) {
return m.Build(source).
WithEnvVariable("PATH", "./vendor/bin:$PATH", ContainerWithEnvVariableOpts{
Expand: true,
}).
WithExec([]string{"phpunit"}).
Stdout(ctx)
}

// return address of published container image
func (m *MyModule) Publish(ctx context.Context, source *Directory, version string, registryAddress string, registryUsername string, registryPassword *Secret, imageName string) (string, error) {
return m.Build(source).
WithLabel("org.opencontainers.image.title", "PHP with Dagger").
WithLabel("org.opencontainers.image.version", version).
// uncomment this to use a custom entrypoint file
// .WithExec([]string{"chmod", "+x", "/var/www/docker-entrypoint.sh"}).
// .WithEntrypoint([]string{"/var/www/docker-entrypoint.sh"}).
WithRegistryAuth(registryAddress, registryUsername, registryPassword).
Publish(ctx, fmt.Sprintf("%s/%s/%s", registryAddress, registryUsername, imageName))
}
warning

The code sample above is illustrative only. Modify it to your application's specific requirements.

Here is an example of calling the Dagger Function to run an application's unit tests:

dagger call test --source=.

Here is an example of calling the Dagger Function to publish the application image to Docker Hub. Replace the DOCKER-HUB-USERNAME and DOCKER-HUB-PASSWORD placeholders with your Docker Hub credentials.

export REGISTRY_PASSWORD=DOCKER-HUB-PASSWORD
dagger call publish \
--source=. \
--version=0.1 \
--registry-address=docker.io \
--registry-username=DOCKER-HUB-USERNAME \
--registry-password=env:REGISTRY_PASSWORD \
--image-name=my-php-app

Some PHP applications may need to perform specific operations on startup, such as running database migrations or reading/writing cache data. This can be accomplished by overriding the container's default entrypoint with a custom entrypoint script for startup operations.

To use such a script, uncomment the relevant lines in the code sample above and create a script named docker-entrypoint.sh in the application directory. Here is an example of one such script, which runs database migrations for a Laravel Web application at startup:

#!/bin/bash
php artisan migrate
apache2-foreground