20211011のlaravelに関する記事は9件です。

Laravel以外のフレームワークでdd()を使う方法

結論 // Laravelのdd() dd(確認したい変数など); // PHPでdd()っぽいことを実行 var_dump(確認したい変数など); die(); 上記の処理でddと同等の処理を実施できます。 PHPのメソッドについては以下をご参照ください。 PHP:var_dump - Manual PHP:die - Manual
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】楽天レシピAPIからレシピを取得する方法

はじめに 献立アプリを作る際に、楽天レシピAPIからレシピ(1カテゴリにつきランキング上位4つのレシピ)を取得したので、そのときのコードを備忘録として残しておきます。 Bladeのbodyタグ内に記述 welcome.blade.php <body> @php $json = json_decode('APIテストフォームでパラメータ(categoryId=10といった感じ)を指定し、GETをクリックしたら出てくるデータをここにコピペ', true); use App\Models\Menu; $array = $json['result']; for($i=0; $i<sizeof($json['result']); $i++){ $menu = new Menu(); $menu->recipe_category_id = 10; $menu->user_id = 1; $menu->step = ''; $menu->seasoning = ''; $menu->menu_name = $array[$i]['recipeTitle']; $menu->image_path = $array[$i]['foodImageUrl']; $menu->description = $array[$i]['recipeDescription']; $menu->ingredient = implode(',', $array[$i]['recipeMaterial']); $menu->save(); } @endphp </body> この記述を行った後、このページをリロードすると、自分で用意したテーブルのカラム内にそれぞれのデータを入れることができます。 また、IDを変えていくことで、そのIDを持つカテゴリの上位4つのレシピをどんどん取得することができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel8 マイページを見られるユーザーを限定する(アクセス制限)

やりたいこと マイページを自分(特定のユーザー)以外がアクセスできないようにしたい。 未ログイン状態からのアクセスがあればログイン画面にリダイレクトしたい。 ログイン済みであっても他人のマイページは閲覧できないようにしたい。 環境 PHP7 Laravel8 前提 マイページそのものは作成しておく マイページのURLにパラメータとしてユーザーIDが表示される状態になっている コントローラー コントローラーでは、if文を使ってパラメーターに入るユーザーIDとアクセスしようとしているユーザーのユーザーIDが一致しないと閲覧できないようにした。 app/Http/Controllers/RecordUsersController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use App\Models\Record; use App\Models\User; use Illuminate\Support\Facades\DB; class RecordUsersController extends Controller { // public function show_by_user($id) { $user = Auth::user(); $id = Auth::id(); $user = User::find($id); $records = Record::where('user_id',$user->id)->sortable()->get(); if($user->id == $id){ return view('record.showbyuser', [ 'user_name' => $user->name, 'records' => $records, ]); }else{ return redirect('/login'); } } } ルーティング ルーティングでは->middleware('auth')を追記して、未ログイン状態からアクセスするとログインを要求するように変更。 routes/web.php use App\Http\Controllers\RecordUsersController; // ユーザー投稿の一覧表示画面 Route::get('/record/user/{user_id}', [RecordUsersController::class, 'show_by_user'])->name('show_by_user_record')->middleware('auth'); できたこと マイページを自分(特定のユーザー)以外がアクセスできないようになった。 未ログイン状態からのアクセスがあればログイン画面にリダイレクトするようになった。 ログイン済みであっても他人のマイページは閲覧できないようになった。 うまくいっていないこと URLパラメーターに入るユーザーIDがアクセスしようとするユーザーIDと一致しないときにエラー文を表示したり、別ページにリダイレクトさせようとしたができなかった。if~else..の記述に問題があると思われるが、現状原因不明のまま。今後改善したい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel5.5 会員の退会機能 論理削除(ソフトデリート)の実装

はじめに laravel5.5を使用しており、最新のバージョンではありません。 論理削除の流れ 退会したユーザのデータをDBから完全に削除せず、 復元が可能であるような方法を論理削除と言います。 ユーザが'退会する'というボタンをクリック ↓ ユーザは登録した情報でログインができなくなる ↓ DBには、ユーザが会員登録したデータは残っている状態 前提 laravelの環境構築を終えている MAMPを使用 DBの接続を終えている ユーザのログイン機能は実装済み 実装手順 ログイン機能が実装済みの方は1から読み進めてください。 0.ログイン機能の実装 1.データベースの編集 2.userモデルの編集 3.seederでデータを入れてみる 4.ルーティングの追加 5.viewの編集 6.コントローラーの作成 7.動作確認 0. ログイン機能の実装 laravelのバージョンによってコマンドが異なります。 ターミナル //Larvel5.8まで $php artisan make:auth //Laravel6.x 以降 $composer require laravel/ui --dev $php artisan ui bootstrap --auth このコマンドのみでログイン機能は完了です。(便利すぎます...!) 本来は$php artisan migrateをターミナルで実行します。 今回はカラムの追加がありますのでそのまま次の作業に進みましょう。 1. データベースの編集 今回は既存のcreate_users_tableを編集していきます。 softDeletes()と定義することで論理削除に必要なカラムが作成されます。 * xxxxには日時などが入ります。 database/migrations/xxxx_create_users_table.php class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('name_kana'); $table->string('address'); $table->char('postal_code', 7); $table->string('email')->unique(); $table->string('password'); $table->rememberToken(); + $table->softDeletes(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('users'); } } カラムが追記できたら下記を忘れずに実行しましょう。 ターミナル $php artisan migrate DBにdeleted_atというカラムが作成されているか確認してみて下さい。 2. userモデルの編集 use SoftDeletes でソフトデリートを使用できるようにしています。 app/User.php <?php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; + use Illuminate\Database\Eloquent\SoftDeletes; class User extends Authenticatable { use Notifiable; + use SoftDeletes; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; } 3. seederでデータを入れてみる まずは、Userモデルのseedを作成します。 ターミナル php artisan make:seeder UsersTableSeeder seedsディレクトリの中に UsersTableSeeder.phpが作成されますので、編集していきましょう。 name,email,passwordは何でも構いませんので自由に決めてください。 ⚠️emailのドメインはなるべくexample.comを使用した方が良いです。 database/seeds/UsersTableSeeder.php <?php use Illuminate\Database\Seeder; class UsersTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { + DB::table('users')->insert([ + 'name' => 'テスト', + 'email' => 'test@example.com', + 'password' => Hash::make('000000'), + ]); } } DatabaseSeeder.phpに以下を追記します。 database/seeds/DatabaseSeeder.php <?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { + $this->call(UsersTableSeeder::class); } } 編集が終わったら、DBに反映させます。 $php artisan db:seed データが入っているか、DBを確認してみましょう。 4. ルーティングの追加 退会処理を行うためのルーティングを追記します。 routes/web.php <?php Route::get('/', function () { return view('welcome'); }); Auth::routes(); Route::get('/home', 'HomeController@index')->name('home'); + Route::post('/user', 'UsersController@withdrawal')->name('user.withdrawal'); 5. viewの編集 今回は、ヘッダーの中に”退会する”というボタンを作成したいと思います。 本来はフォームだけでもいいのですが、既存のheaderに合わせてドロップダウンの中に表示させたいため、 aタグとformを使って実装しています。 confirm('本当に退会しますか?')はアラートを表示させるために記述しています 以下のような確認のアラートが出てきます。 document.getElementById('withdrawal-form').submit()は、 formのid="withdrawal-form"と指定している部分の要素を取得して .submit()で送信処理を行っています。 resources/views/layouts/app.php <body> <div id="app"> <nav class="navbar navbar-default navbar-static-top"> <div class="container"> <div class="collapse navbar-collapse" id="app-navbar-collapse"> ...省略 <!-- Right Side Of Navbar --> <ul class="nav navbar-nav navbar-right"> <!-- Authentication Links --> @guest <li><a href="{{ route('login') }}">Login</a></li> <li><a href="{{ route('register') }}">Register</a></li> @else <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true" v-pre> {{ Auth::user()->name }} <span class="caret"></span> </a> <ul class="dropdown-menu"> <li> <a href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();"> Logout </a> <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;"> {{ csrf_field() }} </form> </li> + <li> + <a href="{{ route('user.withdrawal') }}" + onclick="confirm('本当に退会しますか?'); + event.preventDefault(); + document.getElementById('withdrawal-form').submit();"> + 退会する + </a> + <form id="withdrawal-form" action="{{ route('user.withdrawal') }}" method="post" style="display: none;"> + {{ csrf_field() }} + </form> + </li> </ul> </li> @endguest </ul> </div> </div> </nav> @yield('content') </div> <!-- Scripts --> <script src="{{ asset('js/app.js') }}"></script> </body> 6. コントローラーの作成 まずは、UsersControllerを作成するコマンドを打ちます。 ターミナル $php artisan make:controller UsersController 作成されたら、中身を編集していきます。 Auth::user()は、ログインしている人の情報が取得できます。 ⚠️Authを使用するときはuseを書き忘れないように気をつけましょう。 $user->delete()で削除の処理を行います。 そして、Auth::logout()でログアウトさせています。 app/Http/Controllers/UserController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; + use Illuminate\Support\Facades\Auth; class UsersController extends Controller { + public function withdrawal() + { + $user = Auth::user(); + $user->delete(); + Auth::logout(); + return redirect(route('login')); + } } 7. 動作確認 ここまで作業ができましたら、動作の確認をしてみます。 ①サーバーを立ち上げる ②seederで入れた情報でログインする ③ヘッダーの"退会する"ボタンを押す ④再度、seederで入れた情報でログインしてみる ログインができなければ、きちんと退会機能ができています。 dbも確認してみましょう。 deleted_atの中に日時が入っていれば、OKです。 最後に 今回はルーティングにidを持たせず実装を行いました。 softdeleteを使用すると、とても簡単に実装ができました。 参考文献 この記事は以下の情報を参考にして執筆しました。 [Laravel] ソフトデリートと取得、復元、完全削除
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel facebookログインをローカル環境でテストしてみる。

初めに Facebook,Twitterログインをlaravelに実装したいけど、 それぞれの管理画面で見ると、localhostでは実装できないようになっている。 過去の記事では、できてたようですけど、厳しくなったらしい。 https必須とも記載ありました。 ngrokを使えば、HTTPSでも提供してくれるしできるんじゃね?と思い、試してみました。 SNSログイン完了後に情報を取得するまでが目的です。 結論 ngorkで発行されたURLをそれぞれのSNSの設定画面 コールバックURLを登録し、 .envに記載することでローカル環境でテストできました。 注意点 ngrok の無料プランは接続する度、払い出されるアドレスは変更されるので、 SNSの管理画面のリダイレクトuriと .envの APP_URLは都度変更が必要です。 めんどうであれば、有料プランに変更しましょう。 サーバーに公開する以外で他に簡単な方法あれば教えてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel8 Passport 調査して不思議に感じたこと

初めに laravelを触り始めて2月ほど経ちますが、 ここ数日 Passportを触ってみて面倒だな。と感じたことを残しておきます。 作成されるクライアントのIDが整数 phpmyadminで確認すると、IDがintでした。 シーケンス番号であれば問題ないのですが、実際に使用する際はIDを指定するので、intは困る。 google,facebookなどのSNSログインを実装すると知るのですが、client_idは英数字の羅列です。 ドキュメント記載のphp artisan passport:install --uuidsを実行するとユニークなIDを持ったテーブルを再構築できます。 しかし、この後 php artisan passport:installを実行すると IDにデフォルト値がないとエラーが発生します。 どうやらコマンド実行時に使用されるメソッドは ユニークなIDを発行する機能が存在しません。 今回は直接passportライブラリに追記します。 //ClientRepository.php public function create($userId, $name, $redirect, $provider = null, $personalAccess = false, $password = false, $confidential = true) { $client = Passport::client()->forceFill([ 'id' => (string) Str::orderedUuid(), //idにuuidを付与 'user_id' => $userId, 'name' => $name, 'secret' => ($confidential || $personalAccess) ? Str::random(40) : null, 'provider' => $provider, 'redirect' => $redirect, 'personal_access_client' => $personalAccess, 'password_client' => $password, 'revoked' => false, ]); $client->save(); } 再度コマンド実行することでクライアントを作成できます。 Which user ID should the client be assigned to?: > What should we name the client?: > ****** Where should we redirect the request after authorization? [http://localhost:8080/auth/callback]: > http:localhost:3000/callback.php New client created successfully. Here is your new client secret. This is the only time it will be shown so don't lose it! Client ID: ********************************** Client secret: ********************************** 使用しないルーティングを消すのが面倒だった。 複数の認証方法が使用できる為、RouteRegistrar.phpにルーティングが用意されています。 しかし、不要なルーティングの除外は設定として存在しません。 今回は、Passport.php RouteRegisterを上書きするディレクトリ[packages]を用意、 Composerに追記し、 dump-autoroadを実行し、 app/Providers/AuthServiceProvider に カスタマイズしたrouteを読み込みました。 //composer.jsonに追記 "autoload": { "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", "Database\\Seeders\\": "database/seeders/", "Custom\\": "packages/" //追加 } }, 修正後、 composer dump-autoload を実行し useで読み込めるようにする 他の方がルートを限定する書き方公開されていました。 こちらのほうが楽です。 公開するルートを限定する 用意されているPurgeコマンドが使いづらい。 無効・期限切れのトークンと認可コードを破棄する 無効なトークンと認可コードのみ破棄する 期限切れのトークンと認可コードのみ破棄する と用意されています。 しかし期限切れのトークンを削除するには、有効期限から本日から7日前を経過する必要があリました。 幅を持たせる為に7日前超過にしてるんですかね? でも、発行されたexpired_atをwhereで検索するので、そこまで幅を持たせる必要があるのかな... ドキュメント記載の有効期限を AuthServiceProvider::boot() 内に Passport::tokensExpireIn(now()->addMinutes(60)); を記載して変更しても実際のデータはしばらく残ります。 実際の運用状況で変わるかと思いますが、 config/passport.phpなどで柔軟に対応して欲しいです。 しかし、リフレッシュトークンからアクセストークンを再発行できるのでこのPurgeコマンドもどう使えばいいか悩みますね。 php artisan passport:purgeコマンド実行時のコード //PurgeCommand.php public function handle() { $expired = Carbon::now()->subDays(7); if (($this->option('revoked') && $this->option('expired')) || (! $this->option('revoked') && ! $this->option('expired'))) { Passport::token()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete(); Passport::authCode()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete(); Passport::refreshToken()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete(); $this->info('Purged revoked items and items expired for more than seven days.'); } elseif ($this->option('revoked')) { Passport::token()->where('revoked', 1)->delete(); Passport::authCode()->where('revoked', 1)->delete(); Passport::refreshToken()->where('revoked', 1)->delete(); $this->info('Purged revoked items.'); } elseif ($this->option('expired')) { Passport::token()->whereDate('expires_at', '<', $expired)->delete(); Passport::authCode()->whereDate('expires_at', '<', $expired)->delete(); Passport::refreshToken()->whereDate('expires_at', '<', $expired)->delete(); $this->info('Purged items expired for more than seven days.'); } } ※whereDate()は日付単位での検索になるので、 where()を使用すると分単位で指定できました。  終わり まだ、触ると疑問が出てきますが一旦これで終了します。 Laravel Passportを実際に使用しているサービスってあるんですかね。 ドキュメントだけでは少し不安です。 今回、参考にさせていただいた記事 Laravel Passportの使い方まとめ Query Builder(クエリビルダー) – 各種where句の使い方 Laravel SQLの実行クエリログを出力する > コンソール画面で表示できました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel6】ログをDBに出力(Monologを使う)

Laravel6でArtisanコマンド作成し、そのArtisanコマンドをバッチで実行するような実装をしていました。 ログ出力をlaravel.logではなく、DBに出力する必要があったため、Laravelに標準でインストールされているMonologというパッケージを利用しました。 バージョン:Laravel 6.20.32 作業内容 マイグレーションファイル、モデルの作成 app/Loggers/DbMonologHandler.phpの作成 config/logging.phpにチャネルを追加 .envに追記 Artisanコマンドにログを記述 マイグレーションファイル、モデルの作成 ログ出力先のテーブルを作成します。 今回はd_logsというテーブルを作成。DLogモデルを作成し、マイグレーションも一緒に作成します。 php artisan make:model DLog --migration モデルの記述 使用するテーブルを記載します。(省略した場合、モデル名DLogの場合、d_logsテーブルが使用されるので、省略可能。) すべてのカラムに値の代入可能とするので、protected $guarded = [];とします。 <?php namespace App\models; use Illuminate\Database\Eloquent\Model; class DLog extends Model { protected $table = 'd_logs'; protected $guarded = []; } マイグレーションの記述 id level(debugなら100、errorなら400など) level_name(INFOやERRORなど) message(エラーメッセージなど) 他に必要なカラムがあれば適宜追加してください。 <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class DLogsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('d_logs', function(Blueprint $table) { $table->bigIncrements('id'); $table->text('level')->nullable(); $table->text('level_name')->nullable(); $table->text('message')->nullable(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('d_logs'); } } app/Loggers/DbMonologHandler.phpの作成 今回出力する'level', 'level_name', 'message'を配列$dataに入れてあげます。 <?php namespace App\Loggers; use Illuminate\Support\Facades\DB; use Monolog\Handler\AbstractProcessingHandler; use Monolog\Logger; use App\Models\DLog; use Log; class DbMonologHandler extends AbstractProcessingHandler { public function __construct(string $table, string $connection, $level = Logger::DEBUG, $bubble = true) { $this->table = $table; $this->connection = $connection; parent::__construct($level, $bubble); } protected function write(array $record): void { $data = [ 'message' => $record['message'], 'level' => $record['level'], 'level_name' => $record['level_name'], ]; DLog::insert($data); } } config/logging.phpにチャネルを追加 既存の他のチャネルと同様の記述で、チャネルを追加します。(今回は'db'という名前で追加) ::classは、クラス名を名前空間と一緒に返しています。 'handler_with'で接続先などを指定します。env関数の第二引数には、デフォルト値を記述しているので、.envファイルに記述がない場合、この第二引数の値が使われます。 db' => [ 'driver' => 'monolog', 'handler' => DbMonologHandler::class, 'handler_with' => [ 'table' => env('DB_LOG_TABLE', 'd_logs'), 'connection' => env('DB_LOG_CONNECTION', env('DB_CONNECTION', 'mysql')), ], ], チャネルの一番上、stackに記載のチャネルにログが出力されるので、作成した'db'チャネルを追記します。 'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => ['single', 'db'], 'ignore_exceptions' => false, ], .envに追記 .envファイルに下記を追記。(書かない場合は、logging.phpのenv関数の第二引数の値が使われる。) DB_LOG_TABLE=d_logs DB_LOG_CONNECTION=mysql Artisanコマンドにログを記述 今回は、特定のArtisanコマンドを実行した際に、ログがDBに出力されるようにしたいので、ArtisanコマンドにLogファサードで記述します。今回はバッチでデータをインポートしているので、 インポート開始 インポート完了 エラーメッセージ ロールバック完了 などのログを出力しています。 <?php namespace App\Console\Commands; use Illuminate\Console\Command; use App\Services\UpsertAllByCsvService; use Log; use DB; class ImportOrderDataSetByCsv extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'ImportOrderDataSetByCsv'; /** * The console command description. * * @var string */ protected $description = 'Upsert tables concerned about orders'; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return mixed */ public function handle() { Log::info('インポート開始'); DB::beginTransaction(); try { UpsertAllByCsvService::getOrdersDataByCsv('test'); UpsertAllByCsvService::getOrderDetailsDataByCsv('test'); UpsertAllByCsvService::getShippingsDataByCsv('test'); UpsertAllByCsvService::getShipmentItemsDataByCsv('test'); DB::commit(); Log::info('インポート完了'); } catch (\Exception $e) { DB::rollback(); Log::error($e->getMessage()); Log::info('ロールバック完了'); } } } このArtisanコマンドをTinkerで実行すると、d_logsテーブルにレコードが追加されました! ロールバックのタイミングに注意。ログテーブルのidが飛んでいる場合、ログは生成されているのに、そのログ出力も含めてロールバックされている可能性があります。 この記述だと、DbMonologHandlerで出力されるログは、laravel.logにも出力されます。 DBにのみ出力したい場合は、logging.phpのチャネル設定にて、stackには'db'を記載せず、 ログファサードを使う時に、Log::channel('db')->info('インポート開始');のように記述してください。 参考 https://qiita.com/kd9951/items/35b0a0c4e16353078b70 https://qiita.com/hirorin/items/409a66e63bb3b16245eb
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP のせいでtimestampのカラムが勝手に更新されてしまう

timestampはデフォルトで, CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP属性がつく マイグレーションファイルでtimestampのカラムを設定すると, レコードを更新すると日付が自動更新されるようになっています. DBを確認すると, カラムの属性にCURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPがついています. これを消せばカラムが自動更新することがなくなります. migrate.php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class TestTable extends Migration { public function up() { Schema::create('test_tables', function (Blueprint $table) { $table->timestamp('output_at')->comment('出力日時'); }); } // 略 } nullableにするだけ マイグレーションファイルのカラムを設定するときにnullableと追加すると, CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPが消えるようになります. migrate_new.php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class TestTable extends Migration { public function up() { Schema::create('test_tables', function (Blueprint $table) { $table->timestamp('output_at')->nullable()->comment('出力日時'); }); } // 略
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

おい!なんでその処理をコントローラに書いているんだい?

ある日のパイセン、「データ操作の処理は、コントローラに書かないでくれよ!」 なんだって? そしたらいったい、どこに書けというんだい? モデル? リポジトリ? もっと言えばなぜ、コントローラに書いたらいけないんだい? ファットコントローラを避けるため? 責務を分散させるため? わからないことだらけじゃないか! そんなふうに思っているそこのキミ。 今日はボクがとっておきのモノを紹介しよう! ボクはこれを知って世界が変わったんだ 今まで何となくやる気がでなかったり 身体が重かったりする実装が これを使うことですごくスッキリしてね! なんていうか、幸福感に包まれるんだ。 生きるのが楽しくなるよ。 1度知るともうこれを知らなかった頃の実装には戻れないね。 本当にとっておきなんだ。 いいかい、ママには内緒だよ? 少し知るだけで幸せが訪れる、それがドメイン駆動開発さ ああ、たまたまだったんだよ。 RepositryやServiceという言葉は知っているし、 なんとなく役割もわかる。 なんなら使ったこともある。 そんなボクがこの本を手にとったのはね。 ドメイン駆動開発設計入門 半分くらいまでこの本を読んだボクは、 慣れ親しんだMVCフレームワークの見え方が劇的に変わったんだ! ただ今日触れるのは、ドメイン駆動開発そのものではなく ドメイン駆動開発の考え方を反映したとき どんな処理をどこに書くかということだ ドメイン駆動開発(DDD)について気になる人は ぜひ学んでボクに教えてくれ! Modelには、そのモデルの持つふるまいを書く DDDにおいてのモデルとは何か、みたいな話は置いておこう。 ボクはそれを語れるほど精通しちゃいないからね! (おっと、ちゃんとあっちの精通はしているぞ!) 例えばブログがあったとしよう。 ブログには記事、つまりArticleのようなモデルが存在するはずだろう? Articleには、タイトルと、内容があるだろう タイトルにいたっては、文字数制限があるかもしれないな Articleモデル タイトルが必ず存在する タイトルは30文字以内である 内容が必ず存在する これが、Articleモデルの持つふるまいだ 逆に、こういうふるまいがなければArticleじゃない! ブログの記事に、ビールの在庫なんて項目は登録できないだろう? 登録できたらきっとそれは ボクの家の冷蔵庫のモデルだな! Serviceには、モデルのユースケースを書く Articleには、作成や編集、削除といったユースケースがあるはずだ Serviceにはそんなモデルのユースケースを書いていく Articleサービス 記事を作成できる 記事を確認できる 記事を編集できる 記事を削除できる ここで余談だが、DDDには ドメインサービスとアプリケーションサービスがある その違いは、ここで話すことではないから、ぜひ調べてみてくれ! Repositoryには、モデルのデータの永続化・再構築を書く ModelとServiceをつくったところで ブログはまだ、まったく使い物にはならないな! なにせ、データの永続化(保存)・再構築(復元)ができないんだから! 今のブログはまるで、 料理のできないレストラン、ビールの飲めない人生みたいだ! データの永続化や再構築をするときは、そのモデルのふるまいを いれてあげないとな! Articleリポジトリ 記事を保存できる ┗Articleモデル・ふるまい 記事を復元できる 記事を削除できる そして、データの永続化・再構築ができるようになったら、 Serviceに使えるだろう! Articleサービス 記事を作成できる ┗Articleリポジトリ・保存できる 記事を確認できる ┗Articleリポジトリ・復元できる 記事を編集できる ┗Articleリポジトリ・保存できる 記事を削除できる ┗Articleリポジトリ・削除できる また余談になってしまうが、 ハンバーガーの間のポテトやコークだと思って楽しんでくれ! 本来なら RepositoryにはInterfaceをつくったほうがいい それは、依存関係逆転の原則があるからだ 残念ながら、依存関係逆転の原則や interfaceとは何か、はここで話すことではないんだ ハンバーガー屋でも、小麦粉そのものは売ってないんでね! Controllerはどこへいった? ねえママ! Controllerをどこにやったんだい? ちゃんとここに置いておいたのに! そう思ったかい? モデルのふるまいをModelに ユースケースをServiceに データの永続化・再構築をRepositoryに 書くようにしたことで Controllerには、ほとんど書くことがなくなってしまった! しかし、それでいいんだ Controllerはフロントと、これらのロジックとのデータの橋渡しをするだけでいい! こう考えると、太る理由がわからないだろう? え?ゴシップ好きのトニーがなんで太ってるかって? 彼はハンバーガーの食べすぎさ! ドメイン駆動開発、少量でもこの高揚感! ここまで読んでくれたキミ、ありがとう! ボクはドメイン駆動開発の、ほんの少ししか齧っていないけれど 少量でもとてつもない高揚感に包まれているよ! 最初はあまりにもブッ飛ぶもんだから 人目につきやすいところ使うときは気をつけてくれよな! Follow ME !!! I'm sure to follow you back! twitter: @marty_ojiya
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む