Laravel Scout

Introduction
Laravel Scout provides a simple, driver based solution for adding full-text search to your Eloquent models. Using model observers, Scout will automatically keep your search indexes in sync with your Eloquent records.

Currently, Scout ships with an Algolia driver; however, writing custom drivers is simple and you are free to extend Scout with your own search implementations.

Installation
First, install Scout via the Composer package manager:

composer require laravel/scout
After installing Scout, you should publish the Scout configuration using the vendor:publish Artisan command. This command will publish the scout.php configuration file to your config directory:

php artisan vendor:publish –provider=”Laravel\Scout\ScoutServiceProvider”

Finally, add the Laravel\Scout\Searchable trait to the model you would like to make searchable. This trait will register a model observer to keep the model in sync with your search driver:

namespace App;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
use Searchable;
}

Queueing
While not strictly required to use Scout, you should strongly consider configuring a queue driver before using the library. Running a queue worker will allow Scout to queue all operations that sync your model information to your search indexes, providing much better response times for your application’s web interface.

Once you have configured a queue driver, set the value of the queue option in your config/scout.php configuration file to true:

Driver Prerequisites
Algolia
When using the Algolia driver, you should configure your Algolia id and secret credentials in your config/scout.php configuration file. Once your credentials have been configured, you will also need to install the Algolia PHP SDK via the Composer package manager:

composer require algolia/algoliasearch-client-php

Configuring Model Indexes
Each Eloquent model is synced with a given search “index”, which contains all of the searchable records for that model. In other words, you can think of each index like a MySQL table. By default, each model will be persisted to an index matching the model’s typical “table” name. Typically, this is the plural form of the model name; however, you are free to customize the model’s index by overriding the searchableAs method on the model:

namespace App;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use Searchable;

    /**
     * Get the index name for the model.
     *
     * @return string
     */
    public function searchableAs()
    {
        return 'posts_index';
    }
}

Indexing
Batch Import
If you are installing Scout into an existing project, you may already have database records you need to import into your search driver. Scout provides an import Artisan command that you may use to import all of your existing records into your search indexes:

php artisan scout:import “App\Post”
The flush command may be used to remove all of a model’s records from your search indexes:

php artisan scout:flush “App\Post”
Adding Records
Once you have added the Laravel\Scout\Searchable trait to a model, all you need to do is save a model instance and it will automatically be added to your search index. If you have configured Scout to use queues this operation will be performed in the background by your queue worker:

$order = new App\Order;

// …

$order->save();
Adding Via Query
If you would like to add a collection of models to your search index via an Eloquent query, you may chain the searchable method onto an Eloquent query. The searchable method will chunk the results of the query and add the records to your search index. Again, if you have configured Scout to use queues, all of the chunks will be added in the background by your queue workers:

// Adding via Eloquent query…
App\Order::where(‘price’, ‘>’, 100)->searchable();

// You may also add records via relationships…
$user->orders()->searchable();

// You may also add records via collections…
$orders->searchable();
The searchable method can be considered an “upsert” operation. In other words, if the model record is already in your index, it will be updated. If it does not exist in the search index, it will be added to the index.

Updating Records
To update a searchable model, you only need to update the model instance’s properties and save the model to your database. Scout will automatically persist the changes to your search index:

$order = App\Order::find(1);

// Update the order…

$order->save();
You may also use the searchable method on an Eloquent query to update a collection of models. If the models do not exist in your search index, they will be created:

// Updating via Eloquent query…
App\Order::where(‘price’, ‘>’, 100)->searchable();

// You may also update via relationships…
$user->orders()->searchable();

// You may also update via collections…
$orders->searchable();
Removing Records
To remove a record from your index, delete the model from the database. This form of removal is even compatible with soft deleted models:

$order = App\Order::find(1);

$order->delete();
If you do not want to retrieve the model before deleting the record, you may use the unsearchable method on an Eloquent query instance or collection:

// Removing via Eloquent query…
App\Order::where(‘price’, ‘>’, 100)->unsearchable();

// You may also remove via relationships…
$user->orders()->unsearchable();

// You may also remove via collections…
$orders->unsearchable();
Pausing Indexing
Sometimes you may need to perform a batch of Eloquent operations on a model without syncing the model data to your search index. You may do this using the withoutSyncingToSearch method. This method accepts a single callback which will be immediately executed. Any model operations that occur within the callback will not be synced to the model’s index:

App\Order::withoutSyncingToSearch(function () {
// Perform model actions…
});
Conditionally Searchable Model Instances
Sometimes you may need to only make a model searchable under certain conditions. For example, imagine you have App\Post model that may be in one of two states: “draft” and “published”. You may only want to allow “published” posts to be searchable. To accomplish this, you may define a shouldBeSearchable method on your model:

public function shouldBeSearchable()
{
return $this->isPublished();
}
Searching
You may begin searching a model using the search method. The search method accepts a single string that will be used to search your models. You should then chain the get method onto the search query to retrieve the Eloquent models that match the given search query:

$orders = App\Order::search(‘Star Trek’)->get();
Since Scout searches return a collection of Eloquent models, you may even return the results directly from a route or controller and they will automatically be converted to JSON:

use Illuminate\Http\Request;

Route::get(‘/search’, function (Request $request) {
return App\Order::search($request->search)->get();
});
If you would like to get the raw results before they are converted to Eloquent models, you should use the raw method:

$orders = App\Order::search(‘Star Trek’)->raw();
Search queries will typically be performed on the index specified by the model’s searchableAs method. However, you may use the within method to specify a custom index that should be searched instead:

$orders = App\Order::search(‘Star Trek’)
->within(‘tv_shows_popularity_desc’)
->get();
Where Clauses
Scout allows you to add simple “where” clauses to your search queries. Currently, these clauses only support basic numeric equality checks, and are primarily useful for scoping search queries by a tenant ID. Since a search index is not a relational database, more advanced “where” clauses are not currently supported:

$orders = App\Order::search(‘Star Trek’)->where(‘user_id’, 1)->get();
Pagination
In addition to retrieving a collection of models, you may paginate your search results using the paginate method. This method will return a Paginator instance just as if you had paginated a traditional Eloquent query:

$orders = App\Order::search(‘Star Trek’)->paginate();
You may specify how many models to retrieve per page by passing the amount as the first argument to the paginate method:

$orders = App\Order::search(‘Star Trek’)->paginate(15);
Once you have retrieved the results, you may display the results and render the page links using Blade just as if you had paginated a traditional Eloquent query:

@foreach ($orders as $order)
{{ $order->price }}
@endforeach

{{ $orders->links() }}
Soft Deleting
If your indexed models are soft deleting and you need to search your soft deleted models, set the soft_delete option of the config/scout.php configuration file to true:

‘soft_delete’ => true,
When this configuration option is true, Scout will not remove soft deleted models from the search index. Instead, it will set a hidden __soft_deleted attribute on the indexed record. Then, you may use the withTrashed or onlyTrashed methods to retrieve the soft deleted records when searching:

// Include trashed records when retrieving results…
$orders = App\Order::withTrashed()->search(‘Star Trek’)->get();

// Only include trashed records when retrieving results…
$orders = App\Order::onlyTrashed()->search(‘Star Trek’)->get();
Tip!! When a soft deleted model is permanently deleted using forceDelete, Scout will remove it from the search index automatically.

Customizing Engine Searches
If you need to customize the search behavior of an engine you may pass a callback as the second argument to the search method. For example, you could use this callback to add geo-location data to your search options before the search query is passed to Algolia:

use AlgoliaSearch\Index;

App\Order::search(‘Star Trek’, function (Index $algolia, string $query, array $options) {
$options[‘body’][‘query’][‘bool’][‘filter’][‘geo_distance’] = [
‘distance’ => ‘1000km’,
‘location’ => [‘lat’ => 36, ‘lon’ => 111],
];

return $algolia->search($query, $options);
})->get();
Custom Engines
Writing The Engine
If one of the built-in Scout search engines doesn’t fit your needs, you may write your own custom engine and register it with Scout. Your engine should extend the Laravel\Scout\Engines\Engine abstract class. This abstract class contains seven methods your custom engine must implement:

use Laravel\Scout\Builder;

abstract public function update($models);
abstract public function delete($models);
abstract public function search(Builder $builder);
abstract public function paginate(Builder $builder, $perPage, $page);
abstract public function mapIds($results);
abstract public function map($results, $model);
abstract public function getTotalCount($results);
You may find it helpful to review the implementations of these methods on the Laravel\Scout\Engines\AlgoliaEngine class. This class will provide you with a good starting point for learning how to implement each of these methods in your own engine.

Registering The Engine
Once you have written your custom engine, you may register it with Scout using the extend method of the Scout engine manager. You should call the extend method from the boot method of your AppServiceProvider or any other service provider used by your application. For example, if you have written a MySqlSearchEngine, you may register it like so:

use Laravel\Scout\EngineManager;

/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
resolve(EngineManager::class)->extend(‘mysql’, function () {
return new MySqlSearchEngine;
});
}
Once your engine has been registered, you may specify it as your default Scout driver in your config/scout.php configuration file:

‘driver’ => ‘mysql’,
Builder Macros
If you would like to define a custom builder method, you may use the macro method on the Laravel\Scout\Builder class. Typically, “macros” should be defined within a service provider’s boot method:

engine->getTotalCount(
$this->engine()->search($this)
);
});
}
}
The macro function accepts a name as its first argument, and a Closure as its second. The macro’s Closure will be executed when calling the macro name from a Laravel\Scout\Builder implementation:

App\Order::search(‘Star Trek’)->count();

API Authentication (Passport)

Introduction
Laravel already makes it easy to perform authentication via traditional login forms, but what about APIs? APIs typically use tokens to authenticate users and do not maintain session state between requests. Laravel makes API authentication a breeze using Laravel Passport, which provides a full OAuth2 server implementation for your Laravel application in a matter of minutes. Passport is built on top of the League OAuth2 server that is maintained by Andy Millington and Simon Hamp.

Installation
To get started, install Passport via the Composer package manager:

The Passport service provider registers its own database migration directory with the framework, so you should migrate your database after installing the package. The Passport migrations will create the tables your application needs to store clients and access tokens:

php artisan migrate

Next, you should run the passport:install command. This command will create the encryption keys needed to generate secure access tokens. In addition, the command will create “personal access” and “password grant” clients which will be used to generate access tokens:

php artisan passport:install
After running this command, add the Laravel\Passport\HasApiTokens trait to your App\User model. This trait will provide a few helper methods to your model which allow you to inspect the authenticated user’s token and scopes:

namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}

Next, you should call the Passport::routes method within the boot method of your AuthServiceProvider. This method will register the routes necessary to issue access tokens and revoke access tokens, clients, and personal access tokens:

namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();
    }
}
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

Passport ships with a JSON API that you may use to allow your users to create clients and personal access tokens. However, it can be time consuming to code a frontend to interact with these APIs. So, Passport also includes pre-built Vue components you may use as an example implementation or starting point for your own implementation.

To publish the Passport Vue components, use the vendor:publish Artisan command:

php artisan vendor:publish –tag=passport-components

The published components will be placed in your resources/js/components directory. Once the components have been published, you should register them in your resources/js/app.js file:

Vue.component(
    'passport-clients',
    require('./components/passport/Clients.vue')
);

Vue.component(
    'passport-authorized-clients',
    require('./components/passport/AuthorizedClients.vue')
);

Vue.component(
    'passport-personal-access-tokens',
    require('./components/passport/PersonalAccessTokens.vue')
);
After registering the com

After registering the components, make sure to run npm run dev to recompile your assets. Once you have recompiled your assets, you may drop the components into one of your application’s templates to get started creating clients and personal access tokens:

Configuration
Token Lifetimes
By default, Passport issues long-lived access tokens that expire after one year. If you would like to configure a longer / shorter token lifetime, you may use the tokensExpireIn and refreshTokensExpireIn methods. These methods should be called from the boot method of your AuthServiceProvider:
public function boot()
{
$this->registerPolicies();

Passport::routes();

Passport::tokensExpireIn(now()->addDays(15));

Passport::refreshTokensExpireIn(now()->addDays(30));
}

Overriding Default Models
You are free to extend the models used internally by Passport. Then, you may instruct Passport to use your custom models via the Passport class:

use App\Models\Passport\Client;
use App\Models\Passport\AuthCode;
use App\Models\Passport\TokenModel;
use App\Models\Passport\PersonalAccessClient;

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();

Passport::routes();

Passport::useClientModel(Client::class);
Passport::useTokenModel(TokenModel::class);
Passport::useAuthCodeModel(AuthCode::class);
Passport::usePersonalAccessClientModel(PersonalAccessClient::class);
}

Issuing Access Tokens
Using OAuth2 with authorization codes is how most developers are familiar with OAuth2. When using authorization codes, a client application will redirect a user to your server where they will either approve or deny the request to issue an access token to the client.

Managing Clients
First, developers building applications that need to interact with your application’s API will need to register their application with yours by creating a “client”. Typically, this consists of providing the name of their application and a URL that your application can redirect to after users approve their request for authorization.

The passport:client Command
The simplest way to create a client is using the passport:client Artisan command. This command may be used to create your own clients for testing your OAuth2 functionality. When you run the client command, Passport will prompt you for more information about your client and will provide you with a client ID and secret:

php artisan passport:client
Redirect URLs

If you would like to whitelist multiple redirect URLs for your client, you may specify them using a comma-delimited list when prompted for the URL by the passport:client command:

JSON API
Since your users will not be able to utilize the client command, Passport provides a JSON API that you may use to create clients. This saves you the trouble of having to manually code controllers for creating, updating, and deleting clients.

However, you will need to pair Passport’s JSON API with your own frontend to provide a dashboard for your users to manage their clients. Below, we’ll review all of the API endpoints for managing clients. For convenience, we’ll use Axios to demonstrate making HTTP requests to the endpoints.

The JSON API is guarded by the web and auth middlewares; therefore, it may only be called from your own application. It is not able to be called from an external source.

Laravel Horizon

Introduction
Horizon provides a beautiful dashboard and code-driven configuration for your Laravel powered Redis queues. Horizon allows you to easily monitor key metrics of your queue system such as job throughput, runtime, and job failures.

All of your worker configuration is stored in a single, simple configuration file, allowing your configuration to stay in source control where your entire team can collaborate.

Installation
Note: Due to its usage of async process signals, Horizon requires PHP 7.1+. Secondly, you should ensure that your queue driver is set to redis in your queue configuration file.

You may use Composer to install Horizon into your Laravel project:
composer require laravel/horizon

After installing Horizon, publish its assets using the vendor:publish Artisan command:
php artisan vendor:publish –provider=”Laravel\Horizon\HorizonServiceProvider”

Configuration
After publishing Horizon’s assets, its primary configuration file will be located at config/horizon.php. This configuration file allows you to configure your worker options and each configuration option includes a description of its purpose, so be sure to thoroughly explore this file.

Balance Options
Horizon allows you to choose from three balancing strategies: simple, auto, and false. The simple strategy, which is the default, splits incoming jobs evenly between processes:

‘balance’ => ‘simple’,

The auto strategy adjusts the number of worker processes per queue based on the current workload of the queue. For example, if your notifications queue has 1,000 waiting jobs while your render queue is empty, Horizon will allocate more workers to your notifications queue until it is empty. When the balance option is set to false, the default Laravel behavior will be used, which processes queues in the order they are listed in your configuration.

Job Trimming
The horizon configuration file allows you to configure how long recent and failed jobs should be persisted (in minutes). By default, recent jobs are kept for one hour while failed jobs are kept for a week:

‘trim’ => [
‘recent’ => 60,
‘failed’ => 10080,
],

Dashboard Authentication
Horizon exposes a dashboard at /horizon. By default, you will only be able to access this dashboard in the local environment. To define a more specific access policy for the dashboard, you should use the Horizon::auth method. The auth method accepts a callback which should return true or false, indicating whether the user should have access to the Horizon dashboard. Typically, you should call Horizon::auth in the boot method of your AppServiceProvider:

Horizon::auth(function ($request) {
    // return true / false;
});

Running Horizon
Once you have configured your workers in the config/horizon.php configuration file, you may start Horizon using the horizon Artisan command. This single command will start all of your configured workers:

php artisan horizon

You may pause the Horizon process and instruct it to continue processing jobs using the horizon:pause and horizon:continue Artisan commands:

php artisan horizon:pause

php artisan horizon:continue
You may gracefully terminate the master Horizon process on your machine using the horizon:terminate Artisan command. Any jobs that Horizon is currently processing will be completed and then Horizon will exit:

php artisan horizon:terminate

Tags
Horizon allows you to assign “tags” to jobs, including mailables, event broadcasts, notifications, and queued event listeners. In fact, Horizon will intelligently and automatically tag most jobs depending on the Eloquent models that are attached to the job. For example, take a look at the following job:

video = $video;
}

/**
* Execute the job.
*
* @return void
*/
public function handle()
{
//
}
}
If this job is queued with an App\Video instance that has an id of 1, it will automatically receive the tag App\Video:1. This is because Horizon will examine the job’s properties for any Eloquent models. If Eloquent models are found, Horizon will intelligently tag the job using the model’s class name and primary key:

$video = App\Video::find(1);

App\Jobs\RenderVideo::dispatch($video);
Manually Tagging
If you would like to manually define the tags for one of your queueable objects, you may define a tags method on the class:

class RenderVideo implements ShouldQueue
{
/**
* Get the tags that should be assigned to the job.
*
* @return array
*/
public function tags()
{
return [‘render’, ‘video:’.$this->video->id];
}
}
Notifications
Note: Before using notifications, you should add the guzzlehttp/guzzle Composer package to your project. When configuring Horizon to send SMS notifications, you should also review the prerequisites for the Nexmo notification driver.

If you would like to be notified when one of your queues has a long wait time, you may use the Horizon::routeMailNotificationsTo, Horizon::routeSlackNotificationsTo, and Horizon::routeSmsNotificationsTo methods. You may call these methods from your application’s AppServiceProvider:

Horizon::routeMailNotificationsTo(‘example@example.com’);
Horizon::routeSlackNotificationsTo(‘slack-webhook-url’, ‘#channel’);
Horizon::routeSmsNotificationsTo(‘15556667777’);
Configuring Notification Wait Time Thresholds
You may configure how many seconds are considered a “long wait” within your config/horizon.php configuration file. The waits configuration option within this file allows you to control the long wait threshold for each connection / queue combination:

‘waits’ => [
‘redis:default’ => 60,
],
Metrics
Horizon includes a metrics dashboard which provides information on your job and queue wait times and throughput. In order to populate this dashboard, you should configure Horizon’s snapshot Artisan command to run every five minutes via your application’s scheduler:

/**
* Define the application’s command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command(‘horizon:snapshot’)->everyFiveMinutes();
}

Envoy Task Runner

Introduction
Laravel Envoy provides a clean, minimal syntax for defining common tasks you run on your remote servers. Using Blade style syntax, you can easily setup tasks for deployment, Artisan commands, and more. Currently, Envoy only supports the Mac and Linux operating systems.

Installation
First, install Envoy using the Composer global require command:
composer global require laravel/envoy

Since global Composer libraries can sometimes cause package version conflicts, you may wish to consider using cgr, which is a drop-in replacement for the composer global require command. The cgr library’s installation instructions can be found on GitHub.

Updating Envoy
You may also use Composer to keep your Envoy installation up to date. Issuing the composer global update command will update all of your globally installed Composer packages:
composer global update

Writing Tasks
All of your Envoy tasks should be defined in an Envoy.blade.php file in the root of your project. Here’s an example to get you started:

@servers([‘web’ => [‘user@192.168.1.1’]])

@task(‘foo’, [‘on’ => ‘web’])
ls -la
@endtask
As you can see, an array of @servers is defined at the top of the file, allowing you to reference these servers in the on option of your task declarations. Within your @task declarations, you should place the Bash code that should run on your server when the task is executed.

You can force a script to run locally by specifying the server’s IP address as 127.0.0.1:

@servers([‘localhost’ => ‘127.0.0.1’])
Setup
Sometimes, you may need to execute some PHP code before executing your Envoy tasks. You may use the @setup directive to declare variables and do other general PHP work before any of your other tasks are executed:

Variables
If needed, you may pass option values into Envoy tasks using the command line:

envoy run deploy –branch=master
You may access the options in your tasks via Blade’s “echo” syntax. Of course, you may also use if statements and loops within your tasks. For example, let’s verify the presence of the $branch variable before executing the git pull command:

@servers([‘web’ => ‘192.168.1.1’])

@task(‘deploy’, [‘on’ => ‘web’])
cd site

@if ($branch)
git pull origin {{ $branch }}
@endif

php artisan migrate
@endtask

Notifications
Slack
Envoy also supports sending notifications to Slack after each task is executed. The @slack directive accepts a Slack hook URL and a channel name. You may retrieve your webhook URL by creating an “Incoming WebHooks” integration in your Slack control panel. You should pass the entire webhook URL into the @slack directive:

@finished
@slack(‘webhook-url’, ‘#bots’)
@endfinished
You may provide one of the following as the channel argument:

To send the notification to a channel: #channel
To send the notification to a user: @user

Browser Tests

Introduction
Laravel Dusk provides an expressive, easy-to-use browser automation and testing API. By default, Dusk does not require you to install JDK or Selenium on your machine. Instead, Dusk uses a standalone ChromeDriver installation. However, you are free to utilize any other Selenium compatible driver you wish.

composer require –dev laravel/dusk

php artisan dusk:install

A Browser directory will be created within your tests directory and will contain an example test. Next, set the APP_URL environment variable in your .env file. This value should match the URL you use to access your application in a browser.

To run your tests, use the dusk Artisan command. The dusk command accepts any argument that is also accepted by the phpunit command:

php artisan dusk

php artisan dusk:fails

Using Other Browsers
By default, Dusk uses Google Chrome and a standalone ChromeDriver installation to run your browser tests. However, you may start your own Selenium server and run your tests against any browser you wish.

To get started, open your tests/DuskTestCase.php file, which is the base Dusk test case for your application. Within this file, you can remove the call to the startChromeDriver method. This will stop Dusk from automatically starting the ChromeDriver:

public static function prepare()
{
    // static::startChromeDriver();
}

protected function driver()
{
    return RemoteWebDriver::create(
        'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
    );
}

Getting Started
Generating Tests
To generate a Dusk test, use the dusk:make Artisan command. The generated test will be placed in the tests/Browser directory:

php artisan dusk:make LoginTest

Environment Handling
To force Dusk to use its own environment file when running tests, create a .env.dusk.{environment} file in the root of your project. For example, if you will be initiating the dusk command from your local environment, you should create a .env.dusk.local file.

When running tests, Dusk will back-up your .env file and rename your Dusk environment to .env. Once the tests have completed, your .env file will be restored.

Creating Browsers
To get started, let’s write a test that verifies we can log into our application. After generating a test, we can modify it to navigate to the login page, enter some credentials, and click the “Login” button. To create a browser instance, call the browse method:

namespace Tests\Browser;

use App\User;
use Tests\DuskTestCase;
use Laravel\Dusk\Chrome;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class ExampleTest extends DuskTestCase
{
    use DatabaseMigrations;

    /**
     * A basic browser test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        $user = factory(User::class)->create([
            'email' => 'taylor@laravel.com',
        ]);

        $this->browse(function ($browser) use ($user) {
            $browser->visit('/login')
                    ->type('email', $user->email)
                    ->type('password', 'secret')
                    ->press('Login')
                    ->assertPathIs('/home');
        });
    }
}
$this->browse(function ($first, $second) {
    $first->loginAs(User::find(1))
          ->visit('/home')
          ->waitForText('Message');

    $second->loginAs(User::find(2))
           ->visit('/home')
           ->waitForText('Message')
           ->type('message', 'Hey Taylor')
           ->press('Send');

    $first->waitForText('Hey Taylor')
          ->assertSee('Jeffrey Way');
});
$this->browse(function ($first, $second) {
    $first->loginAs(User::find(1))
          ->visit('/home');
});

Database Migrations
When your test requires migrations, like the authentication example above, you should never use the RefreshDatabase trait. The RefreshDatabase trait leverages database transactions which will not be applicable across HTTP requests. Instead, use the DatabaseMigrations trait:

namespace Tests\Browser;

use App\User;
use Tests\DuskTestCase;
use Laravel\Dusk\Chrome;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class ExampleTest extends DuskTestCase
{
    use DatabaseMigrations;
}

vailable Assertions
Dusk provides a variety of assertions that you may make against your application. All of the available assertions are documented in the list below:

assertTitleassertTitleContainsassertUrlIsassertSchemeIsassertSchemeIsNotassertHostIsassertHostIsNotassertPortIsassertPortIsNotassertPathBeginsWithassertPathIsassertPathIsNotassertRouteIsassertQueryStringHasassertQueryStringMissingassertFragmentIsassertFragmentBeginsWithassertFragmentIsNotassertHasCookieassertCookieMissingassertCookieValueassertPlainCookieValueassertSeeassertDontSeeassertSeeInassertDontSeeInassertSourceHasassertSourceMissingassertSeeLinkassertDontSeeLinkassertInputValueassertInputValueIsNotassertCheckedassertNotCheckedassertRadioSelectedassertRadioNotSelectedassertSelectedassertNotSelectedassertSelectHasOptionsassertSelectMissingOptionsassertSelectHasOptionassertValueassertVisibleassertPresentassertMissingassertDialogOpenedassertEnabledassertDisabledassertFocusedassertNotFocusedassertVueassertVueIsNotassertVueContainsassertVueDoesNotContain

Laravel Cashier

Introduction
Laravel Cashier provides an expressive, fluent interface to Stripe’s and Braintree’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.

Note: If you’re only performing “one-off” charges and do not offer subscriptions, you should not use Cashier. Instead, use the Stripe and Braintree SDKs directly.

Stripe
Composer
First, add the Cashier package for Stripe to your dependencies:
composer require laravel/cashier

Database Migrations
Before using Cashier, we’ll also need to prepare the database. We need to add several columns to your users table and create a new subscriptions table to hold all of our customer’s subscriptions:

Schema::table('users', function ($table) {
    $table->string('stripe_id')->nullable()->collation('utf8mb4_bin');
    $table->string('card_brand')->nullable();
    $table->string('card_last_four', 4)->nullable();
    $table->timestamp('trial_ends_at')->nullable();
});

Schema::create('subscriptions', function ($table) {
    $table->increments('id');
    $table->unsignedInteger('user_id');
    $table->string('name');
    $table->string('stripe_id')->collation('utf8mb4_bin');
    $table->string('stripe_plan');
    $table->integer('quantity');
    $table->timestamp('trial_ends_at')->nullable();
    $table->timestamp('ends_at')->nullable();
    $table->timestamps();
});

Billable Model
Next, 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 credit card information:

use Laravel\Cashier\Billable;
class User extends Authenticatable
{
    use Billable;
}
'stripe' => [
    'model'  => App\User::class,
    'key' => env('STRIPE_KEY'),
    'secret' => env('STRIPE_SECRET'),
],

Plan Credit Coupon
Before using Cashier with Braintree, you will need to define a plan-credit discount in your Braintree control panel. This discount will be used to properly prorate subscriptions that change from yearly to monthly billing, or from monthly to yearly billing.

The discount amount configured in the Braintree control panel can be any value you wish, as Cashier will override the defined amount with our own custom amount each time we apply the coupon. This coupon is needed since Braintree does not natively support prorating subscriptions across subscription frequencies.

Database Migrations
Before using Cashier, we’ll need to prepare the database. We need to add several columns to your users table and create a new subscriptions table to hold all of our customer’s subscriptions:

Schema::table(‘users’, function ($table) {
$table->string(‘braintree_id’)->nullable();
$table->string(‘paypal_email’)->nullable();
$table->string(‘card_brand’)->nullable();
$table->string(‘card_last_four’)->nullable();
$table->timestamp(‘trial_ends_at’)->nullable();
});

Schema::create(‘subscriptions’, function ($table) {
$table->increments(‘id’);
$table->unsignedInteger(‘user_id’);
$table->string(‘name’);
$table->string(‘braintree_id’);
$table->string(‘braintree_plan’);
$table->integer(‘quantity’);
$table->timestamp(‘trial_ends_at’)->nullable();
$table->timestamp(‘ends_at’)->nullable();
$table->timestamps();
});

Billable Model
Next, add the Billable trait to your model definition:

use Laravel\Cashier\Billable;

class User extends Authenticatable
{
use Billable;
}

braintree’ => [
‘model’ => App\User::class,
‘environment’ => env(‘BRAINTREE_ENV’),
‘merchant_id’ => env(‘BRAINTREE_MERCHANT_ID’),
‘public_key’ => env(‘BRAINTREE_PUBLIC_KEY’),
‘private_key’ => env(‘BRAINTREE_PRIVATE_KEY’),
],

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($stripeToken);

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’)) {
//
}

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:

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:

Handling Stripe Webhooks
Both Stripe and Braintree can notify your application of a variety of events via webhooks. To handle Stripe webhooks, define a route that points to Cashier’s webhook controller. This controller will handle all incoming webhook requests and dispatch them to the proper controller method:

Route::post(
    'stripe/webhook',
    '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);

Laravel Mocking

Introduction
When testing Laravel applications, you may wish to “mock” certain aspects of your application so they are not actually executed during a given test. For example, when testing a controller that dispatches an event, you may wish to mock the event listeners so they are not actually executed during the test. This allows you to only test the controller’s HTTP response without worrying about the execution of the event listeners, since the event listeners can be tested in their own test case.

Laravel provides helpers for mocking events, jobs, and facades out of the box. These helpers primarily provide a convenience layer over Mockery so you do not have to manually make complicated Mockery method calls. Of course, you are free to use Mockery or PHPUnit to create your own mocks or spies.

Bus Fake
As an alternative to mocking, you may use the Bus facade’s fake method to prevent jobs from being dispatched. When using fakes, assertions are made after the code under test is executed:

namespace Tests\Feature;
use Tests\TestCase;
use App\Jobs\ShipOrder;
use Illuminate\Support\Facades\Bus;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
    public function testOrderShipping()
    {
        Bus::fake();
        // Perform order shipping...
        Bus::assertDispatched(ShipOrder::class, function ($job) use ($order) {
            return $job->order->id === $order->id;
        });
        // Assert a job was not dispatched...
        Bus::assertNotDispatched(AnotherJob::class);
    }
}

Event Fake
As an alternative to mocking, you may use the Event facade’s fake method to prevent all event listeners from executing. You may then assert that events were dispatched and even inspect the data they received. When using fakes, assertions are made after the code under test is executed:

namespace Tests\Feature;
use Tests\TestCase;
use App\Events\OrderShipped;
use App\Events\OrderFailedToShip;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
    /**
     * Test order shipping.
     */
    public function testOrderShipping()
    {
        Event::fake();
        // Perform order shipping...
        Event::assertDispatched(OrderShipped::class, function ($e) use ($order) {
            return $e->order->id === $order->id;
        });
        // Assert an event was dispatched twice...
        Event::assertDispatched(OrderShipped::class, 2);
        // Assert an event was not dispatched...
        Event::assertNotDispatched(OrderFailedToShip::class);
    }
}

After calling Event::fake(), no event listeners will be executed. So, if your tests use model factories that rely on events, such as creating a UUID during a model’s creating event, you should call Event::fake() after using your factories.

public function testOrderProcess()
{
    Event::fake([
        OrderCreated::class,
    ]);

    $order = factory(Order::class)->create();

    Event::assertDispatched(OrderCreated::class);

    // Other events are dispatched as normal...
    $order->update([...]);
}
namespace Tests\Feature;

use App\Order;
use Tests\TestCase;
use App\Events\OrderCreated;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
    /**
     * Test order process.
     */
    public function testOrderProcess()
    {
        $order = Event::fakeFor(function () {
            $order = factory(Order::class)->create();

            Event::assertDispatched(OrderCreated::class);

            return $order;
        });

        // Events are dispatched as normal and observers will run ...
        $order->update([...]);
    }
}

Resetting The Database After Each Test

It is often useful to reset your database after each test so that data from a previous test does not interfere with subsequent tests. The RefreshDatabase trait takes the most optimal approach to migrating your test database depending on if you are using an in-memory database or a traditional database. Use the trait on your test class and everything will be handled for you:

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class ExampleTest extends TestCase
{
    use RefreshDatabase;

    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->get('/');

        // ...
    }
}

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

use Faker\Generator as Faker;
$factory->define(App\User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'email_verified_at' => now(),
        'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
        'remember_token' => str_random(10),
    ];
});

Within the Closure, which serves as the factory definition, you may return the default test values of all attributes on the model. The Closure will receive an instance of the Faker PHP library, which allows you to conveniently generate various kinds of random data for testing.
You may also create additional factory files for each model for better organization. For example, you could create UserFactory.php and CommentFactory.php files within your database/factories directory. All of the files within the factories directory will automatically be loaded by Laravel.

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

public function testDatabase()
{
    $user = factory(App\User::class)->make();

    // Use model in tests...
}
// Create three App\User instances...
$users = factory(App\User::class, 3)->make();
$users = factory(App\User::class, 5)->states('delinquent')->make();
$users = factory(App\User::class, 5)->states('premium', 'delinquent')->make();
$user = factory(App\User::class)->make([
    'name' => 'Abigail',
]);

Database Testing

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

public function testDatabase()
{
    // Make call to application...

    $this->assertDatabaseHas('users', [
        'email' => 'sally@example.com'
    ]);
}

You can also use the assertDatabaseMissing helper to assert that data does not exist in the database.

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

Generating Factories
To create a factory, use the make:factory Artisan command:
php artisan make:factory PostFactory
The new factory will be placed in your database/factories directory.
The –model option may be used to indicate the name of the model created by the factory. This option will pre-fill the generated factory file with the given model:
php artisan make:factory PostFactory –model=Post

Resetting The Database After Each Test
It is often useful to reset your database after each test so that data from a previous test does not interfere with subsequent tests. The RefreshDatabase trait takes the most optimal approach to migrating your test database depending on if you are using an in-memory database or a traditional database. Use the trait on your test class and everything will be handled for you:

Browser Tests (Laravel Dusk)

Introduction
Laravel Dusk provides an expressive, easy-to-use browser automation and testing API. By default, Dusk does not require you to install JDK or Selenium on your machine. Instead, Dusk uses a standalone ChromeDriver installation. However, you are free to utilize any other Selenium compatible driver you wish.

Seleniumはwebのuiテスト自動化。
Installation
To get started, you should add the laravel/dusk Composer dependency to your project:
composer require –dev laravel/dusk

If you are manually registering Dusk’s service provider, you should never register it in your production environment, as doing so could lead to arbitrary users being able to authenticate with your application.

After installing the Dusk package, run the dusk:install Artisan command:
php artisan dusk:install

A Browser directory will be created within your tests directory and will contain an example test. Next, set the APP_URL environment variable in your .env file. This value should match the URL you use to access your application in a browser.

To run your tests, use the dusk Artisan command. The dusk command accepts any argument that is also accepted by the phpunit command:

php artisan dusk
If you had test failures the last time you ran the dusk command, you may save time by re-running the failing tests first using the dusk:fails command:
php artisan dusk:fails

Using Other Browsers
By default, Dusk uses Google Chrome and a standalone ChromeDriver installation to run your browser tests. However, you may start your own Selenium server and run your tests against any browser you wish.

To get started, open your tests/DuskTestCase.php file, which is the base Dusk test case for your application. Within this file, you can remove the call to the startChromeDriver method. This will stop Dusk from automatically starting the ChromeDriver:

public static function prepare()
{
    // static::startChromeDriver();
}

Next, you may modify the driver method to connect to the URL and port of your choice. In addition, you may modify the “desired capabilities” that should be passed to the WebDriver:

protected function driver()
{
    return RemoteWebDriver::create(
        'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
    );
}

php artisan dusk
If you had test failures the last time you ran the dusk command, you may save time by re-running the failing tests first using the dusk:fails command:

php artisan dusk:fails
The dusk command accepts any argument that is normally accepted by the PHPUnit test runner, allowing you to only run the tests for a given group, etc:

php artisan dusk –group=foo

protected function driver()
{
    return RemoteWebDriver::create(
        'http://localhost:9515', DesiredCapabilities::chrome()
    );
}

Environment Handling
To force Dusk to use its own environment file when running tests, create a .env.dusk.{environment} file in the root of your project. For example, if you will be initiating the dusk command from your local environment, you should create a .env.dusk.local file.

When running tests, Dusk will back-up your .env file and rename your Dusk environment to .env. Once the tests have completed, your .env file will be restored.

$this->browse(function ($first, $second) {
    $first->loginAs(User::find(1))
          ->visit('/home')
          ->waitForText('Message');

    $second->loginAs(User::find(2))
           ->visit('/home')
           ->waitForText('Message')
           ->type('message', 'Hey Taylor')
           ->press('Send');

    $first->waitForText('Hey Taylor')
          ->assertSee('Jeffrey Way');
});

Resizing Browser Windows
You may use the resize method to adjust the size of the browser window:

$browser->resize(1920, 1080);
The maximize method may be used to maximize the browser window:

$browser->maximize();

Authentication
Often, you will be testing pages that require authentication. You can use Dusk’s loginAs method in order to avoid interacting with the login screen during every test. The loginAs method accepts a user ID or user model instance:

$this->browse(function ($first, $second) {
    $first->loginAs(User::find(1))
          ->visit('/home');
});

Database Migrations
When your test requires migrations, like the authentication example above, you should never use the RefreshDatabase trait. The RefreshDatabase trait leverages database transactions which will not be applicable across HTTP requests. Instead, use the DatabaseMigrations trait:

namespace Tests\Browser;

use App\User;
use Tests\DuskTestCase;
use Laravel\Dusk\Chrome;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
}

Text, Values, & Attributes
Retrieving & Setting Values
Dusk provides several methods for interacting with the current display text, value, and attributes of elements on the page. For example, to get the “value” of an element that matches a given selector, use the value method:

Retrieving Text
The text method may be used to retrieve the display text of an element that matches the given selector:
$text = $browser->text(‘selector’);

Retrieving Attributes
Finally, the attribute method may be used to retrieve an attribute of an element matching the given selector:
$attribute = $browser->attribute(‘selector’, ‘value’);

Using Forms
Typing Values
Dusk provides a variety of methods for interacting with forms and input elements. First, let’s take a look at an example of typing text into an input field:

$browser->type(’email’, ‘taylor@laravel.com’);
Note that, although the method accepts one if necessary, we are not required to pass a CSS selector into the type method. If a CSS selector is not provided, Dusk will search for an input field with the given name attribute. Finally, Dusk will attempt to find a textarea with the given name attribute.

To append text to a field without clearing its content, you may use the append method:
$browser->type(‘tags’, ‘foo’)
->append(‘tags’, ‘, bar, baz’);
You may clear the value of an input using the clear method:
$browser->clear(’email’);