Laravelはプログラムを定期実行できる。
サイトマップを定期的に更新したり、DBの同期をしたりするときに役立つ。
本記事では、外部DBのテーブルを、毎日8:00時にローカルのDBに同期することを目標とする。
「スケジュール実行の方法だけ知りたい!DBの接続の話はどうでもいい!」
という方は手順4からみていただければと思います。
1.外部接続可の権限を持つユーザを作成
外部DBにアクセスするには、まず外部からの接続を許可しているユーザを外部DBに作成する必要があります。
この方法については、わかりやすい記事があったのでこちらを確認してください。
2.外部DBの接続情報を定義
Laravelは、複数のDBに接続できます。
config/database.phpを以下のように修正。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 'default' => env('DB_CONNECTION', 'mysql'), 'connections' => [ 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true, 'engine' => null, ], 'mysql_outer' => [ 'driver' => 'mysql', 'host' => 'ホスト名', 'port' => 'ポート', 'database' => 'DB名', 'username' => 'ユーザ名', 'password' => 'パスワード', 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'unix_socket' => env('/var/lib/mysql/mysql.sock'), 'prefix' => '', 'strict' => true, 'engine' => null, ], ], |
mysqlは、普通に今まで使っていたローカルのDBの接続情報ですね。
今回、2つ目のDBとして、mysql_outerを定義しました。
各項目は、外部DBの情報を記述してください。
これにより、今後
DB::connection(‘mysql_outer’)->table(‘テーブル名’)->get();
のようにして、2つ目のDBにアクセスできます。
3.DBを同期するコマンドを生成
まず、下記のコマンドを叩き、「DBを同期するコマンド」syncdbを生成する。
1 | php artisan make:command syncdb |
syncdbは今回適当につけた名前なので他の名前でも大丈夫です。
上記コマンドを叩くと、App/Console/Commandsの中に、新規ファイルが生成されます。
このファイルを以下のように修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; class SyncData extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'command:syncdata'; /** * The console command description. * * @var string */ protected $description = 'Sync data'; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return mixed */ public function handle() { $syncData = DB::connection('mysql_outer')->table('外部DBのテーブル名')->get(); $syncData = $syncData->toArray(); $syncData=array_map(function($item){ return (array) $item; },$syncData); DB::table('ローカルDBのテーブル名')->truncate(); ini_set('max_execution_time', 120); foreach (array_chunk($job_infos,1000) as $job_info) { DB::table('ローカルDBのテーブル名')->insert($syncData); } } } |
15行目で、コマンドを実行する際のコマンド名、22行目がコマンドの説明分です。
41行目で、外部DBのテーブルのデータをすべて取得し、ローカル変数に格納。
42から45行目は、syncDataをオブジェクト型から配列に変換してます。
これは、後にsyncDataをinsert()に渡す際、オブジェクト型のままだとエラーが発生するためです。
46行目で、ローカルDBのテーブルを一度空にする。
48から50行目で、ローカル変数syncDataに格納されているデータをinsertしていってます。
foreachでわざわざ回しているのは、syncDataの配列の要素が多い場合、一度のinsertですべてやろうとするとtimeoutやらメモリーオーバーなんたらかんたらみたいなエラーがでるためです。だから、1000個ずつに分割してinsertしてます。
これで、同期を行うコマンドができました。
あとは、このコマンドを定期的に実行するためのスケジュール設定をしていくだけです。
4.スケジュール設定
編集するファイルは、App/Console/Kernel.phpです。
下記のように、記述する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <?php namespace App\Console; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; class Kernel extends ConsoleKernel { /** * The Artisan commands provided by your application. * * @var array */ protected $commands = [ \App\Console\Commands\SyncData::class, ]; /** * Define the application's command schedule. * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @return void */ protected function schedule(Schedule $schedule) { $schedule->command('command:syncdata')->dailyAt('08:00')->emailOutputTo('実行通知を受け取るメールアドレス'); } /** * Register the commands for the application. * * @return void */ protected function commands() { $this->load(__DIR__.'/Commands'); require base_path('routes/console.php'); } } |
16行目で、手順3で作成したコマンドのクラスファイルを指定。
27行目。
$schedule->command(‘command:syncdata’)->dailyAt(‘8:00’)->emailOutputTo(‘laraveldaisuki@test.co.jp’);
dailyAt(‘実行したい時間’)で、command(‘実行したいコマンド’)を意味している。
emailOutputTo()で、スケジュール実行の通知を受け取りたいメールアドレスを指定できます。
5.cronの設定
crontab -eコマンドで、cronの設定ファイルを開き、下記のように記述する。
* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
これにより、手順4にて設定したスケジュール情報を毎秒確認し、実行するタイミングのものがあればそれを実行するようになる。
path-to-your-projectの箇所は、あなたのLaravelプロジェクトのトップディレクトリのパスに修正してください。
あと、注意点ですが、phpコマンドのパスを指定しないと実行されない場合があります。
xserverの場合は、設置しないといけないです。
そのときは、以下のようにphpコマンドのパスを指定しましょう。
* * * * * /bin/php7.2 /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
自分のphpのバージョンを調べるときは、php -vコマンドで調べてください。
以上です。
これで、動くはずです。