Laravel 5

Last Updated May 2015

Laravel, the "PHP framework for web artisans," is an extremely powerful PHP framework designed to make app development simple and beautiful. This doc walks through using Laravel 5 on Pagoda Box. After reading it, you should be familiar with:

  • Configuring Laravel to run on Pagoda Box
  • Using Laravel's built in tools to manage your app
  • Basking in the awesomeness of Laravel on Pagoda Box

This doc assumes you already have your Laravel 5 app running locally, using either Homestead or your preferred local webserver/environment.

Pagoda Box Laravel 5 Boilerplate

Everything discussed in the doc is already included in the Pagoda Box Laravel 5 Boilerplate. The boilerplate is also available as a quickstart.

Define Laravel Version in your Composer.json

Use Laravel 5.0.19+

In version 5.0.15, a change was made to store the required services.json file inside of the vendor directory. On Pagoda Box, the vendor directory shouldn't be writable, which prevents services.json from being written at this location. A fix was introduced in v5.0.19 that will store the services.json file in the framework directory instead of the vendor directory.

Details of the original change, the community response, and the introduction of the fix can be found in the commit summary.

In your composer.json, set the “laravel/framework” package version to “>=5.0.19”

Specify Laravel Version in composer.json JSON

  "require": {
    "laravel/framework": ">=5.0.19"
  }
composer.json

Use Laravel’s Environment Helpers to Configure Your App

Laravel 5’s config files are pre-populated with environment helpers that allow the codebase to work in multiple environments without much change. Generally these key-value pairs are defined in the .env file, but on Pagoda Box, you just need to create environment variables using the same keys. This can be done in the Boxfile.

Setting Laravel Environment Variables in the Boxfile YAML

  global:
    env:
      - APP_ENV: production
      - APP_DEBUG: false
      - APP_KEY: SomeRandomString
      - DB_HOST: 'MAP:DATABASE1_HOST'
      - DB_DATABASE: 'MAP:DATABASE1_NAME'
      - DB_USERNAME: 'MAP:DATABASE1_USER'
      - DB_PASSWORD: 'MAP:DATABASE1_PASS'
      - CACHE_DRIVER: file
      - SESSION_DRIVER: redis
      - QUEUE_DRIVER: redis
      - MAIL_DRIVER: mail
/Boxfile

Deploying a Boxfile with these environment variables will set Laravel’s config options.

App Environment

The APP_ENV option allows you to specify which environment config to use if your app is setup for multiple environments, which it should be by default.

App Debug

APP_DEBUG defines whether or not Laravel debug information is displayed in-browser. For production apps, this should be set to false.

App Key

APP_KEY defines your application key which is used to encrypt sensitive information. You need to provide your own key. It’s generally a random string of 32 characters.

Database Connection Credentials

Laravel 5 pre-populates database connection credentials using the following keys:

DB_HOST
DB_DATABASE
DB_USERNAME
DB_PASSWORD

Whenever a database is created on Pagoda Box, an environment variables for each connection credential is automatically generated. Through the use of environment variable mapping, the value of the Laravel keys can be mapped to the values of the auto-generated environment variables.

Mapping Database Environment Variables YAML

  global:
    env:
      DB_HOST: 'MAP:DATABASE1_HOST'
      DB_DATABASE: 'MAP:DATABASE1_NAME'
      DB_USERNAME: 'MAP:DATABASE1_USER'
      DB_PASSWORD: 'MAP:DATABASE1_PASS'
/Boxfile

Using these mappings, you won’t have to change any of the database connections in the Laravel codebase.

Cache Driver

CACHE_DRIVER defines which caching backend you’d like to use. The file driver is recommended in conjunction with nonpersistent_writable_dirs, but Laravel provides other options. More information regarding file-based caching below.

Session Driver

The SESSION_DRIVER defines which session backend you’d like to use. We recommend redis, but Laravel provides other options. More information regarding Redis sessions below.

Queue Driver

QUEUE_DRIVER defines which queuing engine you’d like to use when running a worker. Setting the queue driver isn’t necessary if you're not using Laravel’s queueing functionality. More information about queuing and workers is available below.

Mail Driver

MAIL_DRIVER defines how email is sent from your app. We recommend using mail, but there are other options. More information about setting up Laravel mail on Pagoda Box below.

Laravel and Composer require specific PHP extensions in order to function. On Pagoda Box, PHP extensions are enabled in your Boxfile. Lists of what extensions are available can be found in the PHP Extensions doc.

PHP Extensions in the Boxfile YAML

  web1:
    php_extensions:
      - json
      - mbstring
      - mcrypt
      - tokenizer
      - pdo_mysql
      - xcache
      - redis
/Boxfile

Required Extensions

  • json

  • mbstring

  • mcrypt

  • tokenizer

Extensions Required by Data Services

MySQL and Redis are the most commonly used data services used with Laravel. However many other options are available. If you’re using other service types, simply include the appropriate PHP extension(s).

  • pdo_mysql: MySQL adapter. Required if using a MySQL database.

  • redis: Redis adapter. Required if using Redis. Should be used in conjunction with the Predis Library.

  • xcache: Byte-code Caching engine. Provides significant performance gains in most apps.

Set Your App’s Document Root

In Laravel, the public directory is the “web root” of your application. This is enforced through Apache’s DocumentRoot setting. On Pagoda Box, the document root is specified through the httpd_document_root Boxfile setting.

Setting the Document Root in the Boxfile YAML

  web1:
    httpd_document_root: public
/Boxfile

Define Network Directories

Laravel needs a handful of directories inside of storage to be writable. Because apps on Pagoda Box are distributed (multiple instances spread across multiple machines), any directories that need writable permissions must be stored in a centralized location, then shared between instances. This is the purpose of Network Storage and Network Directories.

Specify the storage/framework and storage/app as network_dirs in your Boxfile. This should be done under any code service that needs access to the files inside of the network directories. Adding network_dirs to web1 will not grant worker1 access to those directories. They need to be listed under both.

Network Directories in the Boxfile YAML

  web1:
    network_dirs:
      - storage/framework
      - storage/app
/Boxfile

Manually Create storage/framework/views

When a directory is specified as a network_dir, the directory gets replaced on deploy by a network mount. This mount connects the directory inside your web and worker instances to your storage service. Any content or code inside of a network directory in your repo is essentially hidden behind the mount and will need to be moved or created in your network storage service.

Laravel needs to be able to write to the storage/framework/view directory. Because storage/framework is a network directory, you'll need to manually create the view directory inside of it. This can be done in one of two ways:

1. Through a Deploy Hook

You can use the following before_deploy hook to create the directory as your app gets deployed:

Creating the Views Directory in a Deploy Hook YAML

  web1:
    before_deploy:
      - 'mkdir storage/framework/views' 
/Boxfile

This hook should only be run on a single deploy. We recommend including it in your Boxfile.install so it only runs on the very first deploy. If you've already pushed to your app, just be sure to remove this hook after the deploy completes. The other option is to SSH into your storage and create the view directory.

2. SSH in and Manually Create the Directory

Once your app is deployed and your storage service has been created, enable SSH access to your storage service. With the SSH portal enabled, SSH in using the provided credentials and run the the command:

Creating the Views Directory Terminal

  $ mkdir /data/storage/framework/views

Note: This command uses the absolute server path.

Set Up App Logging

By default, Laravel stores application logs in the filesystem. While these could be stored in network storage, the downside is that you'd have to SSH in and inspect the file in order to view the logs. Pagoda Box allows you to define "log watches" - files that, when written to, are piped into the Pagoda logger. This makes Laravel log entries available in your app dashboard and through the Pagoda CLI. More information is available in the Log Management doc.

Update Log Config to "single"

In config/app.php, update your log config to 'single'. This single file will be log_watch'd and streamed to your app's logs.

Update Log Config PHP

  /*
  |--------------------------------------------------------------------------
  | Logging Configuration
  |--------------------------------------------------------------------------
  |
  | Here you may configure the log settings for your application. Out of
  | the box, Laravel uses the Monolog PHP logging library. This gives
  | you a variety of powerful log handlers / formatters to utilize.
  |
  | Available Settings: "single", "daily", "syslog", "errorlog"
  |
  */

  'log' => 'single',
config/app.php

Add the log_watch to Your Boxfile

Under web1 in your Boxfile, add the destination log file as a log_watch:

Boxfile log_watch YAML

  web1:
    log_watch:
      laravel[error]: 'storage/logs/laravel.log'
/Boxfile

Configure Sessions

Laravel provides multiple options for storing sessions. While all are viable, we recommend using Redis. Redis is an extremely fast, in-memory key-value store that routinely persists to disk. This persistence allows data to remain intact if the service is ever interrupted or scaled.

Set Your Session Driver to "redis"

The simplest way to set your session driver to redis is through creating a SESSION_DRIVER environment variable as noted earlier.

Update Your Redis Host Setting

Every service in a Pagoda Box app is assigned a native 192.168.0.x IP within the app's internal network. Using the auto-generated environment variables, you xN to connect to Redis once it gets created.

In config/database.php, update the default redis host to look for and use the CACHE1_HOST environment variable, then failover to 127.0.0.1 if the variable doesn't exist (for environment portability).

Update Default Redis Host PHP

  'redis' => [

    'cluster' => false,

    'default' => [
      'host'     => env('CACHE1_HOST', '127.0.0.1'),
      'port'     => 6379,
      'database' => 0,
    ],

  ],
config/database.php

Include the Redis PHP Extension

As noted above, you'll need to include the "redis" php_extension in your Boxfile to allow PHP to communicate and interact with your Redis service.

Include the Predis Package

Predis is a PHP/Redis client that can be installed through composer. Just include the Predis package in your composer.json.

Adding the Predis Package to composer.json JSON

  "require": {
    "predis/predis": "~1.1@dev"
  },
composer.json

Configure Your Cache

Laravel provides many different options for storing your app's cache. On Pagoda Box, we recommend using the file driver in conjunction with nonpersistent writable directories. These directories are stored in each of your code instances' local filesystems, so they're extremely fast. More information is available in the Nonpersistent Writable Directories doc.

Set Your Cache Driver to "file"

The simplest way to set your cache driver to file is through creating a CACHE_DRIVER environment variable as noted earlier.

Update Your Cache Directory Location

By default, Laravel's file caching drive stores cached files in storage/framework/cache. However, on Pagoda Box, storage/framework is a network directory and nonpersistent_writable_dirs can't be inside of a network directory. Because of this, you need to update the path of your cache directory.

The cache storage path can be updated in config/cache.php. We suggest storing your cache in storage/cache

Setting Cache Directory Location PHP

  'file' => [
    'driver' => 'file',
    'path'   => storage_path().'/cache',
  ],
config/cache.php

Add Cache Directory as a Nonpersistent Writable Dir

Add storage/cache as a nonpersistent_writable_dir in your Boxfile.

Cache nonpersistent_writable_dir in Boxfile YAML

  web1:
    nonpersistent_writable_dirs:
      - storage/cache
/Boxfile

Setup Mail

Laravel provides many options for handling mail and you're free to use any of them. On Pagoda Box, we recommend using the mail driver for the following reasons:

  • This driver uses PHP's mail() function. Anything passed to the mail() function gets captured by the Pagoda Mail Proxy and relayed to your SMTP provider.

  • The Mail Proxy helps to reduce the risk of emails being flagged as SPAM.

  • Email events passed through the Pagoda Mail Proxy are available in your app's logs.

Set Your Mail Driver to "mail"

The simplest way to set your mail driver is through creating a MAIL_DRIVER environment variable as noted earlier.

Configure Your SMTP Settings in Your Dashboard

To send mail from your app using PHP's mail() function, you need to provide your SMTP credentials in your app dashboard. This is done under Dev Config > Mail.

More information is available in the Sending Mail from Your App doc.

Laravel Workers & Queue Config

Laravel has built-in queueing functionality that makes building job queues really simple. You have a couple of different options for queue drivers, but we suggest Redis.

Set Your Queue Driver

The simplest way to set your queue driver is through creating a QUEUE_DRIVER environment variable as noted earlier.

Note: If using Redis, be sure to include the Predis package, as shown above.

Configure Your Worker

Worker services allow you run background processes that pull from a job queue and process jobs without timeouts and without affecting your web traffic. To setup a worker in the Boxfile, you simply need to provide an exec (the command to start the worker script) and any other relevant configs, such as php_extensions, network_dirs, etc.. Artisan provides a simple command to watch your job queue.

Boxfile Artisan Worker Config YAML

  worker1:
    exec: 'php artisan queue:listen'
    php_extensions:
      - json
      - mbstring
      - mcrypt
      - tokenizer
      - xcache
      - redis
    network_dirs:
      - storage/framework
      - storage/app
    nonpersistent_writable_dirs:
      - storage/cache
    log_watch:
      laravel[error]: 'storage/logs/laravel.log            
/Boxfile

Webs & Workers are Configured Separately

All code services are configured separately. Listing php_extensions on web1 will not enable those extensions on worker1.

Using Artisan on Pagoda Box

Laravel's Artisan CLI provides some really handy commands and tools. Artisan can be used by directly SSH'ing into your app's code services and running commands, or by running commands in build and deploy hooks.

Using Artisan when SSH'd In

To use artisan inside of your live app, you'll need to enable SSH access to one or more of your code services, then SSH in. Once SSH'd in, move into the /data directory and use the php executable to run artisan commands.

Using Artisan While SSH'd In Terminal

  $ cd /data
  $ php artisan [command]

Using Artisan in Build & Deploy Hooks

Artisan provides tools that can be helpful in your app's deploy process. Artisan commands can run in both build and deploy hooks. These hooks run from the root of your repo, so artisan can be executed with just the php artisan command.

Note: Because there's no way to interact with the deploy process, you'll need to include the --no-interaction flag in each command.

Example Artisan Deploy Hook YAML

  web1:
    before_deploy:
      - 'php artisan migrate --no-interaction'
/Boxfile

Optional Deploy Processes

When using Laravel, there are tasks that are commonly run during the deploy process. Below are examples of the most common.

Optimize Classes Loaded Through Composer

One thing that can be done to optimize your app is to aggregate all classes loaded in your app into a single file. This can be done using the composer dump-autoload --optimize command in an after_exec build hook.

Composer Dump-Autoload Build Hook YAML

  build:
    after_exec:
      - 'composer dump-autoload --optimize'
/Boxfile

Database Migrations and Seeding on Deploy

When building an app locally, you'll likely need to create database migrations as you update your data structure. Running migrations on deploy is really simple using the artisan migrate command. More information about creating migrations is available in the Laravel documentation.

Other times you'll need to seed data in a newly created database. This can be done using the artisan db:seed command. Generally databases only need to be seeded on the first deploy of an app, so you may only need to include this deploy hook in a Boxfile.install. More information about database seeding is available in the Laravel documentation.

Database migrations/seeding should run in before_deploy hooks which run after code has been deployed to running instances. Here, your code services have access to your app's data services.

Database Migration & Seeding YAML

  web1:
    before_deploy:
      - "php artisan migrate --no-interaction"
      - "php artisan db:seed --no-interaction"
/Boxfile

Clear Cache on Deploy

If using anything other than the file caching driver and nonpersistent_writable_dirs, you may want to clear your app's cache on each deploy. Artisan provides an extremely simple way to clear your cache using the artisan cache:clear command. This should be run as either a before_deploy or after_deploy hook.

Clearing Cache YAML

  web1:
    before_deploy:
      - 'php artisan cache:clear --no-interaction'
/Boxfile

Using The Same Cache, Session, & Queue Drivers

Be careful when using your caching service for other things as well. The cache:clear command will flush all data in whatever service you're storing your cache. For example, if using using Redis for both your cache and your job queue, both will be flushed. More information is available in this issue on Laravel's Github project.

Using Gulp to Compile Assets on Deploy

Gulp is Laravel's de facto task runner used to compile assets. Running Gulp on deploy is simple, but does require modifications to your app's build config.

NPM is used to load the gulp package. NPM is available in your build zones, but to run NPM's and Composer's install commands, you'll need to list both as build exec's.

Include vendor and node_modules as lib_dirs in your build config.

Once all composer Composer and NPM dependencies are loaded by the exec, you can then run the gulp executable using its full path node_modules/.bin/gulp.

Laravel/Gulp Boxfile Config YAML

  build:
    exec:
      - "composer install --no-interaction --prefer-source"
      - "npm install"
    after_exec:
      - "composer dump-autoload --optimize"
      - "node_modules/.bin/gulp"
    lib_dirs:
      - vendor
      - node_modules
/Boxfile

Table of Contents

Pagoda Box Laravel 5 Boilerplate

Define Laravel Version in your Composer.json

Use Laravel’s Environment Helpers to Configure Your App

Enable Required & Recommended PHP Extensions

Set Your App’s Document Root

Define Network Directories

Set Up App Logging

Configure Sessions

Configure Your Cache

Setup Mail

Laravel Workers & Queue Config

Using Artisan on Pagoda Box

Optional Deploy Processes

If you have any questions, suggestions, or corrections, let us know.