Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Laravel support #2249

Merged
merged 11 commits into from
May 29, 2020
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ ddev is an open source tool that makes it simple to get local PHP development en
* [TYPO3 Quickstart](https://ddev.readthedocs.io/en/stable/users/cli-usage#typo3-quickstart)
* [Magento 1 Quickstart](https://ddev.readthedocs.io/en/stable/users/cli-usage#magento-1-quickstart)
* [Magento 2 Quickstart](https://ddev.readthedocs.io/en/stable/users/cli-usage#magento-2-quickstart)
* [Laravel Quickstart](https://ddev.readthedocs.io/en/stable/users/cli-usage#laravel-quickstart)

Having trouble? See our [support options below](#support). You might have trouble if [another local development tool is already using port 80 or 443](https://ddev.readthedocs.io/en/stable/users/troubleshooting/#unable-listen).

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# ddev laravel config

# You can override ddev's configuration by placing an edited copy
# of this config (or one of the other ones) in .ddev/nginx-site.conf
# See https://ddev.readthedocs.io/en/stable/users/extend/customization-extendibility/#providing-custom-nginx-configuration

# Set https to 'on' if x-forwarded-proto is https
map $http_x_forwarded_proto $fcgi_https {
default off;
https on;
}

server {
listen 80; ## listen for ipv4; this line is default and implied


# The WEBSERVER_DOCROOT variable is substituted with
# its value when the container is started.
root $WEBSERVER_DOCROOT;

include /etc/nginx/monitoring.conf;

include /etc/nginx/nginx_laravel.conf;
include /mnt/ddev_config/nginx/*.conf;
}

server {
listen 443 ssl;


# The WEBSERVER_DOCROOT variable is substituted with
# its value when the container is started.
root $WEBSERVER_DOCROOT;

ssl_certificate /etc/ssl/certs/master.crt;
ssl_certificate_key /etc/ssl/certs/master.key;

include /etc/nginx/monitoring.conf;

include /etc/nginx/nginx_laravel.conf;
include /mnt/ddev_config/nginx/*.conf;
}
54 changes: 54 additions & 0 deletions containers/ddev-webserver/files/etc/nginx/nginx_laravel.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
index index.html index.htm index.php;

# Make site accessible from http://localhost/
server_name _;

charset utf-8;

# Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html
sendfile off;
error_log /dev/stdout info;
access_log /var/log/nginx/access.log;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }

error_page 404 /index.php;

location ~ \.php$ {
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}

# Expire rules for static content
# Feed
location ~* \.(?:rss|atom)$ {
expires 1h;
}

# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}

# Prevent clients from accessing hidden files (starting with a dot)
# This is particularly important if you store .htpasswd files in the site hierarchy
# Access to `/.well-known/` is allowed.
# https://www.mnot.net/blog/2010/04/07/well-known
# https://tools.ietf.org/html/rfc5785
location ~* /\.(?!well-known\/) {
deny all;
}

# Prevent clients from accessing to backup/config/source files
location ~* (?:\.(?:bak|conf|dist|fla|in[ci]|log|psd|sh|sql|sw[op])|~)$ {
deny all;
}
77 changes: 76 additions & 1 deletion docs/users/cli-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ In addition to the *commands* listed above, there are loads and loads of tools i

## Quickstart Guides

Here are quickstart instructions for generic PHP, WordPress, Drupal 6, Drupal 7, Drupal 8, TYPO3, and Backdrop.
Here are quickstart instructions for generic PHP, WordPress, Drupal 6, Drupal 7, Drupal 8, TYPO3, Backdrop, Magento, Magento 2, and Laravel.

**Prerequisites:** Before you start, follow the [installation instructions](../index.md#installation). Make sure to [check the system requirements](../index.md#system-requirements), you will need *docker* and *docker-compose* to use ddev.

Expand Down Expand Up @@ -300,6 +300,81 @@ You may want to add the [Magento 2 Sample Data](https://devdocs.magento.com/guid

Note that Magento 2 is a huge codebase and using `nfs_mount_enabled: true` is recommended for performance on macOS and Windows, see [docs](performance/#using-nfs-to-mount-the-project-into-the-container).

### Laravel Quickstart

Get started with Laravel projects on ddev either using a new or existing composer project or by cloning a git repository.
The Laravel project type can be used for Lumen same as for Laravel.

#### Laravel Composer Setup Example

```
mkdir my-laravel-app
cd my-laravel-app
ddev config --project-type=laravel --docroot=public --create-docroot
ddev start
ddev composer create --prefer-dist laravel/laravel
ddev exec "cat .env.example | sed -E 's/DB_(HOST|DATABASE|USERNAME|PASSWORD)=(.*)/DB_\1=db/g' > .env"
ddev exec "php artisan key:generate"
ddev launch
```

#### Laravel Git Clone Example

Note that the git URL shown below is an example only, you'll need to use your own project.

```
git clone https://github.com/example/example-site
cd example-site
ddev config --project-type=laravel
ddev composer install
ddev exec "cat .env.example | sed -E 's/DB_(HOST|DATABASE|USERNAME|PASSWORD)=(.*)/DB_\1=db/g' > .env"
ddev exec "php artisan key:generate"
ddev launch
```

#### Laravel Database connection

In the examples above we used a one liner to copy `.env.example` as `env`and set the `DB_HOST`, `DB_DATABASE`, `DB_USERNAME` and `DB_PASSWORD` environment variables to the value of `db`.
These values are DDEV's default settings for the Database connection.

Instead of setting each connection variable we can add a ddev to the `connections` array in `config/databases.php` like this:

```
<?php

return [

...

'connections' => [

...

'ddev' => [
'driver' => 'mysql',
'host' => 'db',
'port' => 3306,
'database' => 'db',
'username' => 'db',
'password' => 'db',
'unix_socket' => '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],

],

...

];
```

This way we only need to change the value of `DB_CONNECTION` to `ddev` in the `.env` to work with the `db` service.
This is very handy if you have a local database installed and you want to switch between the connections faster by changing only one variable in `.env`

### Database Imports

Import a database with just one command; We offer support for several file formats, including: **.sql, sql.gz, mysql, mysql.gz, tar, tar.gz, and zip**.
Expand Down
1 change: 1 addition & 0 deletions pkg/ddevapp/apptypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ func init() {
nodeps.AppTypeMagento2: {
settingsCreator: createMagento2SettingsFile, uploadDir: getMagento2UploadDir, hookDefaultComments: nil, apptypeSettingsPaths: setMagento2SiteSettingsPaths, appTypeDetect: isMagento2App, postImportDBAction: nil, configOverrideAction: magento2ConfigOverrideAction, postConfigAction: nil, postStartAction: nil, importFilesAction: magentoImportFilesAction, defaultWorkingDirMap: nil,
},
nodeps.AppTypeLaravel: {appTypeDetect: isLaravelApp, postStartAction: laravelPostStartAction},
}
}

Expand Down
25 changes: 25 additions & 0 deletions pkg/ddevapp/ddevapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,21 @@ var (
DynamicURI: testcommon.URIWithExpect{URI: "/node/1", Expect: "Deep mediterranean quiche"},
FilesImageURI: "/sites/default/files/mediterranean-quiche-umami.jpg",
},
{
Name: "TestPkgLumen",
SourceURL: "https://github.com/drud/ddev_test_tarballs/releases/download/v1.1/ddev-lumen-testapp.tar.gz",
ArchiveInternalExtractionPath: "ddev-lumen-testapp/",
FilesTarballURL: "",
FilesZipballURL: "",
DBTarURL: "https://github.com/drud/ddev_test_tarballs/releases/download/v1.1/ddev-lumen-testapp_sql.tar.gz",
DBZipURL: "https://github.com/drud/ddev_test_tarballs/releases/download/v1.1/ddev-lumen-testapp_sql.zip",
FullSiteTarballURL: "",
Type: nodeps.AppTypeLaravel,
Docroot: "public",
Safe200URIWithExpectation: testcommon.URIWithExpect{URI: "/", Expect: "Laravel Components"},
DynamicURI: testcommon.URIWithExpect{URI: "/api/status-code/200", Expect: "indicates that the request has succeeded."},
FilesImageURI: "/images/200.jpg",
},
}

FullTestSites = TestSites
Expand Down Expand Up @@ -1562,6 +1577,11 @@ func TestDdevImportFilesDir(t *testing.T) {
}

for _, site := range TestSites {
if site.FilesTarballURL == "" && site.FilesZipballURL == "" {
t.Logf("=== SKIP TestDdevImportFilesDir for %s (FilesTarballURL and FilesZipballURL are not provided)\n", site.Name)
continue
}

switchDir := site.Chdir()
runTime := util.TimeTrack(time.Now(), fmt.Sprintf("%s %s", site.Name, t.Name()))
t.Logf("=== BEGIN TestDdevImportFilesDir for %s\n", site.Name)
Expand Down Expand Up @@ -1599,6 +1619,11 @@ func TestDdevImportFiles(t *testing.T) {
app := &ddevapp.DdevApp{}

for _, site := range TestSites {
if site.FilesTarballURL == "" && site.FilesZipballURL == "" && site.FullSiteTarballURL == "" {
t.Logf("=== SKIP TestDdevImportFiles for %s (FilesTarballURL and FilesZipballURL are not provided)\n", site.Name)
continue
}

switchDir := site.Chdir()
runTime := util.TimeTrack(time.Now(), fmt.Sprintf("%s %s", site.Name, t.Name()))

Expand Down
45 changes: 45 additions & 0 deletions pkg/ddevapp/laravel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ddevapp

import (
"github.com/drud/ddev/pkg/fileutil"
"github.com/drud/ddev/pkg/util"
"path/filepath"
)

const (
WarnTypeAbsent = iota
WarnTypeNotConfigured = iota
)

// isLaravelApp returns true if the app is of type laravel
func isLaravelApp(app *DdevApp) bool {
return fileutil.FileExists(filepath.Join(app.AppRoot, "artisan"))
}

func envSettingsWarning(status int) {
var srcFile = ".env"
var message = "Don't forget to configure the database in your .env file"

if WarnTypeAbsent == status {
srcFile += ".example"
message = "Don't forget to create the .env file with proper database settings"
}
util.Warning(message)
util.Warning("You can do it with this one-liner:")
util.Warning("ddev exec \"cat %v | sed -E 's/DB_(HOST|DATABASE|USERNAME|PASSWORD)=(.*)/DB_\\1=db/g' > .env\"", srcFile)
util.Warning("Read more on https://ddev.readthedocs.io/en/stable/users/cli-usage/#laravel-quickstart")
}

func laravelPostStartAction(app *DdevApp) error {
if fileutil.FileExists(filepath.Join(app.AppRoot, ".env")) {
isConfiguredDbHost, err := fileutil.FgrepStringInFile(app.SiteSettingsPath, `DB_HOST=db`)
isConfiguredDbConnection, _ := fileutil.FgrepStringInFile(app.SiteSettingsPath, `DB_CONNECTION=ddev`)
if err == nil && !isConfiguredDbHost && !isConfiguredDbConnection {
envSettingsWarning(WarnTypeNotConfigured)
}
} else {
envSettingsWarning(WarnTypeAbsent)
}

return nil
}
Empty file.
1 change: 1 addition & 0 deletions pkg/nodeps/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ const (
AppTypeWordPress = "wordpress"
AppTypeMagento = "magento"
AppTypeMagento2 = "magento2"
AppTypeLaravel = "laravel"
)

// Ports and other defaults
Expand Down
2 changes: 1 addition & 1 deletion pkg/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var DockerComposeFileFormatVersion = "3.6"
var WebImg = "drud/ddev-webserver"

// WebTag defines the default web image tag for drud dev
var WebTag = "20200515_klausi_remove_extra_nginx_stanza" // Note that this can be overridden by make
var WebTag = "20200513_laravel" // Note that this can be overridden by make

// DBImg defines the default db image used for applications.
var DBImg = "drud/ddev-dbserver"
Expand Down