
https://github.com/yuukanehiro/Laravel-Study/tree/master/Laravel-Pokemon-RepositoryPettern
よくある処理の流れのルーティンをポケモンのモデルを利用して作ってみました。
ソースコードを読めても、実際にどれだけ自分が使えるかわからなかったので。書いて確認しました(。- .•)
もくじ
関連
http://localhost/getMasters/{id}

http://localhost/getMasters/

http://localhost/fight/{id}

ルーティング
routes/web.php
Route::get('/getMasters', 'PokemonMasterController@getMasters');
Route::get('/getMasters/{id}', 'PokemonMasterController@getMaster');
Route::get('/fight/{id}', 'PokemonMasterController@fight');
モデル
- Eloqunetで標準的に取得できるような値を取得する
- 各フィールドの値
- リレーション定義
Models/Master.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
class Master extends Model
{
protected $table = 'masters';
protected $primaryKey = 'master_id';
protected $guarded = [
'master_id'
];
public function pokemon()
{
return $this->belongsToMany('App\Models\Pokemon');
}
public function master_pokemon()
{
return $this->belongsToMany('App\Models\Pokemon',
'master_pokemon',
'master_id',
'pokemon_id')
->withPivot('comment');
}
public function getCntBattle(int $id = null): ?int
{
return $this->cnt_battle;
}
public function getCntWon(int $id = null): ?int
{
return $this->cnt_won;
}
public function getWinningPercentAttribute(): ?float
{
if ($this->getCntBattle() === 0) {
return null;
}
return $this->getCntWon() / $this->getCntBattle();
}
}
Models/Pokemon.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use phpDocumentor\Reflection\Types\Object_;
class Pokemon extends Model
{
protected $table = 'pokemons';
protected $primaryKey = 'pokemon_id';
protected $guarded = [
'pokemon_id'
];
public function master()
{
return $this->belongsToMany('App\Models\Master');
}
public function master_pokemon()
{
return $this->belongsToMany('App\Models\Master', 'master_pokemon', 'pokemon_id', 'master_id')
->withPivot('comment');
}
public static function getPokemonName(int $id) :Object
{
return Pokemon::select('name')->find($id);
}
}
マイグレーションファイル
テーブル定義ファイル
pokemonsテーブル
xxxx_create_pokemons_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePokemonsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('pokemons', function (Blueprint $table) {
$table->bigIncrements('pokemon_id');
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('pokemons');
}
}
mastersテーブル
xxxx_create_masters_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMasterPokemonTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('master_pokemon', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('master_id')->unsigned();
$table->bigInteger('pokemon_id')->unsigned();
$table->string('comment');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('master_pokemon');
}
}
中間テーブル
xxxx_create_master_pokemon_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMasterPokemonTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('master_pokemon', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('master_id')->unsigned();
$table->bigInteger('pokemon_id')->unsigned();
$table->string('comment');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('master_pokemon');
}
}
シーダファイル
テーブルデータのサンプルを流します。
MasterTableSeeder.php
<?php
use Illuminate\Database\Seeder;
class MastersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$master = new \App\Models\Master([
'name' => 'さとし',
'cnt_battle' => 10,
'cnt_won' => 4,
]);
$master->save();
$master = new \App\Models\Master([
'name' => 'たけし',
'cnt_battle' => 100,
'cnt_won' => 20,
]);
$master->save();
$master = new \App\Models\Master([
'name' => 'かすみ'
]);
$master->save();
$master = new \App\Models\Master([
'name' => 'こじろう'
]);
$master->save();
}
}
PokemonTableSeeder.php
<?php
use Illuminate\Database\Seeder;
class PokemonsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$pokemon = new \App\Models\Pokemon([
'name' => 'ピカチュウ'
]);
$pokemon->save();
$pokemon = new \App\Models\Pokemon([
'name' => 'イワーク'
]);
$pokemon->save();
$pokemon = new \App\Models\Pokemon([
'name' => 'スターミー'
]);
$pokemon->save();
$pokemon = new \App\Models\Pokemon([
'name' => 'ニャース'
]);
$pokemon->save();
}
}
Master_PokemonTableSeeder.php
<?php
use Illuminate\Database\Seeder;
class Master_PokemonTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('master_pokemon')->insert([
'master_id' => 1,
'pokemon_id' => 1,
'comment' => "キミに決めた!",
]);
DB::table('master_pokemon')->insert([
'master_id' => 2,
'pokemon_id' => 2,
'comment' => "イワーク、ご苦労だった。"
]);
DB::table('master_pokemon')->insert([
'master_id' => 3,
'pokemon_id' => 3,
'comment' => "いけー!マイ ステディ!"
]);
DB::table('master_pokemon')->insert([
'master_id' => 4,
'pokemon_id' => 4,
'comment' => "ニャースでニャース! (せりふ) うるさい!"
]);
DB::table('master_pokemon')->insert([
'master_id' => 4,
'pokemon_id' => 1,
'comment' => "ピカチュウ!捕まえた〜!",
]);
}
}
AppServiceProvider.php
ワンポイント!
AppServiceProviderで『関連(new)』を行います。
App/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->bind(
\App\Repositories\MasterRepository::class,
function ($app) {
return new \App\Repositories\MasterRepository(new \App\Models\Master);
}
);
$this->app->bind(
\App\Service\PokemonMasterService::class,
function ($app) {
return new App\Service\MasterService(
$app->make('\App\Repositories\MasterRepository')
);
}
);
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
}
AppServiceProvider.phpで指定することで、
リポジトリ(app/Repositories/MasterRepository.php)とサービス(app/Http/Services/Service.php)のコンストラクタでnewしなくて良いようになっています。
例) app/Repositories/MasterRepository.php
class MasterRepository extends Repository
{
public function __construct(Model $model)
{
$this->model = $model;
}
・・・
Modelクラスの指定となっている。
app/Http/Services/Service.php
class PokemonMasterService extends Service
{
private $MasterRepository;
public function __construct(
MasterRepository $MasterRepository
) {
$this->MasterRepository = $MasterRepository;
}
・・・
newしていない。
リポジトリ
- モデルの集合対
- モデルやEloquentを利用したDB処理を行う
app/Repositories/Repository.php
<?php
namespace App\Http\Repositories;
use Illuminate\Database\Eloquent\Model;
abstract class Repository
{
protected $model;
}
app/Repositories/MasterRepository.php
<?php
namespace App\Repositories;
use Illuminate\Database\Eloquent\Model;
use App\Repositories\Repository;
use Illuminate\Database\Eloquent\Collection;
class MasterRepository extends Repository
{
public function __construct(Model $model)
{
$this->model = $model;
}
/**
* バトルの勝利処理
*
* @param int $id
* @return void
*/
public function win(int $id): void
{
$master = $this->model->find($id);
$master->increment('cnt_battle');
$master->increment('cnt_won');
}
/**
* バトルの負け処理
*
* @param int $id
* @return void
*/
public function lose(int $id): void
{
$master = $this->model->find($id);
$master->increment('cnt_battle');
}
/**
* IDを指定してMasterユーザを表示
*
* @param int $id
* @return Collection
*/
public function getMasterById(int $id): Collection
{
$master = $this->model->where('master_id', $id)->get();
return $master;
}
/**
* Masterユーザをリスト表示
*
* @return Collection
*/
public function getAllMaster(): Collection
{
$master = $this->model->get();
return $master;
}
}
サービス
- リポジトリを利用してビジネスロジックを行う
- サービスと言えるような一連のまとまった処理を担当
app/Http/Services/Service.php
<?php
namespace App\Services;
abstract class Service
{
//
}
app/Http/Services/PokemonMasterService.php
<?php
namespace App\Http\Services;
use App\Repositories\MasterRepository;
use App\Models\Master;
use App\Services\Service;
class PokemonMasterService extends Service
{
private $MasterRepository;
public function __construct(
MasterRepository $MasterRepository
) {
$this->MasterRepository = $MasterRepository;
}
public function battle(int $id): array
{
/**
* サイコロバトル
* 偶数:勝ち
* 奇数:負け
*
* @param $id int
* @return float
*/
$dice = (int) rand(1,6);
$result = $dice % 2? 'even' : 'odd';
if ($result === 'even') {
$this->MasterRepository->win($id);
$battleResult['result'] = 'win';
} else {
$this->MasterRepository->lose($id);
$battleResult['result'] = 'lose';
}
return $battleResult;
}
}
ビューモデル
- 仮想カラムを追加
- オブジェクトの付与
- JSONで返すデータの集合体
モデルだけだとテーブルの値そのままなので、ビューモデルを返すオブジェクトを定義して返却します。
app/Http/ViewModel.php
<?php
namespace App\Http\ViewModels;
use Illuminate\Support\Fluent;
abstract class ViewModel extends Fluent
{
abstract public function render();
}
app/Http/MasterViewModel.php
<?php
namespace App\Http\ViewModels;
use App\Models\Master;
use App\Http\Repositories\PokemonMasterRepository;
class MasterViewModel extends ViewModel
{
public function render(): Master
{
return $this->master
->append('winning_percent')
->makeHidden(['master_id',
'created_at',
'updated_at'
]);
}
}
コントローラ
- リクエストの処理を担当
app/Http/Controller.php
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}
app/Http/PokemonMasterController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Services\PokemonMasterService;
use App\Repositories\MasterRepository;
use App\Http\ViewModels\MasterViewModel;
use Illuminate\Routing\ResponseFactory;
class PokemonMasterController extends Controller
{
/**
* Masterユーザをidを指定して取得
*
* @param App\Repositories\MasterRepository $MasterRepository
* @param Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function getMaster(
MasterRepository $MasterRepository,
Request $request
) {
$userId = $request->id;
$master = $MasterRepository->getMasterById($userId);
$responseMaster = $master
->map(function ($item, $key){
return (new MasterViewModel(['master' => $item]))->render();
});
return response()->json($responseMaster);
}
/**
* Masterユーザをリスト取得
*
* @param App\Repositories\MasterRepository $MasterRepository
* @return \Illuminate\Http\Response
*/
public function getMasters(
MasterRepository $MasterRepository,
Request $request
) {
$master = $MasterRepository->getAllMaster();
$responseMaster = $master
->map(function ($item, $key){
return (new MasterViewModel(['master' => $item]))->render();
});
return response()->json($responseMaster);
}
/**
* じゃんけんバトルを行って結果を返却
*
* @param App\Http\Services\PokemonMasterService $pokemonMasterService
* @return \Illuminate\Http\Response
*/
public function fight(
PokemonMasterService $pokemonMasterService,
Request $request
) {
$userId = $request->id;
$battleResult = $pokemonMasterService->battle($userId);
return response()->json($battleResult);
}
}
モデルのフィールドをまとめる
public function getMasterSpecAttribute()
{
if ($this->master_spec_tairyoku === null) {
return null;
}
return [
'tairyoku' => $this->master_spec_tairyoku,
'kawaii' => $this->master_spec_kawaii,
'money' => $this->master_spec_money,
];
}
仮想カラム
『 masuter_spec』 のキーに配列として
- tairyoku
- kawaii
- money
が追加される
[amazon_link asins=’4798052582′ template=’ProductCarousel’ store=’izayoi55-22′ marketplace=’JP’ link_id=’f1a3a821-2747-47c4-90e9-8af2f8583fa3′]
[amazon_link asins=’4798059072′ template=’ProductCarousel’ store=’izayoi55-22′ marketplace=’JP’ link_id=’7af12ba9-cd06-4de0-88a7-a8c932c716c2′]
[amazon_link asins=’4802611846,B01FH3KVNU’ template=’ProductCarousel’ store=’izayoi55-22′ marketplace=’JP’ link_id=’56c7eaa0-a570-41fc-9fed-bf656b6f3043′]

