SlideShare a Scribd company logo
PHP 2大
web フレームワークの
徹底比較!
サポーターズ勉強会@株式会社ウィルゲート Room0
池添 誠(いけぞえ まこと)
• 開発グループ コンテンツユニット所属
• 2015年にウィルゲートに新卒入社(3年目)
• クラウドソーシングサービスのサグーワークスの開発
• 今日は CakePHP 担当
2
自己紹介
池添 誠(いけぞえ まこと)
• 開発グループ コンテンツユニット所属
• 2015年にウィルゲートに新卒入社(3年目)
• クラウドソーシングサービスのサグーワークスの開発
• 今日は CakePHP 担当
3
自己紹介
テストコード
いいぞ
岡田 正平(おかだ しょうへい)
• 開発グループ ソリューションユニット所属
• 2015年にウィルゲートに新卒入社(3年目)
• webコンサルティングツールの開発
• 今日は Laravel 担当
4
自己紹介
岡田 正平(おかだ しょうへい)
• 開発グループ ソリューションユニット所属
• 2015年にウィルゲートに新卒入社(3年目)
• webコンサルティングツールの開発
• 今日は Laravel 担当
5
自己紹介
Vue.js いいぞ
1. 背景
2. Model 層の比較
3. View 層の比較
4. Controller 層の比較
5. その他特徴
6. 全体考察・まとめ
6
目次
1. 背景
2. Model 層の比較
3. View 層の比較
4. Controller 層の比較
5. その他特徴
6. 全体考察・まとめ
7
目次
• もともと CakePHP のみを利用していた
• オフショア開発をやっていた時代にベトナムの開発チームから
Laravel を使いたいという要望が出て採用
• 以降、ソリューションチームでは Laravel が主流に
• 1つ1つのシステムが小粒なので毎回違う技術を選べる
• Slim や FuelPHP を採用したシステムも
• 「チーム移動時のコスト」 < 「多様性により得られる恩恵」
• 同じPHP なので、そこまで大きなギャップではない
• 新たな知見を得られやすい
8
背景 - なぜフレームワークが混在しているか
• サグーワークスのリニューアル(2017年1月)
• CakePHP 1.3 → CakePHP 3.2 にバージョンアップ
• https://www.wantedly.com/companies/willgate2/post_a
rticles/70451
• 新しいコンサルティングツール開発(現在開発中)
• Laravel 5.4 を採用
• 社内に双方の最新メジャーバージョンの知見
• → 「比較・考察は価値のある情報になるのでは?」
9
背景 – 今回の勉強会開催の理由
10
11
徹底比較!!
注意:対象バージョン
• 特に断りのない限り、メインのプロダクトで採用されている
を対象とします。
※2017年9月13日現在の最新バージョンは CakePHP 3.5 および Laravel 5.5
CakePHP 3.2 Laravel 5.4
12
注意:スライドの内容
• 公式サイト等からの引用については枠線で囲い
斜字体で表記します
例)
• 実際に利用したうえでの私見や考察には
「【私見】」や「【考察】」と明記します
13
The Model layer represents the part of your application that implements the
business logic.
モデル層はビジネスロジックを実装するアプリケーションの部品を表しま
す。
1. 背景
2. Model 層の比較
3. View 層の比較
4. Controller 層の比較
5. その他特徴
6. 全体考察・まとめ
14
目次
• ディレクトリ
15
Model 層の比較
The Model layer represents the part of your application that implements the
business logic.
モデル層はビジネスロジックを実装するアプリケーションの部品を表しま
す。
.
├── src/
: :
│ ├── Model/
│ │ ├── Behavior/
│ │ ├── Entity/
│ │ └── Table/
: :
• CakePHP ORM
• 3つの概念に分かれる
• Table
• Entity
• Behavior
16
Model 層の比較
The CakePHP ORM borrows ideas and concepts from both ActiveRecord and
Datamapper patterns. It aims to create a hybrid implementation that
combines aspects of both patterns to create a fast, simple to use ORM.
CakePHP の ORM はアクティブレコードやデータマッパーパターンのアイ
デアやコンセプトを拝借しています。 その目的は、早く作成し、シンプ
ルに ORM を利用するという2つの利点を混成させるためです。
• Table
• Entity
17
Model 層の比較
They allow you to save new records, modify/delete existing ones, define
relations, and perform bulk operations.
これらを利用することで、新しいレコードを保存したり、 既存データの
編集/削除、リレーションの定義、そして一括処理ができます。
Entities represent individual records and allow you to define row/record level
behavior & functionality.
エンティティーは、個々のレコードを意味し、 行/レコードレベルの振る
舞いや機能の定義を可能にします。
• Behavior
• 【考察】
• 処理の種類ごとに記述する場所が規約で決められている
• どこに書くべきか、悩まずに記述できる
• 組み合わせやすい分類になっている
• 共通処理は Behavior
• テーブル単位の操作の Table
• レコード単位の操作は Entity
18
Model 層の比較
Behaviors provide a convenient way to package up behavior that is common
across many models.
ビヘイビアーは、多くのモデルで共通の振る舞いをまとめる便利な方法を
提供します。
• “Models” のようなディレクトリは存在しない
• 【私見】意訳すると、
「“models” という言葉が指す意味は人によって変わるので、
開発したいモノに合わせて各々が判断した場所に置けばよい」
19
Model 層の比較
When getting started with Laravel, many developers are confused by the lack
of a models directory. However, the lack of such a directory is intentional. We
find the word "models" ambiguous since it means many different things to
many different people.
For this reason, we choose to place Eloquent models in the app directory by
default, and allow the developer to place them somewhere else if they
choose.
• 明示的に Model と言っているのは Eloquent ORM のみ
• php artisan make:model の説明
「Create a new Eloquent model class」
• 【考察】
• ORM 即ち Model という意味ではない
• Eloquent model class にビジネスロジックを
記述してもよい
• Eloquent model class を単なる ORM とみなし
他の階層構造にビジネスロジックを記述してもよい
20
Model 層の比較
• Eloquent ORM
• 【私見】「Laravel 強み」としてよく挙げられる
• 【考察】比較的シンプルな記述ができるのが理由か
• 読み方がよく議論になる
• 【私見】では「エロクワント」と読む
21
Model 層の比較
The Eloquent ORM included with Laravel provides a beautiful, simple
ActiveRecord implementation for working with your database.
実現したいこと
• 異なるテーブルのレコード
「クライアントお問い合わせ」
「ユーザお問い合わせ」
• どちらも問い合わせ内容を body というカラムに格納
• 保存する前に body 内に含まれる特殊文字を
HTML エンティティに変換したい
22
Model 層の比較 - コード比較 case 1
※これくらいの処理は本来、ミューテータを使えば良い
23
Model 層の比較 - コード比較 case 1
class SafeStringBehavior extends Behavior
{
public function beforeSave($event, $entity, $options)
{
// h() -> htmlspecialchars()
$entity->body = h($entity->body);
return true;
}
}
class ClientContactsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
// SafeStringBehavior の読み込み
$this->addBehavior('SafeString');
}
}
// UserContractsTable も同様に記述
24
Model 層の比較 - コード比較 case 1
class SafeStringBehavior extends Behavior
{
public function beforeSave($event, $entity, $options)
{
// h() -> htmlspecialchars()
$entity->body = h($entity->body);
return true;
}
}
class ClientContactsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
// SafeStringBehavior の読み込み
$this->addBehavior('SafeString');
}
}
// UserContractsTable も同様に記述する
• 共通の挙動は Behavior に記述する
• 保存前実行される処理は beforeSave
関数に記述する
25
Model 層の比較 - コード比較 case 1
class SafeStringBehavior extends Behavior
{
public function beforeSave($event, $entity, $options)
{
// h() -> htmlspecialchars()
$entity->body = h($entity->body);
return true;
}
}
class ClientContactsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
// SafeStringBehavior の読み込み
$this->addBehavior('SafeString');
}
}
// UserContractsTable も同様に記述する
• Table に addBehavior() を記述する
パターン1
26
Model 層の比較 - コード比較 case 1
class ContactObserver
{
public function saving(Model $model)
{
// e() -> htmlspecialchars()
$model->body = e($model->body);
}
}
// UserContact も同様に記述
class ClientContact extends Model
{
}
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
ClientContact::observe(ContactObserver::class);
UserContact::observe(ContactObserver::class);
}
}
パターン1
27
Model 層の比較 - コード比較 case 1
class ContactObserver
{
public function saving(Model $model)
{
// e() -> htmlspecialchars()
$model->body = e($model->body);
}
}
// UserContact も同様に記述
class ClientContact extends Model
{
}
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
ClientContact::observe(ContactObserver::class);
UserContact::observe(ContactObserver::class);
}
}
• 保存処理の前に発火する
“saving” イベントを観測する
Observer を作成
パターン1
28
Model 層の比較 - コード比較 case 1
class ContactObserver
{
public function saving(Model $model)
{
// e() -> htmlspecialchars()
$model->body = e($model->body);
}
}
// UserContact も同様に記述
class ClientContact extends Model
{
}
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
ClientContact::observe(ContactObserver::class);
UserContact::observe(ContactObserver::class);
}
}
• ServiceProvider 内で対象 Model に
Observer を登録
パターン1
29
Model 層の比較 - コード比較 case 1
class ContactObserver
{
public function saving(Model $model)
{
// e() -> htmlspecialchars()
$model->body = e($model->body);
}
}
// UserContact も同様に記述
class ClientContact extends Model
{
}
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
ClientContact::observe(ContactObserver::class);
UserContact::observe(ContactObserver::class);
}
}
• 欠点:Modelの定義から
処理を辿れない
パターン2
30
Model 層の比較 - コード比較 case 1
// UserContact も同様に記述
class ClientContact extends Model
{
protected $events = [
'saving' => ClientContactSaving::class,
];
}
class Event
{
}
// UserContractSaving も同様に記述
class ClientContactSaving extends Event
{
public $target;
public function __construct(ClientContact $clientContact)
{
$this->target = $clientContact;
}
}
class ConvertToSafeString
{
public function handle(Event $event)
{
$event->target->body = e($event->target->body);
}
}
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
'ClientContactSaving' => [
ConvertToSafeString::class,
],
'UserContactSaving' => [
ConvertToSafeString::class,
],
];
}
パターン2
31
Model 層の比較 - コード比較 case 1
// UserContact も同様に記述
class ClientContact extends Model
{
protected $events = [
'saving' => ClientContactSaving::class,
];
}
class Event
{
}
// UserContractSaving も同様に記述
class ClientContactSaving extends Event
{
public $target;
public function __construct(ClientContact $clientContact)
{
$this->target = $clientContact;
}
}
class ConvertToSafeString
{
public function handle(Event $event)
{
$event->target->body = e($event->target->body);
}
}
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
'ClientContactSaving' => [
ConvertToSafeString::class,
],
'UserContactSaving' => [
ConvertToSafeString::class,
],
];
}
• Model に “saving” イベントを登録
パターン2
32
Model 層の比較 - コード比較 case 1
// UserContact も同様に記述
class ClientContact extends Model
{
protected $events = [
'saving' => ClientContactSaving::class,
];
}
class Event
{
}
// UserContractSaving も同様に記述
class ClientContactSaving extends Event
{
public $target;
public function __construct(ClientContact $clientContact)
{
$this->target = $clientContact;
}
}
class ConvertToSafeString
{
public function handle(Event $event)
{
$event->target->body = e($event->target->body);
}
}
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
'ClientContactSaving' => [
ConvertToSafeString::class,
],
'UserContactSaving' => [
ConvertToSafeString::class,
],
];
}
• Model に対応する
Event を定義
パターン2
33
Model 層の比較 - コード比較 case 1
// UserContact も同様に記述
class ClientContact extends Model
{
protected $events = [
'saving' => ClientContactSaving::class,
];
}
class Event
{
}
// UserContractSaving も同様に記述
class ClientContactSaving extends Event
{
public $target;
public function __construct(ClientContact $clientContact)
{
$this->target = $clientContact;
}
}
class ConvertToSafeString
{
public function handle(Event $event)
{
$event->target->body = e($event->target->body);
}
}
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
'ClientContactSaving' => [
ConvertToSafeString::class,
],
'UserContactSaving' => [
ConvertToSafeString::class,
],
];
}
• Event を捕捉した際に処理を行う
Listener を定義
パターン2
34
Model 層の比較 - コード比較 case 1
// UserContact も同様に記述
class ClientContact extends Model
{
protected $events = [
'saving' => ClientContactSaving::class,
];
}
class Event
{
}
// UserContractSaving も同様に記述
class ClientContactSaving extends Event
{
public $target;
public function __construct(ClientContact $clientContact)
{
$this->target = $clientContact;
}
}
class ConvertToSafeString
{
public function handle(Event $event)
{
$event->target->body = e($event->target->body);
}
}
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
'ClientContactSaving' => [
ConvertToSafeString::class,
],
'UserContactSaving' => [
ConvertToSafeString::class,
],
];
}
• ServiceProvider 内で
Event と Listener の対応を登録
パターン2
35
Model 層の比較 - コード比較 case 1
// UserContact も同様に記述
class ClientContact extends Model
{
protected $events = [
'saving' => ClientContactSaving::class,
];
}
class Event
{
}
// UserContractSaving も同様に記述
class ClientContactSaving extends Event
{
public $target;
public function __construct(ClientContact $clientContact)
{
$this->target = $clientContact;
}
}
class ConvertToSafeString
{
public function handle(Event $event)
{
$event->target->body = e($event->target->body);
}
}
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
'ClientContactSaving' => [
ConvertToSafeString::class,
],
'UserContactSaving' => [
ConvertToSafeString::class,
],
];
}
長所
• Model から処理を追跡できる
短所
• 記述量が多い
• 実現するために考えることが多い
• 突如として現れる
基底クラス Event など
実現したいこと
• クライアントと担当コンサルタントの多対多関係
• 担当コンサルタントの一括更新
36
Model 層の比較 - コード比較 case 2
clients
- id
- name
consultants
- id
- name
client_consultant
- client_id
- consultant_id
client_id consultant_id
1 1
1 2
1 3
client_id consultant_id
1 1
1 4
1 5
37
Model 層の比較 - コード比較 case 2
$Clients = TableRegistry::get('Clients');
$Clients->belongsToMany(
'Consultants',
['saveStrategy' => 'replace']
);
$clientEntity = $Clients->get(
1,
['contain' => 'Consultants']
);
$clientEntity->consultants = $Clients->Consultants
->find('all')
->where(['id IN' => [1, 4, 5]])
->all()
->toArray();
$clientEntity->dirty('consultants', true);
$Clients->save($clientEntity);
class Client extends Model
{
public function consultants()
{
return $this->belongsToMany('App¥Consultant');
}
}
class Consultant extends Model
{
}
$client = Client::find(1);
$client->consultants()->sync([1, 4, 5]);
38
Model 層の比較 - コード比較 case 2
$Clients = TableRegistry::get('Clients');
$Clients->belongsToMany(
'Consultants',
['saveStrategy' => 'replace']
);
$clientEntity = $Clients->get(
1,
['contain' => 'Consultants']
);
$clientEntity->consultants = $Clients->Consultants
->find('all')
->where(['id IN' => [1, 4, 5]])
->all()
->toArray();
$clientEntity->dirty('consultants', true);
$Clients->save($clientEntity);
class Client extends Model
{
public function consultants()
{
return $this->belongsToMany('App¥Consultant');
}
}
class Consultant extends Model
{
}
$client = Client::find(1);
$client->consultants()->sync([1, 4, 5]);
データ取得・更新の処理
CakePHP Laravel
ビジネスロジック Model 層に記述する 記述箇所は規定されていない
(開発者の判断に委ねられてい
る)
Model 層の構造 Table/Entity/Behavior の
3つの概念に分かれている
ActiveRecord 実装の ORM のみを
提供
考察 • 各々にどのような処理を
書くのかが定まっている
→悩まず書ける
• 簡単な処理であれば
クラス定義は必要ない
→コードを書く量が少ない
• ロジックを Model に書いても
良いし、それ意外の場所に別の
名前で書いても良い
→場面にあわせた設計思想の取
り入れができる
• ORM に関する記述はシンプル
になりやすい
39
【考察】Model 層比較
1. 背景
2. Model 層の比較
3. View 層の比較
4. Controller 層の比較
5. その他特徴
6. 全体考察・まとめ
40
目次
• ディレクトリ
41
View 層の比較
Views are responsible for generating the specific output required for the
request.
ビューはリクエストに対する出力を生成する役割を担います。
.
├── src/
: :
│ ├── Template/
│ │ ├── Element/
: : :
│ │ ├── Layout/
│ │ └── Pages/
│ └── View/
│ ├── Helper/
: :
• CakePHP Template
• 「PHP 別の構文」(原文:alternative PHP syntax)
42
View 層の比較
CakePHP のテンプレートファイルは既定の拡張子を .ctp (CakePHP
Template) としており、 制御構造や出力のために PHP 別の構文 を利用す
ることができます。
条件分岐 繰り返し
<?php if ($isSucceeded): ?>
<?= $message ?>
<?php endif; ?>
<?php foreach ($items as $item): ?>
<?= $item['name'] ?>
<?php endforeach; ?>
• CakePHP Template
• 「PHP 別の構文」(原文:alternative PHP syntax)
• つまりPHP
43
View 層の比較
CakePHP のテンプレートファイルは既定の拡張子を .ctp (CakePHP
Template) としており、 制御構造や出力のために PHP 別の構文 を利用す
ることができます。
条件分岐 繰り返し
<?php if ($isSucceeded): ?>
<?= $message ?>
<?php endif; ?>
<?php foreach ($items as $item): ?>
<?= $item['name'] ?>
<?php endforeach; ?>
• 4つの概念に分かれる
• Layout
• View
• Element
• Helper
44
View 層の比較
• Layout
45
アプリケーションの多くのインターフェイスをくるむ表示コードを入れる
テンプレートファイルです。ほとんどのビューはレイアウトの中に描画さ
れます。
View 層の比較
• Layout
46
View 層の比較
アプリケーションの多くのインターフェイスをくるむ表示コードを入れる
テンプレートファイルです。ほとんどのビューはレイアウトの中に描画さ
れます。
サイド
バー
メインコンテンツ
メニューバー
• View
47
View 層の比較
テンプレートは実行中のアクション固有のページの一部分です。 アプリ
ケーションの応答の中心となります。
• View
48
View 層の比較
テンプレートは実行中のアクション固有のページの一部分です。 アプリ
ケーションの応答の中心となります。
サイド
バー
メインコンテンツ
View
メニューバー
• Element
49
View 層の比較
小さな、再利用可能なちょっとしたコードです。エレメントは通常、
ビューの中で描画されます。
• Element
50
View 層の比較
小さな、再利用可能なちょっとしたコードです。エレメントは通常、
ビューの中で描画されます。
メニューバーエレメント
• Element
51
View 層の比較
小さな、再利用可能なちょっとしたコードです。エレメントは通常、
ビューの中で描画されます。
サイド
バー
• Element
52
View 層の比較
小さな、再利用可能なちょっとしたコードです。エレメントは通常、
ビューの中で描画されます。
バナーエレメント
• Element
53
View 層の比較
小さな、再利用可能なちょっとしたコードです。エレメントは通常、
ビューの中で描画されます。
タブエレメント
• Element
54
View 層の比較
小さな、再利用可能なちょっとしたコードです。エレメントは通常、
ビューの中で描画されます。
案件一覧エレメント
• Helper
55
View 層の比較
これらのクラスはビューレイヤーの様々な場所で必要とされるロジックを
カプセル化します。
• Helper
56
View 層の比較
これらのクラスはビューレイヤーの様々な場所で必要とされるロジックを
カプセル化します。
案件ヘルパー
案件ヘルパー
• 【考察】
• 処理の種類ごとに記述する場所が規約で決められている
• どこに書くべきか、悩まずに記述できる
• 組み合わせやすい分類になっている
57
View 層の比較
• 表示のためのロジックを切り離すもの
• ディレクトリ
• views 以下には blade template ファイルのみが置かれる
58
View 層の比較
Views contain the HTML served by your application and separate your
controller / application logic from your presentation logic.
.
:
├── resources
: :
│ └── views
:
• Blade
• シンプルかつ強力
• <?php ?> タグを使わずに記述
• ヘルパー等は別途実装するかパッケージインストールが必要
59
View 層の比較
Blade is the simple, yet powerful templating engine provided with Laravel.
Unlike other popular PHP templating engines, Blade does not restrict you
from using plain PHP code in your views.
条件分岐 繰り返し
@if ($isSucceeded)
{{ $message }}
@endif
@foreach ($items as $item)
{{ $item['name'] }}
@endforeach
• 継承等の機能も Blade 自体が提供
60
View 層の比較 - コード比較 case 1
<html>
<head>
<title>@yield('title')</title>
</head>
<body>
<div>
@yield('content')
</div>
</body>
</html>
@extends('layouts.master')
@section('title')
ここにタイトル
@endsection
@section('content')
ここにコンテンツ
@endsection
views/layouts/master.blade.php views/index.blade.php
• Layout の場合は記述を省略できる
61
View 層の比較 - コード比較 case 1
<html>
<head>
<title><?= $this->fetch('title'); ?></title>
</head>
<body>
<div>
<?= $this->fetch('content'); ?>
</div>
</body>
</html>
<?php
// layoutの継承は自動で行われる
// $this->extend('layout/master');
$this->assign('title', 'ここにタイトル');
// viewの出力はすべて content に出力されるので不要
//$this->start('content');
?>
ここにコンテンツ
<?php // $this->end(); ?>
Layout/top.ctp View/top/index.ctp
62
View 層の比較 - コード比較 case 2
{{-- パッケージ "laravelcollective/html" の
インストール・設定が必要 --}}
{!!
Form::open(
[
'url' => '/user',
'method' => 'post',
]
);
!!}
{!!
Form::text('email', 'example@gmail.com');
!!}
// デフォルトで利用可能
echo $this->Form->create(
$userEntity,
[
'url' => '/user',
'type' => 'POST',
]
);
echo $this->Form->input(
'email',
[
'type' => 'text',
'value' => 'example@gmail.com',
]
);
63
【考察】View 層比較
CakePHP Laravel
View 層の構造 • Layout / View / Element /
Helper の4層に分かれる
• 表示の制御に携わる部分は
全て Blade が担う
• CakePHP の Helper に
該当するものは実装または
インストールが必要
考察 • Model 層と同様、
各々にどのような処理を
書くのかが定まっている
→迷わず書ける
• 共通処理の実装をどこに書くかは
規定されていない
→ヘルパーの実装・Facade・
blade 拡張など実現方法は多岐にわ
たる
• Blade template の記法がシンプル
1. 背景
2. Model 層の比較
3. View 層の比較
4. Controller 層の比較
5. その他特徴
6. 全体考察・まとめ
64
目次
• ディレクトリ
65
Controller 層の比較
.
:
├── src/
: :
│ ├── Controller/
│ │ └── Component/
: :
Your controller should handle interpreting the request data, making sure the
correct models are called, and the right response or view is rendered.
Controllers can be thought of as middle layer between the Model and View.
コントローラーはリクエストを解釈して、適切なモデルが 呼ばれるのを
確認して、正しいレスポンスまたはビューを書き出します。コントロー
ラーはモデルとビューの 中間層とみなすことができます。
• Component
• ルーティング
• フォールバックメソッド
• デフォルトで /Controller名/action名 のルーティングが
読み込まれる
66
Controller 層の比較
コンポーネントはコントローラー間で共有されるロジックのパッケージで
す。
• ドキュメント内に「Controller とは何か」という説明は
明示されていない
• 【考察】単にリクエストをハンドリングするロジックを
記述するクラスという位置づけ
• ディレクトリ
67
Controller 層の比較
Instead of defining all of your request handling logic as Closures in route
files, you may wish to organize this behavior using Controller classes.
.
├── app
: :
│ ├── Http/
│ │ ├── Controllers/
│ │ :
: :
• メソッドインジェクション
• メソッドの引数に型情報を与えることで
クラスの依存性解決を自動的に行う
• ¥Illuminate¥Http¥Request を引数に指定することで
リクエストパラメータを扱うことができる
68
Controller 層の比較
In addition to constructor injection, you may also type-hint dependencies on
your controller's methods.
class UserController extends Controller
{
/**
* Store a new user.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->name;
//
}
}
69
【考察】Controller 層比較
CakePHP Laravel
特徴 • Component
• 共通処理を記述
• デフォルトで
/Controller名/action名 の
ルーティングが読み込まれる
• メソッドインジェクション
• 引数に型情報を
与えることで依存性解決
考察 機能に関しての違いがあるが
基本的な役割は2つのフレームワーク間で変わらない
1. 背景
2. Model 層の比較
3. View 層の比較
4. Controller 層の比較
5. その他特徴
6. 全体考察・まとめ
70
目次
71
同様な概念の比較
CakePHP Laravel
CLI /bin/cake /artisan
設定変数の
読み書き
Configure::read(‘debug’);
Configure::write(‘debug’, true);
config(‘app.debug’);
config([‘app.debug’ => true]);
バリデーション 「保存しようとするデータ」が
対象
「リクエスト内のデータ」が
対象
日時操作 Cake¥I18n¥Time
(Chronos ベース)
Carbon
※ Chronos へ移行する
Proposal あり
ログ Cake¥Log
(独自)
Monolog
単体テスト
フレームワーク
PHP Unit PHP Unit
• Utility
• 例)
• Hash 配列操作をサポート
• Text 文字列操作をサポート
• Number 数値操作をサポート
• Debug Kit
72
その他特徴
DebugKit は、CakePHP アプリケーションを簡単にデバッグするための
ツールバーを提供する コアチームがサポートしているプラグインです。
Debug Kit
73
その他特徴
Debug Kit
74
その他特徴
Debug Kit
75
その他特徴
• Service Container
• クラス依存性解決のための仕組み
• 複数の解決方法が提供されており、
場面に合わせた方法を選ぶことができる
• DI(依存性注入)がやりやすい
→テストの書きやすいコードに
76
その他特徴
The Laravel service container is a powerful tool for managing class
dependencies and performing dependency injection.
class UserController extends Controller
{
protected $users;
public function __construct(UserRepository $users)
{
$this->users = $users;
}
• Facade
• Service Container に格納されているインスタンスの
メソッドを static メソッドのように利用可能
• デフォルトで Log, DB, Session などといった
Facade を提供
• 自分で Facade 実装することもできる
77
その他特徴
Facades provide a "static" interface to classes that are available in the
application's service container. Laravel ships with many facades which
provide access to almost all of Laravel's features.
¥DB::transaction(function () {
// トランザクション開始
});
¥Log::debug('debug log');
¥Log::info('info log');
¥Log::error('error log');
• Laravel を取り巻くサービス・プロダクトが豊富
78
その他特徴
• Laravel を取り巻くサービス・プロダクトが豊富
• Homestead
• Vagrant を利用した開発環境
• Laracasts
• Laravel および PHP に関する
チュートリアル動画を配信しているサイト
• Laravel Mix
• webpack の設定の wrapper (npm パッケージ)
• デフォルトで Vue.js や SASS を利用可能
• など
79
その他特徴
1. 背景
2. Model 層の比較
3. View 層の比較
4. Controller 層の比較
5. その他特徴
6. 全体考察・まとめ
80
目次
81
【考察】全体考察・まとめ
CakePHP Laravel
特徴 「設定より規約」にもとづいて
少ないコードで機能を実現する
拡張のための機能を提供し
コードを美しく保つ
長所 • 規約に則れば絶対的なコード記述量が
少なくて済む
• 「正しい書き方」を公式が
提示してくれている
• 「特有の書き方」「暗黙の了解」
を強制される場面が少ない
• ORM や View テンプレートの記述が
比較的シンプル
• 拡張するための仕組みが
提供されている
短所 • 「正しい書き方」を把握していないと
いびつな造りになるおそれがある
• 自力で拡張するためには CakePHP の
実装レベルの理解が必要になる
• クラスの階層構造などの設計を
自力でできないと道に迷ってしまう
• 設定を明示的に書くことが多いため
絶対的な記述量は多くなりがち
82
【考察】全体考察・まとめ
CakePHP Laravel
特徴 「設定より規約」にもとづいて
少ないコードで機能を実現する
拡張のための機能を提供し
コードを美しく保つ
長所 • 規約に則れば絶対的なコード記述量が
少なくて済む
• 「正しい書き方」を公式が
提示してくれている
• 「特有の書き方」「暗黙の了解」
を強制される場面が少ない
• ORM や View テンプレートの記述が
比較的シンプル
• 拡張するための仕組みが
提供されている
短所 • 「正しい書き方」を把握していないと
いびつな造りになるおそれがある
• 自力で拡張するためには CakePHP の
実装レベルの理解が必要になる
• クラスの階層構造などの設計を
自力でできないと道に迷ってしまう
• 設定を明示的に書くことが多いため
絶対的な記述量は多くなりがち
規約に則り、記述を減らすことで早く書きたい → CakePHP
自力で進み方を決め、柔軟に拡張していきたい → Laravel

More Related Content

PHP 2大 web フレームワークの徹底比較!

  • 2. 池添 誠(いけぞえ まこと) • 開発グループ コンテンツユニット所属 • 2015年にウィルゲートに新卒入社(3年目) • クラウドソーシングサービスのサグーワークスの開発 • 今日は CakePHP 担当 2 自己紹介
  • 3. 池添 誠(いけぞえ まこと) • 開発グループ コンテンツユニット所属 • 2015年にウィルゲートに新卒入社(3年目) • クラウドソーシングサービスのサグーワークスの開発 • 今日は CakePHP 担当 3 自己紹介 テストコード いいぞ
  • 4. 岡田 正平(おかだ しょうへい) • 開発グループ ソリューションユニット所属 • 2015年にウィルゲートに新卒入社(3年目) • webコンサルティングツールの開発 • 今日は Laravel 担当 4 自己紹介
  • 5. 岡田 正平(おかだ しょうへい) • 開発グループ ソリューションユニット所属 • 2015年にウィルゲートに新卒入社(3年目) • webコンサルティングツールの開発 • 今日は Laravel 担当 5 自己紹介 Vue.js いいぞ
  • 6. 1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 6 目次
  • 7. 1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 7 目次
  • 8. • もともと CakePHP のみを利用していた • オフショア開発をやっていた時代にベトナムの開発チームから Laravel を使いたいという要望が出て採用 • 以降、ソリューションチームでは Laravel が主流に • 1つ1つのシステムが小粒なので毎回違う技術を選べる • Slim や FuelPHP を採用したシステムも • 「チーム移動時のコスト」 < 「多様性により得られる恩恵」 • 同じPHP なので、そこまで大きなギャップではない • 新たな知見を得られやすい 8 背景 - なぜフレームワークが混在しているか
  • 9. • サグーワークスのリニューアル(2017年1月) • CakePHP 1.3 → CakePHP 3.2 にバージョンアップ • https://www.wantedly.com/companies/willgate2/post_a rticles/70451 • 新しいコンサルティングツール開発(現在開発中) • Laravel 5.4 を採用 • 社内に双方の最新メジャーバージョンの知見 • → 「比較・考察は価値のある情報になるのでは?」 9 背景 – 今回の勉強会開催の理由
  • 10. 10
  • 13. 注意:スライドの内容 • 公式サイト等からの引用については枠線で囲い 斜字体で表記します 例) • 実際に利用したうえでの私見や考察には 「【私見】」や「【考察】」と明記します 13 The Model layer represents the part of your application that implements the business logic. モデル層はビジネスロジックを実装するアプリケーションの部品を表しま す。
  • 14. 1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 14 目次
  • 15. • ディレクトリ 15 Model 層の比較 The Model layer represents the part of your application that implements the business logic. モデル層はビジネスロジックを実装するアプリケーションの部品を表しま す。 . ├── src/ : : │ ├── Model/ │ │ ├── Behavior/ │ │ ├── Entity/ │ │ └── Table/ : :
  • 16. • CakePHP ORM • 3つの概念に分かれる • Table • Entity • Behavior 16 Model 層の比較 The CakePHP ORM borrows ideas and concepts from both ActiveRecord and Datamapper patterns. It aims to create a hybrid implementation that combines aspects of both patterns to create a fast, simple to use ORM. CakePHP の ORM はアクティブレコードやデータマッパーパターンのアイ デアやコンセプトを拝借しています。 その目的は、早く作成し、シンプ ルに ORM を利用するという2つの利点を混成させるためです。
  • 17. • Table • Entity 17 Model 層の比較 They allow you to save new records, modify/delete existing ones, define relations, and perform bulk operations. これらを利用することで、新しいレコードを保存したり、 既存データの 編集/削除、リレーションの定義、そして一括処理ができます。 Entities represent individual records and allow you to define row/record level behavior & functionality. エンティティーは、個々のレコードを意味し、 行/レコードレベルの振る 舞いや機能の定義を可能にします。
  • 18. • Behavior • 【考察】 • 処理の種類ごとに記述する場所が規約で決められている • どこに書くべきか、悩まずに記述できる • 組み合わせやすい分類になっている • 共通処理は Behavior • テーブル単位の操作の Table • レコード単位の操作は Entity 18 Model 層の比較 Behaviors provide a convenient way to package up behavior that is common across many models. ビヘイビアーは、多くのモデルで共通の振る舞いをまとめる便利な方法を 提供します。
  • 19. • “Models” のようなディレクトリは存在しない • 【私見】意訳すると、 「“models” という言葉が指す意味は人によって変わるので、 開発したいモノに合わせて各々が判断した場所に置けばよい」 19 Model 層の比較 When getting started with Laravel, many developers are confused by the lack of a models directory. However, the lack of such a directory is intentional. We find the word "models" ambiguous since it means many different things to many different people. For this reason, we choose to place Eloquent models in the app directory by default, and allow the developer to place them somewhere else if they choose.
  • 20. • 明示的に Model と言っているのは Eloquent ORM のみ • php artisan make:model の説明 「Create a new Eloquent model class」 • 【考察】 • ORM 即ち Model という意味ではない • Eloquent model class にビジネスロジックを 記述してもよい • Eloquent model class を単なる ORM とみなし 他の階層構造にビジネスロジックを記述してもよい 20 Model 層の比較
  • 21. • Eloquent ORM • 【私見】「Laravel 強み」としてよく挙げられる • 【考察】比較的シンプルな記述ができるのが理由か • 読み方がよく議論になる • 【私見】では「エロクワント」と読む 21 Model 層の比較 The Eloquent ORM included with Laravel provides a beautiful, simple ActiveRecord implementation for working with your database.
  • 22. 実現したいこと • 異なるテーブルのレコード 「クライアントお問い合わせ」 「ユーザお問い合わせ」 • どちらも問い合わせ内容を body というカラムに格納 • 保存する前に body 内に含まれる特殊文字を HTML エンティティに変換したい 22 Model 層の比較 - コード比較 case 1 ※これくらいの処理は本来、ミューテータを使えば良い
  • 23. 23 Model 層の比較 - コード比較 case 1 class SafeStringBehavior extends Behavior { public function beforeSave($event, $entity, $options) { // h() -> htmlspecialchars() $entity->body = h($entity->body); return true; } } class ClientContactsTable extends Table { public function initialize(array $config) { parent::initialize($config); // SafeStringBehavior の読み込み $this->addBehavior('SafeString'); } } // UserContractsTable も同様に記述
  • 24. 24 Model 層の比較 - コード比較 case 1 class SafeStringBehavior extends Behavior { public function beforeSave($event, $entity, $options) { // h() -> htmlspecialchars() $entity->body = h($entity->body); return true; } } class ClientContactsTable extends Table { public function initialize(array $config) { parent::initialize($config); // SafeStringBehavior の読み込み $this->addBehavior('SafeString'); } } // UserContractsTable も同様に記述する • 共通の挙動は Behavior に記述する • 保存前実行される処理は beforeSave 関数に記述する
  • 25. 25 Model 層の比較 - コード比較 case 1 class SafeStringBehavior extends Behavior { public function beforeSave($event, $entity, $options) { // h() -> htmlspecialchars() $entity->body = h($entity->body); return true; } } class ClientContactsTable extends Table { public function initialize(array $config) { parent::initialize($config); // SafeStringBehavior の読み込み $this->addBehavior('SafeString'); } } // UserContractsTable も同様に記述する • Table に addBehavior() を記述する
  • 26. パターン1 26 Model 層の比較 - コード比較 case 1 class ContactObserver { public function saving(Model $model) { // e() -> htmlspecialchars() $model->body = e($model->body); } } // UserContact も同様に記述 class ClientContact extends Model { } class AppServiceProvider extends ServiceProvider { public function boot() { ClientContact::observe(ContactObserver::class); UserContact::observe(ContactObserver::class); } }
  • 27. パターン1 27 Model 層の比較 - コード比較 case 1 class ContactObserver { public function saving(Model $model) { // e() -> htmlspecialchars() $model->body = e($model->body); } } // UserContact も同様に記述 class ClientContact extends Model { } class AppServiceProvider extends ServiceProvider { public function boot() { ClientContact::observe(ContactObserver::class); UserContact::observe(ContactObserver::class); } } • 保存処理の前に発火する “saving” イベントを観測する Observer を作成
  • 28. パターン1 28 Model 層の比較 - コード比較 case 1 class ContactObserver { public function saving(Model $model) { // e() -> htmlspecialchars() $model->body = e($model->body); } } // UserContact も同様に記述 class ClientContact extends Model { } class AppServiceProvider extends ServiceProvider { public function boot() { ClientContact::observe(ContactObserver::class); UserContact::observe(ContactObserver::class); } } • ServiceProvider 内で対象 Model に Observer を登録
  • 29. パターン1 29 Model 層の比較 - コード比較 case 1 class ContactObserver { public function saving(Model $model) { // e() -> htmlspecialchars() $model->body = e($model->body); } } // UserContact も同様に記述 class ClientContact extends Model { } class AppServiceProvider extends ServiceProvider { public function boot() { ClientContact::observe(ContactObserver::class); UserContact::observe(ContactObserver::class); } } • 欠点:Modelの定義から 処理を辿れない
  • 30. パターン2 30 Model 層の比較 - コード比較 case 1 // UserContact も同様に記述 class ClientContact extends Model { protected $events = [ 'saving' => ClientContactSaving::class, ]; } class Event { } // UserContractSaving も同様に記述 class ClientContactSaving extends Event { public $target; public function __construct(ClientContact $clientContact) { $this->target = $clientContact; } } class ConvertToSafeString { public function handle(Event $event) { $event->target->body = e($event->target->body); } } class EventServiceProvider extends ServiceProvider { protected $listen = [ 'ClientContactSaving' => [ ConvertToSafeString::class, ], 'UserContactSaving' => [ ConvertToSafeString::class, ], ]; }
  • 31. パターン2 31 Model 層の比較 - コード比較 case 1 // UserContact も同様に記述 class ClientContact extends Model { protected $events = [ 'saving' => ClientContactSaving::class, ]; } class Event { } // UserContractSaving も同様に記述 class ClientContactSaving extends Event { public $target; public function __construct(ClientContact $clientContact) { $this->target = $clientContact; } } class ConvertToSafeString { public function handle(Event $event) { $event->target->body = e($event->target->body); } } class EventServiceProvider extends ServiceProvider { protected $listen = [ 'ClientContactSaving' => [ ConvertToSafeString::class, ], 'UserContactSaving' => [ ConvertToSafeString::class, ], ]; } • Model に “saving” イベントを登録
  • 32. パターン2 32 Model 層の比較 - コード比較 case 1 // UserContact も同様に記述 class ClientContact extends Model { protected $events = [ 'saving' => ClientContactSaving::class, ]; } class Event { } // UserContractSaving も同様に記述 class ClientContactSaving extends Event { public $target; public function __construct(ClientContact $clientContact) { $this->target = $clientContact; } } class ConvertToSafeString { public function handle(Event $event) { $event->target->body = e($event->target->body); } } class EventServiceProvider extends ServiceProvider { protected $listen = [ 'ClientContactSaving' => [ ConvertToSafeString::class, ], 'UserContactSaving' => [ ConvertToSafeString::class, ], ]; } • Model に対応する Event を定義
  • 33. パターン2 33 Model 層の比較 - コード比較 case 1 // UserContact も同様に記述 class ClientContact extends Model { protected $events = [ 'saving' => ClientContactSaving::class, ]; } class Event { } // UserContractSaving も同様に記述 class ClientContactSaving extends Event { public $target; public function __construct(ClientContact $clientContact) { $this->target = $clientContact; } } class ConvertToSafeString { public function handle(Event $event) { $event->target->body = e($event->target->body); } } class EventServiceProvider extends ServiceProvider { protected $listen = [ 'ClientContactSaving' => [ ConvertToSafeString::class, ], 'UserContactSaving' => [ ConvertToSafeString::class, ], ]; } • Event を捕捉した際に処理を行う Listener を定義
  • 34. パターン2 34 Model 層の比較 - コード比較 case 1 // UserContact も同様に記述 class ClientContact extends Model { protected $events = [ 'saving' => ClientContactSaving::class, ]; } class Event { } // UserContractSaving も同様に記述 class ClientContactSaving extends Event { public $target; public function __construct(ClientContact $clientContact) { $this->target = $clientContact; } } class ConvertToSafeString { public function handle(Event $event) { $event->target->body = e($event->target->body); } } class EventServiceProvider extends ServiceProvider { protected $listen = [ 'ClientContactSaving' => [ ConvertToSafeString::class, ], 'UserContactSaving' => [ ConvertToSafeString::class, ], ]; } • ServiceProvider 内で Event と Listener の対応を登録
  • 35. パターン2 35 Model 層の比較 - コード比較 case 1 // UserContact も同様に記述 class ClientContact extends Model { protected $events = [ 'saving' => ClientContactSaving::class, ]; } class Event { } // UserContractSaving も同様に記述 class ClientContactSaving extends Event { public $target; public function __construct(ClientContact $clientContact) { $this->target = $clientContact; } } class ConvertToSafeString { public function handle(Event $event) { $event->target->body = e($event->target->body); } } class EventServiceProvider extends ServiceProvider { protected $listen = [ 'ClientContactSaving' => [ ConvertToSafeString::class, ], 'UserContactSaving' => [ ConvertToSafeString::class, ], ]; } 長所 • Model から処理を追跡できる 短所 • 記述量が多い • 実現するために考えることが多い • 突如として現れる 基底クラス Event など
  • 36. 実現したいこと • クライアントと担当コンサルタントの多対多関係 • 担当コンサルタントの一括更新 36 Model 層の比較 - コード比較 case 2 clients - id - name consultants - id - name client_consultant - client_id - consultant_id client_id consultant_id 1 1 1 2 1 3 client_id consultant_id 1 1 1 4 1 5
  • 37. 37 Model 層の比較 - コード比較 case 2 $Clients = TableRegistry::get('Clients'); $Clients->belongsToMany( 'Consultants', ['saveStrategy' => 'replace'] ); $clientEntity = $Clients->get( 1, ['contain' => 'Consultants'] ); $clientEntity->consultants = $Clients->Consultants ->find('all') ->where(['id IN' => [1, 4, 5]]) ->all() ->toArray(); $clientEntity->dirty('consultants', true); $Clients->save($clientEntity); class Client extends Model { public function consultants() { return $this->belongsToMany('App¥Consultant'); } } class Consultant extends Model { } $client = Client::find(1); $client->consultants()->sync([1, 4, 5]);
  • 38. 38 Model 層の比較 - コード比較 case 2 $Clients = TableRegistry::get('Clients'); $Clients->belongsToMany( 'Consultants', ['saveStrategy' => 'replace'] ); $clientEntity = $Clients->get( 1, ['contain' => 'Consultants'] ); $clientEntity->consultants = $Clients->Consultants ->find('all') ->where(['id IN' => [1, 4, 5]]) ->all() ->toArray(); $clientEntity->dirty('consultants', true); $Clients->save($clientEntity); class Client extends Model { public function consultants() { return $this->belongsToMany('App¥Consultant'); } } class Consultant extends Model { } $client = Client::find(1); $client->consultants()->sync([1, 4, 5]); データ取得・更新の処理
  • 39. CakePHP Laravel ビジネスロジック Model 層に記述する 記述箇所は規定されていない (開発者の判断に委ねられてい る) Model 層の構造 Table/Entity/Behavior の 3つの概念に分かれている ActiveRecord 実装の ORM のみを 提供 考察 • 各々にどのような処理を 書くのかが定まっている →悩まず書ける • 簡単な処理であれば クラス定義は必要ない →コードを書く量が少ない • ロジックを Model に書いても 良いし、それ意外の場所に別の 名前で書いても良い →場面にあわせた設計思想の取 り入れができる • ORM に関する記述はシンプル になりやすい 39 【考察】Model 層比較
  • 40. 1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 40 目次
  • 41. • ディレクトリ 41 View 層の比較 Views are responsible for generating the specific output required for the request. ビューはリクエストに対する出力を生成する役割を担います。 . ├── src/ : : │ ├── Template/ │ │ ├── Element/ : : : │ │ ├── Layout/ │ │ └── Pages/ │ └── View/ │ ├── Helper/ : :
  • 42. • CakePHP Template • 「PHP 別の構文」(原文:alternative PHP syntax) 42 View 層の比較 CakePHP のテンプレートファイルは既定の拡張子を .ctp (CakePHP Template) としており、 制御構造や出力のために PHP 別の構文 を利用す ることができます。 条件分岐 繰り返し <?php if ($isSucceeded): ?> <?= $message ?> <?php endif; ?> <?php foreach ($items as $item): ?> <?= $item['name'] ?> <?php endforeach; ?>
  • 43. • CakePHP Template • 「PHP 別の構文」(原文:alternative PHP syntax) • つまりPHP 43 View 層の比較 CakePHP のテンプレートファイルは既定の拡張子を .ctp (CakePHP Template) としており、 制御構造や出力のために PHP 別の構文 を利用す ることができます。 条件分岐 繰り返し <?php if ($isSucceeded): ?> <?= $message ?> <?php endif; ?> <?php foreach ($items as $item): ?> <?= $item['name'] ?> <?php endforeach; ?>
  • 44. • 4つの概念に分かれる • Layout • View • Element • Helper 44 View 層の比較
  • 48. • View 48 View 層の比較 テンプレートは実行中のアクション固有のページの一部分です。 アプリ ケーションの応答の中心となります。 サイド バー メインコンテンツ View メニューバー
  • 57. • 【考察】 • 処理の種類ごとに記述する場所が規約で決められている • どこに書くべきか、悩まずに記述できる • 組み合わせやすい分類になっている 57 View 層の比較
  • 58. • 表示のためのロジックを切り離すもの • ディレクトリ • views 以下には blade template ファイルのみが置かれる 58 View 層の比較 Views contain the HTML served by your application and separate your controller / application logic from your presentation logic. . : ├── resources : : │ └── views :
  • 59. • Blade • シンプルかつ強力 • <?php ?> タグを使わずに記述 • ヘルパー等は別途実装するかパッケージインストールが必要 59 View 層の比較 Blade is the simple, yet powerful templating engine provided with Laravel. Unlike other popular PHP templating engines, Blade does not restrict you from using plain PHP code in your views. 条件分岐 繰り返し @if ($isSucceeded) {{ $message }} @endif @foreach ($items as $item) {{ $item['name'] }} @endforeach
  • 60. • 継承等の機能も Blade 自体が提供 60 View 層の比較 - コード比較 case 1 <html> <head> <title>@yield('title')</title> </head> <body> <div> @yield('content') </div> </body> </html> @extends('layouts.master') @section('title') ここにタイトル @endsection @section('content') ここにコンテンツ @endsection views/layouts/master.blade.php views/index.blade.php
  • 61. • Layout の場合は記述を省略できる 61 View 層の比較 - コード比較 case 1 <html> <head> <title><?= $this->fetch('title'); ?></title> </head> <body> <div> <?= $this->fetch('content'); ?> </div> </body> </html> <?php // layoutの継承は自動で行われる // $this->extend('layout/master'); $this->assign('title', 'ここにタイトル'); // viewの出力はすべて content に出力されるので不要 //$this->start('content'); ?> ここにコンテンツ <?php // $this->end(); ?> Layout/top.ctp View/top/index.ctp
  • 62. 62 View 層の比較 - コード比較 case 2 {{-- パッケージ "laravelcollective/html" の インストール・設定が必要 --}} {!! Form::open( [ 'url' => '/user', 'method' => 'post', ] ); !!} {!! Form::text('email', '[email protected]'); !!} // デフォルトで利用可能 echo $this->Form->create( $userEntity, [ 'url' => '/user', 'type' => 'POST', ] ); echo $this->Form->input( 'email', [ 'type' => 'text', 'value' => '[email protected]', ] );
  • 63. 63 【考察】View 層比較 CakePHP Laravel View 層の構造 • Layout / View / Element / Helper の4層に分かれる • 表示の制御に携わる部分は 全て Blade が担う • CakePHP の Helper に 該当するものは実装または インストールが必要 考察 • Model 層と同様、 各々にどのような処理を 書くのかが定まっている →迷わず書ける • 共通処理の実装をどこに書くかは 規定されていない →ヘルパーの実装・Facade・ blade 拡張など実現方法は多岐にわ たる • Blade template の記法がシンプル
  • 64. 1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 64 目次
  • 65. • ディレクトリ 65 Controller 層の比較 . : ├── src/ : : │ ├── Controller/ │ │ └── Component/ : : Your controller should handle interpreting the request data, making sure the correct models are called, and the right response or view is rendered. Controllers can be thought of as middle layer between the Model and View. コントローラーはリクエストを解釈して、適切なモデルが 呼ばれるのを 確認して、正しいレスポンスまたはビューを書き出します。コントロー ラーはモデルとビューの 中間層とみなすことができます。
  • 66. • Component • ルーティング • フォールバックメソッド • デフォルトで /Controller名/action名 のルーティングが 読み込まれる 66 Controller 層の比較 コンポーネントはコントローラー間で共有されるロジックのパッケージで す。
  • 67. • ドキュメント内に「Controller とは何か」という説明は 明示されていない • 【考察】単にリクエストをハンドリングするロジックを 記述するクラスという位置づけ • ディレクトリ 67 Controller 層の比較 Instead of defining all of your request handling logic as Closures in route files, you may wish to organize this behavior using Controller classes. . ├── app : : │ ├── Http/ │ │ ├── Controllers/ │ │ : : :
  • 68. • メソッドインジェクション • メソッドの引数に型情報を与えることで クラスの依存性解決を自動的に行う • ¥Illuminate¥Http¥Request を引数に指定することで リクエストパラメータを扱うことができる 68 Controller 層の比較 In addition to constructor injection, you may also type-hint dependencies on your controller's methods. class UserController extends Controller { /** * Store a new user. * * @param Request $request * @return Response */ public function store(Request $request) { $name = $request->name; // } }
  • 69. 69 【考察】Controller 層比較 CakePHP Laravel 特徴 • Component • 共通処理を記述 • デフォルトで /Controller名/action名 の ルーティングが読み込まれる • メソッドインジェクション • 引数に型情報を 与えることで依存性解決 考察 機能に関しての違いがあるが 基本的な役割は2つのフレームワーク間で変わらない
  • 70. 1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 70 目次
  • 71. 71 同様な概念の比較 CakePHP Laravel CLI /bin/cake /artisan 設定変数の 読み書き Configure::read(‘debug’); Configure::write(‘debug’, true); config(‘app.debug’); config([‘app.debug’ => true]); バリデーション 「保存しようとするデータ」が 対象 「リクエスト内のデータ」が 対象 日時操作 Cake¥I18n¥Time (Chronos ベース) Carbon ※ Chronos へ移行する Proposal あり ログ Cake¥Log (独自) Monolog 単体テスト フレームワーク PHP Unit PHP Unit
  • 72. • Utility • 例) • Hash 配列操作をサポート • Text 文字列操作をサポート • Number 数値操作をサポート • Debug Kit 72 その他特徴 DebugKit は、CakePHP アプリケーションを簡単にデバッグするための ツールバーを提供する コアチームがサポートしているプラグインです。
  • 76. • Service Container • クラス依存性解決のための仕組み • 複数の解決方法が提供されており、 場面に合わせた方法を選ぶことができる • DI(依存性注入)がやりやすい →テストの書きやすいコードに 76 その他特徴 The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. class UserController extends Controller { protected $users; public function __construct(UserRepository $users) { $this->users = $users; }
  • 77. • Facade • Service Container に格納されているインスタンスの メソッドを static メソッドのように利用可能 • デフォルトで Log, DB, Session などといった Facade を提供 • 自分で Facade 実装することもできる 77 その他特徴 Facades provide a "static" interface to classes that are available in the application's service container. Laravel ships with many facades which provide access to almost all of Laravel's features. ¥DB::transaction(function () { // トランザクション開始 }); ¥Log::debug('debug log'); ¥Log::info('info log'); ¥Log::error('error log');
  • 79. • Laravel を取り巻くサービス・プロダクトが豊富 • Homestead • Vagrant を利用した開発環境 • Laracasts • Laravel および PHP に関する チュートリアル動画を配信しているサイト • Laravel Mix • webpack の設定の wrapper (npm パッケージ) • デフォルトで Vue.js や SASS を利用可能 • など 79 その他特徴
  • 80. 1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 80 目次
  • 81. 81 【考察】全体考察・まとめ CakePHP Laravel 特徴 「設定より規約」にもとづいて 少ないコードで機能を実現する 拡張のための機能を提供し コードを美しく保つ 長所 • 規約に則れば絶対的なコード記述量が 少なくて済む • 「正しい書き方」を公式が 提示してくれている • 「特有の書き方」「暗黙の了解」 を強制される場面が少ない • ORM や View テンプレートの記述が 比較的シンプル • 拡張するための仕組みが 提供されている 短所 • 「正しい書き方」を把握していないと いびつな造りになるおそれがある • 自力で拡張するためには CakePHP の 実装レベルの理解が必要になる • クラスの階層構造などの設計を 自力でできないと道に迷ってしまう • 設定を明示的に書くことが多いため 絶対的な記述量は多くなりがち
  • 82. 82 【考察】全体考察・まとめ CakePHP Laravel 特徴 「設定より規約」にもとづいて 少ないコードで機能を実現する 拡張のための機能を提供し コードを美しく保つ 長所 • 規約に則れば絶対的なコード記述量が 少なくて済む • 「正しい書き方」を公式が 提示してくれている • 「特有の書き方」「暗黙の了解」 を強制される場面が少ない • ORM や View テンプレートの記述が 比較的シンプル • 拡張するための仕組みが 提供されている 短所 • 「正しい書き方」を把握していないと いびつな造りになるおそれがある • 自力で拡張するためには CakePHP の 実装レベルの理解が必要になる • クラスの階層構造などの設計を 自力でできないと道に迷ってしまう • 設定を明示的に書くことが多いため 絶対的な記述量は多くなりがち 規約に則り、記述を減らすことで早く書きたい → CakePHP 自力で進み方を決め、柔軟に拡張していきたい → Laravel