Lumen Offline Documentation
Lumen Offline Documentation
Heru Rusdianto
Buy on Leanpub

Release Notes

Lumen 5.2.0

Lumen 5.2.0 upgrades the framework to use the 5.2 family of Laravel components, as well as introduces some significant changes to Lumen’s underlying philosophy and purpose.

Only Stateless APIs

Lumen 5.2 represents a shift on slimming Lumen to focus solely on serving stateless, JSON APIs. As such, sessions and views are no longer included with the framework. If you need access to these features, you should use the full Laravel framework. Upgrading your Lumen application to the full Laravel framework mainly involves copying your routes and classes over into a fresh installation of Laravel. Since Laravel and Lumen share many of the same components, your classes should not require any modification.

Authentication

Because sessions are no longer included with Lumen, authentication must be done statelessly using API tokens or headers. You have complete control over the authentication process in the new AuthServiceProvider. Please review the authentication documentation for more information.

Testing Helpers

Since sessions are no longer included with Lumen, all of the form interaction testing helpers have been removed. The testing helpers for JSON APIs remain, so be sure to review the testing documentation.

Lumen 5.1.0

Lumen 5.1.0 upgrades the framework to use the 5.1 family of Laravel components. Features such as event broadcasting, middleware parameters, and testing improvements are now available in Lumen. For the full Laravel 5.1 release notes, consult the Laravel documentation.

Lumen 5.0.4

When upgrading to Lumen 5.0.4, you should update your bootstrap/app.php file’s creation of the Lumen application class to the following:

1 $app = new Laravel\Lumen\Application(
2 	realpath(__DIR__.'/../')
3 );

Note: This is not a required change; however, it should prevent some bugs when using the Artisan CLI and PHP’s built-in web server.

Lumen 5.0

Lumen 5.0 is the initial release of the Lumen framework, and is based on the Laravel 5.x series of PHP components.

Upgrade Guide

Upgrading To 5.2.0 From 5.1

Lumen 5.2 represents a more decided shift towards focusing on stateless APIs. Therefore, sessions have been removed from the framework. If you would like to use these features, you should upgrade your Lumen 5.1 application to Laravel 5.2.

Upgrading your Lumen application to the full Laravel framework mainly involves copying your routes and classes over into a fresh installation of Laravel. Since Laravel and Lumen share many of the same components, your classes should not require any modification.

Updating Dependencies

Update your composer.json file to point to laravel/lumen-framework 5.2.* and vlucas/phpdotenv ~2.2.

Bootstrap

In the bootstrap/app.php file you need to modify the Dotenv::load(...) method call to the following:

1 try {
2     (new Dotenv\Dotenv(__DIR__.'/../'))->load();
3 } catch (Dotenv\Exception\InvalidPathException $e) {
4     //
5 }

Application

Lumen no longer implements the Illuminate\Contracts\Foundation\Application contract. Any Application contract type-hints should be updated to reference the Laravel\Lumen\Application class directly.

Authentication

Since sessions are no longer support in Lumen, authentication is totally based on stateless authentication via API tokens or headers. You should review the full authentication documentation for more information on how to use the authentication system.

Collections

Eloquent Base Collections

The Eloquent collection instance now returns a base Collection (Illuminate\Support\Collection) for the following methods: pluck, keys, zip, collapse, flatten, flip.

Key Preservation

The slice, chunk, and reverse methods now preserve keys on the collection. If you do not want these methods to preserve keys, use the values method on the Collection instance.

Database

MySQL Dates

Starting with MySQL 5.7, 0000-00-00 00:00:00 is no longer considered a valid date, since strict mode is enabled by default. All timestamp columns should receive a valid default value when you insert records into your database. You may use the useCurrent method in your migrations to default the timestamp columns to the current timestamps, or you may make the timestamps nullable to allow null values:

1 $table->timestamp('foo')->nullable();
2 
3 $table->timestamp('foo')->useCurrent();
4 
5 $table->nullableTimestamps();
MySQL JSON Column Type

The json column type now creates actual JSON columns when used by the MySQL driver. If you are not running MySQL 5.7 or above, this column type will not be available to you. Instead, use the text column type in your migration.

Eloquent

Date Casts

Any attributes that have been added to your $casts property as date or datetime will now be converted to a string when toArray is called on the model or collection of models. This makes the date casting conversion consistent with dates specified in your $dates array.

Global Scopes

The global scopes implementation has been re-written to be much easier to use. Your global scopes no longer need a remove method, so it may be removed from any global scopes you have written.

If we were calling getQuery on an Eloquent query builder to access the underlying query builder instance, you should now call toBase.

If you were calling the remove method directly for any reason, you should change this call to $eloquentBuilder->withoutGlobalScope($scope).

New methods withoutGlobalScope and withoutGlobalScopes have been added to the Eloquent query builder. Any calls to $model->removeGlobalScopes($builder) may be changed to simply $builder->withoutGlobalScopes().

Primary keys

By default, Eloquent assumes your primary keys are integers and will automatically cast them to integers. For any primary key that is not an integer you should override the $incrementing property on your Eloquent model to false:

1 /**
2  * Indicates if the IDs are auto-incrementing.
3  *
4  * @var bool
5  */
6 public $incrementing = true;

Exception Handling

Your App\Exceptions\Handler class’ $dontReport property should be updated to include at least the following exception types:

 1 use Illuminate\Validation\ValidationException;
 2 use Illuminate\Auth\Access\AuthorizationException;
 3 use Illuminate\Database\Eloquent\ModelNotFoundException;
 4 use Symfony\Component\HttpKernel\Exception\HttpException;
 5 
 6 /**
 7  * A list of the exception types that should not be reported.
 8  *
 9  * @var array
10  */
11 protected $dontReport = [
12     AuthorizationException::class,
13     HttpException::class,
14     ModelNotFoundException::class,
15     ValidationException::class,
16 ];

IronMQ

The IronMQ queue driver has been moved into its own package and is no longer shipped with the core framework.

http://github.com/LaravelCollective/iron-queue

Storage

If you made use of Laravel’s Flysystem integration, you will need to register the filesystem binding. Add the following code to your bootstrap/app.php:

1 $app->singleton('filesystem', function ($app) {
2     return $app->loadComponent(
3         'filesystems',
4         Illuminate\Filesystem\FilesystemServiceProvider::class,
5         'filesystem'
6     );
7 });

Validation

The ValidatesRequests trait has been merged into the ProvidesConvenienceMethods trait used by Lumen’s base controller.

If you previously used the ValidatesRequests trait outside of the BaseController, you may copy it from the 5.1 branch or use the full ProvidesConvenienceMethods trait.

Testing

The DatabaseMigrations and DatabaseTransactions traits have moved from Illuminate\Foundation\Testing\DatabaseMigrations and Illuminate\Foundation\Testing\DatabaseTransactions to a new location. Update your tests to import the new namespace:

1 <?php
2 
3 use Laravel\Lumen\Testing\DatabaseMigrations;
4 use Laravel\Lumen\Testing\DatabaseTransactions;
5 
6 class ExampleTest extends TestCase
7 {
8     use DatabaseMigrations;
9 }

Installation

Installation

Server Requirements

The Lumen framework has a few system requirements. Of course, all of these requirements are satisfied by the Laravel Homestead virtual machine, so it’s highly recommended that you use Homestead as your local Lumen development environment.

However, if you are not using Homestead, you will need to make sure your server meets the following requirements:

  • PHP >= 5.5.9
  • OpenSSL PHP Extension
  • PDO PHP Extension
  • Mbstring PHP Extension

Installing Lumen

Lumen utilizes Composer to manage its dependencies. So, before using Lumen, make sure you have Composer installed on your machine.

Via Lumen Installer

First, download the Lumen installer using Composer:

1 composer global require "laravel/lumen-installer"

Make sure to place the ~/.composer/vendor/bin directory in your PATH so the lumen executable can be located by your system.

Once installed, the lumen new command will create a fresh Lumen installation in the directory you specify. For instance, lumen new blog will create a directory named blog containing a fresh Lumen installation with all of Lumen’s dependencies already installed. This method of installation is much faster than installing via Composer:

1 lumen new blog
Via Composer Create-Project

You may also install Lumen by issuing the Composer create-project command in your terminal:

1 composer create-project --prefer-dist laravel/lumen blog

Configuration

All of the configuration options for the Lumen framework are stored in the .env file. Once Lumen is installed, you should also configure your local environment.

Application Key

The next thing you should do after installing Lumen is set your application key to a random string. Typically, this string should be 32 characters long. The key can be set in the .env environment file. If you have not renamed the .env.example file to .env, you should do that now. If the application key is not set, your user encrypted data will not be secure!

Configuration

Introduction

All of the configuration options for the Lumen framework are stored in the .env file.

Accessing Configuration Values

You may easily access your configuration values using the global config helper function from anywhere in your application. The configuration values may be accessed using “dot” syntax, which includes the name of the file and option you wish to access. A default value may also be specified and will be returned if the configuration option does not exist:

1 $value = config('app.timezone');

To set configuration values at runtime, pass an array to the config helper:

1 config(['app.timezone' => 'America/Chicago']);

Environment Configuration

It is often helpful to have different configuration values based on the environment the application is running in. For example, you may wish to use a different cache driver locally than you do on your production server. It’s easy using environment based configuration.

To make this a cinch, Lumen utilizes the DotEnv PHP library by Vance Lucas. In a fresh Lumen installation, the root directory of your application will contain a .env.example file. You should rename the .env.example file to .env when creating your application.

All of the variables listed in this file will be loaded into the $_ENV PHP super-global when your application receives a request. The env function may be used to retrieve the values of your environment variables:

1 $debug = env('APP_DEBUG', true);

The second value passed to the env function is the “default value”. This value will be used if no environment variable exists for the given key.

Your .env file should not be committed to your application’s source control, since each developer / server using your application could require a different environment configuration.

If you are developing with a team, you may wish to continue including a .env.example file with your application. By putting place-holder values in the example configuration file, other developers on your team can clearly see which environment variables are needed to run your application.

Determining The Current Environment

The current application environment is determined via the APP_ENV variable from your .env file. You may access this value via the environment method on the application instance:

1 $environment = app()->environment();

You may also pass arguments to the environment method to check if the environment matches a given value. If necessary, you may even pass multiple values to the environment method. If the environment matches any of the given values, the method will return true:

1 if (app()->environment('local')) {
2     // The environment is local
3 }
4 
5 if (app()->environment('local', 'staging')) {
6     // The environment is either local OR staging...
7 }

HTTP Routing

Basic Routing

You will define all of the routes for your application in the app/Http/routes.php file. The most basic Lumen routes simply accept a URI and a Closure:

1 $app->get('foo', function () {
2     return 'Hello World';
3 });
4 
5 $app->post('foo', function () {
6     //
7 });
Available Router Methods

The router allows you to register routes that respond to any HTTP verb:

1 $app->get($uri, $callback);
2 $app->post($uri, $callback);
3 $app->put($uri, $callback);
4 $app->patch($uri, $callback);
5 $app->delete($uri, $callback);
6 $app->options($uri, $callback);

Route Parameters

Required Parameters

Of course, sometimes you will need to capture segments of the URI within your route. For example, you may need to capture a user’s ID from the URL. You may do so by defining route parameters:

1 $app->get('user/{id}', function ($id) {
2     return 'User '.$id;
3 });

You may define as many route parameters as required by your route:

1 $app->get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
2     //
3 });

Route parameters are always encased within “curly” braces. The parameters will be passed into your route’s Closure when the route is executed.

Note: Route parameters cannot contain the - character. Use an underscore (_) instead.

Named Routes

Named routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route using the as array key when defining the route:

1 $app->get('profile', ['as' => 'profile', function () {
2     //
3 }]);

You may also specify route names for controller actions:

1 $app->get('profile', [
2     'as' => 'profile', 'uses' => 'UserController@showProfile'
3 ]);
Generating URLs To Named Routes

Once you have assigned a name to a given route, you may use the route’s name when generating URLs or redirects via the global route function:

1 // Generating URLs...
2 $url = route('profile');
3 
4 // Generating Redirects...
5 return redirect()->route('profile');

If the named route defines parameters, you may pass the parameters as the second argument to the route function. The given parameters will automatically be inserted into the URL in their correct positions:

1 $app->get('user/{id}/profile', ['as' => 'profile', function ($id) {
2     //
3 }]);
4 
5 $url = route('profile', ['id' => 1]);

Route Groups

Route groups allow you to share route attributes, such as middleware or namespaces, across a large number of routes without needing to define those attributes on each individual route. Shared attributes are specified in an array format as the first parameter to the $app->group method.

To learn more about route groups, we’ll walk through several common use-cases for the feature.

Middleware

To assign middleware to all routes within a group, you may use the middleware key in the group attribute array. Middleware will be executed in the order you define this array:

1 $app->group(['middleware' => 'auth'], function () use ($app) {
2     $app->get('/', function ()    {
3         // Uses Auth Middleware
4     });
5 
6     $app->get('user/profile', function () {
7         // Uses Auth Middleware
8     });
9 });

Namespaces

Another common use-case for route groups is assigning the same PHP namespace to a group of controllers. You may use the namespace parameter in your group attribute array to specify the namespace for all controllers within the group:

1 $app->group(['namespace' => 'App\Http\Controllers\Admin'], function() use ($app)
2 {
3     // Controllers Within The "App\Http\Controllers\Admin" Namespace
4 
5     $app->group(['namespace' => 'App\Http\Controllers\Admin\User'], function() u\
6 se ($app) {
7         // Controllers Within The "App\Http\Controllers\Admin\User" Namespace
8     });
9 });

Remember, by default, the bootstrap/app.php file includes your routes.php file within a namespace group, allowing you to register controller routes without specifying the full App\Http\Controllers namespace prefix. So, we only need to specify the portion of the namespace that comes after the base App\Http\Controllers namespace.

Route Prefixes

The prefix group attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with admin:

1 $app->group(['prefix' => 'admin'], function () use ($app) {
2     $app->get('users', function ()    {
3         // Matches The "/admin/users" URL
4     });
5 });

You may also use the prefix parameter to specify common parameters for your grouped routes:

1 $app->group(['prefix' => 'accounts/{account_id}'], function () use ($app) {
2     $app->get('detail', function ($accountId)    {
3         // Matches The "/accounts/{account_id}/detail" URL
4     });
5 });

HTTP Middleware

Introduction

HTTP middleware provide a convenient mechanism for filtering HTTP requests entering your application. For example, Lumen includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.

Of course, additional middleware can be written to perform a variety of tasks besides authentication. A CORS middleware might be responsible for adding the proper headers to all responses leaving your application. A logging middleware might log all incoming requests to your application.

All middleware should be stored in the app/Http/Middleware directory.

Defining Middleware

To create a new middleware, copy the ExampleMiddleware that is included with the default Lumen application. In our new middleware, we will only allow access to the route if the supplied age is greater than 200. Otherwise, we will redirect the users back to the “home” URI.

 1 <?php
 2 
 3 namespace App\Http\Middleware;
 4 
 5 use Closure;
 6 
 7 class OldMiddleware
 8 {
 9     /**
10      * Run the request filter.
11      *
12      * @param  \Illuminate\Http\Request  $request
13      * @param  \Closure  $next
14      * @return mixed
15      */
16     public function handle($request, Closure $next)
17     {
18         if ($request->input('age') <= 200) {
19             return redirect('home');
20         }
21 
22         return $next($request);
23     }
24 
25 }

As you can see, if the given age is less than or equal to 200, the middleware will return an HTTP redirect to the client; otherwise, the request will be passed further into the application. To pass the request deeper into the application (allowing the middleware to “pass”), simply call the $next callback with the $request.

It’s best to envision middleware as a series of “layers” HTTP requests must pass through before they hit your application. Each layer can examine the request and even reject it entirely.

Before / After Middleware

Whether a middleware runs before or after a request depends on the middleware itself. For example, the following middleware would perform some task before the request is handled by the application:

 1 <?php
 2 
 3 namespace App\Http\Middleware;
 4 
 5 use Closure;
 6 
 7 class BeforeMiddleware
 8 {
 9     public function handle($request, Closure $next)
10     {
11         // Perform action
12 
13         return $next($request);
14     }
15 }

However, this middleware would perform its task after the request is handled by the application:

 1 <?php
 2 
 3 namespace App\Http\Middleware;
 4 
 5 use Closure;
 6 
 7 class AfterMiddleware
 8 {
 9     public function handle($request, Closure $next)
10     {
11         $response = $next($request);
12 
13         // Perform action
14 
15         return $response;
16     }
17 }

Registering Middleware

Global Middleware

If you want a middleware to be run during every HTTP request to your application, simply list the middleware class in the call to the $app->middleware() method in your bootstrap/app.php file:

1 $app->middleware([
2    App\Http\Middleware\OldMiddleware::class
3 ]);

Assigning Middleware To Routes

If you would like to assign middleware to specific routes, you should first assign the middleware a short-hand key in bootstrap/app.php file’s call to the $app->routeMiddleware() method:

1 $app->routeMiddleware([
2     'auth' => App\Http\Middleware\Authenticate::class,
3 ]);

Once the middleware has been defined in the HTTP kernel, you may use the middleware key in the route options array:

1 $app->get('admin/profile', ['middleware' => 'auth', function () {
2     //
3 }]);

Use an array to assign multiple middleware to the route:

1 $app->get('/', ['middleware' => ['first', 'second'], function () {
2     //
3 }]);

Middleware Parameters

Middleware can also receive additional custom parameters. For example, if your application needs to verify that the authenticated user has a given “role” before performing a given action, you could create a RoleMiddleware that receives a role name as an additional argument.

Additional middleware parameters will be passed to the middleware after the $next argument:

 1 <?php
 2 
 3 namespace App\Http\Middleware;
 4 
 5 use Closure;
 6 
 7 class RoleMiddleware
 8 {
 9     /**
10      * Run the request filter.
11      *
12      * @param  \Illuminate\Http\Request  $request
13      * @param  \Closure  $next
14      * @param  string  $role
15      * @return mixed
16      */
17     public function handle($request, Closure $next, $role)
18     {
19         if (! $request->user()->hasRole($role)) {
20             // Redirect...
21         }
22 
23         return $next($request);
24     }
25 
26 }

Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a :. Multiple parameters should be delimited by commas:

1 $app->put('post/{id}', ['middleware' => 'role:editor', function ($id) {
2     //
3 }]);

Terminable Middleware

Sometimes a middleware may need to do some work after the HTTP response has already been sent to the browser. For example, the “session” middleware included with Lumen writes the session data to storage after the response has been sent to the browser. To accomplish this, define the middleware as “terminable” by adding a terminate method to the middleware:

 1 <?php
 2 
 3 namespace Illuminate\Session\Middleware;
 4 
 5 use Closure;
 6 
 7 class StartSession
 8 {
 9     public function handle($request, Closure $next)
10     {
11         return $next($request);
12     }
13 
14     public function terminate($request, $response)
15     {
16         // Store the session data...
17     }
18 }

The terminate method should receive both the request and the response. Once you have defined a terminable middleware, you should add it to the list of global middleware in your bootstrap/app.php file.

When calling the terminate method on your middleware, Lumen will resolve a fresh instance of the middleware from the service container. If you would like to use the same middleware instance when the handle and terminate methods are called, register the middleware with the container using the container’s singleton method.

HTTP Controllers

Introduction

Instead of defining all of your request handling logic in a single routes.php file, you may wish to organize this behavior using Controller classes. Controllers can group related HTTP request handling logic into a class. Controllers are stored in the app/Http/Controllers directory.

Basic Controllers

Here is an example of a basic controller class. All Lumen controllers should extend the base controller class included with the default Lumen installation:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use App\User;
 6 
 7 class UserController extends Controller
 8 {
 9     /**
10      * Retrieve the user for the given ID.
11      *
12      * @param  int  $id
13      * @return Response
14      */
15     public function show($id)
16     {
17         return User::findOrFail($id);
18     }
19 }

We can route to the controller action like so:

1 $app->get('user/{id}', 'UserController@show');

Now, when a request matches the specified route URI, the show method on the UserController class will be executed. Of course, the route parameters will also be passed to the method.

Controllers & Namespaces

It is very important to note that we did not need to specify the full controller namespace when defining the controller route. We only defined the portion of the class name that comes after the App\Http\Controllers namespace “root”. By default, the bootstrap/app.php file will load the routes.php file within a route group containing the root controller namespace.

If you choose to nest or organize your controllers using PHP namespaces deeper into the App\Http\Controllers directory, simply use the specific class name relative to the App\Http\Controllers root namespace. So, if your full controller class is App\Http\Controllers\Photos\AdminController, you would register a route like so:

1 $app->get('foo', 'Photos\AdminController@method');
Naming Controller Routes

Like Closure routes, you may specify names on controller routes:

1 $app->get('foo', ['uses' => 'FooController@method', 'as' => 'name']);

You may also use the route helper to generate a URL to a named controller route:

1 $url = route('name');

Controller Middleware

Middleware may be assigned to the controller’s routes like so:

1 $app->get('profile', [
2     'middleware' => 'auth',
3     'uses' => 'UserController@showProfile'
4 ]);

However, it is more convenient to specify middleware within your controller’s constructor. Using the middleware method from your controller’s constructor, you may easily assign middleware to the controller. You may even restrict the middleware to only certain methods on the controller class:

 1 class UserController extends Controller
 2 {
 3     /**
 4      * Instantiate a new UserController instance.
 5      *
 6      * @return void
 7      */
 8     public function __construct()
 9     {
10         $this->middleware('auth');
11 
12         $this->middleware('log', ['only' => [
13             'fooAction',
14             'barAction',
15         ]]);
16 
17         $this->middleware('subscribed', ['except' => [
18             'fooAction',
19             'barAction',
20         ]]);
21     }
22 }

Dependency Injection & Controllers

Constructor Injection

The Lumen service container is used to resolve all Lumen controllers. As a result, you are able to type-hint any dependencies your controller may need in its constructor. The dependencies will automatically be resolved and injected into the controller instance:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use App\Repositories\UserRepository;
 6 
 7 class UserController extends Controller
 8 {
 9     /**
10      * The user repository instance.
11      */
12     protected $users;
13 
14     /**
15      * Create a new controller instance.
16      *
17      * @param  UserRepository  $users
18      * @return void
19      */
20     public function __construct(UserRepository $users)
21     {
22         $this->users = $users;
23     }
24 }
Method Injection

In addition to constructor injection, you may also type-hint dependencies on your controller’s action methods. For example, let’s type-hint the Illuminate\Http\Request instance on one of our methods:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use Illuminate\Http\Request;
 6 
 7 class UserController extends Controller
 8 {
 9     /**
10      * Store a new user.
11      *
12      * @param  Request  $request
13      * @return Response
14      */
15     public function store(Request $request)
16     {
17         $name = $request->input('name');
18 
19         //
20     }
21 }

If your controller method is also expecting input from a route parameter, simply list your route arguments after your other dependencies. For example, if your route is defined like so:

1 $app->put('user/{id}', 'UserController@update');

You may still type-hint the Illuminate\Http\Request and access your route parameter id by defining your controller method like the following:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use Illuminate\Http\Request;
 6 use Illuminate\Routing\Controller;
 7 
 8 class UserController extends Controller
 9 {
10     /**
11      * Update the specified user.
12      *
13      * @param  Request  $request
14      * @param  string  $id
15      * @return Response
16      */
17     public function update(Request $request, $id)
18     {
19         //
20     }
21 }

HTTP Requests

Accessing The Request

To obtain an instance of the current HTTP request via dependency injection, you should type-hint the Illuminate\Http\Request class on your controller constructor or method. The current request instance will automatically be injected by the service container:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use Illuminate\Http\Request;
 6 
 7 class UserController extends Controller
 8 {
 9     /**
10      * Store a new user.
11      *
12      * @param  Request  $request
13      * @return Response
14      */
15     public function store(Request $request)
16     {
17         $name = $request->input('name');
18 
19         //
20     }
21 }

If your controller method is also expecting input from a route parameter, simply list your route arguments after your other dependencies. For example, if your route is defined like so:

1 $app->put('user/{id}', 'UserController@update');

You may still type-hint the Illuminate\Http\Request and access your route parameter id by defining your controller method like the following:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use Illuminate\Http\Request;
 6 
 7 class UserController extends Controller
 8 {
 9     /**
10      * Update the specified user.
11      *
12      * @param  Request  $request
13      * @param  string  $id
14      * @return Response
15      */
16     public function update(Request $request, $id)
17     {
18         //
19     }
20 }

Basic Request Information

The Illuminate\Http\Request instance provides a variety of methods for examining the HTTP request for your application and extends the Symfony\Component\HttpFoundation\Request class. Here are a few more of the useful methods available on this class:

Retrieving The Request URI

The path method returns the request’s URI. So, if the incoming request is targeted at http://domain.com/foo/bar, the path method will return foo/bar:

1 $uri = $request->path();

The is method allows you to verify that the incoming request URI matches a given pattern. You may use the * character as a wildcard when utilizing this method:

1 if ($request->is('admin/*')) {
2     //
3 }

To get the full URL, not just the path info, you may use the url or fullUrl methods on the request instance:

1 // Without Query String...
2 $url = $request->url();
3 
4 // With Query String...
5 $url = $request->fullUrl();
Retrieving The Request Method

The method method will return the HTTP verb for the request. You may also use the isMethod method to verify that the HTTP verb matches a given string:

1 $method = $request->method();
2 
3 if ($request->isMethod('post')) {
4     //
5 }

PSR-7 Requests

The PSR-7 standard specifies interfaces for HTTP messages, including requests and responses. If you would like to obtain an instance of a PSR-7 request, you will first need to install a few libraries. Laravel uses the Symfony HTTP Message Bridge component to convert typical Laravel requests and responses into PSR-7 compatible implementations:

1 composer require symfony/psr-http-message-bridge
2 
3 composer require zendframework/zend-diactoros

Once you have installed these libraries, you may obtain a PSR-7 request by simply type-hinting the request type on your route or controller:

1 use Psr\Http\Message\ServerRequestInterface;
2 
3 $app->get('/', function (ServerRequestInterface $request) {
4     //
5 });

If you return a PSR-7 response instance from a route or controller, it will automatically be converted back to a Laravel response instance and be displayed by the framework.

Retrieving Input

Retrieving An Input Value

Using a few simple methods, you may access all user input from your Illuminate\Http\Request instance. You do not need to worry about the HTTP verb used for the request, as input is accessed in the same way for all verbs:

1 $name = $request->input('name');

You may pass a default value as the second argument to the input method. This value will be returned if the requested input value is not present on the request:

1 $name = $request->input('name', 'Sally');

When working on forms with array inputs, you may use “dot” notation to access the arrays:

1 $name = $request->input('products.0.name');
2 
3 $names = $request->input('products.*.name');
Determining If An Input Value Is Present

To determine if a value is present on the request, you may use the has method. The has method returns true if the value is present and is not an empty string:

1 if ($request->has('name')) {
2     //
3 }
Retrieving All Input Data

You may also retrieve all of the input data as an array using the all method:

1 $input = $request->all();
Retrieving A Portion Of The Input Data

If you need to retrieve a sub-set of the input data, you may use the only and except methods. Both of these methods will accept a single array or a dynamic list of arguments:

1 $input = $request->only(['username', 'password']);
2 
3 $input = $request->only('username', 'password');
4 
5 $input = $request->except(['credit_card']);
6 
7 $input = $request->except('credit_card');

Files

Retrieving Uploaded Files

You may access uploaded files that are included with the Illuminate\Http\Request instance using the file method. The object returned by the file method is an instance of the Symfony\Component\HttpFoundation\File\UploadedFile class, which extends the PHP SplFileInfo class and provides a variety of methods for interacting with the file:

1 $file = $request->file('photo');

You may determine if a file is present on the request using the hasFile method:

1 if ($request->hasFile('photo')) {
2     //
3 }
Validating Successful Uploads

In addition to checking if the file is present, you may verify that there were no problems uploading the file via the isValid method:

1 if ($request->file('photo')->isValid()) {
2     //
3 }
Moving Uploaded Files

To move the uploaded file to a new location, you should use the move method. This method will move the file from its temporary upload location (as determined by your PHP configuration) to a more permanent destination of your choosing:

1 $request->file('photo')->move($destinationPath);
2 
3 $request->file('photo')->move($destinationPath, $fileName);
Other File Methods

There are a variety of other methods available on UploadedFile instances. Check out the API documentation for the class for more information regarding these methods.

HTTP Responses

Basic Responses

Of course, all routes and controllers should return some kind of response to be sent back to the user’s browser. Lumen provides several different ways to return responses. The most basic response is simply returning a string from a route or controller:

1 $app->get('/', function () {
2     return 'Hello World';
3 });

The given string will automatically be converted into an HTTP response by the framework.

Response Objects

However, for most routes and controller actions, you will be returning a full Illuminate\Http\Response instance. Returning a full Response instance allows you to customize the response’s HTTP status code and headers. A Response instance inherits from the Symfony\Component\HttpFoundation\Response class, providing a variety of methods for building HTTP responses:

1 use Illuminate\Http\Response;
2 
3 $app->get('home', function () {
4     return (new Response($content, $status))
5                   ->header('Content-Type', $value);
6 });

For convenience, you may also use the response helper:

1 $app->get('home', function () {
2     return response($content, $status)
3                   ->header('Content-Type', $value);
4 });

Note: For a full list of available Response methods, check out its API documentation and the Symfony API documentation.

Attaching Headers To Responses

Keep in mind that most response methods are chainable, allowing for the fluent building of responses. For example, you may use the header method to add a series of headers to the response before sending it back to the user:

1 return response($content)
2             ->header('Content-Type', $type)
3             ->header('X-Header-One', 'Header Value')
4             ->header('X-Header-Two', 'Header Value');

Or, you may use the withHeaders method to specify an array of headers to be added to the response:

1 return response($content)
2             ->withHeaders([
3                 'Content-Type' => $type,
4                 'X-Header-One' => 'Header Value',
5                 'X-Header-Two' => 'Header Value',
6             ]);

Other Response Types

The response helper may be used to conveniently generate other types of response instances. When the response helper is called without arguments, an implementation of the Illuminate\Contracts\Routing\ResponseFactory contract is returned. This contract provides several helpful methods for generating responses.

JSON Responses

The json method will automatically set the Content-Type header to application/json, as well as convert the given array into JSON using the json_encode PHP function:

1 return response()->json(['name' => 'Abigail', 'state' => 'CA']);

If you would like to create a JSONP response, you may use the json method in addition to setCallback:

1 return response()
2             ->json(['name' => 'Abigail', 'state' => 'CA'])
3             ->setCallback($request->input('callback'));
File Downloads

The download method may be used to generate a response that forces the user’s browser to download the file at the given path. The download method accepts a file name as the second argument to the method, which will determine the file name that is seen by the user downloading the file. Finally, you may pass an array of HTTP headers as the third argument to the method:

1 return response()->download($pathToFile);
2 
3 return response()->download($pathToFile, $name, $headers);

Note: Symfony HttpFoundation, which manages file downloads, requires the file being downloaded to have an ASCII file name.

Redirects

Redirect responses are instances of the Illuminate\Http\RedirectResponse class, and contain the proper headers needed to redirect the user to another URL. There are several ways to generate a RedirectResponse instance. The simplest method is to use the global redirect helper method:

1 $app->get('dashboard', function () {
2     return redirect('home/dashboard');
3 });
Redirecting To Named Routes

When you call the redirect helper with no parameters, an instance of Laravel\Lumen\Http\Redirector is returned, allowing you to call any method on the Redirector instance. For example, to generate a RedirectResponse to a named route, you may use the route method:

1 return redirect()->route('login');

If your route has parameters, you may pass them as the second argument to the route method:

1 // For a route with the following URI: profile/{id}
2 
3 return redirect()->route('profile', ['id' => 1]);

If you are redirecting to a route with an “ID” parameter that is being populated from an Eloquent model, you may simply pass the model itself. The ID will be extracted automatically:

1 return redirect()->route('profile', [$user]);

Authentication

Introduction

Authentication in Lumen, while using the same underlying libraries as Laravel, is configured quite differently from the full Laravel framework. Since Lumen does not support session state, incoming requests that you wish to authenticate must be authenticated via a stateless mechanism such as API tokens.

Getting Started

Authentication Service Provider

Note: Before using Lumen’s authentication features, you should uncomment the call to register the AuthServiceProvider service provider in your bootstrap/app.php file.

The AuthServiceProvider located in your app/Providers directory contains a single call to Auth::viaRequest. The viaRequest method accepts a Closure which will be called when the incoming request needs to be authenticated. Within this Closure, you may resolve your App\User instance however you wish. If no authenticated user can be found for the request, the Closure should return null:

1 $this->app['auth']->viaRequest('api', function ($request) {
2     // Return User or null...
3 });

Again, you may retrieve the authenticated user however you wish. You may use an API token in the request headers or query string, a bearer token on the request, or using any other approach your application requires.

Accessing The Authenticated User

Just like in the full Laravel framework, you may use the Auth::user() method to retrieve the current user. Alternatively, you may use the $request->user() method on an Illuminate\Http\Request instance:

 1 use Illuminate\Http\Request;
 2 
 3 $app->get('/post/{id}', ['middleware' => 'auth', function (Request $request, $id\
 4 ) {
 5     $user = Auth::user();
 6 
 7     $user = $request->user();
 8 
 9     //
10 }]);

Note: If you would like to use Auth::user() to access the currently authenticated user, you should uncomment the $app->withFacades() method in your bootstrap/app.php file.

Of course, any routes you wish to authenticate should be assigned the auth middleware, so you should uncomment the call to $app->routeMiddleware() in your bootstrap/app.php file:

1 $app->routeMiddleware([
2     'auth' => App\Http\Middleware\Authenticate::class,
3 ]);

Authorization

Introduction

In addition to providing authentication services out of the box, Lumen also provides a simple way to organize authorization logic and control access to resources. There are a variety of methods and helpers to assist you in organizing your authorization logic.

In general, authorization can be used in Lumen the same way it is used in Laravel. We will cover a few differences here, but you should refer to the full Laravel documentation for additional details.

Differences From Laravel

Defining Abilities

The primary difference when using authorization in Lumen compared to Laravel is in regards to how abilities are defined. In Lumen, you may simply use the Gate facade in your AuthServiceProvider to define abilities:

1 Gate::define('update-post', function ($user, $post) {
2     return $user->id === $post->user_id;
3 });
Defining Policies

Unlike Laravel, Lumen does not have a $policies array on its AuthServiceProvider. However, you may still call the policy method on the Gate facade from within the provider’s boot method:

1 Gate::policy(Post::class, PostPolicy::class);

Again, to learn more about policies, you should consult the full Laravel documentation.

Checking Abilities

You may “check” abilities just as you would in the full Laravel framework. First, you may use the Gate facade. If you choose to use the facade, be sure to enable facades in your bootstrap/app.php file. Remember, we don’t need to pass the User instance into the allows method since the currently authenticated user will automatically be passed to your authorization callback:

1 if (Gate::allows('update-post', $post)) {
2     //
3 }
4 
5 if (Gate::denies('update-post', $post)) {
6     abort(403);
7 }

Of course, you may also check if a given User instance has a given ability:

1 if ($request->user()->can('update-post', $post)) {
2     abort(403);
3 }
4 
5 if ($request->user()->cannot('update-post', $post)) {
6     abort(403);
7 }

Cache

Introduction

Laravel provides a unified API for various caching systems. The cache configuration is located in the .env file. In this file you may specify which cache driver you would like used by default throughout your application. Laravel supports popular caching backends like Memcached and Redis out of the box.

Differences From Laravel

The Lumen cache drivers utilize the exact same code as the full Laravel cache drivers. Beyond configuration, there are no differences between using the cache in Lumen and using the cache in Laravel; therefore, please consult the full Laravel documentation for usage examples.

Note: Before using the Cache facade, be sure you have uncommented the $app->withFacades() method call in your bootstrap/app.php file.

Redis Support

Before using a Redis cache with Lumen, you will need to install the predis/predis (~1.0) and illuminate/redis (5.2.*) packages via Composer. Then, you should register the Illuminate\Redis\RedisServiceProvider in your bootstrap/app.php file.

If you have not called $app->withEloquent() in your bootstrap/app.php file, then you should call $app->configure('database'); in the bootstrap/app.php file to ensure the Redis database configuration is properly loaded.

Database

Configuration

Lumen makes connecting with databases and running queries extremely simple. Currently Lumen supports four database systems: MySQL, Postgres, SQLite, and SQL Server.

You may use the DB_* configuration options in your .env configuration file to configure your database settings, such as the driver, host, username, and password.

Basic Usage

Note: If you would like to use the DB facade, you should uncomment the $app->withFacades() call in your bootstrap/app.php file.

For example, without facades enabled, you may access a database connection via the app helper:

1 $results = app('db')->select("SELECT * FROM users");

Or, with facades enabled, you may access the database connection via the DB facade:

1 $results = DB::select("SELECT * FROM users");
Basic Queries

To learn how to execute basic, raw SQL queries via the database component, you may consult the full Laravel documentation.

Query Builder

Lumen may also utilize the Laravel fluent query builder. To learn more about this feature, consult the full Laravel documentation.

Eloquent ORM

If you would like to use the Eloquent ORM, you should uncomment the $app->withEloquent() call in your bootstrap/app.php file.

Of course, you may easily use the full Eloquent ORM with Lumen. To learn how to use Eloquent, check out the full Laravel documentation.

Migrations

For further information on how to create database tables and run migrations, check out the Laravel documentation on the migrations.

Encryption

Configuration

Before using Lumens’s encrypter, you should set the APP_KEY option of your .env file to a 32 character, random string. If this value is not properly set, all values encrypted by Lumen will be insecure.

Basic Usage

Encrypting A Value

You may encrypt a value using the Crypt facade. All encrypted values are encrypted using OpenSSL and the AES-256-CBC cipher. Furthermore, all encrypted values are signed with a message authentication code (MAC) to detect any modifications to the encrypted string.

For example, we may use the encrypt method to encrypt a secret and store it on an Eloquent model:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use Crypt;
 6 use App\User;
 7 use Illuminate\Http\Request;
 8 
 9 class UserController extends Controller
10 {
11 	/**
12 	 * Store a secret message for the user.
13 	 *
14 	 * @param  Request  $request
15 	 * @param  int  $id
16 	 * @return Response
17 	 */
18 	public function storeSecret(Request $request, $id)
19 	{
20 		$user = User::findOrFail($id);
21 
22 		$user->fill([
23 			'secret' => Crypt::encrypt($request->secret)
24 		])->save();
25 	}
26 }
Decrypting A Value

Of course, you may decrypt values using the decrypt method on the Crypt facade. If the value can not be properly decrypted, such as when the MAC is invalid, an Illuminate\Contracts\Encryption\DecryptException will be thrown:

1 use Illuminate\Contracts\Encryption\DecryptException;
2 
3 try {
4 	$decrypted = Crypt::decrypt($encryptedValue);
5 } catch (DecryptException $e) {
6 	//
7 }

Errors & Logging

Introduction

When you start a new Lumen project, error and exception handling is already configured for you. In addition, Lumen is integrated with the Monolog logging library, which provides support for a variety of powerful log handlers.

Configuration

Error Detail

The amount of error detail your application displays through the browser is controlled by the APP_DEBUG configuration option in your .env file.

For local development, you should set the APP_DEBUG environment variable to true. In your production environment, this value should always be false.

Custom Monolog Configuration

If you would like to have complete control over how Monolog is configured for your application, you may use the application’s configureMonologUsing method. You should place a call to this method in your bootstrap/app.php file:

1 $app->configureMonologUsing(function($monolog) {
2     $monolog->pushHandler(...);
3     
4     return $monolog;
5 });
6 
7 return $app;

The Exception Handler

All exceptions are handled by the App\Exceptions\Handler class. This class contains two methods: report and render. We’ll examine each of these methods in detail.

The Report Method

The report method is used to log exceptions or send them to an external service like BugSnag. By default, the report method simply passes the exception to the base class where the exception is logged. However, you are free to log exceptions however you wish.

For example, if you need to report different types of exceptions in different ways, you may use the PHP instanceof comparison operator:

 1 /**
 2  * Report or log an exception.
 3  *
 4  * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
 5  *
 6  * @param  \Exception  $e
 7  * @return void
 8  */
 9 public function report(Exception $e)
10 {
11     if ($e instanceof CustomException) {
12         //
13     }
14 
15     return parent::report($e);
16 }
Ignoring Exceptions By Type

The $dontReport property of the exception handler contains an array of exception types that will not be logged. By default, exceptions resulting from 404 errors are not written to your log files. You may add other exception types to this array as needed.

The Render Method

The render method is responsible for converting a given exception into an HTTP response that should be sent back to the browser. By default, the exception is passed to the base class which generates a response for you. However, you are free to check the exception type or return your own custom response:

 1 /**
 2  * Render an exception into an HTTP response.
 3  *
 4  * @param  \Illuminate\Http\Request  $request
 5  * @param  \Exception  $e
 6  * @return \Illuminate\Http\Response
 7  */
 8 public function render($request, Exception $e)
 9 {
10     if ($e instanceof CustomException) {
11         return response('Custom Message');
12     }
13 
14     return parent::render($request, $e);
15 }

HTTP Exceptions

Some exceptions describe HTTP error codes from the server. For example, this may be a “page not found” error (404), an “unauthorized error” (401) or even a developer generated 500 error. In order to generate such a response from anywhere in your application, use the following:

1 abort(404);

The abort method will immediately raise an exception which will be rendered by the exception handler. Optionally, you may provide the response text:

1 abort(403, 'Unauthorized action.');

This method may be used at any time during the request’s lifecycle.

Logging

The Lumen logging facilities provide a simple layer on top of the powerful Monolog library. By default, Lumen is configured to create a single log file for your application which is stored in the storage/logs directory. You may write information to the logs using the Log facade:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use Log;
 6 use App\User;
 7 use App\Http\Controllers\Controller;
 8 
 9 class UserController extends Controller
10 {
11     /**
12      * Show the user for the given ID.
13      *
14      * @param  int  $id
15      * @return Response
16      */
17     public function show($id)
18     {
19         Log::info('Showing user: '.$id);
20 
21         return User::findOrFail($id);
22     }
23 }

Note: Before using the Log facade, be sure you have uncommented the $app->withFacades() method call in your bootstrap/app.php file.

The logger provides the eight logging levels defined in RFC 5424: emergency, alert, critical, error, warning, notice, info and debug.

1 Log::emergency($error);
2 Log::alert($error);
3 Log::critical($error);
4 Log::error($error);
5 Log::warning($error);
6 Log::notice($error);
7 Log::info($error);
8 Log::debug($error);
Contextual Information

An array of contextual data may also be passed to the log methods. This contextual data will be formatted and displayed with the log message:

1 Log::info('User failed to login.', ['id' => $user->id]);

Events

Introduction

Lumen’s events provides a simple observer implementation, allowing you to subscribe and listen for events in your application. Event classes are typically stored in the app/Events directory, while their listeners are stored in app/Listeners.

Differences From Laravel

In general, events in Lumen function exactly like they do in the full-stack Laravel framework, so please review the full Laravel documentation. Event broadcasting is even supported in Lumen, which allows you to listen for your server side events in your client-side JavaScript. However, there are a few minor differences which warrant discussion.

Generators

In Lumen, there are no generator commands to generate events and listeners for you, so you should simply copy the ExampleEvent or ExampleListener classes to define your own events and listeners. These example classes provide the basic structure of every event and listener.

Registering Events / Listeners

Like the full Laravel framework, the EventServiceProvider included with your Lumen application provides a convenient place to register all event listeners. The listen property contains an array of all events (keys) and their listeners (values). Of course, you may add as many events to this array as your application requires:

 1 /**
 2  * The event listener mappings for the application.
 3  *
 4  * @var array
 5  */
 6 protected $listen = [
 7     'App\Events\ExampleEvent' => [
 8         'App\Listeners\ExampleListener',
 9     ],
10 ];
Firing Events

You may use the event helper function or Event facade to fire events throughout your Lumen application. Again, these functions behave exactly like their full Laravel framework equivalent:

1 event(new ExampleEvent);
2 
3 Event::fire(new ExampleEvent);

Queues

Introduction

The Lumen queue service provides a unified API across a variety of different queue back-ends. Queues allow you to defer the processing of a time consuming task, such as performing a task on a remote server, until a later time which drastically speeds up web requests to your application.

Like many other parts of the framework, Lumen’s queued jobs function identically to Laravel’s queued jobs. So, to learn more about queuing jobs in Lumen, please review the full Laravel queue documentation.

Configuration

The queue configuration options are in the .env file.

If you would like to thoroughly customize the queue configuration, then you must copy the entire vendor/laravel/lumen-framework/config/queue.php file to the config directory in the root of your project and adjust the necessary configuration options as needed. If the config directory does not exist, then you should create it.

Driver Prerequisites

Database

In order to use the database queue driver, you will need a database table to hold the jobs:

 1 Schema::create('jobs', function (Blueprint $table) {
 2     $table->bigIncrements('id');
 3     $table->string('queue');
 4     $table->longText('payload');
 5     $table->tinyInteger('attempts')->unsigned();
 6     $table->tinyInteger('reserved')->unsigned();
 7     $table->unsignedInteger('reserved_at')->nullable();
 8     $table->unsignedInteger('available_at');
 9     $table->unsignedInteger('created_at');
10     $table->index(['queue', 'reserved', 'reserved_at']);
11 });
Other Queue Dependencies

The following dependencies are needed for the listed queue drivers:

  • Amazon SQS: aws/aws-sdk-php ~3.0
  • Beanstalkd: pda/pheanstalk ~3.0
  • Redis: predis/predis ~1.0

Differences From Laravel

Like many other parts of the framework, Lumen’s queued jobs function identically to Laravel’s queued jobs. So, to learn more about queuing jobs in Lumen, please review the full Laravel queue documentation.

However, there are a few minor differences that we will discuss now. First, let’s talk about how queued jobs are generated in Lumen.

Generators

Lumen does not include generators for automatically creating new Job classes. Instead, you should copy the ExampleJob class that is included with the framework. This class provides the basic structure that is shared by every Job class. The base Job that is used by the ExampleJob already includes the needed InteractsWithQueue, Queueable, and SerializesModels traits:

 1 <?php
 2 
 3 namespace App\Jobs;
 4 
 5 class ExampleJob extends Job
 6 {
 7     /**
 8      * Create a new job instance.
 9      *
10      * @return void
11      */
12     public function __construct()
13     {
14         //
15     }
16 
17     /**
18      * Execute the job.
19      *
20      * @return void
21      */
22     public function handle()
23     {
24         //
25     }
26 }
Dispatching Jobs

Again, you should consult the full Laravel documentation for complete information on dispatching queued jobs; however, just like in the Laravel framework, you may use the dispatch function to dispatch jobs from anywhere within your Lumen application:

1 dispatch(new ExampleJob);

Of course, you may also use the Queue facade. If you choose to use the facade, be sure to uncomment the call to $app->withFacades() in your bootstrap/app.php file:

1 Queue::push(new ExampleJob);

Service Container

Introduction

The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are “injected” into the class via the constructor or, in some cases, “setter” methods.

Differences From Laravel

Lumen uses the exact same service container as the Laravel framework, so you have access to all of its powerful features. For complete documentation on the container, check out the full Laravel container documentation.

Accessing The Container

The Laravel\Lumen\Application instance is an extension of Illuminate\Container\Container, so may be treated as the service container for your application.

Typically, you will register bindings into the container within your service providers. Of course, you may use the bind, singleton, instance, and other container methods provided by the container. Remember, all of these methods are documented in the full Laravel container documentation.

Resolving Instances

To resolve things out of the container, you may either type-hint the dependency you need on a class that is already automatically resolved by the container, such as a route Closure, controller constructor, controller method, middleware, event listener, or queued job. Or, you may use the app function from anywhere in your application:

1 $instance = app(Something::class);

Service Providers

Introduction

Service providers are the central place of all Lumen application bootstrapping. Your own application, as well as all of Lumen’s core services are bootstrapped via service providers.

But, what do we mean by “bootstrapped”? In general, we mean registering things, including registering service container bindings, event listeners, middleware, and even routes. Service providers are the central place to configure your application.

If you open the bootstrap/app.php file included with Lumen, you will see a call to $app->register(). You may add additional calls to this method to register as many service providers as your application requires.

Writing Service Providers

All service providers extend the Illuminate\Support\ServiceProvider class. This abstract class requires that you define at least one method on your provider: register. Within the register method, you should only bind things into the service container. You should never attempt to register any event listeners, routes, or any other piece of functionality within the register method.

The Register Method

As mentioned previously, within the register method, you should only bind things into the service container. You should never attempt to register any event listeners, routes, or any other piece of functionality within the register method. Otherwise, you may accidentally use a service that is provided by a service provider which has not loaded yet.

Now, let’s take a look at a basic service provider:

 1 <?php
 2 
 3 namespace App\Providers;
 4 
 5 use Riak\Connection;
 6 use Illuminate\Support\ServiceProvider;
 7 
 8 class RiakServiceProvider extends ServiceProvider
 9 {
10     /**
11      * Register bindings in the container.
12      *
13      * @return void
14      */
15     public function register()
16     {
17         $this->app->singleton(Connection::class, function ($app) {
18             return new Connection(config('riak'));
19         });
20     }
21 }

This service provider only defines a register method, and uses that method to define an implementation of Riak\Connection in the service container. If you don’t understand how the service container works, check out its documentation.

The Boot Method

So, what if we need to register a view composer within our service provider? This should be done within the boot method. This method is called after all other service providers have been registered, meaning you have access to all other services that have been registered by the framework:

 1 <?php
 2 
 3 namespace App\Providers;
 4 
 5 use Queue;
 6 use Illuminate\Support\ServiceProvider;
 7 
 8 class AppServiceProvider extends ServiceProvider
 9 {
10     // Other Service Provider Properties...
11 
12     /**
13      * Bootstrap any application services.
14      *
15      * @return void
16      */
17     public function boot()
18     {
19         Queue::failing(function ($event) {
20 
21         });
22     }
23 }

Registering Providers

All service providers are registered in the bootstrap/app.php file. This file contains a call to the $app->register() method. You may add as many calls to the register method as needed to register all of your providers.

Testing

Introduction

Lumen is built with testing in mind. In fact, support for testing with PHPUnit is included out of the box, and a phpunit.xml file is already setup for your application. The framework also ships with convenient helper methods allowing you to expressively test your application’s JSON responses.

An ExampleTest.php file is provided in the tests directory. After installing a new Lumen application, simply run phpunit on the command line to run your tests.

Test Environment

Lumen automatically configures the cache to the array driver while testing, meaning no cache data will be persisted while testing.

You are free to create other testing environment configurations as necessary. The testing environment variables may be configured in the phpunit.xml file.

Defining & Running Tests

To create a test case, simply create a new test file in the tests directory. The test class should extend TestCase. You may then define test methods as you normally would using PHPUnit. To run your tests, simply execute the phpunit command from your terminal:

1 <?php
2 
3 class FooTest extends TestCase
4 {
5     public function testSomethingIsTrue()
6     {
7         $this->assertTrue(true);
8     }
9 }

Note: If you define your own setUp method within a test class, be sure to call parent::setUp.

Application Testing

Lumen provides a very fluent API for making HTTP requests to your application and examining the output.

Testing JSON APIs

Lumen also provides several helpers for testing JSON APIs and their responses. For example, the get, post, put, patch, and delete methods may be used to issue requests with various HTTP verbs. You may also easily pass data and headers to these methods. To get started, let’s write a test to make a POST request to /user and assert that a given array was returned in JSON format:

 1 <?php
 2 
 3 class ExampleTest extends TestCase
 4 {
 5     /**
 6      * A basic functional test example.
 7      *
 8      * @return void
 9      */
10     public function testBasicExample()
11     {
12         $this->json('POST', '/user', ['name' => 'Sally'])
13              ->seeJson([
14                 'created' => true,
15              ]);
16     }
17 }

The seeJson method converts the given array into JSON, and then verifies that the JSON fragment occurs anywhere within the entire JSON response returned by the application. So, if there are other properties in the JSON response, this test will still pass as long as the given fragment is present.

Verify Exact JSON Match

If you would like to verify that the given array is an exact match for the JSON returned by the application, you should use the seeJsonEquals method:

 1 <?php
 2 
 3 class ExampleTest extends TestCase
 4 {
 5     /**
 6      * A basic functional test example.
 7      *
 8      * @return void
 9      */
10     public function testBasicExample()
11     {
12         $this->post('/user', ['name' => 'Sally'])
13              ->seeJsonEquals([
14                 'created' => true,
15              ]);
16     }
17 }

Authentication

The actingAs helper method provides a simple way to authenticate a given user as the current user:

 1 <?php
 2 
 3 class ExampleTest extends TestCase
 4 {
 5     public function testApplication()
 6     {
 7         $user = factory('App\User')->create();
 8 
 9         $this->actingAs($user)
10              ->get('/user');
11     }
12 }

Custom HTTP Requests

If you would like to make a custom HTTP request into your application and get the full Illuminate\Http\Response object, you may use the call method:

1 public function testApplication()
2 {
3     $response = $this->call('GET', '/');
4 
5     $this->assertEquals(200, $response->status());
6 }

If you are making POST, PUT, or PATCH requests you may pass an array of input data with the request. Of course, this data will be available in your routes and controller via the Request instance:

1 $response = $this->call('POST', '/user', ['name' => 'Taylor']);

Working With Databases

Lumen also provides a variety of helpful tools to make it easier to test your database driven applications. First, you may use the seeInDatabase helper to assert that data exists in the database matching a given set of criteria. For example, if we would like to verify that there is a record in the users table with the email value of sally@example.com, we can do the following:

1 public function testDatabase()
2 {
3     // Make call to application...
4 
5     $this->seeInDatabase('users', ['email' => 'sally@foo.com']);
6 }

Of course, the seeInDatabase method and other helpers like it are for convenience. You are free to use any of PHPUnit’s built-in assertion methods to supplement your tests.

Resetting The Database After Each Test

It is often useful to reset your database after each test so that data from a previous test does not interfere with subsequent tests.

Using Migrations

One option is to rollback the database after each test and migrate it before the next test. Lumen provides a simple DatabaseMigrations trait that will automatically handle this for you. Simply use the trait on your test class:

 1 <?php
 2 
 3 use Laravel\Lumen\Testing\DatabaseMigrations;
 4 use Laravel\Lumen\Testing\DatabaseTransactions;
 5 
 6 class ExampleTest extends TestCase
 7 {
 8     use DatabaseMigrations;
 9 
10     /**
11      * A basic functional test example.
12      *
13      * @return void
14      */
15     public function testBasicExample()
16     {
17         $this->get('/foo');
18     }
19 }
Using Transactions

Another option is to wrap every test case in a database transaction. Again, Lumen provides a convenient DatabaseTransactions trait that will automatically handle this:

 1 <?php
 2 
 3 use Laravel\Lumen\Testing\DatabaseMigrations;
 4 use Laravel\Lumen\Testing\DatabaseTransactions;
 5 
 6 class ExampleTest extends TestCase
 7 {
 8     use DatabaseTransactions;
 9 
10     /**
11      * A basic functional test example.
12      *
13      * @return void
14      */
15     public function testBasicExample()
16     {
17         $this->get('/foo');
18     }
19 }

Model Factories

When testing, it is common to need to insert a few records into your database before executing your test. Instead of manually specifying the value of each column when you create this test data, Lumen allows you to define a default set of attributes for each of your Eloquent models using “factories”. To get started, take a look at the database/factories/ModelFactory.php file in your application. Out of the box, this file contains one factory definition:

1 $factory->define('App\User', function ($faker) {
2     return [
3         'name' => $faker->name,
4         'email' => $faker->email,
5     ];
6 });

Within the Closure, which serves as the factory definition, you may return the default test values of all attributes on the model. The Closure will receive an instance of the Faker PHP library, which allows you to conveniently generate various kinds of random data for testing.

Of course, you are free to add your own additional factories to the ModelFactory.php file.

Multiple Factory Types

Sometimes you may wish to have multiple factories for the same Eloquent model class. For example, perhaps you would like to have a factory for “Administrator” users in addition to normal users. You may define these factories using the defineAs method:

1 $factory->defineAs('App\User', 'admin', function ($faker) {
2     return [
3         'name' => $faker->name,
4         'email' => $faker->email,
5         'admin' => true,
6     ];
7 });

Instead of duplicating all of the attributes from your base user factory, you may use the raw method to retrieve the base attributes. Once you have the attributes, simply supplement them with any additional values you require:

1 $factory->defineAs('App\User', 'admin', function ($faker) use ($factory) {
2     $user = $factory->raw('App\User');
3 
4     return array_merge($user, ['admin' => true]);
5 });
Using Factories In Tests

Once you have defined your factories, you may use them in your tests or database seed files to generate model instances using the global factory function. So, let’s take a look at a few examples of creating models. First, we’ll use the make method, which creates models but does not save them to the database:

1 public function testDatabase()
2 {
3     $user = factory('App\User')->make();
4 
5     // Use model in tests...
6 }

If you would like to override some of the default values of your models, you may pass an array of values to the make method. Only the specified values will be replaced while the rest of the values remain set to their default values as specified by the factory:

1 $user = factory('App\User')->make([
2     'name' => 'Abigail',
3 ]);

You may also create a Collection of many models or create models of a given type:

1 // Create three App\User instances...
2 $users = factory('App\User', 3)->make();
3 
4 // Create an App\User "admin" instance...
5 $user = factory('App\User', 'admin')->make();
6 
7 // Create three App\User "admin" instances...
8 $users = factory('App\User', 'admin', 3)->make();
Persisting Factory Models

The create method not only creates the model instances, but also saves them to the database using Eloquent’s save method:

1 public function testDatabase()
2 {
3     $user = factory('App\User')->create();
4 
5     // Use model in tests...
6 }

Again, you may override attributes on the model by passing an array to the create method:

1 $user = factory('App\User')->create([
2     'name' => 'Abigail',
3 ]);
Adding Relations To Models

You may even persist multiple models to the database. In this example, we’ll even attach a relation to the created models. When using the create method to create multiple models, an Eloquent collection instance is returned, allowing you to use any of the convenient functions provided by the collection, such as each:

1 $users = factory('App\User', 3)
2            ->create()
3            ->each(function($u) {
4                 $u->posts()->save(factory('App\Post')->make());
5             });

Mocking

Mocking Events

If you are making heavy use of Lumen’s event system, you may wish to silence or mock certain events while testing. For example, if you are testing user registration, you probably do not want all of a UserRegistered event’s handlers firing, since these may send “welcome” e-mails, etc.

Lumen provides a convenient expectsEvents method that verifies the expected events are fired, but prevents any handlers for those events from running:

 1 <?php
 2 
 3 class ExampleTest extends TestCase
 4 {
 5     public function testUserRegistration()
 6     {
 7         $this->expectsEvents('App\Events\UserRegistered');
 8 
 9         // Test user registration code...
10     }
11 }

If you would like to prevent all event handlers from running, you may use the withoutEvents method:

 1 <?php
 2 
 3 class ExampleTest extends TestCase
 4 {
 5     public function testUserRegistration()
 6     {
 7         $this->withoutEvents();
 8 
 9         // Test user registration code...
10     }
11 }

Mocking Jobs

Sometimes, you may wish to simply test that specific jobs are dispatched by your controllers when making requests to your application. This allows you to test your routes / controllers in isolation - set apart from your job’s logic. Of course, you can then test the job itself in a separate test class.

Lumen provides a convenient expectsJobs method that will verify that the expected jobs are dispatched, but the job itself will not be executed:

 1 <?php
 2 
 3 class ExampleTest extends TestCase
 4 {
 5     public function testPurchasePodcast()
 6     {
 7         $this->expectsJobs('App\Jobs\PurchasePodcast');
 8 
 9         // Test purchase podcast code...
10     }
11 }

Note: This method only detects jobs that are dispatched via the dispatch global helper function or the $this->dispatch method from a route or controller. It does not detect jobs that are sent directly to Queue::push.

Mocking Facades

When testing, you may often want to mock a call to a Lumen facade. For example, consider the following controller action:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use Cache;
 6 
 7 class UserController extends Controller
 8 {
 9     /**
10      * Show a list of all users of the application.
11      *
12      * @return Response
13      */
14     public function index()
15     {
16         $value = Cache::get('key');
17 
18         //
19     }
20 }

We can mock the call to the Cache facade by using the shouldReceive method, which will return an instance of a Mockery mock. Since facades are actually resolved and managed by the Lumen service container, they have much more testability than a typical static class. For example, let’s mock our call to the Cache facade:

 1 <?php
 2 
 3 class FooTest extends TestCase
 4 {
 5     public function testGetIndex()
 6     {
 7         Cache::shouldReceive('get')
 8                     ->once()
 9                     ->with('key')
10                     ->andReturn('value');
11 
12         $this->get('/users');
13     }
14 }

Note: You should not mock the Request facade. Instead, pass the input you desire into the HTTP helper methods such as call and post when running your test.

Validation

Introduction

Lumen provides several different approaches to validate your application’s incoming data. By default, Lumen’s base controller class uses a ProvidesConvenienceMethods trait which provides a convenient method to validate incoming HTTP request with a variety of powerful validation rules.

In general, validation in Lumen works exactly like validation in Laravel, so you should consult the full Laravel validation documentation; however, there are a few important differences.

Differences From Laravel

Form Requests

Form requests are not supported by Lumen. If you would like to use form requests, you should use the full Laravel framework.

The $this->validate Method

The $this->validate helper which is available in Lumen will always return a JSON response with the relevant error messages. This is in contrast to the Laravel version of the method which will return a redirect response if the request is not an AJAX request. Since Lumen is stateless and does not support sessions, flashing errors to the session is not a possibility. If you would like to use redirects and flashed error data, you should use the full Laravel framework.

Unlike Laravel, Lumen provides access to the validate method from within Route closures:

 1 use Illuminate\Http\Request;
 2 
 3 $app->post('/user', function (Request $request) {
 4 	$this->validate($request, [
 5 		'name' => 'required',
 6 		'email' => 'required|email|unique:users'
 7 	]);
 8 
 9 	// Store User...
10 });

Of course, you are free to manually create validator instances using the Validator::make facade method just as you would in Laravel.

The $errors View Variable

Lumen does not support sessions out of the box, so the $errors view variable that is available in every view in Laravel is not available in Lumen. Should validation fail, the $this->validate helper will throw Illuminate\Validation\ValidationException with embedded JSON response that includes all relevant error messages. If you are not building a stateless API that solely sends JSON responses, you should use the full Laravel framework.