がっつりパッケージ開発とかじゃなくてモジュール再利用したい場合とかに便利そうなのでメモ。
参考: Laravel JP Conference で Laravel のパッケージ開発に関する登壇をしてきました。
Laravelのインストール
$ composer global require laravel/installer
パッケージ用ディレクトリの作成
管理画面向けAPI(admin)、ユーザ画面向けAPI(front)、共通ロジック(common)という構成を例にします。
composer.json の作成(common)
package/luftgarden/common/composer.json
{
"name": "luftgarden/common",
"minimum-stability": "dev",
"require": {
"barryvdh/laravel-cors": "^0.11.0",
"nicolaslopezj/searchable": "1.*",
"intervention/image": "^2.4",
"aws/aws-sdk-php-laravel": "~3.0",
"barryvdh/laravel-dompdf": "^0.8.0",
"azuyalabs/yasumi": "2.0.*",
"sentry/sentry-laravel": "1.3.0",
"itsgoingd/clockwork": "^4.0.0",
"spatie/laravel-backup": "^6.0.0"
},
"extra": {
"laravel": {
"providers": [
"LuftGarden\\Common\\CommonServiceProvider",
"Barryvdh\\Cors\\ServiceProvider",
"Intervention\\Image\\ImageServiceProvider",
"Aws\\Laravel\\AwsServiceProvider",
"Barryvdh\\DomPDF\\ServiceProvider",
"Sentry\\Laravel\\ServiceProvider",
"Clockwork\\Support\\Laravel\\ClockworkServiceProvider"
],
"aliases": {
"LuftCommon": "LuftGarden\\Common\\CommonFacade",
"Image": "Intervention\\Image\\Facades\\Image",
"AWS": "Aws\\Laravel\\AwsFacade",
"PDF": "Barryvdh\\DomPDF\\Facade",
"Sentry": "Sentry\\Laravel\\Facade",
"Clockwork": "Clockwork\\Support\\Laravel\\Facade"
},
"dont-discover": []
}
},
"autoload": {
"psr-4": {
"LuftGarden\\Common\\": "./src"
}
}
}
今回作成するパッケージ用に CommonServiceProvider
と CommonFacade
を指定しているのがポイント。
あとは autoload にも namespace を指定しておく。
require するパッケージは必要に応じて調整する。
親側でパッケージを入れる際に dev でインストールする(後述)ので、何かしらライブラリをインストールする場合は不安定なバージョンが入らないように明示的にバージョン指定しておいたほうがいい。
extra.laravel 配下にサービスプロバイダとファサードを指定しておけば Auto Discovery が働いてくれる。
(laravel-backupとか指定無しで大丈夫なので必須ではないかもです)
CommonServiceProvider の作成
common 用のサービスプロバイダを作成する。
※以下の例はコピペでは動かないので適当に調整してください
package/luftgarden/common/CommonServiceProvider.php
<?php
namespace LuftGarden\Common;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;
use LuftGarden\Common\Console\Commands\SampleCommand;
use LuftGarden\Common\Guard\CustomTokenGuard;
use LuftGarden\Common\Model\User;
use LuftGarden\Common\Observers\UserObserver;
class CommonServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->app->singleton( 'CommonService', function () {
return new CommonService();
} );
}
/**
* Bootstrap services.
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function boot( \Illuminate\Routing\Router $router )
{
/**
* Add custom Guard
*/
$this->app['auth']->extend( 'custom_token', function ( $app, $name, array $config ) {
return new CustomTokenGuard( Auth::createUserProvider( $config['provider'] ), $app['request'] );
} );
/**
* Define Gates
*/
$this->defineGates();
/**
* Middleware alias name
*/
$router->aliasMiddleware(
'sample.middleware',
\LuftGarden\Common\Http\Middleware\SampleMiddleware::class
);
/**
* Front API custom middleware group
*/
$router->middlewareGroup( 'front', [
'throttle:60,1',
'bindings',
\Barryvdh\Cors\HandleCors::class,
] );
/**
* Admin API custom middleware group
*
* @see \App\Http\Kernel.php $middlewareGroups['api']
*/
$router->middlewareGroup( 'admin', [
'throttle:60,1',
'bindings',
\Barryvdh\Cors\HandleCors::class,
] );
/**
* Configs
*/
$this->mergeConfigFrom( __DIR__ . '/config/common.php', 'common' );
/**
* Common routes / Migrations
*/
$this->loadRoutesFrom( __DIR__ . '/routes/common.php' );
$this->loadMigrationsFrom( __DIR__ . '/database/migrations' );
/**
* Commands
*/
if ( $this->app->runningInConsole() ) {
$this->commands( [
SampleCommand::class,
] );
}
/**
* Schedules
*/
$this->app->booted( function () {
$schedule = $this->app->make( Schedule::class );
$schedule->command( 'sample:command' )->everyFiveMinutes();
} );
/**
* Observer
*
* @see https://readouble.com/laravel/6.0/ja/eloquent.html#observers
*/
User::observe( UserObserver::class );
}
/**
* Gateの定義追加
*/
private function defineGates()
{
/**
* データ所有者の一致
*/
Gate::define( 'possessor', function ( $user, $target_user ) {
return $user->id === $target_user->id;
} );
}
}
register メソッドはシングルトンでサービスクラスを用意しているだけ。
重要なのは boot メソッドのほう。コメント毎に説明していきます。
Add custom Guard
カスタムガードの登録。通常のLaravel認証を使うなら必要ない。
カスタムガードの作り方自体は以下の記事とかを参考に。
[Laravel] Token認証で利用するキー(api_token)の名前を変更する
Define Gates
ゲートの登録。
ここだけメソッド化しているけど好きにしてください。
Middleware alias name
ミドルウェアクラスのエイリアス名を登録。
Front (Admin) API custom middleware group
Laravel標準のAPIミドルウェアに laravel-cors を加えただけ。
throttleが足りなければ適当に調整する。
Laravel 6.0 認可
Configs
コンフィグの登録。
複数登録して細分化しておけば捗る(適当)。
Laravel 6.0 設定
Commands
コマンドの登録。runningInConsole()
で判定するのがポイント。
Schedules
タスクスケジュールの登録。
もちろん前項で登録したコマンドはここで割り当てることができる。
Observer
オブザーバの登録。
論理削除と物理削除で処理を変えたいときは Model::isForceDeleting()
を使えばいい。
オブザーバのドキュメントは場所が分かり辛いので頑張って探す。
Laravel 6.0 Eloquent:利用の開始 | オブザーバ
CommonFacade と CommonService の作成
作成必須ではない(作成しない場合は composer.json
と CommonServiceProvider.php
から対象コードを削除しておく)。
/package/luftgarden/common/CommonFacade.php
<?php
namespace LuftGarden\Common;
use Illuminate\Support\Facades\Facade;
class CommonFacade extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'LuftCommon';
}
}
/package/luftgarden/common/CommonService.php
<?php
namespace LuftGarden\Common;
class CommonService
{
public function getClass()
{
return __CLASS__;
}
}
common パッケージのインストール
ここまで作業が終わったら親側でパッケージをインストールしてみる。
composer.json の編集
作成した common パッケージを親側(Laravelルート)の composer.json
に追加する。
composer.json
{
//...中略...
"repositories": [
{
"type": "path",
"url": "package/luftgarden/common"
}
],
}
パッケージのインストールと動作確認
$ composer require luftgarden/common:*@dev
$ php artisan serve
composer.json の作成(admin)
次は admin 用の composer.json
を作成する。
/package/luftgarden/admin/composer.json
{
"name": "luftgarden/admin",
"minimum-stability": "dev",
"require": {},
"extra": {
"laravel": {
"providers": [
"LuftGarden\\Admin\\AdminServiceProvider"
],
"aliases": {
"LuftAdmin": "LuftGarden\\Admin\\AdminFacade"
},
"dont-discover": []
}
},
"autoload": {
"psr-4": {
"LuftGarden\\Admin\\": "./src"
}
}
}
AdminServiceProvider の作成
admin 用のサービスプロバイダを作成する。
package/luftgarden/admin/AdminServiceProvider.php
<?php
namespace LuftGarden\Admin;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
class AdminServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->app->singleton( 'AdminService', function () {
return new AdminService();
} );
$this->map();
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapAdminRoutes();
}
/**
* Define the admin API routes for the application.
*
* @return void
*/
protected function mapAdminRoutes()
{
Route::prefix( 'api/v1/admin' )
->middleware( 'admin' )
->name( 'admin.' )
->group( __DIR__ . '/routes/admin.php' );
}
}
AdminService の登録と map()
メソッドでルーティング登録してるだけなのでシンプル。middleware( 'admin' )
とすることで、CommonServiceProvider.php
で定義したAdmin用のミドルウェアグループをルート全体に適用している。また、 name( 'admin.' )
とすれば各ルートにプリフィックス付けられて便利。
AdminFacade と AdminService の作成
こちらも common と同様に作成必須ではない。
/package/luftgarden/admin/AdminFacade.php
<?php
namespace LuftGarden\Admin;
use Illuminate\Support\Facades\Facade;
class AdminFacade extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'LuftAdmin';
}
}
/package/luftgarden/admin/AdminService.php
<?php
namespace LuftGarden\Admin;
class AdminService
{
public function getClass()
{
return __CLASS__;
}
}
admin パッケージのインストール
最後に common パッケージと同様の手順でインストールする。
composer.json の編集
作成した admin パッケージを親側(Laravelルート)の composer.json
に追加する。
composer.json
{
//...中略...
"repositories": [
{
"type": "path",
"url": "package/luftgarden/common"
},
{
"type": "path",
"url": "package/luftgarden/admin"
}
],
}
パッケージのインストールと動作確認
$ composer require luftgarden/admin:*@dev
$ php artisan serve
おわりに
front も admin と同様の手順で作成できます。
最終的には以下のようなディレクトリ/ファイル構成になります(見づらい)。