Edited at

Laravel5を使ってドメイン駆動設計で作るサンプルアプリ。

More than 3 years have passed since last update.


Laravel5で変更に強いアプリケーションを作成する。

サンプルとして経費(本)を記録するだけのWebアプリケーションを作成。

日付、タイトル、価格、URLを1テーブルにしてMySQLへ格納。


Laravelインストール

% composer create-project laravel/laravel keihi

% cd keihi

% php artisan -V
Laravel Framework version 5.1.20 (LTS)


名前空間を更新

Keihiという名前空間にします。

// namespaceを「App」から「Keihi」へ変更

% php artisan app:name Keihi

namespace指定してある箇所が全部以下のように変更されます。


composer.json

         "psr-4": {

- "App\\": "app/"
+ "Keihi\\": "app/"
}


app/Console/Kernel.php

 <?php

-namespace App\Console;
+namespace Keihi\Console;



Databaseを用意


MAMPでMYSQLサーバー起動、UTF8でDB作成。

以下、MAMPのソケットで繋ぐときに必要な処理。


UNIX_SOCKET追記


/config/database.php

        'mysql' => [

'driver' => 'mysql',
'unix_socket' => env('DB_UNIX_SOCKET'),// 1行追記
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),


.envのDB設定を編集してDB_UNIX_SOCKETは追記。


.env

DB_UNIX_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock

DB_HOST=localhost
DB_DATABASE=keihi_db
DB_USERNAME=test
DB_PASSWORD=test


マイグレーション作成


作成コマンド

% php artisan make:migration create_keihi_table --create=keihi 

Created Migration: 2015_10_23_235515_create_keihi_table


ファイル編集


/database/migrations/2015_10_23_235515_create_keihi_table.php

public function up()

{
Schema::create('keihi', function (Blueprint $table) {
$table->increments('id'); // ID
$table->char('title', 100); // タイトル
$table->integer('price'); // 価格
$table->text('url'); // URL
$table->timestamps(); // 作成時刻
});
}


マイグレーション実行

MySQLにテーブルが作成。(keihi以外はデフォルトで存在するもの)

% php artisan migrate

Migration table created successfully.
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrated: 2015_10_23_235515_create_keihi_table


エレクエント作成

Keihiモデル(/app/Keihi.php)を作成。

% php artisan make:model Keihi


エレクエント編集

Keihiモデルに紐づくテーブルを「keihi」に設定。


/app/Keihi.php

<?php

namespace Keihi;

use Illuminate\Database\Eloquent\Model;

class Keihi extends Model
{
protected $table = 'keihi';
}



リポジトリ作成


インターフェース作成


/app/Repositories/KeihiInterface.php

<?php

/**
* Interface KeihiInterface
*/

interface KeihiInterface
{
/**
* 取得
* @param $id
* @return mixed
*/

public function get($id);

/**
* 一覧取得
* @return mixed
*/

public function getList();

/**
* 更新
* @param $id
* @param $data
* @return mixed
*/

public function update($id, $data);

/**
* 新規登録
* @param $data
* @return mixed
*/

public function create($data);

/**
* 削除
* @param $id
* @return mixed
*/

public function delete($id);
}



リポジトリ実装

インターフェースを使用して実装します。

コンストラクタでエレクエントモデルを依存注入します。


/app/Repositories/KeihiRepository.php

<?php

namespace Keihi\Repositories;

use Keihi\Repositories\KeihiInterface;
use Keihi\Keihi;

/**
* Class KeihiRepository
* @package Keihi\Repositories
*/

class KeihiRepository implements KeihiInterface
{
/**
* @var Keihi
*/

protected $keihi;

/**
* @param Keihi $keihi
*/

public function __construct(Keihi $keihi)
{
$this->keihi = $keihi;
}

/**
* 取得
* @param $id
* @return mixed
*/

public function get($id)
{
     
}



サービスプロバイダー作成

リポジトリ用のサービスプロバイダー作成

php artisan make:provider RepositoryProvider


サービスプロバイダー編集


/app/Providers/RepositoryProvider.php

    /**

* Register the application services.
*
* @return void
*/

public function register()
{
// 経費インターフェスと経費リポジトリの連結
$this->app->bind(KeihiInterface::class, KeihiRepository::class);
}


リポジトリサービスプロバイダーの読込


/config/app.php

        /*

* Application Service Providers...
*/

Keihi\Providers\AppServiceProvider::class,
Keihi\Providers\AuthServiceProvider::class,
Keihi\Providers\EventServiceProvider::class,
Keihi\Providers\RouteServiceProvider::class,
Keihi\Providers\RepositoryProvider::class,// 1行追加
],


テストデータ投入


シーダー作成

% php artisan make:seeder KeihiSeeder


シーダー編集

エレクエントモデルを利用してテスト用データを記述。


/database/seeds/KeihiSeeder.php

<?php

use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Keihi\Keihi;

class KeihiSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/

public function run()
{
Model::unguard();
Keihi::create([
'id' => 1,
'title' => 'WEB+DB PRESS Vol.89',
'price' => 1598,
'url' => 'http://www.amazon.co.jp/gp/product/4774176389'
]);
Keihi::create([
'id' => 2,
'title' => 'Docker実践入門――Linuxコンテナ技術の基礎から応用まで (Software Design plus)',
'price' => 2894,
'url' => 'http://www.amazon.co.jp/gp/product/4774176540'
]);
Keihi::create([
'id' => 3,
'title' => 'HTML5 Web標準API バイブル',
'price' => 3218,
'url' => 'http://www.amazon.co.jp/gp/product/4774176540'
]);
}
}



データ投入

% php artisan db:seed --class=KeihiSeeder


単体テスト(PHPUnit)

単体テスト作成


/tests/Repositories/KeihiRepositoryTest.php

<?php

use Keihi\Repositories\KeihiInterface;

class KeihiRepositoryTest extends TestCase
{
protected $repo;

public function setUp()
{
parent::setUp();
$this->repo = $this->app->make(KeihiInterface::class);
}

public function testGet()
{
$result = $this->repo->get(1);
$this->assertSame($result->title, 'WEB+DB PRESS Vol.89');
$this->assertSame($result->price, 1598);
$this->assertSame($result->url, 'http://www.amazon.co.jp/gp/product/4774176389');
}

public function testGetList()
{
$result = $this->repo->getList();
$this->assertCount(3, $result);
$this->assertSame($result[2]->title, 'HTML5 Web標準API バイブル');
$this->assertSame($result[2]->price, 3218);
$this->assertSame($result[2]->url, 'http://www.amazon.co.jp/gp/product/4774176540');
}

}



単体テスト実行

% php vendor/bin/phpunit --tap

TAP version 13
ok 1 - ExampleTest::testBasicExample
ok 2 - KeihiRepositoryTest::testGet
ok 3 - KeihiRepositoryTest::testGetList
1..3


サービス作成

コーントローラー内でリポジトリを操作する為のサービスを作成。

インターフェースを作成。


/app/Services/KeihiServiceInterface.php

/**

* Interface KeihiServiceInterface
* @package Keihi\Services
*/

interface KeihiServiceInterface
{
/**
* 単体取得
* @return mixed
*/

public function get($id);

/**
* 一覧取得
* @return mixed
*/

public function getList();

/**
* 保存
* @param $input
* @param $id | null
* @return $id | null
*/

public function save($input, $id=null);

/**
* 削除
* @param $id
* @return $id
*/

public function delete($id);

/**
* エンティティ作成
* @return $entity
*/

public function createEntity();


インターフェースを使用して実装。

データ検証の役割を持たせる。


/app/Services/KeihiService.php

<?php

namespace Keihi\Services;

use Keihi\Services\KeihiServiceInterface;
use Keihi\Repositories\KeihiInterface;
use Illuminate\Validation\Factory as ValidateFactory;

/**
* Class KeihiService
* @package Keihi\Services
*/

class KeihiService implements KeihiServiceInterface
{
/**
* @var KeihiInterface
*/

protected $keihiInterface;

/**
* @var ValidateFactory
*/

protected $validateFactory;

/**
* @var array
*/

protected $rules = ["title" => "required|max: 100", "price" => "required|integer|min:0|max:100000", "url" => "required"];

/**
* @param KeihiInterface $keihiInterface
* @param ValidateFactory $validateFactory
*/

public function __construct(KeihiInterface $keihiInterface, ValidateFactory $validateFactory)
{
$this->keihiInterface = $keihiInterface;
$this->validateFactory = $validateFactory;
}

/**
* @param $id
* @return mixed
*/

public function get($id)
{
return $this->keihiInterface->get($id);
}

/**
* @return mixed
*/

public function getList()
{
return $this->keihiInterface->getList();
}

/**
* @param $request
* @param $id
* @return $id
*/

public function save($request, $id=null)
{
$input = $request->only(['title', 'price', 'url']);
$v = $this->validateFactory->make($input, $this->rules);
if ($v->fails()) {
return null;
}

if (is_null($id)) {
$id = $this->keihiInterface->create($input);
} else {
$id = $this->keihiInterface->update($id, $input);
}

return $id;
}

/**
* @param $id
* @return bool
*/

public function delete($id)
{
$this->keihiInterface->delete($id);
return true;
}

/**
* @return mixed
*/

public function createEntity()
{
return $this->keihiInterface->createEntity();
}
}


Appサービスプロバイダーに登録。


/app/Providers/AppServiceProvider.php

    /**

* Register any application services.
*
* @return void
*/

public function register()
{
// 経費サービス
$this->app->singleton(KeihiServiceInterface::class, KeihiService::class);
}


コントローラー作成。

経費サービスインターフェースを依存注入して使用します。

% php artisan make:controller KeihiController


/app/Http/Controllers/KeihiController.php

<?php

namespace Keihi\Http\Controllers;

use Illuminate\Http\Request;
use Keihi\Http\Requests;
use Keihi\Http\Controllers\Controller;
use Keihi\Services\KeihiServiceInterface;

/**
* Class KeihiController
* @package Keihi\Http\Controllers
*/

class KeihiController extends Controller
{
/**
* @var KeihiServiceInterface
*/

private $keihiService;

/**
* @param KeihiServiceInterface $keihiServiceInterface
*/

public function __construct(KeihiServiceInterface $keihiServiceInterface)
{
$this->keihiService = $keihiServiceInterface;
}

/**
* 一覧
* @return \Illuminate\Http\Response
*/

public function index()
{
$list = $this->keihiService->getList();
return view('keihi.list', compact('list'));
}

/**
* 新規入力画面
* @return \Illuminate\Http\Response
*/

public function create()
{
$keihi = $this->keihiService->createEntity();
return view('keihi.edit', compact('keihi'));
}

/**
* 新規登録処理
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/

public function store(Request $request)
{
$id = $this->keihiService->save($request);
return $this->show($id);
}

/**
* 詳細
* @param int $id
* @return \Illuminate\Http\Response
*/

public function show($id)
{
$keihi = $this->keihiService->get($id);
return view('keihi.detail', compact('keihi'));
}

/**
* 編集画面
* @param int $id
* @return \Illuminate\Http\Response
*/

public function edit($id)
{
$keihi = $this->keihiService->get($id);
return view('keihi.edit', compact('keihi'));
}

/**
* 更新処理
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/

public function update(Request $request, $id)
{
$id = $this->keihiService->save($request, $id);
return $this->show($id);
}

/**
* 削除処理
*
* @param int $id
* @return \Illuminate\Http\Response
*/

public function destroy($id)
{
$this->keihiService->delete($id);
return $this->index();
}
}



ルーティング


/app/Http/routes.php

Route::resource('keihi', 'KeihiController');


ルーティングの確認。

% php artisan route:list

+--------+----------+--------------------+---------------+------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+--------------------+---------------+------------------------------------------------+------------+
| | GET|HEAD | / | | Closure | |
| | GET|HEAD | keihi | keihi.index | Keihi\Http\Controllers\KeihiController@index | |
| | POST | keihi | keihi.store | Keihi\Http\Controllers\KeihiController@store | |
| | GET|HEAD | keihi/create | keihi.create | Keihi\Http\Controllers\KeihiController@create | |
| | DELETE | keihi/{keihi} | keihi.destroy | Keihi\Http\Controllers\KeihiController@destroy | |
| | PATCH | keihi/{keihi} | | Keihi\Http\Controllers\KeihiController@update | |
| | GET|HEAD | keihi/{keihi} | keihi.show | Keihi\Http\Controllers\KeihiController@show | |
| | PUT | keihi/{keihi} | keihi.update | Keihi\Http\Controllers\KeihiController@update | |
| | GET|HEAD | keihi/{keihi}/edit | keihi.edit | Keihi\Http\Controllers\KeihiController@edit | |
+--------+----------+--------------------+---------------+------------------------------------------------+------------+