1. Project Overview & Quickstart (z-song/issues)
issues
Open-source repository z-song/issues
Repository Details
- Repository: z-song/issues
- Primary Language: Code
Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.
2. Official Technical Reference & Guides (z-song/docs)
File: readme.md
Laravel Documentation
You can find the online version of the Laravel documentation at https://laravel.com/docs
Contribution Guidelines
If you are submitting documentation for the current stable release, submit it to the corresponding branch. For example, documentation for Laravel 5.8 would be submitted to the 5.8 branch. Documentation intended for the next release of Laravel should be submitted to the master branch.
File: api-authentication.md
API Authentication
Introduction
By default, Laravel ships with a simple solution to API authentication via a random token assigned to each user of your application. In your config/auth.php configuration file, an api guard is already defined and utilizes a token driver. This driver is responsible for inspecting the API token on the incoming request and verifying that it matches the user's assigned token in the database.
Note: While Laravel ships with a simple, token based authentication guard, we strongly recommend you consider using Laravel Passport for robust, production applications that offer API authentication.
Configuration
Database Preparation
Before using the token driver, you will need to create a migration which adds an api_token column to your users table:
Schema::table('users', function ($table) {
$table->string('api_token', 80)->after('password')
->unique()
->nullable()
->default(null);
});Once the migration has been created, run the migrate Artisan command.
{tip} If you choose to use a different column name, be sure to update your API's
storage_keyconfiguration option within theconfig/auth.phpconfiguration file.
Generating Tokens
Once the api_token column has been added to your users table, you are ready to assign random API tokens to each user that registers with your application. You should assign these tokens when a User model is created for the user during registration. When using the authentication scaffolding provided by the laravel/ui Composer package, this may be done in the create method of the RegisterController:
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'api_token' => Str::random(60),
]);
}Hashing Tokens
In the examples above, API tokens are stored in your database as plain-text. If you would like to hash your API tokens using SHA-256 hashing, you may set the hash option of your api guard configuration to true. The api guard is defined in your config/auth.php configuration file:
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => true,
],Generating Hashed Tokens
When using hashed API tokens, you should not generate your API tokens during user registration. Instead, you will need to implement your own API token management page within your application. This page should allow users to initialize and refresh their API token. When a user makes a request to initialize or refresh their token, you should store a hashed copy of the token in the database, and return the plain-text copy of token to the view / frontend client for one-time display.
For example, a controller method that initializes / refreshes the token for a given user and returns the plain-text token as a JSON response might look like the following:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class ApiTokenController extends Controller
{
/**
* Update the authenticated user's API token.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function update(Request $request)
{
$token = Str::random(60);
$request->user()->forceFill([
'api_token' => hash('sha256', $token),
])->save();
return ['token' => $token];
}
}{tip} Since the API tokens in the example above have sufficient entropy, it is impractical to create "rainbow tables" to lookup the original value of the hashed token. Therefore, slow hashing methods such as
bcryptare unnecessary.
Protecting Routes
Laravel includes an authentication guard that will automatically validate API tokens on incoming requests. You only need to specify the auth:api middleware on any route that requires a valid access token:
use Illuminate\Http\Request;
Route::middleware('auth:api')->get('/user', function(Request $request) {
return $request->user();
});Passing Tokens In Requests
There are several ways of passing the API token to your application. We'll discuss each of these approaches while using the Guzzle HTTP library to demonstrate their usage. You may choose any of these approaches based on the needs of your application.
Query String
Your application's API consumers may specify their token as an api_token query string value:
$response = $client->request('GET', '/api/user?api_token='.$token);Request Payload
Your application's API consumers may include their API token in the request's form parameters as an api_token:
$response = $client->request('POST', '/api/user', [
'headers' => [
'Accept' => 'application/json',
],
'form_params' => [
'api_token' => $token,
],
]);Bearer Token
Your application's API consumers may provide their API token as a Bearer token in the Authorization header of the request:
$response = $client->request('POST', '/api/user', [
'headers' => [
'Authorization' => 'Bearer '.$token,
'Accept' => 'application/json',
],
]);File: artisan.md
Artisan Console
- Introduction
- Writing Commands
- Defining Input Expectations
- Command I/O
- Registering Commands
- Programmatically Executing Commands
Introduction
Artisan is the command-line interface included with Laravel. It provides a number of helpful commands that can assist you while you build your application. To view a list of all available Artisan commands, you may use the list command:
php artisan listEvery command also includes a "help" screen which displays and describes the command's available arguments and options. To view a help screen, precede the name of the command with help:
php artisan help migrateTinker (REPL)
All Laravel applications include Tinker, a REPL powered by the PsySH package. Tinker allows you to interact with your entire Laravel application on the command line, including the Eloquent ORM, jobs, events, and more. To enter the Tinker environment, run the tinker Artisan command:
php artisan tinkerYou can publish Tinker's configuration file using the vendor:publish command:
php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"Command Whitelist
Tinker utilizes a white-list to determine which Artisan commands are allowed to be run within its shell. By default, you may run the clear-compiled, down, env, inspire, migrate, optimize, and up commands. If you would like to white-list more commands you may add them to the commands array in your tinker.php configuration file:
'commands' => [
// App\Console\Commands\ExampleCommand::class,
],Alias Blacklist
Typically, Tinker automatically aliases classes as you require them in Tinker. However, you may wish to never alias some classes. You may accomplish this by listing the classes in the dont_alias array of your tinker.php configuration file:
'dont_alias' => [
App\User::class,
],Writing Commands
In addition to the commands provided with Artisan, you may also build your own custom commands. Commands are typically stored in the app/Console/Commands directory; however, you are free to choose your own storage location as long as your commands can be loaded by Composer.
Generating Commands
To create a new command, use the make:command Artisan command. This command will create a new command class in the app/Console/Commands directory. Don't worry if this directory does not exist in your application, since it will be created the first time you run the make:command Artisan command. The generated command will include the default set of properties and methods that are present on all commands:
php artisan make:command SendEmailsCommand Structure
After generating your command, you should fill in the signature and description properties of the class, which will be used when displaying your command on the list screen. The handle method will be called when your command is executed. You may place your command logic in this method.
{tip} For greater code reuse, it is good practice to keep your console commands light and let them defer to application services to accomplish their tasks. In the example below, note that we inject a service class to do the "heavy lifting" of sending the e-mails.
Let's take a look at an example command. Note that we are able to inject any dependencies we need into the command's handle method. The Laravel service container will automatically inject all dependencies that are type-hinted in this method's signature:
<?php
namespace App\Console\Commands;
use App\DripEmailer;
use App\User;
use Illuminate\Console\Command;
class SendEmails extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'email:send {user}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send drip e-mails to a user';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @param \App\DripEmailer $drip
* @return mixed
*/
public function handle(DripEmailer $drip)
{
$drip->send(User::find($this->argument('user')));
}
}Closure Commands
Closure based commands provide an alternative to defining console commands as classes. In the same way that route Closures are an alternative to controllers, think of command Closures as an alternative to command classes. Within the commands method of your app/Console/Kernel.php file, Laravel loads the routes/console.php file:
/**
* Register the Closure based commands for the application.
*
* @return void
*/
protected function commands()
{
require base_path('routes/console.php');
}Even though this file does not define HTTP routes, it defines console based entry points (routes) into your application. Within this file, you may define all of your Closure based routes using the Artisan::command method. The command method accepts two arguments: the command signature and a Closure which receives the commands arguments and options:
Artisan::command('build {project}', function ($project) {
$this->info("Building {$project}!");
});The Closure is bound to the underlying command instance, so you have full access to all of the helper methods you would typically be able to access on a full command class.
Type-Hinting Dependencies
In addition to receiving your command's arguments and options, command Closures may also type-hint additional dependencies that you would like resolved out of the service container:
use App\DripEmailer;
use App\User;
Artisan::command('email:send {user}', function (DripEmailer $drip, $user) {
$drip->send(User::find($user));
});Closure Command Descriptions
When defining a Closure based command, you may use the describe method to add a description to the command. This description will be displayed when you run the php artisan list or php artisan help commands:
Artisan::command('build {project}', function ($project) {
$this->info("Building {$project}!");
})->describe('Build the project');Defining Input Expectations
When writing console commands, it is common to gather input from the user through arguments or options. Laravel makes it very convenient to define the input you expect from the user using the signature property on your commands. The signature property allows you to define the name, arguments, and options for the command in a single, expressive, route-like syntax.
Arguments
All user supplied arguments and options are wrapped in curly braces. In the following example, the command defines one required argument: user:
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'email:send {user}';You may also make arguments optional and define default values for arguments:
// Optional argument...
email:send {user?}
// Optional argument with default value...
email:send {user=foo}Options
Options, like arguments, are another form of user input. Options are prefixed by two hyphens (--) when they are specified on the command line. There are two types of options: those that receive a value and those that don't. Options that don't receive a value serve as a boolean "switch". Let's take a look at an example of this type of option:
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'email:send {user} {--queue}';In this example, the --queue switch may be specified when calling the Artisan command. If the --queue switch is passed, the value of the option will be true. Otherwise, the value will be false:
php artisan email:send 1 --queueOptions With Values
Next, let's take a look at an option that expects a value. If the user must specify a value for an option, suffix the option name with a = sign:
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'email:send {user} {--queue=}';In this example, the user may pass a value for the option like so:
php artisan email:send 1 --queue=defaultYou may assign default values to options by specifying the default value after the option name. If no option value is passed by the user, the default value will be used:
email:send {user} {--queue=default}Option Shortcuts
To assign a shortcut when defining an option, you may specify it before the option name and use a | delimiter to separate the shortcut from the full option name:
email:send {user} {--Q|queue}Input Arrays
If you would like to define arguments or options to expect array inputs, you may use the * character. First, let's take a look at an example that specifies an array argument:
email:send {user*}When calling this method, the user arguments may be passed in order to the command line. For example, the following command will set the value of user to ['foo', 'bar']:
php artisan email:send foo barWhen defining an option that expects an array input, each option value passed to the command should be prefixed with the option name:
email:send {user} {--id=*}
php artisan email:send --id=1 --id=2Input Descriptions
You may assign descriptions to input arguments and options by separating the parameter from the description using a colon. If you need a little extra room to define your command, feel free to spread the definition across multiple lines:
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'email:send
{user : The ID of the user}
{--queue= : Whether the job should be queued}';Command I/O
Retrieving Input
While your command is executing, you will obviously need to access the values for the arguments and options accepted by your command. To do so, you may use the argument and option methods:
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$userId = $this->argument('user');
//
}If you need to retrieve all of the arguments as an array, call the arguments method:
$arguments = $this->arguments();Options may be retrieved just as easily as arguments using the option method. To retrieve all of the options as an array, call the options method:
// Retrieve a specific option...
$queueName = $this->option('queue');
// Retrieve all options...
$options = $this->options();If the argument or option does not exist, null will be returned.
Prompting For Input
In addition to displaying output, you may also ask the user to provide input during the execution of your command. The ask method will prompt the user with the given question, accept their input, and then return the user's input back to your command:
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$name = $this->ask('What is your name?');
}The secret method is similar to ask, but the user's input will not be visible to them as they type in the console. This method is useful when asking for sensitive information such as a password:
$password = $this->secret('What is the password?');Asking For Confirmation
If you need to ask the user for a simple confirmation, you may use the confirm method. By default, this method will return false. However, if the user enters y or yes in response to the prompt, the method will return true.
if ($this->confirm('Do you wish to continue?')) {
//
}Auto-Completion
The anticipate method can be used to provide auto-completion for possible choices. The user can still choose any answer, regardless of the auto-completion hints:
$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);Multiple Choice Questions
If you need to give the user a predefined set of choices, you may use the choice method. You may set the array index of the default value to be returned if no option is chosen:
$name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $defaultIndex);Writing Output
To send output to the console, use the line, info, comment, question and error methods. Each of these methods will use appropriate ANSI colors for their purpose. For example, let's display some general information to the user. Typically, the info method will display in the console as green text:
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->info('Display this on the screen');
}To display an error message, use the error method. Error message text is typically displayed in red:
$this->error('Something went wrong!');If you would like to display plain, uncolored console output, use the line method:
$this->line('Display this on the screen');Table Layouts
The table method makes it easy to correctly format multiple rows / columns of data. Just pass in the headers and rows to the method. The width and height will be dynamically calculated based on the given data:
$headers = ['Name', 'Email'];
$users = App\User::all(['name', 'email'])->toArray();
$this->table($headers, $users);Progress Bars
For long running tasks, it could be helpful to show a progress indicator. Using the output object, we can start, advance and stop the Progress Bar. First, define the total number of steps the process will iterate through. Then, advance the Progress Bar after processing each item:
$users = App\User::all();
$bar = $this->output->createProgressBar(count($users));
$bar->start();
foreach ($users as $user) {
$this->performTask($user);
$bar->advance();
}
$bar->finish();For more advanced options, check out the Symfony Progress Bar component documentation.
Registering Commands
Because of the load method call in your console kernel's commands method, all commands within the app/Console/Commands directory will automatically be registered with Artisan. In fact, you are free to make additional calls to the load method to scan other directories for Artisan commands:
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
$this->load(__DIR__.'/MoreCommands');
// ...
}You may also manually register commands by adding its class name to the $commands property of your app/Console/Kernel.php file. When Artisan boots, all the commands listed in this property will be resolved by the service container and registered with Artisan:
protected $commands = [
Commands\SendEmails::class
];Programmatically Executing Commands
Sometimes you may wish to execute an Artisan command outside of the CLI. For example, you may wish to fire an Artisan command from a route or controller. You may use the call method on the Artisan facade to accomplish this. The call method accepts either the command's name or class as the first argument, and an array of command parameters as the second argument. The exit code will be returned:
Route::get('/foo', function () {
$exitCode = Artisan::call('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
});Alternatively, you may pass the entire Artisan command to the call method as a string:
Artisan::call('email:send 1 --queue=default');Using the queue method on the Artisan facade, you may even queue Artisan commands so they are processed in the background by your queue workers. Before using this method, make sure you have configured your queue and are running a queue listener:
Route::get('/foo', function () {
Artisan::queue('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
});You may also specify the connection or queue the Artisan command should be dispatched to:
Artisan::queue('email:send', [
'user' => 1, '--queue' => 'default'
])->onConnection('redis')->onQueue('commands');Passing Array Values
If your command defines an option that accepts an array, you may pass an array of values to that option:
Route::get('/foo', function () {
$exitCode = Artisan::call('email:send', [
'user' => 1, '--id' => [5, 13]
]);
});Passing Boolean Values
If you need to specify the value of an option that does not accept string values, such as the --force flag on the migrate:refresh command, you should pass true or false:
$exitCode = Artisan::call('migrate:refresh', [
'--force' => true,
]);Calling Commands From Other Commands
Sometimes you may wish to call other commands from an existing Artisan command. You may do so using the call method. This call method accepts the command name and an array of command parameters:
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->call('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
}If you would like to call another console command and suppress all of its output, you may use the callSilent method. The callSilent method has the same signature as the call method:
$this->callSilent('email:send', [
'user' => 1, '--queue' => 'default'
]);File: authentication.md
Authentication
- Introduction
- Authentication Quickstart
- Manually Authenticating Users
- HTTP Basic Authentication
- Logging Out
- Social Authentication
- Adding Custom Guards
- Adding Custom User Providers
- Events
Introduction
{tip} Want to get started fast? Install the
laravel/uiComposer package and runphp artisan ui vue --authin a fresh Laravel application. After migrating your database, navigate your browser tohttp://your-app.test/registeror any other URL that is assigned to your application. These commands will take care of scaffolding your entire authentication system!
Laravel makes implementing authentication very simple. In fact, almost everything is configured for you out of the box. The authentication configuration file is located at config/auth.php, which contains several well documented options for tweaking the behavior of the authentication services.
At its core, Laravel's authentication facilities are made up of "guards" and "providers". Guards define how users are authenticated for each request. For example, Laravel ships with a session guard which maintains state using session storage and cookies.
Providers define how users are retrieved from your persistent storage. Laravel ships with support for retrieving users using Eloquent and the database query builder. However, you are free to define additional providers as needed for your application.
Don't worry if this all sounds confusing now! Many applications will never need to modify the default authentication configuration.
Database Considerations
By default, Laravel includes an App\User Eloquent model in your app directory. This model may be used with the default Eloquent authentication driver. If your application is not using Eloquent, you may use the database authentication driver which uses the Laravel query builder.
When building the database schema for the App\User model, make sure the password column is at least 60 characters in length. Maintaining the default string column length of 255 characters would be a good choice.
Also, you should verify that your users (or equivalent) table contains a nullable, string remember_token column of 100 characters. This column will be used to store a token for users that select the "remember me" option when logging into your application.
Authentication Quickstart
Laravel ships with several pre-built authentication controllers, which are located in the App\Http\Controllers\Auth namespace. The RegisterController handles new user registration, the LoginController handles authentication, the ForgotPasswordController handles e-mailing links for resetting passwords, and the ResetPasswordController contains the logic to reset passwords. Each of these controllers uses a trait to include their necessary methods. For many applications, you will not need to modify these controllers at all.
Routing
Laravel's laravel/ui package provides a quick way to scaffold all of the routes and views you need for authentication using a few simple commands:
composer require laravel/ui --dev
php artisan ui vue --authThis command should be used on fresh applications and will install a layout view, registration and login views, as well as routes for all authentication end-points. A HomeController will also be generated to handle post-login requests to your application's dashboard.
{tip} If your application doesnโt need registration, you may disable it by removing the newly created
RegisterControllerand modifying your route declaration:Auth::routes(['register' => false]);.
Views
As mentioned in the previous section, the laravel/ui package's php artisan ui vue --auth command will create all of the views you need for authentication and place them in the resources/views/auth directory.
The ui command will also create a resources/views/layouts directory containing a base layout for your application. All of these views use the Bootstrap CSS framework, but you are free to customize them however you wish.
Authenticating
Now that you have routes and views setup for the included authentication controllers, you are ready to register and authenticate new users for your application! You may access your application in a browser since the authentication controllers already contain the logic (via their traits) to authenticate existing users and store new users in the database.
Path Customization
When a user is successfully authenticated, they will be redirected to the /home URI. You can customize the post-authentication redirect location by defining a redirectTo property on the LoginController, RegisterController, ResetPasswordController, and VerificationController:
protected $redirectTo = '/';Next, you should modify the RedirectIfAuthenticated middleware's handle method to use your new URI when redirecting the user.
If the redirect path needs custom generation logic you may define a redirectTo method instead of a redirectTo property:
protected function redirectTo()
{
return '/path';
}{tip} The
redirectTomethod will take precedence over theredirectToproperty.
Username Customization
By default, Laravel uses the email field for authentication. If you would like to customize this, you may define a username method on your LoginController:
public function username()
{
return 'username';
}Guard Customization
You may also customize the "guard" that is used to authenticate and register users. To get started, define a guard method on your LoginController, RegisterController, and ResetPasswordController. The method should return a guard instance:
use Illuminate\Support\Facades\Auth;
protected function guard()
{
return Auth::guard('guard-name');
}Validation / Storage Customization
To modify the form fields that are required when a new user registers with your application, or to customize how new users are stored into your database, you may modify the RegisterController class. This class is responsible for validating and creating new users of your application.
The validator method of the RegisterController contains the validation rules for new users of the application. You are free to modify this method as you wish.
The create method of the RegisterController is responsible for creating new App\User records in your database using the Eloquent ORM. You are free to modify this method according to the needs of your database.
Retrieving The Authenticated User
You may access the authenticated user via the Auth facade:
use Illuminate\Support\Facades\Auth;
// Get the currently authenticated user...
$user = Auth::user();
// Get the currently authenticated user's ID...
$id = Auth::id();Alternatively, once a user is authenticated, you may access the authenticated user via an Illuminate\Http\Request instance. Remember, type-hinted classes will automatically be injected into your controller methods:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
/**
* Update the user's profile.
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
// $request->user() returns an instance of the authenticated user...
}
}Determining If The Current User Is Authenticated
To determine if the user is already logged into your application, you may use the check method on the Auth facade, which will return true if the user is authenticated:
use Illuminate\Support\Facades\Auth;
if (Auth::check()) {
// The user is logged in...
}{tip} Even though it is possible to determine if a user is authenticated using the
checkmethod, you will typically use a middleware to verify that the user is authenticated before allowing the user access to certain routes / controllers. To learn more about this, check out the documentation on protecting routes.
Protecting Routes
Route middleware can be used to only allow authenticated users to access a given route. Laravel ships with an auth middleware, which is defined at Illuminate\Auth\Middleware\Authenticate. Since this middleware is already registered in your HTTP kernel, all you need to do is attach the middleware to a route definition:
Route::get('profile', function () {
// Only authenticated users may enter...
})->middleware('auth');If you are using controllers, you may call the middleware method from the controller's constructor instead of attaching it in the route definition directly:
public function __construct()
{
$this->middleware('auth');
}Redirecting Unauthenticated Users
When the auth middleware detects an unauthorized user, it will redirect the user to the login named route. You may modify this behavior by updating the redirectTo function in your app/Http/Middleware/Authenticate.php file:
/**
* Get the path the user should be redirected to.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
protected function redirectTo($request)
{
return route('login');
}Specifying A Guard
When attaching the auth middleware to a route, you may also specify which guard should be used to authenticate the user. The guard specified should correspond to one of the keys in the guards array of your auth.php configuration file:
public function __construct()
{
$this->middleware('auth:api');
}Password Confirmation
Sometimes, you may wish to require the user to confirm their password before accessing a specific area of your application. For example, you may require this before the user modifies any billing settings within the application.
To accomplish this, Laravel provides a password.confirm middleware. Attaching the password.confirm middleware to a route will redirect users to a screen where they need to confirm their password before they can continue:
Route::get('/settings/security', function () {
// Users must confirm their password before continuing...
})->middleware(['auth', 'password.confirm']);After the user has successfully confirmed their password, the user is redirected to the route they originally tried to access. By default, after confirming their password, the user will not have to confirm their password again for three hours. You are free to customize the length of time before the user must re-confirm their password using the auth.password_timeout configuration option.
Login Throttling
If you are using Laravel's built-in LoginController class, the Illuminate\Foundation\Auth\ThrottlesLogins trait will already be included in your controller. By default, the user will not be able to login for one minute if they fail to provide the correct credentials after several attempts. The throttling is unique to the user's username / e-mail address and their IP address.
Manually Authenticating Users
Note that you are not required to use the authentication controllers included with Laravel. If you choose to remove these controllers, you will need to manage user authentication using the Laravel authentication classes directly. Don't worry, it's a cinch!
We will access Laravel's authentication services via the Auth facade, so we'll need to make sure to import the Auth facade at the top of the class. Next, let's check out the attempt method:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
/**
* Handle an authentication attempt.
*
* @param \Illuminate\Http\Request $request
*
* @return Response
*/
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
// Authentication passed...
return redirect()->intended('dashboard');
}
}
}The attempt method accepts an array of key / value pairs as its first argument. The values in the array will be used to find the user in your database table. So, in the example above, the user will be retrieved by the value of the email column. If the user is found, the hashed password stored in the database will be compared with the password value passed to the method via the array. You should not hash the password specified as the password value, since the framework will automatically hash the value before comparing it to the hashed password in the database. If the two hashed passwords match an authenticated session will be started for the user.
The attempt method will return true if authentication was successful. Otherwise, false will be returned.
The intended method on the redirector will redirect the user to the URL they were attempting to access before being intercepted by the authentication middleware. A fallback URI may be given to this method in case the intended destination is not available.
Specifying Additional Conditions
If you wish, you may also add extra conditions to the authentication query in addition to the user's e-mail and password. For example, we may verify that user is marked as "active":
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// The user is active, not suspended, and exists.
}{note} In these examples,
Accessing Specific Guard Instances
You may specify which guard instance you would like to utilize using the guard method on the Auth facade. This allows you to manage authentication for separate parts of your application using entirely separate authenticatable models or user tables.
The guard name passed to the guard method should correspond to one of the guards configured in your auth.php configuration file:
if (Auth::guard('admin')->attempt($credentials)) {
//
}Logging Out
To log users out of your application, you may use the logout method on the Auth facade. This will clear the authentication information in the user's session:
Auth::logout();Remembering Users
If you would like to provide "remember me" functionality in your application, you may pass a boolean value as the second argument to the attempt method, which will keep the user authenticated indefinitely, or until they manually logout. Your users table must include the string remember_token column, which will be used to store the "remember me" token.
if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
// The user is being remembered...
}{tip} If you are using the built-in
LoginControllerthat is shipped with Laravel, the proper logic to "remember" users is already implemented by the traits used by the controller.
If you are "remembering" users, you may use the viaRemember method to determine if the user was authenticated using the "remember me" cookie:
if (Auth::viaRemember()) {
//
}Other Authentication Methods
Authenticate A User Instance
If you need to log an existing user instance into your application, you may call the login method with the user instance. The given object must be an implementation of the Illuminate\Contracts\Auth\Authenticatable contract. The App\User model included with Laravel already implements this interface:
Auth::login($user);
// Login and "remember" the given user...
Auth::login($user, true);You may specify the guard instance you would like to use:
Auth::guard('admin')->login($user);Authenticate A User By ID
To log a user into the application by their ID, you may use the loginUsingId method. This method accepts the primary key of the user you wish to authenticate:
Auth::loginUsingId(1);
// Login and "remember" the given user...
Auth::loginUsingId(1, true);Authenticate A User Once
You may use the once method to log a user into the application for a single request. No sessions or cookies will be utilized, which means this method may be helpful when building a stateless API:
if (Auth::once($credentials)) {
//
}HTTP Basic Authentication
HTTP Basic Authentication provides a quick way to authenticate users of your application without setting up a dedicated "login" page. To get started, attach the auth.basic middleware to your route. The auth.basic middleware is included with the Laravel framework, so you do not need to define it:
Route::get('profile', function () {
// Only authenticated users may enter...
})->middleware('auth.basic');Once the middleware has been attached to the route, you will automatically be prompted for credentials when accessing the route in your browser. By default, the auth.basic middleware will use the email column on the user record as the "username".
A Note On FastCGI
If you are using PHP FastCGI, HTTP Basic authentication may not work correctly out of the box. The following lines should be added to your .htaccess file:
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]Stateless HTTP Basic Authentication
You may also use HTTP Basic Authentication without setting a user identifier cookie in the session, which is particularly useful for API authentication. To do so, define a middleware that calls the onceBasic method. If no response is returned by the onceBasic method, the request may be passed further into the application:
<?php
namespace App\Http\Middleware;
use Illuminate\Support\Facades\Auth;
class AuthenticateOnceWithBasicAuth
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, $next)
{
return Auth::onceBasic() ?: $next($request);
}
}Next, register the route middleware and attach it to a route:
Route::get('api/user', function () {
// Only authenticated users may enter...
})->middleware('auth.basic.once');Logging Out
To manually log users out of your application, you may use the logout method on the Auth facade. This will clear the authentication information in the user's session:
use Illuminate\Support\Facades\Auth;
Auth::logout();Invalidating Sessions On Other Devices
Laravel also provides a mechanism for invalidating and "logging out" a user's sessions that are active on other devices without invalidating the session on their current device. Before getting started, you should make sure that the Illuminate\Session\Middleware\AuthenticateSession middleware is present and un-commented in your app/Http/Kernel.php class' web middleware group:
'web' => [
// ...
\Illuminate\Session\Middleware\AuthenticateSession::class,
// ...
],Then, you may use the logoutOtherDevices method on the Auth facade. This method requires the user to provide their current password, which your application should accept through an input form:
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($password);{note} When the
logoutOtherDevicesmethod is invoked, the user's other sessions will be invalidated entirely, meaning they will be "logged out" of all guards they were previously authenticated by.
Adding Custom Guards
You may define your own authentication guards using the extend method on the Auth facade. You should place this call to extend within a service provider. Since Laravel already ships with an AuthServiceProvider, we can place the code in that provider:
<?php
namespace App\Providers;
use App\Services\Auth\JwtGuard;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::extend('jwt', function ($app, $name, array $config) {
// Return an instance of Illuminate\Contracts\Auth\Guard...
return new JwtGuard(Auth::createUserProvider($config['provider']));
});
}
}As you can see in the example above, the callback passed to the extend method should return an implementation of Illuminate\Contracts\Auth\Guard. This interface contains a few methods you will need to implement to define a custom guard. Once your custom guard has been defined, you may use this guard in the guards configuration of your auth.php configuration file:
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],Closure Request Guards
The simplest way to implement a custom, HTTP request based authentication system is by using the Auth::viaRequest method. This method allows you to quickly define your authentication process using a single Closure.
To get started, call the Auth::viaRequest method within the boot method of your AuthServiceProvider. The viaRequest method accepts an authentication driver name as its first argument. This name can be any string that describes your custom guard. The second argument passed to the method should be a Closure that receives the incoming HTTP request and returns a user instance or, if authentication fails, null:
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::viaRequest('custom-token', function ($request) {
return User::where('token', $request->token)->first();
});
}Once your custom authentication driver has been defined, you use it as a driver within guards configuration of your auth.php configuration file:
'guards' => [
'api' => [
'driver' => 'custom-token',
],
],Adding Custom User Providers
If you are not using a traditional relational database to store your users, you will need to extend Laravel with your own authentication user provider. We will use the provider method on the Auth facade to define a custom user provider:
<?php
namespace App\Providers;
use App\Extensions\RiakUserProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::provider('riak', function ($app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new RiakUserProvider($app->make('riak.connection'));
});
}
}After you have registered the provider using the provider method, you may switch to the new user provider in your auth.php configuration file. First, define a provider that uses your new driver:
'providers' => [
'users' => [
'driver' => 'riak',
],
],Finally, you may use this provider in your guards configuration:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],The User Provider Contract
The Illuminate\Contracts\Auth\UserProvider implementations are only responsible for fetching a Illuminate\Contracts\Auth\Authenticatable implementation out of a persistent storage system, such as MySQL, Riak, etc. These two interfaces allow the Laravel authentication mechanisms to continue functioning regardless of how the user data is stored or what type of class is used to represent it.
Let's take a look at the Illuminate\Contracts\Auth\UserProvider contract:
<?php
namespace Illuminate\Contracts\Auth;
interface UserProvider
{
public function retrieveById($identifier);
public function retrieveByToken($identifier, $token);
public function updateRememberToken(Authenticatable $user, $token);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(Authenticatable $user, array $credentials);
}The retrieveById function typically receives a key representing the user, such as an auto-incrementing ID from a MySQL database. The Authenticatable implementation matching the ID should be retrieved and returned by the method.
The retrieveByToken function retrieves a user by their unique $identifier and "remember me" $token, stored in a field remember_token. As with the previous method, the Authenticatable implementation should be returned.
The updateRememberToken method updates the $user field remember_token with the new $token. A fresh token is assigned on a successful "remember me" login attempt or when the user is logging out.
The retrieveByCredentials method receives the array of credentials passed to the Auth::attempt method when attempting to sign into an application. The method should then "query" the underlying persistent storage for the user matching those credentials. Typically, this method will run a query with a "where" condition on $credentials['username']. The method should then return an implementation of Authenticatable. This method should not attempt to do any password validation or authentication.
The validateCredentials method should compare the given $user with the $credentials to authenticate the user. For example, this method should probably use Hash::check to compare the value of $user->getAuthPassword() to the value of $credentials['password']. This method should return true or false indicating on whether the password is valid.
The Authenticatable Contract
Now that we have explored each of the methods on the UserProvider, let's take a look at the Authenticatable contract. Remember, the provider should return implementations of this interface from the retrieveById, retrieveByToken, and retrieveByCredentials methods:
<?php
namespace Illuminate\Contracts\Auth;
interface Authenticatable
{
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}This interface is simple. The getAuthIdentifierName method should return the name of the "primary key" field of the user and the getAuthIdentifier method should return the "primary key" of the user. In a MySQL back-end, again, this would be the auto-incrementing primary key. The getAuthPassword should return the user's hashed password. This interface allows the authentication system to work with any User class, regardless of what ORM or storage abstraction layer you are using. By default, Laravel includes a User class in the app directory which implements this interface, so you may consult this class for an implementation example.
Events
Laravel raises a variety of events during the authentication process. You may attach listeners to these events in your EventServiceProvider:
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Illuminate\Auth\Events\Registered' => [
'App\Listeners\LogRegisteredUser',
],
'Illuminate\Auth\Events\Attempting' => [
'App\Listeners\LogAuthenticationAttempt',
],
'Illuminate\Auth\Events\Authenticated' => [
'App\Listeners\LogAuthenticated',
],
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
'Illuminate\Auth\Events\Failed' => [
'App\Listeners\LogFailedLogin',
],
'Illuminate\Auth\Events\Logout' => [
'App\Listeners\LogSuccessfulLogout',
],
'Illuminate\Auth\Events\Lockout' => [
'App\Listeners\LogLockout',
],
'Illuminate\Auth\Events\PasswordReset' => [
'App\Listeners\LogPasswordReset',
],
];File: authorization.md
Authorization
Introduction
In addition to providing authentication services out of the box, Laravel also provides a simple way to authorize user actions against a given resource. Like authentication, Laravel's approach to authorization is simple, and there are two primary ways of authorizing actions: gates and policies.
Think of gates and policies like routes and controllers. Gates provide a simple, Closure based approach to authorization while policies, like controllers, group their logic around a particular model or resource. We'll explore gates first and then examine policies.
You do not need to choose between exclusively using gates or exclusively using policies when building an application. Most applications will most likely contain a mixture of gates and policies, and that is perfectly fine! Gates are most applicable to actions which are not related to any model or resource, such as viewing an administrator dashboard. In contrast, policies should be used when you wish to authorize an action for a particular model or resource.
Gates
Writing Gates
Gates are Closures that determine if a user is authorized to perform a given action and are typically defined in the App\Providers\AuthServiceProvider class using the Gate facade. Gates always receive a user instance as their first argument, and may optionally receive additional arguments such as a relevant Eloquent model:
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('edit-settings', function ($user) {
return $user->isAdmin;
});
Gate::define('update-post', function ($user, $post) {
return $user->id === $post->user_id;
});
}Gates may also be defined using a Class@method style callback string, like controllers:
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', 'App\Policies\PostPolicy@update');
}Authorizing Actions
To authorize an action using gates, you should use the allows or denies methods. Note that you are not required to pass the currently authenticated user to these methods. Laravel will automatically take care of passing the user into the gate Closure:
if (Gate::allows('edit-settings')) {
// The current user can edit settings
}
if (Gate::allows('update-post', $post)) {
// The current user can update the post...
}
if (Gate::denies('update-post', $post)) {
// The current user can't update the post...
}If you would like to determine if a particular user is authorized to perform an action, you may use the forUser method on the Gate facade:
if (Gate::forUser($user)->allows('update-post', $post)) {
// The user can update the post...
}
if (Gate::forUser($user)->denies('update-post', $post)) {
// The user can't update the post...
}You may authorize multiple actions at a time with the any or none methods:
if (Gate::any(['update-post', 'delete-post'], $post)) {
// The user can update or delete the post
}
if (Gate::none(['update-post', 'delete-post'], $post)) {
// The user cannot update or delete the post
}Authorizing Or Throwing Exceptions
If you would like to attempt to authorize an action and automatically throw an Illuminate\Auth\Access\AuthorizationException if the user is not allowed to perform the given action, you may use the Gate::authorize method. Instances of AuthorizationException are automatically converted to 403 HTTP response:
Gate::authorize('update-post', $post);
// The action is authorized...Supplying Additional Context
The gate methods for authorizing abilities (allows, denies, check, any, none, authorize, can, cannot) and the authorization Blade directives (@can, @cannot, @canany) can receive an array as the second argument. These array elements are passed as parameters to gate, and can be used for additional context when making authorization decisions:
Gate::define('create-post', function ($user, $category, $extraFlag) {
return $category->group > 3 && $extraFlag === true;
});
if (Gate::check('create-post', [$category, $extraFlag])) {
// The user can create the post...
}Gate Responses
So far, we have only examined gates that return simple boolean values. However, sometimes you may wish to return a more detail response, including an error message. To do so, you may return a Illuminate\Auth\Access\Response from your gate:
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
Gate::define('edit-settings', function ($user) {
return $user->isAdmin
? Response::allow()
: Response::deny('You must be a super administrator.');
});When returning an authorization response from your gate, the Gate::allows method will still return a simple boolean value; however, you may use the Gate::inspect method to get the full authorization response returned by the gate:
$response = Gate::inspect('edit-settings', $post);
if ($response->allowed()) {
// The action is authorized...
} else {
echo $response->message();
}Of course, when using the Gate::authorize method to throw an AuthorizationException if the action is not authorized, the error message provided by the authorization response will be propagated to the HTTP response:
Gate::authorize('edit-settings', $post);
// The action is authorized...Intercepting Gate Checks
Sometimes, you may wish to grant all abilities to a specific user. You may use the before method to define a callback that is run before all other authorization checks:
Gate::before(function ($user, $ability) {
if ($user->isSuperAdmin()) {
return true;
}
});If the before callback returns a non-null result that result will be considered the result of the check.
You may use the after method to define a callback to be executed after all other authorization checks:
Gate::after(function ($user, $ability, $result, $arguments) {
if ($user->isSuperAdmin()) {
return true;
}
});Similar to the before check, if the after callback returns a non-null result that result will be considered the result of the check.
Creating Policies
Generating Policies
Policies are classes that organize authorization logic around a particular model or resource. For example, if your application is a blog, you may have a Post model and a corresponding PostPolicy to authorize user actions such as creating or updating posts.
You may generate a policy using the make:policy artisan command. The generated policy will be placed in the app/Policies directory. If this directory does not exist in your application, Laravel will create it for you:
php artisan make:policy PostPolicyThe make:policy command will generate an empty policy class. If you would like to generate a class with the basic "CRUD" policy methods already included in the class, you may specify a --model when executing the command:
php artisan make:policy PostPolicy --model=Post{tip} All policies are resolved via the Laravel service container, allowing you to type-hint any needed dependencies in the policy's constructor to have them automatically injected.
Registering Policies
Once the policy exists, it needs to be registered. The AuthServiceProvider included with fresh Laravel applications contains a policies property which maps your Eloquent models to their corresponding policies. Registering a policy will instruct Laravel which policy to utilize when authorizing actions against a given model:
<?php
namespace App\Providers;
use App\Policies\PostPolicy;
use App\Post;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
Post::class => PostPolicy::class,
];
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}Policy Auto-Discovery
Instead of manually registering model policies, Laravel can auto-discover policies as long as the model and policy follow standard Laravel naming conventions. Specifically, the policies must be in a Policies directory below the directory that contains the models. So, for example, the models may be placed in the app directory while the policies may be placed in the app/Policies directory. In addition, the policy name must match the model name and have a Policy suffix. So, a User model would correspond to a UserPolicy class.
If you would like to provide your own policy discovery logic, you may register a custom callback using the Gate::guessPolicyNamesUsing method. Typically, this method should be called from the boot method of your application's AuthServiceProvider:
use Illuminate\Support\Facades\Gate;
Gate::guessPolicyNamesUsing(function ($modelClass) {
// return policy class name...
});{note} Any policies that are explicitly mapped in your
AuthServiceProviderwill take precedence over any potential auto-discovered policies.
Writing Policies
Policy Methods
Once the policy has been registered, you may add methods for each action it authorizes. For example, let's define an update method on our PostPolicy which determines if a given User can update a given Post instance.
The update method will receive a User and a Post instance as its arguments, and should return true or false indicating whether the user is authorized to update the given Post. So, for this example, let's verify that the user's id matches the user_id on the post:
<?php
namespace App\Policies;
use App\Post;
use App\User;
class PostPolicy
{
/**
* Determine if the given post can be updated by the user.
*
* @param \App\User $user
* @param \App\Post $post
* @return bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}You may continue to define additional methods on the policy as needed for the various actions it authorizes. For example, you might define view or delete methods to authorize various Post actions, but remember you are free to give your policy methods any name you like.
{tip} If you used the
--modeloption when generating your policy via the Artisan console, it will already contain methods for theview,create,update,delete,restore, andforceDeleteactions.
Policy Responses
So far, we have only examined policy methods that return simple boolean values. However, sometimes you may wish to return a more detail response, including an error message. To do so, you may return a Illuminate\Auth\Access\Response from your policy method:
use Illuminate\Auth\Access\Response;
/**
* Determine if the given post can be updated by the user.
*
* @param \App\User $user
* @param \App\Post $post
* @return bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id
? Response::allow()
: Response::deny('You do not own this post.');
}When returning an authorization response from your policy, the Gate::allows method will still return a simple boolean value; however, you may use the Gate::inspect method to get the full authorization response returned by the gate:
$response = Gate::inspect('update', $post);
if ($response->allowed()) {
// The action is authorized...
} else {
echo $response->message();
}Of course, when using the Gate::authorize method to throw an AuthorizationException if the action is not authorized, the error message provided by the authorization response will be propagated to the HTTP response:
Gate::authorize('update', $post);
// The action is authorized...Methods Without Models
Some policy methods only receive the currently authenticated user and not an instance of the model they authorize. This situation is most common when authorizing create actions. For example, if you are creating a blog, you may wish to check if a user is authorized to create any posts at all.
When defining policy methods that will not receive a model instance, such as a create method, it will not receive a model instance. Instead, you should define the method as only expecting the authenticated user:
/**
* Determine if the given user can create posts.
*
* @param \App\User $user
* @return bool
*/
public function create(User $user)
{
//
}Guest Users
By default, all gates and policies automatically return false if the incoming HTTP request was not initiated by an authenticated user. However, you may allow these authorization checks to pass through to your gates and policies by declaring an "optional" type-hint or supplying a null default value for the user argument definition:
<?php
namespace App\Policies;
use App\Post;
use App\User;
class PostPolicy
{
/**
* Determine if the given post can be updated by the user.
*
* @param \App\User $user
* @param \App\Post $post
* @return bool
*/
public function update(?User $user, Post $post)
{
return $user->id === $post->user_id;
}
}Policy Filters
For certain users, you may wish to authorize all actions within a given policy. To accomplish this, define a before method on the policy. The before method will be executed before any other methods on the policy, giving you an opportunity to authorize the action before the intended policy method is actually called. This feature is most commonly used for authorizing application administrators to perform any action:
public function before($user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}If you would like to deny all authorizations for a user you should return false from the before method. If null is returned, the authorization will fall through to the policy method.
{note} The
beforemethod of a policy class will not be called if the class doesn't contain a method with a name matching the name of the ability being checked.
Authorizing Actions Using Policies
Via The User Model
The User model that is included with your Laravel application includes two helpful methods for authorizing actions: can and cant. The can method receives the action you wish to authorize and the relevant model. For example, let's determine if a user is authorized to update a given Post model:
if ($user->can('update', $post)) {
//
}If a policy is registered for the given model, the can method will automatically call the appropriate policy and return the boolean result. If no policy is registered for the model, the can method will attempt to call the Closure based Gate matching the given action name.
Actions That Don't Require Models
Remember, some actions like create may not require a model instance. In these situations, you may pass a class name to the can method. The class name will be used to determine which policy to use when authorizing the action:
use App\Post;
if ($user->can('create', Post::class)) {
// Executes the "create" method on the relevant policy...
}Via Middleware
Laravel includes a middleware that can authorize actions before the incoming request even reaches your routes or controllers. By default, the Illuminate\Auth\Middleware\Authorize middleware is assigned the can key in your App\Http\Kernel class. Let's explore an example of using the can middleware to authorize that a user can update a blog post:
use App\Post;
Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,post');In this example, we're passing the can middleware two arguments. The first is the name of the action we wish to authorize and the second is the route parameter we wish to pass to the policy method. In this case, since we are using implicit model binding, a Post model will be passed to the policy method. If the user is not authorized to perform the given action, a HTTP response with a 403 status code will be generated by the middleware.
Actions That Don't Require Models
Again, some actions like create may not require a model instance. In these situations, you may pass a class name to the middleware. The class name will be used to determine which policy to use when authorizing the action:
Route::post('/post', function () {
// The current user may create posts...
})->middleware('can:create,App\Post');Via Controller Helpers
In addition to helpful methods provided to the User model, Laravel provides a helpful authorize method to any of your controllers which extend the App\Http\Controllers\Controller base class. Like the can method, this method accepts the name of the action you wish to authorize and the relevant model. If the action is not authorized, the authorize method will throw an Illuminate\Auth\Access\AuthorizationException, which the default Laravel exception handler will convert to an HTTP response with a 403 status code:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Update the given blog post.
*
* @param Request $request
* @param Post $post
* @return Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// The current user can update the blog post...
}
}Actions That Don't Require Models
As previously discussed, some actions like create may not require a model instance. In these situations, you should pass a class name to the authorize method. The class name will be used to determine which policy to use when authorizing the action:
/**
* Create a new blog post.
*
* @param Request $request
* @return Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(Request $request)
{
$this->authorize('create', Post::class);
// The current user can create blog posts...
}Authorizing Resource Controllers
If you are utilizing resource controllers, you may make use of the authorizeResource method in the controller's constructor. This method will attach the appropriate can middleware definitions to the resource controller's methods.
The authorizeResource method accepts the model's class name as its first argument, and the name of the route / request parameter that will contain the model's ID as its second argument:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
}The following controller methods will be mapped to their corresponding policy method:
| Controller Method | Policy Method |
|---|---|
| index | viewAny |
| show | view |
| create | create |
| store | create |
| edit | update |
| update | update |
| destroy | delete |
{tip} You may use the
make:policycommand with the--modeloption to quickly generate a policy class for a given model:php artisan make:policy PostPolicy --model=Post.
Via Blade Templates
When writing Blade templates, you may wish to display a portion of the page only if the user is authorized to perform a given action. For example, you may wish to show an update form for a blog post only if the user can actually update the post. In this situation, you may use the @can and @cannot family of directives:
@can('update', $post)
@elsecan('create', App\Post::class)
@endcan
@cannot('update', $post)
@elsecannot('create', App\Post::class)
@endcannotThese directives are convenient shortcuts for writing @if and @unless statements. The @can and @cannot statements above respectively translate to the following statements:
@if (Auth::user()->can('update', $post))
@endif
@unless (Auth::user()->can('update', $post))
@endunlessYou may also determine if a user has any authorization ability from a given list of abilities. To accomplish this, use the @canany directive:
@canany(['update', 'view', 'delete'], $post)
// The current user can update, view, or delete the post
@elsecanany(['create'], \App\Post::class)
// The current user can create a post
@endcananyActions That Don't Require Models
Like most of the other authorization methods, you may pass a class name to the @can and @cannot directives if the action does not require a model instance:
@can('create', App\Post::class)
@endcan
@cannot('create', App\Post::class)
@endcannotSupplying Additional Context
When authorizing actions using policies, you may pass an array as the second argument to the various authorization functions and helpers. The first element in the array will be used to determine which policy should be invoked, while the rest of the array elements are passed as parameters to the policy method and can be used for additional context when making authorization decisions. For example, consider the following PostPolicy method definition which contains an additional $category parameter:
/**
* Determine if the given post can be updated by the user.
*
* @param \App\User $user
* @param \App\Post $post
* @param int $category
* @return bool
*/
public function update(User $user, Post $post, int $category)
{
return $user->id === $post->user_id &&
$category > 3;
}When attempting to determine if the authenticated user can update a given post, we can invoke this policy method like so:
/**
* Update the given blog post.
*
* @param Request $request
* @param Post $post
* @return Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post)
{
$this->authorize('update', [$post, $request->input('category')]);
// The current user can update the blog post...
}File: billing.md
Laravel Cashier
- Introduction
- Upgrading Cashier
- Installation
- Configuration
- Customers
- Payment Methods
- Subscriptions
- Subscription Trials
- Handling Stripe Webhooks
- Single Charges
- Invoices
- Strong Customer Authentication (SCA)
Introduction
Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services. It handles almost all of the boilerplate subscription billing code you are dreading writing. In addition to basic subscription management, Cashier can handle coupons, swapping subscription, subscription "quantities", cancellation grace periods, and even generate invoice PDFs.
Upgrading Cashier
When upgrading to a new version of Cashier, it's important that you carefully review the upgrade guide.
{note} To prevent breaking changes, Cashier uses a fixed Stripe API version. Cashier 10.1 utilizes Stripe API version
2019-08-14. The Stripe API version will be updated on minor releases in order to make use of new Stripe features and improvements.
Installation
First, require the Cashier package for Stripe with Composer:
composer require laravel/cashier{note} To ensure Cashier properly handles all Stripe events, remember to set up Cashier's webhook handling.
Database Migrations
The Cashier service provider registers its own database migration directory, so remember to migrate your database after installing the package. The Cashier migrations will add several columns to your users table as well as create a new subscriptions table to hold all of your customer's subscriptions:
php artisan migrateIf you need to overwrite the migrations that ship with the Cashier package, you can publish them using the vendor:publish Artisan command:
php artisan vendor:publish --tag="cashier-migrations"If you would like to prevent Cashier's migrations from running entirely, you may use the ignoreMigrations provided by Cashier. Typically, this method should be called in the register method of your AppServiceProvider:
use Laravel\Cashier\Cashier;
Cashier::ignoreMigrations();{note} Stripe recommends that any column used for storing Stripe identifiers should be case-sensitive. Therefore, you should ensure the column collation for the
stripe_idcolumn is set to, for example,utf8_binin MySQL. More info can be found in the Stripe documentation.
Configuration
Billable Model
Before using Cashier, add the Billable trait to your model definition. This trait provides various methods to allow you to perform common billing tasks, such as creating subscriptions, applying coupons, and updating payment method information:
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
}Cashier assumes your Billable model will be the App\User class that ships with Laravel. If you wish to change this you can specify a different model in your .env file:
CASHIER_MODEL=App\User{note} If you're using a model other than Laravel's supplied
App\Usermodel, you'll need to publish and alter the migrations provided to match your alternative model's table name.
API Keys
Next, you should configure your Stripe key in your .env file. You can retrieve your Stripe API keys from the Stripe control panel.
STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secretCurrency Configuration
The default Cashier currency is United States Dollars (USD). You can change the default currency by setting the CASHIER_CURRENCY environment variable:
CASHIER_CURRENCY=eurIn addition to configuring Cashier's currency, you may also specify a locale to be used when formatting money values for display on invoices. Internally, Cashier utilizes PHP's NumberFormatter class to set the currency locale:
CASHIER_CURRENCY_LOCALE=nl_BE{note} In order to use locales other than
en, ensure theext-intlPHP extension is installed and configured on your server.
Logging
Cashier allows you to specify the log channel to be used when logging all Stripe related exceptions. You may specify the log channel using the CASHIER_LOGGER environment variable:
CASHIER_LOGGER=defaultCustomers
Creating Customers
Occasionally, you may wish to create a Stripe customer without beginning a subscription. You may accomplish this using the createAsStripeCustomer method:
$user->createAsStripeCustomer();Once the customer has been created in Stripe, you may begin a subscription at a later date.
Payment Methods
Storing Payment Methods
In order to create subscriptions or perform "one off" charges with Stripe, you will need to store a payment method and retrieve its identifier from Stripe. The approach used to accomplish differs based on whether you plan to use the payment method for subscriptions or single charges, so we will examine both below.
Payment Methods For Subscriptions
When storing credit cards to a customer for future use, the Stripe Setup Intents API must be used to securely gather the customer's payment method details. A "Setup Intent" indicates to Stripe the intention to charge a customer's payment method. Cashier's Billable trait includes the createSetupIntent to easily create a new Setup Intent. You should call this method from the route or controller that will render the form which gathers your customer's payment method details:
return view('update-payment-method', [
'intent' => $user->createSetupIntent()
]);After you have created the Setup Intent and passed it to the view, you should attach its secret to the element that will gather the payment method. For example, consider this "update payment method" form:
client_secret }}">
Update Payment MethodNext, the Stripe.js library may be used to attach a Stripe Element to the form and securely gather the customer's payment details:
<script src="https://js.stripe.com/v3/"></script>
<script>
const stripe = Stripe('stripe-public-key');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
</script>Next, the card can be verified and a secure "payment method identifier" can be retrieved from Stripe using Stripe's handleCardSetup method:
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
const clientSecret = cardButton.dataset.secret;
cardButton.addEventListener('click', async (e) => {
const { setupIntent, error } = await stripe.handleCardSetup(
clientSecret, cardElement, {
payment_method_data: {
billing_details: { name: cardHolderName.value }
}
}
);
if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});After the card has been verified by Stripe, you may pass the resulting setupIntent.payment_method identifier to your Laravel application, where it can be attached to the customer. The payment method can either be added as a new payment method or used to update the default payment method. You can also immediately use the payment method identifier to create a new subscription.
{tip} If you would like more information about Setup Intents and gathering customer payment details please review this overview provided by Stripe.
Payment Methods For Single Charges
Of course, when making a single charge against a customer's payment method we'll only need to use a payment method identifier a single time. Due to Stripe limitations, you may not use the stored default payment method of a customer for single charges. You must allow the customer to enter their payment method details using the Stripe.js library. For example, consider the following form:
Process PaymentNext, the Stripe.js library may be used to attach a Stripe Element to the form and securely gather the customer's payment details:
<script src="https://js.stripe.com/v3/"></script>
<script>
const stripe = Stripe('stripe-public-key');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
</script>Next, the card can be verified and a secure "payment method identifier" can be retrieved from Stripe using Stripe's createPaymentMethod method:
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
cardButton.addEventListener('click', async (e) => {
const { paymentMethod, error } = await stripe.createPaymentMethod(
'card', cardElement, {
billing_details: { name: cardHolderName.value }
}
);
if (error) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});If the card is verified successfully, you may pass the paymentMethod.id to your Laravel application and process a single charge.
Retrieving Payment Methods
The paymentMethods method on the Billable model instance returns a collection of Laravel\Cashier\PaymentMethod instances:
$paymentMethods = $user->paymentMethods();To retrieve the default payment method, the defaultPaymentMethod method may be used;
$paymentMethod = $user->defaultPaymentMethod();Determining If A User Has A Payment Method
To determine if a Billable model has a payment method attached to their account, use the hasPaymentMethod method:
if ($user->hasPaymentMethod()) {
//
}Updating The Default Payment Method
The updateDefaultPaymentMethod method may be used to update a customer's default payment method information. This method accepts a Stripe payment method identifier and will assign the new payment method as the default billing payment method:
$user->updateDefaultPaymentMethod($paymentMethod);To sync your default payment method information with the customer's default payment method information in Stripe, you may use the updateDefaultPaymentMethodFromStripe method:
$user->updateDefaultPaymentMethodFromStripe();{note} The default payment method on a customer can only be used for invoicing and creating new subscriptions. Due to limitations from Stripe, it may not be used for single charges.
Adding Payment Methods
To add a new payment method, you may call the addPaymentMethod method on the billable user, passing the payment method identifier:
$user->addPaymentMethod($paymentMethod);{tip} To learn how to retrieve payment method identifiers please review the payment method storage documentation.
Deleting Payment Methods
To delete a payment method, you may call the delete method on the Laravel\Cashier\PaymentMethod instance you wish to delete:
$paymentMethod->delete();The deletePaymentMethods method will delete all of the payment method information for the Billable model:
$user->deletePaymentMethods();{note} If a user has an active subscription, you should prevent them from deleting their default payment method.
Subscriptions
Creating Subscriptions
To create a subscription, first retrieve an instance of your billable model, which typically will be an instance of App\User. Once you have retrieved the model instance, you may use the newSubscription method to create the model's subscription:
$user = User::find(1);
$user->newSubscription('main', 'premium')->create($paymentMethod);The first argument passed to the newSubscription method should be the name of the subscription. If your application only offers a single subscription, you might call this main or primary. The second argument is the specific plan the user is subscribing to. This value should correspond to the plan's identifier in Stripe.
The create method, which accepts a Stripe payment method identifier or Stripe PaymentMethod object, will begin the subscription as well as update your database with the customer ID and other relevant billing information.
{note} Passing a payment method identifier directly to the
create()subscription method will also automatically add it to the user's stored payment methods.
Additional User Details
If you would like to specify additional customer details, you may do so by passing them as the second argument to the create method:
$user->newSubscription('main', 'monthly')->create($paymentMethod, [
'email' => $email,
]);To learn more about the additional fields supported by Stripe, check out Stripe's documentation on customer creation.
Coupons
If you would like to apply a coupon when creating the subscription, you may use the withCoupon method:
$user->newSubscription('main', 'monthly')
->withCoupon('code')
->create($paymentMethod);Checking Subscription Status
Once a user is subscribed to your application, you may easily check their subscription status using a variety of convenient methods. First, the subscribed method returns true if the user has an active subscription, even if the subscription is currently within its trial period:
if ($user->subscribed('main')) {
//
}The subscribed method also makes a great candidate for a route middleware, allowing you to filter access to routes and controllers based on the user's subscription status:
public function handle($request, Closure $next)
{
if ($request->user() && ! $request->user()->subscribed('main')) {
// This user is not a paying customer...
return redirect('billing');
}
return $next($request);
}If you would like to determine if a user is still within their trial period, you may use the onTrial method. This method can be useful for displaying a warning to the user that they are still on their trial period:
if ($user->subscription('main')->onTrial()) {
//
}The subscribedToPlan method may be used to determine if the user is subscribed to a given plan based on a given Stripe plan ID. In this example, we will determine if the user's main subscription is actively subscribed to the monthly plan:
if ($user->subscribedToPlan('monthly', 'main')) {
//
}By passing an array to the subscribedToPlan method, you may determine if the user's main subscription is actively subscribed to the monthly or the yearly plan:
if ($user->subscribedToPlan(['monthly', 'yearly'], 'main')) {
//
}The recurring method may be used to determine if the user is currently subscribed and is no longer within their trial period:
if ($user->subscription('main')->recurring()) {
//
}Cancelled Subscription Status
To determine if the user was once an active subscriber, but has cancelled their subscription, you may use the cancelled method:
if ($user->subscription('main')->cancelled()) {
//
}You may also determine if a user has cancelled their subscription, but are still on their "grace period" until the subscription fully expires. For example, if a user cancels a subscription on March 5th that was originally scheduled to expire on March 10th, the user is on their "grace period" until March 10th. Note that the subscribed method still returns true during this time:
if ($user->subscription('main')->onGracePeriod()) {
//
}To determine if the user has cancelled their subscription and is no longer within their "grace period", you may use the ended method:
if ($user->subscription('main')->ended()) {
//
}Incomplete and Past Due Status
If a subscription requires a secondary payment action after creation the subscription will be marked as incomplete. Subscription statuses are stored in the stripe_status column of Cashier's subscriptions database table.
Similarly, if a secondary payment action is required when swapping plans the subscription will be marked as past_due. When your subscription is in either of these states it will not be active until the customer has confirmed their payment. Checking if a subscription has an incomplete payment can be done using the hasIncompletePayment method on the Billable model or a subscription instance:
if ($user->hasIncompletePayment('main')) {
//
}
if ($user->subscription('main')->hasIncompletePayment()) {
//
}When a subscription has an incomplete payment, you should direct the user to Cashier's payment confirmation page, passing the latestPayment identifier. You may use the latestPayment method available on subscription instance to retrieve this identifier:
<a href="{{ route('cashier.payment', $subscription->latestPayment()->id) }}">
Please confirm your payment.
</a>{note} When a subscription is in an
incompletestate it cannot be changed until the payment is confirmed. Therefore, theswapandupdateQuantitymethods will throw an exception when the subscription is in anincompletestate.
Changing Plans
After a user is subscribed to your application, they may occasionally want to change to a new subscription plan. To swap a user to a new subscription, pass the plan's identifier to the swap method:
$user = App\User::find(1);
$user->subscription('main')->swap('provider-plan-id');If the user is on trial, the trial period will be maintained. Also, if a "quantity" exists for the subscription, that quantity will also be maintained.
If you would like to swap plans and cancel any trial period the user is currently on, you may use the skipTrial method:
$user->subscription('main')
->skipTrial()
->swap('provider-plan-id');If you would like to swap plans and immediately invoice the user instead of waiting for their next billing cycle, you may use the swapAndInvoice method:
$user = App\User::find(1);
$user->subscription('main')->swapAndInvoice('provider-plan-id');Subscription Quantity
Sometimes subscriptions are affected by "quantity". For example, your application might charge $10 per month per user on an account. To easily increment or decrement your subscription quantity, use the incrementQuantity and decrementQuantity methods:
$user = User::find(1);
$user->subscription('main')->incrementQuantity();
// Add five to the subscription's current quantity...
$user->subscription('main')->incrementQuantity(5);
$user->subscription('main')->decrementQuantity();
// Subtract five to the subscription's current quantity...
$user->subscription('main')->decrementQuantity(5);Alternatively, you may set a specific quantity using the updateQuantity method:
$user->subscription('main')->updateQuantity(10);The noProrate method may be used to update the subscription's quantity without pro-rating the charges:
$user->subscription('main')->noProrate()->updateQuantity(10);For more information on subscription quantities, consult the Stripe documentation.
Subscription Taxes
To specify the tax percentage a user pays on a subscription, implement the taxPercentage method on your billable model, and return a numeric value between 0 and 100, with no more than 2 decimal places.
public function taxPercentage()
{
return 20;
}The taxPercentage method enables you to apply a tax rate on a model-by-model basis, which may be helpful for a user base that spans multiple countries and tax rates.
{note} The
taxPercentagemethod only applies to subscription charges. If you use Cashier to make "one off" charges, you will need to manually specify the tax rate at that time.
Syncing Tax Percentages
When changing the hard-coded value returned by the taxPercentage method, the tax settings on any existing subscriptions for the user will remain the same. If you wish to update the tax value for existing subscriptions with the returned taxPercentage value, you should call the syncTaxPercentage method on the user's subscription instance:
$user->subscription('main')->syncTaxPercentage();Subscription Anchor Date
By default, the billing cycle anchor is the date the subscription was created, or if a trial period is used, the date that the trial ends. If you would like to modify the billing anchor date, you may use the anchorBillingCycleOn method:
use App\User;
use Carbon\Carbon;
$user = User::find(1);
$anchor = Carbon::parse('first day of next month');
$user->newSubscription('main', 'premium')
->anchorBillingCycleOn($anchor->startOfDay())
->create($paymentMethod);For more information on managing subscription billing cycles, consult the Stripe billing cycle documentation
Cancelling Subscriptions
To cancel a subscription, call the cancel method on the user's subscription:
$user->subscription('main')->cancel();When a subscription is cancelled, Cashier will automatically set the ends_at column in your database. This column is used to know when the subscribed method should begin returning false. For example, if a customer cancels a subscription on March 1st, but the subscription was not scheduled to end until March 5th, the subscribed method will continue to return true until March 5th.
You may determine if a user has cancelled their subscription but are still on their "grace period" using the onGracePeriod method:
if ($user->subscription('main')->onGracePeriod()) {
//
}If you wish to cancel a subscription immediately, call the cancelNow method on the user's subscription:
$user->subscription('main')->cancelNow();Resuming Subscriptions
If a user has cancelled their subscription and you wish to resume it, use the resume method. The user must still be on their grace period in order to resume a subscription:
$user->subscription('main')->resume();If the user cancels a subscription and then resumes that subscription before the subscription has fully expired, they will not be billed immediately. Instead, their subscription will be re-activated, and they will be billed on the original billing cycle.
Subscription Trials
With Payment Method Up Front
If you would like to offer trial periods to your customers while still collecting payment method information up front, you should use the trialDays method when creating your subscriptions:
$user = User::find(1);
$user->newSubscription('main', 'monthly')
->trialDays(10)
->create($paymentMethod);This method will set the trial period ending date on the subscription record within the database, as well as instruct Stripe to not begin billing the customer until after this date. When using the trialDays method, Cashier will overwrite any default trial period configured for the plan in Stripe.
{note} If the customer's subscription is not cancelled before the trial ending date they will be charged as soon as the trial expires, so you should be sure to notify your users of their trial ending date.
The trialUntil method allows you to provide a DateTime instance to specify when the trial period should end:
use Carbon\Carbon;
$user->newSubscription('main', 'monthly')
->trialUntil(Carbon::now()->addDays(10))
->create($paymentMethod);You may determine if the user is within their trial period using either the onTrial method of the user instance, or the onTrial method of the subscription instance. The two examples below are identical:
if ($user->onTrial('main')) {
//
}
if ($user->subscription('main')->onTrial()) {
//
}Without Payment Method Up Front
If you would like to offer trial periods without collecting the user's payment method information up front, you may set the trial_ends_at column on the user record to your desired trial ending date. This is typically done during user registration:
$user = User::create([
// Populate other user properties...
'trial_ends_at' => now()->addDays(10),
]);{note} Be sure to add a date mutator for
trial_ends_atto your model definition.
Cashier refers to this type of trial as a "generic trial", since it is not attached to any existing subscription. The onTrial method on the User instance will return true if the current date is not past the value of trial_ends_at:
if ($user->onTrial()) {
// User is within their trial period...
}You may also use the onGenericTrial method if you wish to know specifically that the user is within their "generic" trial period and has not created an actual subscription yet:
if ($user->onGenericTrial()) {
// User is within their "generic" trial period...
}Once you are ready to create an actual subscription for the user, you may use the newSubscription method as usual:
$user = User::find(1);
$user->newSubscription('main', 'monthly')->create($paymentMethod);Handling Stripe Webhooks
{tip} You may use Laravel Valet's
valet sharecommand to help test webhooks during local development.
Stripe can notify your application of a variety of events via webhooks. By default, a route that points to Cashier's webhook controller is configured through the Cashier service provider. This controller will handle all incoming webhook requests.
By default, this controller will automatically handle cancelling subscriptions that have too many failed charges (as defined by your Stripe settings), customer updates, customer deletions, subscription updates, and payment method changes; however, as we'll soon discover, you can extend this controller to handle any webhook event you like.
To ensure your application can handle Stripe webhooks, be sure to configure the webhook URL in the Stripe control panel. The full list of all webhooks you should configure in the Stripe control panel are:
customer.subscription.updatedcustomer.subscription.deletedcustomer.updatedcustomer.deletedinvoice.payment_action_required
{note} Make sure you protect incoming requests with Cashier's included webhook signature verification middleware.
Webhooks & CSRF Protection
Since Stripe webhooks need to bypass Laravel's CSRF protection, be sure to list the URI as an exception in your VerifyCsrfToken middleware or list the route outside of the web middleware group:
protected $except = [
'stripe/*',
];Defining Webhook Event Handlers
Cashier automatically handles subscription cancellation on failed charges, but if you have additional webhook events you would like to handle, extend the Webhook controller. Your method names should correspond to Cashier's expected convention, specifically, methods should be prefixed with handle and the "camel case" name of the webhook you wish to handle. For example, if you wish to handle the invoice.payment_succeeded webhook, you should add a handleInvoicePaymentSucceeded method to the controller:
<?php
namespace App\Http\Controllers;
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
class WebhookController extends CashierController
{
/**
* Handle invoice payment succeeded.
*
* @param array $payload
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handleInvoicePaymentSucceeded($payload)
{
// Handle The Event
}
}Next, define a route to your Cashier controller within your routes/web.php file. This will overwrite the default shipped route:
Route::post(
'stripe/webhook',
'\App\Http\Controllers\WebhookController@handleWebhook'
);Failed Subscriptions
What if a customer's credit card expires? No worries - Cashier's Webhook controller will cancel the customer's subscription for you. Failed payments will automatically be captured and handled by the controller. The controller will cancel the customer's subscription when Stripe determines the subscription has failed (normally after three failed payment attempts).
Verifying Webhook Signatures
To secure your webhooks, you may use Stripe's webhook signatures. For convenience, Cashier automatically includes a middleware which validates that the incoming Stripe webhook request is valid.
To enable webhook verification, ensure that the STRIPE_WEBHOOK_SECRET environment variable is set in your .env file. The webhook secret may be retrieved from your Stripe account dashboard.
Single Charges
Simple Charge
{note} The
chargemethod accepts the amount you would like to charge in the lowest denominator of the currency used by your application.
If you would like to make a "one off" charge against a subscribed customer's payment method, you may use the charge method on a billable model instance. You'll need to provide a payment method identifier as the second argument:
// Stripe Accepts Charges In Cents...
$stripeCharge = $user->charge(100, $paymentMethod);The charge method accepts an array as its third argument, allowing you to pass any options you wish to the underlying Stripe charge creation. Consult the Stripe documentation regarding the options available to you when creating charges:
$user->charge(100, $paymentMethod, [
'custom_option' => $value,
]);The charge method will throw an exception if the charge fails. If the charge is successful, an instance of Laravel\Cashier\Payment will be returned from the method:
try {
$payment = $user->charge(100, $paymentMethod);
} catch (Exception $e) {
//
}Charge With Invoice
Sometimes you may need to make a one-time charge but also generate an invoice for the charge so that you may offer a PDF receipt to your customer. The invoiceFor method lets you do just that. For example, let's invoice the customer $5.00 for a "One Time Fee":
// Stripe Accepts Charges In Cents...
$user->invoiceFor('One Time Fee', 500);The invoice will be charged immediately against the user's default payment method. The invoiceFor method also accepts an array as its third argument. This array contains the billing options for the invoice item. The fourth argument accepted by the method is also an array. This final argument accepts the billing options for the invoice itself:
$user->invoiceFor('Stickers', 500, [
'quantity' => 50,
], [
'tax_percent' => 21,
]);{note} The
invoiceFormethod will create a Stripe invoice which will retry failed billing attempts. If you do not want invoices to retry failed charges, you will need to close them using the Stripe API after the first failed charge.
Refunding Charges
If you need to refund a Stripe charge, you may use the refund method. This method accepts the Stripe Payment Intent ID as its first argument:
$payment = $user->charge(100, $paymentMethod);
$user->refund($payment->id);Invoices
You may easily retrieve an array of a billable model's invoices using the invoices method:
$invoices = $user->invoices();
// Include pending invoices in the results...
$invoices = $user->invoicesIncludingPending();When listing the invoices for the customer, you may use the invoice's helper methods to display the relevant invoice information. For example, you may wish to list every invoice in a table, allowing the user to easily download any of them:
| {{ $invoice->date()->toFormattedDateString() }} | {{ $invoice->total() }} | [Download](/user/invoice/{{ $invoice->id }}) |
|---|
Generating Invoice PDFs
From within a route or controller, use the downloadInvoice method to generate a PDF download of the invoice. This method will automatically generate the proper HTTP response to send the download to the browser:
use Illuminate\Http\Request;
Route::get('user/invoice/{invoice}', function (Request $request, $invoiceId) {
return $request->user()->downloadInvoice($invoiceId, [
'vendor' => 'Your Company',
'product' => 'Your Product',
]);
});Strong Customer Authentication
If your business is based in Europe you will need to abide by the Strong Customer Authentication (SCA) regulations. These regulations were imposedย in September 2019 by the European Union to prevent payment fraud. Luckily, Stripe and Cashier are prepared for building SCA compliant applications.
{note} Before getting started, review Stripe's guide on PSD2 and SCA as well as their documentation on the new SCA API's.
Payments Requiring Additional Confirmation
SCA regulations often require extra verification in order to confirm and process a payment. When this happens, Cashier will throw an IncompletePayment exception that informs you that this extra verification is needed. After catching this exception, you have two options on how to proceed.
First, you could redirect your customer to the dedicated payment confirmation page which is included with Cashier. This page already has an associated route that is registered via Cashier's service provider. So, you may catch the IncompletePayment exception and redirect to the payment confirmation page:
use Laravel\Cashier\Exceptions\IncompletePayment;
try {
$subscription = $user->newSubscription('default', $planId)
->create($paymentMethod);
} catch (IncompletePayment $exception) {
return redirect()->route(
'cashier.payment',
[$exception->payment->id, 'redirect' => route('home')]
);
}On the payment confirmation page, the customer will be prompted to enter their credit card info again and perform any additional actions required by Stripe, such as "3D Secure" confirmation. After confirming their payment, the user will be redirected to the URL provided by the redirect parameter specified above.
Alternatively, you could allow Stripe to handle the payment confirmation for you. In this case, instead of redirecting to the payment confirmation page, you may setup Stripe's automatic billing emails in your Stripe dashboard. However, if an IncompletePayment exception is caught, you should still inform the user they will receive an email with further payment confirmation instructions.
Incomplete payment exceptions may be thrown for the following methods: charge, invoiceFor, and invoice on the Billable user. When handling subscriptions, the create method on the SubscriptionBuilder, and the incrementAndInvoice and swapAndInvoice methods on the Subscription model may throw exceptions.
Incomplete and Past Due State
When a payment needs additional confirmation, the subscription will remain in an incomplete or past_due state as indicated by its stripe_status database column. Cashier will make automatically activate the customer's subscription via a webhook as soon as payment confirmation is complete.
For more information on incomplete and past_due states, please refer to our additional documentation.
Off-Session Payment Notifications
Since SCA regulations require customers to occasionally verify their payment details even while their subscription is active, Cashier can send a payment notification to the customer when off-session payment confirmation is required. For example, this may occur when a subscription is renewing. Cashier's payment notification can be enabled by setting the CASHIER_PAYMENT_NOTIFICATION environment variable to a notification class. By default, this notification is disabled. Of course, Cashier includes a notification class you may use for this purpose, but you are free to provide your own notification class if desired:
CASHIER_PAYMENT_NOTIFICATION=Laravel\Cashier\Notifications\ConfirmPaymentTo ensure that off-session payment confirmation notifications are delivered, verify that Stripe webhooks are configured for your application and the invoice.payment_action_required webhook is enabled in your Stripe dashboard. In addition, your Billable model should also use Laravel's Illuminate\Notifications\Notifiable trait.
{note} Notifications will be sent even when customers are manually making a payment that requires additional confirmation. Unfortunately, there is no way for Stripe to know that the payment was done manually or "off-session". But, a customer will simply see a "Payment Successful" message if they visit the payment page after already confirming their payment. The customer will not be allowed to accidentally confirm the same payment twice and incur an accidental second charge.
File: blade.md
Blade Templates
- Introduction
- Template Inheritance
- Components & Slots
- Displaying Data
- Control Structures
- Forms
- Including Sub-Views
- Stacks
- Service Injection
- Extending Blade
Introduction
Blade is the simple, yet powerful templating engine provided with Laravel. Unlike other popular PHP templating engines, Blade does not restrict you from using plain PHP code in your views. In fact, all Blade views are compiled into plain PHP code and cached until they are modified, meaning Blade adds essentially zero overhead to your application. Blade view files use the .blade.php file extension and are typically stored in the resources/views directory.
Template Inheritance
Defining A Layout
Two of the primary benefits of using Blade are template inheritance and sections. To get started, let's take a look at a simple example. First, we will examine a "master" page layout. Since most web applications maintain the same general layout across various pages, it's convenient to define this layout as a single Blade view:
<html>
<head>
<title>App Name - @yield('title')</title>
</head>
@section('sidebar')
This is the master sidebar.
@show
@yield('content')
</html>As you can see, this file contains typical HTML mark-up. However, take note of the @section and @yield directives. The @section directive, as the name implies, defines a section of content, while the @yield directive is used to display the contents of a given section.
Now that we have defined a layout for our application, let's define a child page that inherits the layout.
Extending A Layout
When defining a child view, use the Blade @extends directive to specify which layout the child view should "inherit". Views which extend a Blade layout may inject content into the layout's sections using @section directives. Remember, as seen in the example above, the contents of these sections will be displayed in the layout using @yield:
@extends('layouts.app')
@section('title', 'Page Title')
@section('sidebar')
@@parent
This is appended to the master sidebar.
@endsection
@section('content')
This is my body content.
@endsectionIn this example, the sidebar section is utilizing the @@parent directive to append (rather than overwriting) content to the layout's sidebar. The @@parent directive will be replaced by the content of the layout when the view is rendered.
{tip} Contrary to the previous example, this
sidebarsection ends with@endsectioninstead of@show. The@endsectiondirective will only define a section while@showwill define and immediately yield the section.
The @yield directive also accepts a default value as its second parameter. This value will be rendered if the section being yielded is undefined:
@yield('content', View::make('view.name'))Blade views may be returned from routes using the global view helper:
Route::get('blade', function () {
return view('child');
});Components & Slots
Components and slots provide similar benefits to sections and layouts; however, some may find the mental model of components and slots easier to understand. First, let's imagine a reusable "alert" component we would like to reuse throughout our application:
{{ $slot }}The {{ $slot }} variable will contain the content we wish to inject into the component. Now, to construct this component, we can use the @component Blade directive:
@component('alert')
**Whoops!** Something went wrong!
@endcomponentTo instruct Laravel to load the first view that exists from a given array of possible views for the component, you may use the componentFirst directive:
@componentFirst(['custom.alert', 'alert'])
**Whoops!** Something went wrong!
@endcomponentSometimes it is helpful to define multiple slots for a component. Let's modify our alert component to allow for the injection of a "title". Named slots may be displayed by "echoing" the variable that matches their name:
{{ $title }}
{{ $slot }}Now, we can inject content into the named slot using the @slot directive. Any content not within a @slot directive will be passed to the component in the $slot variable:
@component('alert')
@slot('title')
Forbidden
@endslot
You are not allowed to access this resource!
@endcomponentPassing Additional Data To Components
Sometimes you may need to pass additional data to a component. For this reason, you can pass an array of data as the second argument to the @component directive. All of the data will be made available to the component template as variables:
@component('alert', ['foo' => 'bar'])
...
@endcomponentAliasing Components
If your Blade components are stored in a sub-directory, you may wish to alias them for easier access. For example, imagine a Blade component that is stored at resources/views/components/alert.blade.php. You may use the component method to alias the component from components.alert to alert. Typically, this should be done in the boot method of your AppServiceProvider:
use Illuminate\Support\Facades\Blade;
Blade::component('components.alert', 'alert');Once the component has been aliased, you may render it using a directive:
@alert(['type' => 'danger'])
You are not allowed to access this resource!
@endalertYou may omit the component parameters if it has no additional slots:
@alert
You are not allowed to access this resource!
@endalertDisplaying Data
You may display data passed to your Blade views by wrapping the variable in curly braces. For example, given the following route:
Route::get('greeting', function () {
return view('welcome', ['name' => 'Samantha']);
});You may display the contents of the name variable like so:
Hello, {{ $name }}.{tip} Blade
{{ }}statements are automatically sent through PHP'shtmlspecialcharsfunction to prevent XSS attacks.
You are not limited to displaying the contents of the variables passed to the view. You may also echo the results of any PHP function. In fact, you can put any PHP code you wish inside of a Blade echo statement:
The current UNIX timestamp is {{ time() }}.Displaying Unescaped Data
By default, Blade {{ }} statements are automatically sent through PHP's htmlspecialchars function to prevent XSS attacks. If you do not want your data to be escaped, you may use the following syntax:
Hello, {!! $name !!}.{note} Be very careful when echoing content that is supplied by users of your application. Always use the escaped, double curly brace syntax to prevent XSS attacks when displaying user supplied data.
Rendering JSON
Sometimes you may pass an array to your view with the intention of rendering it as JSON in order to initialize a JavaScript variable. For example:
<script>
var app = <?php echo json_encode($array); ?>;
</script>However, instead of manually calling json_encode, you may use the @json Blade directive. The @json directive accepts the same arguments as PHP's json_encode function:
<script>
var app = @json($array);
var app = @json($array, JSON_PRETTY_PRINT);
</script>{note} You should only use the
@jsondirective to render existing variables as JSON. The Blade templating is based on regular expressions and attempts to pass a complex expression to the directive may cause unexpected failures.
The @json directive is also useful for seeding Vue components or data-* attributes:
<example-component :some-prop='@json($array)'></example-component>{note} Using
@jsonin element attributes requires that it be surrounded by single quotes.
HTML Entity Encoding
By default, Blade (and the Laravel e helper) will double encode HTML entities. If you would like to disable double encoding, call the Blade::withoutDoubleEncoding method from the boot method of your AppServiceProvider:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Blade::withoutDoubleEncoding();
}
}Blade & JavaScript Frameworks
Since many JavaScript frameworks also use "curly" braces to indicate a given expression should be displayed in the browser, you may use the @ symbol to inform the Blade rendering engine an expression should remain untouched. For example:
<h1>Laravel</h1>
Hello, @{{ name }}.In this example, the @ symbol will be removed by Blade; however, {{ name }} expression will remain untouched by the Blade engine, allowing it to instead be rendered by your JavaScript framework.
The `@verbatim` Directive
If you are displaying JavaScript variables in a large portion of your template, you may wrap the HTML in the @verbatim directive so that you do not have to prefix each Blade echo statement with an @ symbol:
@verbatim
Hello, {{ name }}.
@endverbatimControl Structures
In addition to template inheritance and displaying data, Blade also provides convenient shortcuts for common PHP control structures, such as conditional statements and loops. These shortcuts provide a very clean, terse way of working with PHP control structures, while also remaining familiar to their PHP counterparts.
If Statements
You may construct if statements using the @if, @elseif, @else, and @endif directives. These directives function identically to their PHP counterparts:
@if (count($records) === 1)
I have one record!
@elseif (count($records) > 1)
I have multiple records!
@else
I don't have any records!
@endifFor convenience, Blade also provides an @unless directive:
@unless (Auth::check())
You are not signed in.
@endunlessIn addition to the conditional directives already discussed, the @isset and @empty directives may be used as convenient shortcuts for their respective PHP functions:
@isset($records)
// $records is defined and is not null...
@endisset
@empty($records)
// $records is "empty"...
@endemptyAuthentication Directives
The @auth and @guest directives may be used to quickly determine if the current user is authenticated or is a guest:
@auth
// The user is authenticated...
@endauth
@guest
// The user is not authenticated...
@endguestIf needed, you may specify the authentication guard that should be checked when using the @auth and @guest directives:
@auth('admin')
// The user is authenticated...
@endauth
@guest('admin')
// The user is not authenticated...
@endguestSection Directives
You may check if a section has content using the @hasSection directive:
@hasSection('navigation')
@yield('navigation')
@endifSwitch Statements
Switch statements can be constructed using the @switch, @case, @break, @default and @endswitch directives:
@switch($i)
@case(1)
First case...
@break
@case(2)
Second case...
@break
@default
Default case...
@endswitchLoops
In addition to conditional statements, Blade provides simple directives for working with PHP's loop structures. Again, each of these directives functions identically to their PHP counterparts:
@for ($i = 0; $i < 10; $i++)
The current value is {{ $i }}
@endfor
@foreach ($users as $user)
This is user {{ $user->id }}
@endforeach
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty
No users
@endforelse
@while (true)
I'm looping forever.
@endwhile{tip} When looping, you may use the loop variable to gain valuable information about the loop, such as whether you are in the first or last iteration through the loop.
When using loops you may also end the loop or skip the current iteration:
@foreach ($users as $user)
@if ($user->type == 1)
@continue
@endif
<li>{{ $user->name }}</li>
@if ($user->number == 5)
@break
@endif
@endforeachYou may also include the condition with the directive declaration in one line:
@foreach ($users as $user)
@continue($user->type == 1)
<li>{{ $user->name }}</li>
@break($user->number == 5)
@endforeachThe Loop Variable
When looping, a $loop variable will be available inside of your loop. This variable provides access to some useful bits of information such as the current loop index and whether this is the first or last iteration through the loop:
@foreach ($users as $user)
@if ($loop->first)
This is the first iteration.
@endif
@if ($loop->last)
This is the last iteration.
@endif
This is user {{ $user->id }}
@endforeachIf you are in a nested loop, you may access the parent loop's $loop variable via the parent property:
@foreach ($users as $user)
@foreach ($user->posts as $post)
@if ($loop->parent->first)
This is first iteration of the parent loop.
@endif
@endforeach
@endforeachThe $loop variable also contains a variety of other useful properties:
| Property | Description |
|---|---|
$loop->index |
The index of the current loop iteration (starts at 0). |
$loop->iteration |
The current loop iteration (starts at 1). |
$loop->remaining |
The iterations remaining in the loop. |
$loop->count |
The total number of items in the array being iterated. |
$loop->first |
Whether this is the first iteration through the loop. |
$loop->last |
Whether this is the last iteration through the loop. |
$loop->even |
Whether this is an even iteration through the loop. |
$loop->odd |
Whether this is an odd iteration through the loop. |
$loop->depth |
The nesting level of the current loop. |
$loop->parent |
When in a nested loop, the parent's loop variable. |
Comments
Blade also allows you to define comments in your views. However, unlike HTML comments, Blade comments are not included in the HTML returned by your application:
{{-- This comment will not be present in the rendered HTML --}}PHP
In some situations, it's useful to embed PHP code into your views. You can use the Blade @php directive to execute a block of plain PHP within your template:
@php
//
@endphp{tip} While Blade provides this feature, using it frequently may be a signal that you have too much logic embedded within your template.
Forms
CSRF Field
Anytime you define an HTML form in your application, you should include a hidden CSRF token field in the form so that the CSRF protection middleware can validate the request. You may use the @csrf Blade directive to generate the token field:
<form method="POST" action="/profile">
@csrf
...
</form>Method Field
Since HTML forms can't make PUT, PATCH, or DELETE requests, you will need to add a hidden _method field to spoof these HTTP verbs. The @method Blade directive can create this field for you:
<form action="/foo/bar" method="POST">
@method('PUT')
...
</form>Validation Errors
The @error directive may be used to quickly check if validation error messages exist for a given attribute. Within an @error directive, you may echo the $message variable to display the error message:
<label for="title">Post Title</label>
@error('title')
{{ $message }}
@enderrorYou may pass the name of a specific error bag as the second parameter to the @error directive to retrieve validation error messages on pages containing multiple forms:
<label for="email">Email address</label>
@error('email', 'login')
{{ $message }}
@enderrorIncluding Sub-Views
Blade's @include directive allows you to include a Blade view from within another view. All variables that are available to the parent view will be made available to the included view:
@include('shared.errors')
<form>
</form>Even though the included view will inherit all data available in the parent view, you may also pass an array of extra data to the included view:
@include('view.name', ['some' => 'data'])If you attempt to @include a view which does not exist, Laravel will throw an error. If you would like to include a view that may or may not be present, you should use the @includeIf directive:
@includeIf('view.name', ['some' => 'data'])If you would like to @include a view depending on a given boolean condition, you may use the @includeWhen directive:
@includeWhen($boolean, 'view.name', ['some' => 'data'])To include the first view that exists from a given array of views, you may use the includeFirst directive:
@includeFirst(['custom.admin', 'admin'], ['some' => 'data']){note} You should avoid using the
__DIR__and__FILE__constants in your Blade views, since they will refer to the location of the cached, compiled view.
Aliasing Includes
If your Blade includes are stored in a sub-directory, you may wish to alias them for easier access. For example, imagine a Blade include that is stored at resources/views/includes/input.blade.php with the following content:
You may use the include method to alias the include from includes.input to input. Typically, this should be done in the boot method of your AppServiceProvider:
use Illuminate\Support\Facades\Blade;
Blade::include('includes.input', 'input');Once the include has been aliased, you may render it using the alias name as the Blade directive:
@input(['type' => 'email'])Rendering Views For Collections
You may combine loops and includes into one line with Blade's @each directive:
@each('view.name', $jobs, 'job')The first argument is the view partial to render for each element in the array or collection. The second argument is the array or collection you wish to iterate over, while the third argument is the variable name that will be assigned to the current iteration within the view. So, for example, if you are iterating over an array of jobs, typically you will want to access each job as a job variable within your view partial. The key for the current iteration will be available as the key variable within your view partial.
You may also pass a fourth argument to the @each directive. This argument determines the view that will be rendered if the given array is empty.
@each('view.name', $jobs, 'job', 'view.empty'){note} Views rendered via
@eachdo not inherit the variables from the parent view. If the child view requires these variables, you should use@foreachand@includeinstead.
Stacks
Blade allows you to push to named stacks which can be rendered somewhere else in another view or layout. This can be particularly useful for specifying any JavaScript libraries required by your child views:
@push('scripts')
<script src="/example.js"></script>
@endpushYou may push to a stack as many times as needed. To render the complete stack contents, pass the name of the stack to the @stack directive:
<head>
@stack('scripts')
</head>If you would like to prepend content onto the beginning of a stack, you should use the @prepend directive:
@push('scripts')
This will be second...
@endpush
// Later...
@prepend('scripts')
This will be first...
@endprependService Injection
The @inject directive may be used to retrieve a service from the Laravel service container. The first argument passed to @inject is the name of the variable the service will be placed into, while the second argument is the class or interface name of the service you wish to resolve:
@inject('metrics', 'App\Services\MetricsService')
Monthly Revenue: {{ $metrics->monthlyRevenue() }}.Extending Blade
Blade allows you to define your own custom directives using the directive method. When the Blade compiler encounters the custom directive, it will call the provided callback with the expression that the directive contains.
The following example creates a @datetime($var) directive which formats a given $var, which should be an instance of DateTime:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Blade::directive('datetime', function ($expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
}
}As you can see, we will chain the format method onto whatever expression is passed into the directive. So, in this example, the final PHP generated by this directive will be:
<?php echo ($var)->format('m/d/Y H:i'); ?>{note} After updating the logic of a Blade directive, you will need to delete all of the cached Blade views. The cached Blade views may be removed using the
view:clearArtisan command.
Custom If Statements
Programming a custom directive is sometimes more complex than necessary when defining simple, custom conditional statements. For that reason, Blade provides a Blade::if method which allows you to quickly define custom conditional directives using Closures. For example, let's define a custom conditional that checks the current application environment. We may do this in the boot method of our AppServiceProvider:
use Illuminate\Support\Facades\Blade;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Blade::if('env', function ($environment) {
return app()->environment($environment);
});
}Once the custom conditional has been defined, we can easily use it on our templates:
@env('local')
// The application is in the local environment...
@elseenv('testing')
// The application is in the testing environment...
@else
// The application is not in the local or testing environment...
@endenvFile: broadcasting.md
Broadcasting
- Introduction
- Concept Overview
- Defining Broadcast Events
- Authorizing Channels
- Broadcasting Events
- Receiving Broadcasts
- Presence Channels
- Client Events
- Notifications
Introduction
In many modern web applications, WebSockets are used to implement realtime, live-updating user interfaces. When some data is updated on the server, a message is typically sent over a WebSocket connection to be handled by the client. This provides a more robust, efficient alternative to continually polling your application for changes.
To assist you in building these types of applications, Laravel makes it easy to "broadcast" your events over a WebSocket connection. Broadcasting your Laravel events allows you to share the same event names between your server-side code and your client-side JavaScript application.
{tip} Before diving into event broadcasting, make sure you have read all of the documentation regarding Laravel events and listeners.
Configuration
All of your application's event broadcasting configuration is stored in the config/broadcasting.php configuration file. Laravel supports several broadcast drivers out of the box: Pusher Channels, Redis, and a log driver for local development and debugging. Additionally, a null driver is included which allows you to totally disable broadcasting. A configuration example is included for each of these drivers in the config/broadcasting.php configuration file.
Broadcast Service Provider
Before broadcasting any events, you will first need to register the App\Providers\BroadcastServiceProvider. In fresh Laravel applications, you only need to uncomment this provider in the providers array of your config/app.php configuration file. This provider will allow you to register the broadcast authorization routes and callbacks.
CSRF Token
Laravel Echo will need access to the current session's CSRF token. You should verify that your application's head HTML element defines a meta tag containing the CSRF token:
<meta name="csrf-token" content="{{ csrf_token() }}">Driver Prerequisites
Pusher Channels
If you are broadcasting your events over Pusher Channels, you should install the Pusher Channels PHP SDK using the Composer package manager:
composer require pusher/pusher-php-server "~4.0"Next, you should configure your Channels credentials in the config/broadcasting.php configuration file. An example Channels configuration is already included in this file, allowing you to quickly specify your Channels key, secret, and application ID. The config/broadcasting.php file's pusher configuration also allows you to specify additional options that are supported by Channels, such as the cluster:
'options' => [
'cluster' => 'eu',
'useTLS' => true
],When using Channels and Laravel Echo, you should specify pusher as your desired broadcaster when instantiating the Echo instance in your resources/js/bootstrap.js file:
import Echo from "laravel-echo";
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-channels-key'
});Redis
If you are using the Redis broadcaster, you should install the Predis library:
composer require predis/predisThe Redis broadcaster will broadcast messages using Redis' pub / sub feature; however, you will need to pair this with a WebSocket server that can receive the messages from Redis and broadcast them to your WebSocket channels.
When the Redis broadcaster publishes an event, it will be published on the event's specified channel names and the payload will be a JSON encoded string containing the event name, a data payload, and the user that generated the event's socket ID (if applicable).
Socket.IO
If you are going to pair the Redis broadcaster with a Socket.IO server, you will need to include the Socket.IO JavaScript client library in your application. You may install it via the NPM package manager:
npm install --save socket.io-clientNext, you will need to instantiate Echo with the socket.io connector and a host.
import Echo from "laravel-echo"
window.io = require('socket.io-client');
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});Finally, you will need to run a compatible Socket.IO server. Laravel does not include a Socket.IO server implementation; however, a community driven Socket.IO server is currently maintained at the tlaverdure/laravel-echo-server GitHub repository.
Queue Prerequisites
Before broadcasting events, you will also need to configure and run a queue listener. All event broadcasting is done via queued jobs so that the response time of your application is not seriously affected.
Concept Overview
Laravel's event broadcasting allows you to broadcast your server-side Laravel events to your client-side JavaScript application using a driver-based approach to WebSockets. Currently, Laravel ships with Pusher Channels and Redis drivers. The events may be easily consumed on the client-side using the Laravel Echo Javascript package.
Events are broadcast over "channels", which may be specified as public or private. Any visitor to your application may subscribe to a public channel without any authentication or authorization; however, in order to subscribe to a private channel, a user must be authenticated and authorized to listen on that channel.
Using An Example Application
Before diving into each component of event broadcasting, let's take a high level overview using an e-commerce store as an example. We won't discuss the details of configuring Pusher Channels or Laravel Echo since that will be discussed in detail in other sections of this documentation.
In our application, let's assume we have a page that allows users to view the shipping status for their orders. Let's also assume that a ShippingStatusUpdated event is fired when a shipping status update is processed by the application:
event(new ShippingStatusUpdated($update));The `ShouldBroadcast` Interface
When a user is viewing one of their orders, we don't want them to have to refresh the page to view status updates. Instead, we want to broadcast the updates to the application as they are created. So, we need to mark the ShippingStatusUpdated event with the ShouldBroadcast interface. This will instruct Laravel to broadcast the event when it is fired:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class ShippingStatusUpdated implements ShouldBroadcast
{
/**
* Information about the shipping status update.
*
* @var string
*/
public $update;
}The ShouldBroadcast interface requires our event to define a broadcastOn method. This method is responsible for returning the channels that the event should broadcast on. An empty stub of this method is already defined on generated event classes, so we only need to fill in its details. We only want the creator of the order to be able to view status updates, so we will broadcast the event on a private channel that is tied to the order:
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\PrivateChannel
*/
public function broadcastOn()
{
return new PrivateChannel('order.'.$this->update->order_id);
}Authorizing Channels
Remember, users must be authorized to listen on private channels. We may define our channel authorization rules in the routes/channels.php file. In this example, we need to verify that any user attempting to listen on the private order.1 channel is actually the creator of the order:
Broadcast::channel('order.{orderId}', function ($user, $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});The channel method accepts two arguments: the name of the channel and a callback which returns true or false indicating whether the user is authorized to listen on the channel.
All authorization callbacks receive the currently authenticated user as their first argument and any additional wildcard parameters as their subsequent arguments. In this example, we are using the {orderId} placeholder to indicate that the "ID" portion of the channel name is a wildcard.
Listening For Event Broadcasts
Next, all that remains is to listen for the event in our JavaScript application. We can do this using Laravel Echo. First, we'll use the private method to subscribe to the private channel. Then, we may use the listen method to listen for the ShippingStatusUpdated event. By default, all of the event's public properties will be included on the broadcast event:
Echo.private(`order.${orderId}`)
.listen('ShippingStatusUpdated', (e) => {
console.log(e.update);
});Defining Broadcast Events
To inform Laravel that a given event should be broadcast, implement the Illuminate\Contracts\Broadcasting\ShouldBroadcast interface on the event class. This interface is already imported into all event classes generated by the framework so you may easily add it to any of your events.
The ShouldBroadcast interface requires you to implement a single method: broadcastOn. The broadcastOn method should return a channel or array of channels that the event should broadcast on. The channels should be instances of Channel, PrivateChannel, or PresenceChannel. Instances of Channel represent public channels that any user may subscribe to, while PrivateChannels and PresenceChannels represent private channels that require channel authorization:
<?php
namespace App\Events;
use App\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class ServerCreated implements ShouldBroadcast
{
use SerializesModels;
public $user;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('user.'.$this->user->id);
}
}Then, you only need to fire the event as you normally would. Once the event has been fired, a queued job will automatically broadcast the event over your specified broadcast driver.
Broadcast Name
By default, Laravel will broadcast the event using the event's class name. However, you may customize the broadcast name by defining a broadcastAs method on the event:
/**
* The event's broadcast name.
*
* @return string
*/
public function broadcastAs()
{
return 'server.created';
}If you customize the broadcast name using the broadcastAs method, you should make sure to register your listener with a leading . character. This will instruct Echo to not prepend the application's namespace to the event:
.listen('.server.created', function (e) {
....
});Broadcast Data
When an event is broadcast, all of its public properties are automatically serialized and broadcast as the event's payload, allowing you to access any of its public data from your JavaScript application. So, for example, if your event has a single public $user property that contains an Eloquent model, the event's broadcast payload would be:
{
"user": {
"id": 1,
"name": "Patrick Stewart"
...
}
}However, if you wish to have more fine-grained control over your broadcast payload, you may add a broadcastWith method to your event. This method should return the array of data that you wish to broadcast as the event payload:
/**
* Get the data to broadcast.
*
* @return array
*/
public function broadcastWith()
{
return ['id' => $this->user->id];
}Broadcast Queue
By default, each broadcast event is placed on the default queue for the default queue connection specified in your queue.php configuration file. You may customize the queue used by the broadcaster by defining a broadcastQueue property on your event class. This property should specify the name of the queue you wish to use when broadcasting:
/**
* The name of the queue on which to place the event.
*
* @var string
*/
public $broadcastQueue = 'your-queue-name';If you want to broadcast your event using the sync queue instead of the default queue driver, you can implement the ShouldBroadcastNow interface instead of ShouldBroadcast:
<?php
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class ShippingStatusUpdated implements ShouldBroadcastNow
{
//
}Broadcast Conditions
Sometimes you want to broadcast your event only if a given condition is true. You may define these conditions by adding a broadcastWhen method to your event class:
/**
* Determine if this event should broadcast.
*
* @return bool
*/
public function broadcastWhen()
{
return $this->value > 100;
}Authorizing Channels
Private channels require you to authorize that the currently authenticated user can actually listen on the channel. This is accomplished by making an HTTP request to your Laravel application with the channel name and allowing your application to determine if the user can listen on that channel. When using Laravel Echo, the HTTP request to authorize subscriptions to private channels will be made automatically; however, you do need to define the proper routes to respond to these requests.
Defining Authorization Routes
Thankfully, Laravel makes it easy to define the routes to respond to channel authorization requests. In the BroadcastServiceProvider included with your Laravel application, you will see a call to the Broadcast::routes method. This method will register the /broadcasting/auth route to handle authorization requests:
Broadcast::routes();The Broadcast::routes method will automatically place its routes within the web middleware group; however, you may pass an array of route attributes to the method if you would like to customize the assigned attributes:
Broadcast::routes($attributes);Customizing The Authorization Endpoint
By default, Echo will use the /broadcasting/auth endpoint to authorize channel access. However, you may specify your own authorization endpoint by passing the authEndpoint configuration option to your Echo instance:
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-channels-key',
authEndpoint: '/custom/endpoint/auth'
});Defining Authorization Callbacks
Next, we need to define the logic that will actually perform the channel authorization. This is done in the routes/channels.php file that is included with your application. In this file, you may use the Broadcast::channel method to register channel authorization callbacks:
Broadcast::channel('order.{orderId}', function ($user, $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});The channel method accepts two arguments: the name of the channel and a callback which returns true or false indicating whether the user is authorized to listen on the channel.
All authorization callbacks receive the currently authenticated user as their first argument and any additional wildcard parameters as their subsequent arguments. In this example, we are using the {orderId} placeholder to indicate that the "ID" portion of the channel name is a wildcard.
Authorization Callback Model Binding
Just like HTTP routes, channel routes may also take advantage of implicit and explicit route model binding. For example, instead of receiving the string or numeric order ID, you may request an actual Order model instance:
use App\Order;
Broadcast::channel('order.{order}', function ($user, Order $order) {
return $user->id === $order->user_id;
});Authorization Callback Authentication
Private and presence broadcast channels authenticate the current user via your application's default authentication guard. If the user is not authenticated, channel authorization is automatically denied and the authorization callback is never executed. However, you may assign multiple, custom guards that should authenticate the incoming request if necessary:
Broadcast::channel('channel', function() {
// ...
}, ['guards' => ['web', 'admin']]);Defining Channel Classes
If your application is consuming many different channels, your routes/channels.php file could become bulky. So, instead of using Closures to authorize channels, you may use channel classes. To generate a channel class, use the make:channel Artisan command. This command will place a new channel class in the App/Broadcasting directory.
php artisan make:channel OrderChannelNext, register your channel in your routes/channels.php file:
use App\Broadcasting\OrderChannel;
Broadcast::channel('order.{order}', OrderChannel::class);Finally, you may place the authorization logic for your channel in the channel class' join method. This join method will house the same logic you would have typically placed in your channel authorization Closure. You may also take advantage of channel model binding:
<?php
namespace App\Broadcasting;
use App\Order;
use App\User;
class OrderChannel
{
/**
* Create a new channel instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Authenticate the user's access to the channel.
*
* @param \App\User $user
* @param \App\Order $order
* @return array|bool
*/
public function join(User $user, Order $order)
{
return $user->id === $order->user_id;
}
}{tip} Like many other classes in Laravel, channel classes will automatically be resolved by the service container. So, you may type-hint any dependencies required by your channel in its constructor.
Broadcasting Events
Once you have defined an event and marked it with the ShouldBroadcast interface, you only need to fire the event using the event function. The event dispatcher will notice that the event is marked with the ShouldBroadcast interface and will queue the event for broadcasting:
event(new ShippingStatusUpdated($update));Only To Others
When building an application that utilizes event broadcasting, you may substitute the event function with the broadcast function. Like the event function, the broadcast function dispatches the event to your server-side listeners:
broadcast(new ShippingStatusUpdated($update));However, the broadcast function also exposes the toOthers method which allows you to exclude the current user from the broadcast's recipients:
broadcast(new ShippingStatusUpdated($update))->toOthers();To better understand when you may want to use the toOthers method, let's imagine a task list application where a user may create a new task by entering a task name. To create a task, your application might make a request to a /task end-point which broadcasts the task's creation and returns a JSON representation of the new task. When your JavaScript application receives the response from the end-point, it might directly insert the new task into its task list like so:
axios.post('/task', task)
.then((response) => {
this.tasks.push(response.data);
});However, remember that we also broadcast the task's creation. If your JavaScript application is listening for this event in order to add tasks to the task list, you will have duplicate tasks in your list: one from the end-point and one from the broadcast. You may solve this by using the toOthers method to instruct the broadcaster to not broadcast the event to the current user.
{note} Your event must use the
Illuminate\Broadcasting\InteractsWithSocketstrait in order to call thetoOthersmethod.
Configuration
When you initialize a Laravel Echo instance, a socket ID is assigned to the connection. If you are using Vue and Axios, the socket ID will automatically be attached to every outgoing request as a X-Socket-ID header. Then, when you call the toOthers method, Laravel will extract the socket ID from the header and instruct the broadcaster to not broadcast to any connections with that socket ID.
If you are not using Vue and Axios, you will need to manually configure your JavaScript application to send the X-Socket-ID header. You may retrieve the socket ID using the Echo.socketId method:
var socketId = Echo.socketId();Receiving Broadcasts
Installing Laravel Echo
Laravel Echo is a JavaScript library that makes it painless to subscribe to channels and listen for events broadcast by Laravel. You may install Echo via the NPM package manager. In this example, we will also install the pusher-js package since we will be using the Pusher Channels broadcaster:
npm install --save laravel-echo pusher-jsOnce Echo is installed, you are ready to create a fresh Echo instance in your application's JavaScript. A great place to do this is at the bottom of the resources/js/bootstrap.js file that is included with the Laravel framework:
import Echo from "laravel-echo"
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-channels-key'
});When creating an Echo instance that uses the pusher connector, you may also specify a cluster as well as whether the connection must be made over TLS (by default, when forceTLS is false, a non-TLS connection will be made if the page was loaded over HTTP, or as a fallback if a TLS connection fails):
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-channels-key',
cluster: 'eu',
forceTLS: true
});Using An Existing Client Instance
If you already have a Pusher Channels or Socket.io client instance that you would like Echo to utilize, you may pass it to Echo via the client configuration option:
const client = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-channels-key',
client: client
});Listening For Events
Once you have installed and instantiated Echo, you are ready to start listening for event broadcasts. First, use the channel method to retrieve an instance of a channel, then call the listen method to listen for a specified event:
Echo.channel('orders')
.listen('OrderShipped', (e) => {
console.log(e.order.name);
});If you would like to listen for events on a private channel, use the private method instead. You may continue to chain calls to the listen method to listen for multiple events on a single channel:
Echo.private('orders')
.listen(...)
.listen(...)
.listen(...);Leaving A Channel
To leave a channel, you may call the leaveChannel method on your Echo instance:
Echo.leaveChannel('orders');If you would like to leave a channel and also its associated private and presence channels, you may call the leave method:
Echo.leave('orders');Namespaces
You may have noticed in the examples above that we did not specify the full namespace for the event classes. This is because Echo will automatically assume the events are located in the App\Events namespace. However, you may configure the root namespace when you instantiate Echo by passing a namespace configuration option:
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-channels-key',
namespace: 'App.Other.Namespace'
});Alternatively, you may prefix event classes with a . when subscribing to them using Echo. This will allow you to always specify the fully-qualified class name:
Echo.channel('orders')
.listen('.Namespace\\Event\\Class', (e) => {
//
});Presence Channels
Presence channels build on the security of private channels while exposing the additional feature of awareness of who is subscribed to the channel. This makes it easy to build powerful, collaborative application features such as notifying users when another user is viewing the same page.
Authorizing Presence Channels
All presence channels are also private channels; therefore, users must be authorized to access them. However, when defining authorization callbacks for presence channels, you will not return true if the user is authorized to join the channel. Instead, you should return an array of data about the user.
The data returned by the authorization callback will be made available to the presence channel event listeners in your JavaScript application. If the user is not authorized to join the presence channel, you should return false or null:
Broadcast::channel('chat.{roomId}', function ($user, $roomId) {
if ($user->canJoinRoom($roomId)) {
return ['id' => $user->id, 'name' => $user->name];
}
});Joining Presence Channels
To join a presence channel, you may use Echo's join method. The join method will return a PresenceChannel implementation which, along with exposing the listen method, allows you to subscribe to the here, joining, and leaving events.
Echo.join(`chat.${roomId}`)
.here((users) => {
//
})
.joining((user) => {
console.log(user.name);
})
.leaving((user) => {
console.log(user.name);
});The here callback will be executed immediately once the channel is joined successfully, and will receive an array containing the user information for all of the other users currently subscribed to the channel. The joining method will be executed when a new user joins a channel, while the leaving method will be executed when a user leaves the channel.
Broadcasting To Presence Channels
Presence channels may receive events just like public or private channels. Using the example of a chatroom, we may want to broadcast NewMessage events to the room's presence channel. To do so, we'll return an instance of PresenceChannel from the event's broadcastOn method:
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel('room.'.$this->message->room_id);
}Like public or private events, presence channel events may be broadcast using the broadcast function. As with other events, you may use the toOthers method to exclude the current user from receiving the broadcast:
broadcast(new NewMessage($message));
broadcast(new NewMessage($message))->toOthers();You may listen for the join event via Echo's listen method:
Echo.join(`chat.${roomId}`)
.here(...)
.joining(...)
.leaving(...)
.listen('NewMessage', (e) => {
//
});Client Events
{tip} When using Pusher Channels, you must enable the "Client Events" option in the "App Settings" section of your application dashboard in order to send client events.
Sometimes you may wish to broadcast an event to other connected clients without hitting your Laravel application at all. This can be particularly useful for things like "typing" notifications, where you want to alert users of your application that another user is typing a message on a given screen.
To broadcast client events, you may use Echo's whisper method:
Echo.private('chat')
.whisper('typing', {
name: this.user.name
});To listen for client events, you may use the listenForWhisper method:
Echo.private('chat')
.listenForWhisper('typing', (e) => {
console.log(e.name);
});Notifications
By pairing event broadcasting with notifications, your JavaScript application may receive new notifications as they occur without needing to refresh the page. First, be sure to read over the documentation on using the broadcast notification channel.
Once you have configured a notification to use the broadcast channel, you may listen for the broadcast events using Echo's notification method. Remember, the channel name should match the class name of the entity receiving the notifications:
Echo.private(`App.User.${userId}`)
.notification((notification) => {
console.log(notification.type);
});In this example, all notifications sent to App\User instances via the broadcast channel would be received by the callback. A channel authorization callback for the App.User.{id} channel is included in the default BroadcastServiceProvider that ships with the Laravel framework.
File: cache.md
Cache
Configuration
Laravel provides an expressive, unified API for various caching backends. The cache configuration is located at config/cache.php. In this file you may specify which cache driver you would like to be used by default throughout your application. Laravel supports popular caching backends like Memcached and Redis out of the box.
The cache configuration file also contains various other options, which are documented within the file, so make sure to read over these options. By default, Laravel is configured to use the file cache driver, which stores the serialized, cached objects in the filesystem. For larger applications, it is recommended that you use a more robust driver such as Memcached or Redis. You may even configure multiple cache configurations for the same driver.
Driver Prerequisites
Database
When using the database cache driver, you will need to setup a table to contain the cache items. You'll find an example Schema declaration for the table below:
Schema::create('cache', function ($table) {
$table->string('key')->unique();
$table->text('value');
$table->integer('expiration');
});{tip} You may also use the
php artisan cache:tableArtisan command to generate a migration with the proper schema.
Memcached
Using the Memcached driver requires the Memcached PECL package to be installed. You may list all of your Memcached servers in the config/cache.php configuration file:
'memcached' => [
[
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 100
],
],You may also set the host option to a UNIX socket path. If you do this, the port option should be set to 0:
'memcached' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],Redis
Before using a Redis cache with Laravel, you will need to either install the PhpRedis PHP extension via PECL or install the predis/predis package (~1.0) via Composer.
For more information on configuring Redis, consult its Laravel documentation page.
Cache Usage
Obtaining A Cache Instance
The Illuminate\Contracts\Cache\Factory and Illuminate\Contracts\Cache\Repository contracts provide access to Laravel's cache services. The Factory contract provides access to all cache drivers defined for your application. The Repository contract is typically an implementation of the default cache driver for your application as specified by your cache configuration file.
However, you may also use the Cache facade, which is what we will use throughout this documentation. The Cache facade provides convenient, terse access to the underlying implementations of the Laravel cache contracts:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**
* Show a list of all users of the application.
*
* @return Response
*/
public function index()
{
$value = Cache::get('key');
//
}
}Accessing Multiple Cache Stores
Using the Cache facade, you may access various cache stores via the store method. The key passed to the store method should correspond to one of the stores listed in the stores configuration array in your cache configuration file:
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 600); // 10 MinutesRetrieving Items From The Cache
The get method on the Cache facade is used to retrieve items from the cache. If the item does not exist in the cache, null will be returned. If you wish, you may pass a second argument to the get method specifying the default value you wish to be returned if the item doesn't exist:
$value = Cache::get('key');
$value = Cache::get('key', 'default');You may even pass a Closure as the default value. The result of the Closure will be returned if the specified item does not exist in the cache. Passing a Closure allows you to defer the retrieval of default values from a database or other external service:
$value = Cache::get('key', function () {
return DB::table(...)->get();
});Checking For Item Existence
The has method may be used to determine if an item exists in the cache. This method will return false if the value is null:
if (Cache::has('key')) {
//
}Incrementing / Decrementing Values
The increment and decrement methods may be used to adjust the value of integer items in the cache. Both of these methods accept an optional second argument indicating the amount by which to increment or decrement the item's value:
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);Retrieve & Store
Sometimes you may wish to retrieve an item from the cache, but also store a default value if the requested item doesn't exist. For example, you may wish to retrieve all users from the cache or, if they don't exist, retrieve them from the database and add them to the cache. You may do this using the Cache::remember method:
$value = Cache::remember('users', $seconds, function () {
return DB::table('users')->get();
});If the item does not exist in the cache, the Closure passed to the remember method will be executed and its result will be placed in the cache.
You may use the rememberForever method to retrieve an item from the cache or store it forever:
$value = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});Retrieve & Delete
If you need to retrieve an item from the cache and then delete the item, you may use the pull method. Like the get method, null will be returned if the item does not exist in the cache:
$value = Cache::pull('key');Storing Items In The Cache
You may use the put method on the Cache facade to store items in the cache:
Cache::put('key', 'value', $seconds);If the storage time is not passed to the put method, the item will be stored indefinitely:
Cache::put('key', 'value');Instead of passing the number of seconds as an integer, you may also pass a DateTime instance representing the expiration time of the cached item:
Cache::put('key', 'value', now()->addMinutes(10));Store If Not Present
The add method will only add the item to the cache if it does not already exist in the cache store. The method will return true if the item is actually added to the cache. Otherwise, the method will return false:
Cache::add('key', 'value', $seconds);Storing Items Forever
The forever method may be used to store an item in the cache permanently. Since these items will not expire, they must be manually removed from the cache using the forget method:
Cache::forever('key', 'value');{tip} If you are using the Memcached driver, items that are stored "forever" may be removed when the cache reaches its size limit.
Removing Items From The Cache
You may remove items from the cache using the forget method:
Cache::forget('key');You may also remove items by providing a zero or negative TTL:
Cache::put('key', 'value', 0);
Cache::put('key', 'value', -5);You may clear the entire cache using the flush method:
Cache::flush();{note} Flushing the cache does not respect the cache prefix and will remove all entries from the cache. Consider this carefully when clearing a cache which is shared by other applications.
Atomic Locks
{note} To utilize this feature, your application must be using the
memcached,dynamodb, orrediscache driver as your application's default cache driver. In addition, all servers must be communicating with the same central cache server.
Atomic locks allow for the manipulation of distributed locks without worrying about race conditions. For example, Laravel Forge uses atomic locks to ensure that only one remote task is being executed on a server at a time. You may create and manage locks using the Cache::lock method:
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('foo', 10);
if ($lock->get()) {
// Lock acquired for 10 seconds...
$lock->release();
}The get method also accepts a Closure. After the Closure is executed, Laravel will automatically release the lock:
Cache::lock('foo')->get(function () {
// Lock acquired indefinitely and automatically released...
});If the lock is not available at the moment you request it, you may instruct Laravel to wait for a specified number of seconds. If the lock can not be acquired within the specified time limit, an Illuminate\Contracts\Cache\LockTimeoutException will be thrown:
use Illuminate\Contracts\Cache\LockTimeoutException;
$lock = Cache::lock('foo', 10);
try {
$lock->block(5);
// Lock acquired after waiting maximum of 5 seconds...
} catch (LockTimeoutException $e) {
// Unable to acquire lock...
} finally {
optional($lock)->release();
}
Cache::lock('foo', 10)->block(5, function () {
// Lock acquired after waiting maximum of 5 seconds...
});Managing Locks Across Processes
Sometimes, you may wish to acquire a lock in one process and release it in another process. For example, you may acquire a lock during a web request and wish to release the lock at the end of a queued job that is triggered by that request. In this scenario, you should pass the lock's scoped "owner token" to the queued job so that the job can re-instantiate the lock using the given token:
// Within Controller...
$podcast = Podcast::find($id);
$lock = Cache::lock('foo', 120);
if ($result = $lock->get()) {
ProcessPodcast::dispatch($podcast, $lock->owner());
}
// Within ProcessPodcast Job...
Cache::restoreLock('foo', $this->owner)->release();If you would like to release a lock without respecting its current owner, you may use the forceRelease method:
Cache::lock('foo')->forceRelease();The Cache Helper
In addition to using the Cache facade or cache contract, you may also use the global cache function to retrieve and store data via the cache. When the cache function is called with a single, string argument, it will return the value of the given key:
$value = cache('key');If you provide an array of key / value pairs and an expiration time to the function, it will store values in the cache for the specified duration:
cache(['key' => 'value'], $seconds);
cache(['key' => 'value'], now()->addMinutes(10));When the cache function is called without any arguments, it returns an instance of the Illuminate\Contracts\Cache\Factory implementation, allowing you to call other caching methods:
cache()->remember('users', $seconds, function () {
return DB::table('users')->get();
});{tip} When testing call to the global
cachefunction, you may use theCache::shouldReceivemethod just as if you were testing a facade.
Cache Tags
{note} Cache tags are not supported when using the
fileordatabasecache drivers. Furthermore, when using multiple tags with caches that are stored "forever", performance will be best with a driver such asmemcached, which automatically purges stale records.
Storing Tagged Cache Items
Cache tags allow you to tag related items in the cache and then flush all cached values that have been assigned a given tag. You may access a tagged cache by passing in an ordered array of tag names. For example, let's access a tagged cache and put value in the cache:
Cache::tags(['people', 'artists'])->put('John', $john, $seconds);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $seconds);Accessing Tagged Cache Items
To retrieve a tagged cache item, pass the same ordered list of tags to the tags method and then call the get method with the key you wish to retrieve:
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');Removing Tagged Cache Items
You may flush all items that are assigned a tag or list of tags. For example, this statement would remove all caches tagged with either people, authors, or both. So, both Anne and John would be removed from the cache:
Cache::tags(['people', 'authors'])->flush();In contrast, this statement would remove only caches tagged with authors, so Anne would be removed, but not John:
Cache::tags('authors')->flush();Adding Custom Cache Drivers
Writing The Driver
To create our custom cache driver, we first need to implement the Illuminate\Contracts\Cache\Store contract. So, a MongoDB cache implementation would look something like this:
<?php
namespace App\Extensions;
use Illuminate\Contracts\Cache\Store;
class MongoStore implements Store
{
public function get($key) {}
public function many(array $keys) {}
public function put($key, $value, $seconds) {}
public function putMany(array $values, $seconds) {}
public function increment($key, $value = 1) {}
public function decrement($key, $value = 1) {}
public function forever($key, $value) {}
public function forget($key) {}
public function flush() {}
public function getPrefix() {}
}We just need to implement each of these methods using a MongoDB connection. For an example of how to implement each of these methods, take a look at the Illuminate\Cache\MemcachedStore in the framework source code. Once our implementation is complete, we can finish our custom driver registration.
Cache::extend('mongo', function ($app) {
return Cache::repository(new MongoStore);
});{tip} If you're wondering where to put your custom cache driver code, you could create an
Extensionsnamespace within yourappdirectory. However, keep in mind that Laravel does not have a rigid application structure and you are free to organize your application according to your preferences.
Registering The Driver
To register the custom cache driver with Laravel, we will use the extend method on the Cache facade. The call to Cache::extend could be done in the boot method of the default App\Providers\AppServiceProvider that ships with fresh Laravel applications, or you may create your own service provider to house the extension - just don't forget to register the provider in the config/app.php provider array:
<?php
namespace App\Providers;
use App\Extensions\MongoStore;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;
class CacheServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Cache::extend('mongo', function ($app) {
return Cache::repository(new MongoStore);
});
}
}The first argument passed to the extend method is the name of the driver. This will correspond to your driver option in the config/cache.php configuration file. The second argument is a Closure that should return an Illuminate\Cache\Repository instance. The Closure will be passed an $app instance, which is an instance of the service container.
Once your extension is registered, update your config/cache.php configuration file's driver option to the name of your extension.
Events
To execute code on every cache operation, you may listen for the events fired by the cache. Typically, you should place these event listeners within your EventServiceProvider:
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Illuminate\Cache\Events\CacheHit' => [
'App\Listeners\LogCacheHit',
],
'Illuminate\Cache\Events\CacheMissed' => [
'App\Listeners\LogCacheMissed',
],
'Illuminate\Cache\Events\KeyForgotten' => [
'App\Listeners\LogKeyForgotten',
],
'Illuminate\Cache\Events\KeyWritten' => [
'App\Listeners\LogKeyWritten',
],
];