VPS

Laravelの特徴/インストール/設定/開発方法(8.x対応)

目次
  1. 文章目的
  2. Laravelの良い点
  3. Laravelのインストール
  4. Laravelのコマンド一覧
  5. Laravelの開発
  6. Laravelでのシステム運用
  7. Laravelの勉強で役立つコンテンツ

文章目的

ここではWebフレームワークとして2020/09時点でGithub Starで1番のLaravelの特徴とインストール方法について説明していきます。
Webフレームワークの選択で悩んでる方は、別記事になりますが、DjangoとLaravelの比較記事が役立つかもしれませんので、ご参照下さい。

Laravelの良い点

– PHPである事(CMSの王様WordPressと共通の言語&DBで開発できる)
– 動画/文章が充実してる(但し英語ね)
– リリースのサイクルが定められており、機能の革新が早い。メジャーリリースは半年に1回(2月と8月辺り)。LTS版は2年のバグフィックスと3年のセキュリティフィックス、それ以外の版は半年のバグフィックスと1年のセキュリティフィックスの提供が保証されている。

Laravelのインストール

素でのインストール

PHPの用意

PHP 7系のインストール・設定方法
をご参照下さい

データベースの用意

MariaDBのインストール・設定方法
をご参照下さい。

Laravelのインストール

composer global require laravel/installer;

編集したいファイルを置きたい場所にcdして

PJ=プロジェクト名;
laravel new $PJ --jet;

なお、–jetをつける事で、Laravel8から導入された、ユーザーログインシステムのjetstreamを使う事が出来る。
[0] livewire
[1] inertia
のどちらを使うかを要求される。
vueでSPAを作るのなら1、そうでなければ0を選ぶ。

その次には、
Will your application use teams? (yes/no) [no]:
と、チームという仕組みを使うかどうかが聞かれる。

そしたら、Laravelのプロジェクトフォルダが$PJ以下に出来る。

それから秘密鍵の設定

cd $PJ;
php artisan key:generate;

開発用に動かしてみるだけなら

php artisan serve;

http://127.0.0.1:8000

のURLで作動が確認できる

Laradockを使ったインストール

Laradockとは

https://laradock.io/
LaradockとはLaravelの開発に必要なサーバー群をdocker経由で利用できるようにしたセットです。
Dockerのインストール・使い方については別記事をご参照下さい。

Laradockの使い方

git clone

0から開発するのなら

git clone https://github.com/Laradock/laradock.git;
cd laradock;

既にgitのフォルダを作っているのなら、その中で

git submodule add https://github.com/Laradock/laradock.git;

laradockのトップディレクトリを置いているディレクトリに移動して

PJ=プロジェクト名;
laravel new $PJ;

これで
laradock
$PJ
というディレクトリが同じ階層に出来る

動かすためにlaradock/.envファイルを作る

cd laradock;
cp env-example .env;

laradock/.envファイルのAPP_CODE_PATH_HOSTがLaravel用に作ったPJへパスが通るように設定

APP_CODE_PATH_HOST=../$PJ

更に$PJ/.envを編集して、docker系DB系等を利用する設定をする

DB_CONNECTION=mysql
DB_HOST=mariadb
DB_PORT=3306
DB_DATABASE=default
DB_USERNAME=default
DB_PASSWORD=secret

ユニークな秘密鍵を$PJ/.envに設定
$PJディレクトリ内で

php artisan key:generate;

docker環境をアップする

cd laradock;
docker-compose up -d nginx mariadb workspace;

但し
docker-compose
で立ち上げるサービスを覚えておくのは面倒なので、

#!/bin/sh
cd laradock;
docker-compose up -d nginx mariadb workspace;

と言った内容を含むshellファイルを作っておき、そっちで立ち上げる様にするか、docker-compose.ymlのオリジナルを別にコピーして、自分が使うものだけに減らしておくようにしておく。

間違えて
docker-compose -d
と打つと、利用できる全てのサービスが立ち上がり、ディスク容量等を一気に使ってしまうので。

立ち上げ終わったら
http://localhost/
でLaravelのサイトが表示される事を確認出来る。

webサーバーへのログインは

docker-compose exec workspace bash;

mariadbコンテナへのログインは

docker-compose exec mariadb bash;

mariadb自体へのログインは

docker-compose exec mariadb mysql -udefault -psecret;

コマンドが長くて面倒だなという場合には、一時的にaliasを作るシェルをそのディレクトリ内に用意しておけば良い。

#!/bin/sh
alias dlvl='docker-compose exec workspace ';
alias dmariadb='docker-compose exec mariadb mysql -udefault -psecret;';
alias dmariadb_bash='docker-compose exec mariadb bash;';

そしたら

source alias.sh 

と打って反映させる

その他設定ファイルの編集

$PJ/.env

必要に応じて以下の値を触ります。

APP_NAME
APP_ENV
APP_DEBUG
APP_URL
...
DB_HOST
DB_DATABASE
DB_USERNAME
DB_PASSWORD

$PJ/config/app.php

    'timezone' => 'UTC',
    'locale' => 'en',
    'faker_locale' => 'en_US',

を日本向けのサービスなら

    'timezone' => 'Asia/Tokyo',
    'locale' => 'ja',
    'faker_locale' => 'ja_JP',

に編集

尚、セッションの持続時間は

SESSION_LIFETIME=120

に分単位で定義されているので、変更したければその数値を変更する。


Cacheを使う為の設定

RedisをCacheのDBとして使う場合

composer require predis/predis;

でPredisをインストール

php artisan cache:table;

でCache用のテーブルを作って

php artisan migrate;

でDBに反映

なお、公式の方法だと、Keyを自分で作らないといけないが、実行されるSQLに基づいて行うという楽をしたい場合には
https://github.com/dwightwatson/rememberable
を使うと楽できる。


Laravelのバージョン確認とバージョンアップデート

一旦作ったLaravelのバージョンは

php artisan --version;

で確認できる。

もしも古くてアップデートしたいのなら

composer update;

でアップデート出来る

Laravelが使っているライブラリ情報の確認

composer.phar show laravel/framework

と打つと、色々情報を見る事が出来る

Laravelのコマンド一覧

php artisan …で色々便利な機能をLaravelでは使えるが、以下の様な機能が提供されている。

Laravel Framework 7.15.0

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
      --env[=ENV]       The environment the command should run under
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  clear-compiled       Remove the compiled class file
  down                 Put the application into maintenance mode
  env                  Display the current framework environment
  help                 Displays help for a command
  inspire              Display an inspiring quote
  list                 Lists commands
  migrate              Run the database migrations
  optimize             Cache the framework bootstrap files
  serve                Serve the application on the PHP development server
  test                 Run the application tests
  tinker               Interact with your application
  ui                   Swap the front-end scaffolding for the application
  up                   Bring the application out of maintenance mode
 auth
  auth:clear-resets    Flush expired password reset tokens
 cache
  cache:clear          Flush the application cache
  cache:forget         Remove an item from the cache
  cache:table          Create a migration for the cache database table
 config
  config:cache         Create a cache file for faster configuration loading
  config:clear         Remove the configuration cache file
 db
  db:seed              Seed the database with records
  db:wipe              Drop all tables, views, and types
 event
  event:cache          Discover and cache the application's events and listeners
  event:clear          Clear all cached events and listeners
  event:generate       Generate the missing events and listeners based on registration
  event:list           List the application's events and listeners
 key
  key:generate         Set the application key
 make
  make:cast            Create a new custom Eloquent cast class
  make:channel         Create a new channel class
  make:command         Create a new Artisan command
  make:component       Create a new view component class
  make:controller      Create a new controller class
  make:event           Create a new event class
  make:exception       Create a new custom exception class
  make:factory         Create a new model factory
  make:job             Create a new job class
  make:listener        Create a new event listener class
  make:mail            Create a new email class
  make:middleware      Create a new middleware class
  make:migration       Create a new migration file
  make:model           Create a new Eloquent model class
  make:notification    Create a new notification class
  make:observer        Create a new observer class
  make:policy          Create a new policy class
  make:provider        Create a new service provider class
  make:request         Create a new form request class
  make:resource        Create a new resource
  make:rule            Create a new validation rule
  make:seeder          Create a new seeder class
  make:test            Create a new test class
 migrate
  migrate:fresh        Drop all tables and re-run all migrations
  migrate:install      Create the migration repository
  migrate:refresh      Reset and re-run all migrations
  migrate:reset        Rollback all database migrations
  migrate:rollback     Rollback the last database migration
  migrate:status       Show the status of each migration
 notifications
  notifications:table  Create a migration for the notifications table
 optimize
  optimize:clear       Remove the cached bootstrap files
 package
  package:discover     Rebuild the cached package manifest
 queue
  queue:failed         List all of the failed queue jobs
  queue:failed-table   Create a migration for the failed queue jobs database table
  queue:flush          Flush all of the failed queue jobs
  queue:forget         Delete a failed queue job
  queue:listen         Listen to a given queue
  queue:restart        Restart queue worker daemons after their current job
  queue:retry          Retry a failed queue job
  queue:table          Create a migration for the queue jobs database table
  queue:work           Start processing jobs on the queue as a daemon
 route
  route:cache          Create a route cache file for faster route registration
  route:clear          Remove the route cache file
  route:list           List all registered routes
 schedule
  schedule:run         Run the scheduled commands
 session
  session:table        Create a migration for the session database table
 storage
  storage:link         Create the symbolic links configured for the application
 stub
  stub:publish         Publish all stubs that are available for customization
 ui
  ui:auth              Scaffold basic login and registration views and routes
  ui:controllers       Scaffold the authentication controllers
 vendor
  vendor:publish       Publish any publishable assets from vendor packages
 view
  view:cache           Compile all of the application's Blade templates
  view:clear           Clear all compiled view files

Laravelの開発

命名規則

Class・Classファイルはアッパーキャメル UpperCamel
methodはローワーキャメル lowerCamel()
変数、Viewファイルはスネークケース $snake_case
で書くと良い

vendor系(3rd Party)のPHPライブラリをLaravelで使えるようにする

例えばhikarine3/csv-parserを使いたい場合には

“`
composer requirer $パッケージ名
“`
でインストールした後
composer.jsonのautoload > classmapの配列にそのClassへのパスを追加し

    "autoload": {
        "classmap": [
      ...
           "vendor/hikarine3/csv-parser/src"
        ],
        "psr-4": {
            "App\\": "app/"
        }
    },

“`
composer dump-autoload;
“`
と打つと、Laravel内で使えるようになる。

デフォルトで用意されているテーブル

$PJ/database/migrations
にデフォルトとして作られるテーブルの定義がある

users

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

failed_jobs

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateFailedJobsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('failed_jobs', function (Blueprint $table) {
            $table->id();
            $table->text('connection');
            $table->text('queue');
            $table->longText('payload');
            $table->longText('exception');
            $table->timestamp('failed_at')->useCurrent();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('failed_jobs');
    }
}

これをデータベースに反映して、データベースへの接続がきちんと設定されている事を確認する。
laradockのディレクトリ内に移動して

php artisan migrate;

(尚Docker環境で実行する場合にはDBヘの反映が必要な為 docker-compose exec workspace php artisan migrate; とdocker環境内で実行する必要有り)

成功すれば以下のような結果が表示される。

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.14 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.05 seconds)

反映を取り消したい場合には

php artisan migrate:reset;

新しいモデル(テーブル)の作成

以下のようなコマンドを打つとmigrationsフォルダ以下に空の定義が出来るので、それの中に入れ込んでいく。
なお、-aオプションは
–migration –controller –resource –factory
オプション全て指定と等しい。

コマンド例

php artisan make:model Country -a;

そうすると

app/Country.php <= Modle
app/Http/Controllers/CountryController.php
database/factories/CountryFactory.php
database/migratoins/$YEAR_$MON_$DAY_$TIME_create_countries_table.php
database/seeds/CountrySeeder.php

といったファイルの雛形が出来る。

なお
–resource

Controllerの中のメソッドにCRUD(Create, Read, Update, Delete)のアプリを作るのに必要なメソッドのテンプレを生成してくれる

初期データの追加

https://laravel.com/docs/7.x/seeding

php artisan make:seeder CountrySeeder;

でSeedeerのテンプレを作って適切に編集

Seederのコーディング例

<?php

use Illuminate\Database\Seeder;
use Hikarine3\CsvParser;
use Carbon\Carbon;

class CountrySeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        ini_set('memory_limit','1024M');
        $file = __DIR__ .'/data/locations/countries.tsv';
        $parser = new CsvParser();
        $datas = $parser->parse(['delimiter' => "\t", 'file' => $file]);

        foreach ($datas as $data) {
            if(isset($data['id']) && isset($data['name']) ) {
                DB::table('countries')->insert([
                    'id' => $data['id'],
                    'name' => $data['name'],
                    'created_at' => Carbon::now(),
                    'updated_at' => Carbon::now()
                ]);
            }
        }
    }
}

なお、CSVの読込の為に、

composer require hikarine3/csv-parser;

でライブラリを追加して、その上で
composer.jsonに

    "autoload": {
        "classmap": [
      ...
           "vendor/hikarine3/csv-parser/src"
[code]
と加え、
[code]
composer dump-autoload;

と打ってCSV Parserの機能を使えるようにしています。

そしたら

composer dump-autoload;
php artisan db:seed;
# 一部指定する時は
# php artisan db:seed --class=UserSeeder

で反映

テーブルの作り直し+データを一旦空にして入れ直したければ

php artisan migrate:refresh --seed

開発途中には役立つかと思います(本番システムでは実行してはいけない)。

テーブル定義の修正

型の修正をする場合には

composer require doctrine/dbal;

をしておく。

変更の仕方は

php artisan make:migration some_table_fix_name --table=テーブル名;

でmigrationファイルを作って

Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->change();
});

の様な形に記述してから

php artisan migrate;

で行う

URLと表示内容の結びつけ

routes/web.php
を編集して定義する。
Controllerに渡すパラメーターと渡し先Controllerのメソッドを指定する。
基本的にはそのメソッドの中でViewファイルの場所を指定する。

Route::get('/', 'Country@list');
Route::get('/geo/{countryId}/', 'State@list');

Laravelのデータタイプ

Laravelのデータ定義とMariaDBのデータ型の対応関係

Laravelの型MariaDBの型説明
$table->bigIncrements(‘id’);BIGINT数値がINSERTで自動的に増える
$table->bigInteger(‘…’);BIGINT
$table->binary(‘…’);BLOB
$table->boolean(‘…’);BOOLEAN
$table->char(‘…’, $NUM);CHAR($NUM)
$table->date(‘…’);DATE
$table->dateTime(‘…’);DATETIME
$table->dateTimeTz(‘…’);DATETIME
$table->decimal(‘…’, 数値表現最大長, 小数点桁数);Decimal(‘…’, 数値表現最大長, 小数点桁数)
$table->double(‘…’, 数値表現最大長, 小数点桁数);Double(‘…’, 数値表現最大長, 小数点桁数)
$table->enum(‘…’, [‘…’, ‘…’]);ENUM
$table->float(‘…’);FLOAT
$table->foreignId(テーブル名);`テーブル名_id` varchar(255)CONSTRAINT `jobs_city_id_foreign` FOREIGN KEY (`city_id`) REFERENCES `cities` (`id`)といった外部キー制約も追加する
$table->geometry(‘…’);Geometry
$table->geometryCollection(‘…’);GeometryCollection
$table->id();bigintAuto-incrementing UNSIGNED BIGINT (primary key)
$table->increments(‘…’);int
$table->integer(‘…’);int
$table->ipAddress(‘…’);
$table->json(‘…’);longtext CHECK (json_valid(`…`))MariaDB/MySQLではサポートされておらずlongtextに
PostgreSQLならjsonになる
$table->jsonb(‘…’);longtext CHECK (json_valid(`…`))MariaDB/MySQLではサポートされておらずlongtextに
PostgreSQLならjsonbになる
$table->linestring(‘…’);linestringMariaDB/MySQLではサポートされてない。
PostgreSQLのみ現在サポート
$table->longText(‘…’);longtext
$table->macAddress(‘…’);varchar(17)
$table->mediumInteger(‘…’);mediumint
$table->mediumText(‘…’);mediumtext
$table->morphs(‘…’);varchar(255)
$table->multiLineString(‘…’);multiLinestring
$table->multiPoint(‘…’);multipoint
$table->multiPolygon(‘…’);multipolygon
$table->nullableTimestamps();
$table->point(‘…’);point
$table->polygon(‘…’);polygon
$table->rememberToken();`remember_token` varchar(100)
$table->smallInteger(‘…’);smallint
$table->tinyInteger(‘…’);tinyint
$table->set(…);timestampdeleted_at
$table->softDeletes();`softDeletes` timestampdeleted_at
$table->softDeletesTz();`softDeletesTz` timestampdeleted_at
$table->string(‘…’);varchar(255)
$table->string(‘…’, $LEN);varchar(‘…’, $LEN)
$table->text(‘…’);text
$table->time(‘…’);time
$table->timeTz(‘…’);time
$table->timestamp(‘…’);TIMESTAMP
$table->timestamps();`created_at` timestamp
`updated_at` timestamp
$table->uuidchar(‘…’);char(36)
$table->uuidMorphs(‘…’);bigint(20)
$table->year(‘…’);char(4)
$table->rememberToken();Adds remember_token as VARCHAR(100) NULL
->nullable()NULLDesignate that the column allows NULL values
->default($value)DEFAULT VALUEDeclare a default value for a column
->unsigned()INT UNSIGNEDSet INTEGER to UNSIGNED

Viewの開発

Ver7以前迄

composer require laravel/ui;

と打つと、Bootstrap, react, vueで開発するのに役立つテンプレを簡単に得る事が出来る。

Bootstrapで開発したい場合は

php artisan ui bootstrap --auth;

Reactで開発したい場合は

php artisan ui react --auth;

Vueで開発したい場合は

php artisan ui vue --auth

と打つと、認証・ログイン機能のUIと共にテンプレが出来るので、そこから開発を始めると良い。
なお、このコマンドは択一な為、打ち直すと生成されたファイル群

auth/login.blade.php
auth/passwords/confirm.blade.php
auth/passwords/email.blade.php
auth/passwords/reset.blade.php
auth/register.blade.php
auth/verify.blade.php
resources/js/app.js
resources/js/bootstrap.js
resources/sass/app.scss
resources/views/home.blade.php
resources/views/layouts/app.blade.php
app/HTTP/Controllers/HomeController.php

を書き換えるので注意。

ログイン関係ファイルの日本語化

Webの方は
resources/views/auth
以下を触れば良いが、メールの部分は

php artisan vendor:publish --tag=laravel-notifications

と打って
resources/vendor/notifications/email.blade.php
を編集すると変更が可能。
といっても、そこは、値を埋め込む形で生成されているので、
resources/lang/en/*
以下を
resources/lang/ja/
にコピーして、そこに対応する日本語化の値セットを作る。

そこにないものは
resources/lang/ja.json

{
  "Login": "ログイン",
  "Register": "新規登録",
}

という形で定義する事で、設定できる。

なお、日本語の方の値を使う為には、config/app.phpのlocaleの値がjaになっている必要がある。

モデルファイルの設定注意点

モデルのファイルは触らなくても動く事が多いが、以下の点を必要に応じて変更する様に注意

Primary Key名がidではない場合

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
    protected $primaryKey = 'flight_id';
}

Primary KeyがAuto incrementなタイプでない場合

<?php
class Flight extends Model
{
    public $incrementing = false;
}

Primary Keyがint型ではない場合

<?php
class Flight extends Model
{
    protected $keyType = 'string';
}

ソーシャルログイン機能の追加

https://laravel.com/docs/7.x/socialiteを参照

composer require laravel/socialite;

vi config/services.php

'facebook' => [
    'client_id' => env('FACEBOOK_CLIENT_ID'),
    'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
    'redirect' => 'http://your-callback-url',
],
// 
'google' => [
    'client_id' => env('GOOGLE_CLIENT_ID'),
    'client_secret' => env('GOOGLE_CLIENT_SECRET'),
    'redirect' => 'http://your-callback-url',
],
'linkedin' => [
    'client_id' => env('LINKEDIN_CLIENT_ID'),
    'client_secret' => env('LINKEDIN_CLIENT_SECRET'),
    'redirect' => 'http://your-callback-url',
],
'twitter' => [
    'client_id' => env('TWITTER_CLIENT_ID'),
    'client_secret' => env('TWITTER_CLIENT_SECRET'),
    'redirect' => 'http://your-callback-url',
],

キーはそれぞれ
https://developers.facebook.com/apps/

https://console.developers.google.com/apis/credentials

https://developer.twitter.com/en/apps

https://www.linkedin.com/developers/apps/
で取得する

値は.envファイルから取得するようにしているので、.envに

FACEBOOK_CLIENT_ID=...
FACEBOOK_CLIENT_SECRET=...
FACEBOOK_CALLBACK_URL=...
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GOOGLE_CALLBACK_URL=...
LINKEDIN_CLIENT_ID=...
LINKEDIN_CLIENT_SECRET=...
LINKEDIN_CALLBACK_URL=...
TWITTER_CLIENT_ID=...
TWITTER_CLIENT_SECRET=...
TWITTER_CALLBACK_URL=...

と定義しておく

fontawesomeを使う

npm install @fortawesome/fontawesome-free --save;

resources/app/sass/app.scss
を編集して
[code]
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/solid';
@import '~@fortawesome/fontawesome-free/scss/brands';
npm run dev;

メールの送信

メール送信用のクラスは別途作り、別のControllerから呼び出す形で使う。

php artisan make:mail SubscribeDemo;

こう打つと
app/Mail/SubscribeDemo.php
が。

検索機能の追加

https://laravel.com/docs/7.x/scoutを参照

MariaDB(MySQL)ではfulltextという全文検索機能がサポートされているが、並び替えをするには、全部結果を得てから並び替えるという処理が内部では行われているので、十分な速度が出ない。

なので、きちんとした検索機能を実装したい場合には、別途全文検索機能を使う事になる。

Laravelでは公式でサポートされているのがAlgolia。
https://www.algolia.com/
費用感的に問題ないのなら、一番楽なので、その手順に従って使ってみるのが良いだろう。

ここでは費用を考え、自前でElasticsearchを運用し、連携させるとする

ElasticSearchは先に動かしておく必要がある。
ElasticSearchのインストール・設定・運用方法についてはこちらの記事をご参照下さい。

Laradockを使っているのなら

docker-compose -d elasticsearch kibana up;

で起動出来る(ElasticSearchと連携する可視化ツールKibanaも同時に立ち上げてしまう)。

ElasticSearchはLaravel公式ではサポートされてないので、ライブラリの利用を考える。

世の中には古い版でしか動かない記事が溢れてますが、参考にした記事はこちら(英語)。

composer require laravel/scout;
composer require elasticsearch/elasticsearch;
composer require babenkoivan/elastic-migrations;
composer require babenkoivan/elastic-scout-driver;
composer require babenkoivan/elastic-scout-driver-plus;

php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider";
php artisan migrate;

.envの編集

ELASTIC_HOST=elasticsearch:9200
SCOUT_DRIVER=elastic

対象モデルファイルの編集(Jobというモデルの場合)

<?php

namespace App;

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

class Job extends Model
{
    use Searchable;

    public function toSearchableArray()
    {
// Elasticサーチの項目名とDBのテーブル名の紐付け
        return [
            'fulltime' => $this->fulltime,
            'search_content' => $this->search_content,
            'search_location' => $this->search_location,
            'registered_date' => $this->registered_date,
            'public_end_date' => $this->public_end_date,
            'age_limit_lower' => $this->age_limit_lower,
            'age_limit_upper' => $this->age_limit_upper,
            'minimum_salary' => $this->minimum_salary,
            'maximum_salary' => $this->maximum_salary
        ];
    }
}

データの取り込み

php artisan scout:import "App\Job";

これで
App:Search(“キーワード”)->take(5)->get();
といった形で検索は出来るようになった

とはいえ、これだけでは、並び替え等複雑な検索が出来ないので、以下のようにCustomSearchを追加する。

<?php
namespace App;

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

class Job extends Model
{
    use Searchable, CustomSearch;
    public function toSearchableArray()
    {
// Elasticサーチの項目名とDBのテーブル名の紐付け
        return [
            'fulltime' => $this->fulltime,
            'search_content' => $this->search_content,
            'search_location' => $this->search_location,
            'registered_date' => $this->registered_date,
            'public_end_date' => $this->public_end_date,
            'age_limit_lower' => $this->age_limit_lower,
            'age_limit_upper' => $this->age_limit_upper,
            'minimum_salary' => $this->minimum_salary,
            'maximum_salary' => $this->maximum_salary
        ];
    }
}

そうすると

Job::boolSearch()->must('match', ['search_content' => ['query'=>'インターロッキング', 'operator'=>'and'] ])->must('match', ['search_location' => ['query'=>'栃木', 'operator'=>'and'] ])->sort('maximum_salary', 'desc')->execute()->models();

といったより複雑な検索も実行できるようになる。
詳しくは
https://github.com/babenkoivan/elastic-scout-driver-plus
参照

ElasticSearchに作られたデータの可視化ツールとして立ち上げたKibanaは
http://localhost:5601/
で確認出来る。

ページの表示に使われてるSQLと処理時間を常に開発・ステージング環境では確認する

本番環境は兎も角、開発環境・ステージング環境では、見てるページで実行されているSQLとかかっている時間を確認したい。
そんな時には、以下のような処理をControllerのメソッドに書く。

以下は、例としてBigJobCategoryStatisticsControllerのshowメソッドで使われたSQLを全部把握する為の例

なお、サーバー名が
stg.helloworkplus.com

localhost
の時だけ表示する様にしているが、ここら辺の条件は必要に応じてカスタマイズ・厳格化して下さい。

<?php
...
use Illuminate\Support\Facades\DB;

class BigJobCategoryStatisticsController extends Controller
{
    public function show(...)
    {
// メソッドの初めに
        if($_SERVER['HTTP_HOST']=='stg.helloworkplus.com' || $_SERVER['HTTP_HOST']=='localhost'){
            DB::enableQueryLog();
        }
...
// メソッド終わりでreturnする直前に
        $sql_logs = [];
        if($_SERVER['HTTP_HOST']=='stg.helloworkplus.com' || $_SERVER['HTTP_HOST']=='localhost'){
            $sql_logs = DB::getQueryLog();
        }

        return view('big_job_category_statistics.show')->with(compact(..., 'sql_logs'));
    }
...

それをlayouts側で表示する様にする。
以下の様なコードを、layoutsの下部に埋め込む。

...
@if(isset($sql_logs) && $sql_logs)
<pre>
@foreach($sql_logs as $sql)
  <?php print_r($sql); ?>
  <br />
@endforeach
</pre>
@endif

そうすると

Array
(
    [query] => select * from "jobs" where ("id" = ?) limit 1
    [bindings] => Array
        (
            [0] => 12080-15964701
        )

    [time] => 116.14
)


Array
(
    [query] => select * from "companies" where ("id" = ?) limit 1
    [bindings] => Array
        (
            [0] => 1208-102323-4
        )

    [time] => 36.86
)


Array
(
    [query] => select * from "cities" where "id" = ? limit 1
    [bindings] => Array
        (
            [0] => 12217
        )

    [time] => 1.9
)

と、そのメソッド内で実行されたSQLが全て実行秒数と共に、ページの挿入した部分に表示される。
timeはマイクロセカンドなので1000で1秒になる。

Redisの様なキャッシュシステムを使っている場合には、そもそもこのSQLがなるべく表示されない様にする=DBに問合せを投げさせない事が、Webアプリの速度向上に繋がる指標になります。

configで定義した値へのアクセス

config('...')

でアクセスできる。
例えば
config/app.php
内で

'key' => env('APP_KEY'),

と定義されている値にアクセスしたければ

config('app.key')

でアクセスできる。

JetStreamでのリセット時のパスワード制限長の最低限の変更

app/Actions/Fortify/PasswordValidationRules.php

return [‘required’, ‘string’, new Password, ‘confirmed’];
を例えばパスワード5文字に変更したければ
return [‘required’, ‘string’, (new Password)->length(5), ‘confirmed’];
と変更

Laravelでのシステム運用

本番環境へのDeploy

composer install --optimize-autoloader --no-dev;
php artisan config:cache;
php artisan route:cache;
php artisan view:cache;
npm run prod;

なお、

php artisan config:cache;

を使うとエラーが起き得る環境/configのセットがあるので注意(例: Taggingをcacheで使っているのにcacheとsessionの保存先にfileをしている場合等)。

Read replicaサーバーを複数台使いつつ、サーバーが落ちてても、エラー出さずに表示処理を継続する方法

LaravelはReadサーバーに複数のサーバーを指定する事が出来ます。
これは負荷分散の為に使える機能ではありますが、実はそれを指定していると、接続しようとしているサーバーに接続しようとして繋がらない場合には、一定時間したら別のDBサーバーに接続しに行ってくれる事で、サービスの提供を継続できるという、Fail Overの機能も利用可能です。
インフラ側で、特別に中間にその為のDB Proxy的なサービスを組み込まずとも、簡単にLaravel側の設定だけでそうした処理ができるのは、利用ユーザーの観点でも、SEOの観点でも、この機能は運用上助かります。

なお、これは公式の文章には書かかれてはいませんが、ソースコードを読むとそういう実装になっている事が分かります。

ただ、接続できないと諦めの判断処理に30秒とか長い時間がかかってしまうので、サービスの提供を継続できていていても、ユーザービリティ・SEOで問題になってしまいます。

その対策として、接続出来ない場合により早く諦めるTIMEOUT設定を、database.phpに定義しておきましょう。

        'pgsql' => [
            'driver' => 'pgsql',
            'url' => env('DATABASE_URL'),
            //'host' => env('DB_HOST', '127.0.0.1'),
            'read' => [
                'host' => [
                    env('DB_HOST1', 'forge'),
                    env('DB_HOST2', 'forge'),
                ],
            ],
            'write' => [
                'host' => [
                    env('DB_HOST1', 'forge'),
                ],
            ],
            'sticky' => true,
            ...
            'options' => [
                PDO::ATTR_TIMEOUT => 1,
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
            ]
        ],

みたいな感じでoptionsに指定します。
なお、PDO::ATTR_TIMEOUTでは1秒と指定していますが、自分のPostgreSQLとの組み合わせの場合2秒諦めにかかっています。
あと、これをするとサービスは確かに落ちなくなる上に、ある程度正常にサービスの提供を継続できますが、Webサーバー側のダウンで異常を検知できなくなるので、DB側はDB側で別途きちんと監視しておく様にしましょう。

Laravelの勉強で役立つコンテンツ

  1. 公式の文章
    Laravelの素晴らしい所は、機能の充実もあるけれども、文章の質の高さ・読み易さも大きい。
  2. Laravel News
    Laravel関連の役立つ記事が配信される
  3. Laracasts
    Laravelでの開発役立ち情報が動画で配信される
  4. Laravel Tutorial: Step by Step Guide to Building Your First Laravel Application
    Laravelの基本的な処理を学ぶのに役立つ記事。簡易にまとめられている