Slide 1

Slide 1 text

PHP 2大 web フレームワークの 徹底比較! サポーターズ勉強会@株式会社ウィルゲート Room0

Slide 2

Slide 2 text

池添 誠(いけぞえ まこと) • 開発グループ コンテンツユニット所属 • 2015年にウィルゲートに新卒入社(3年目) • クラウドソーシングサービスのサグーワークスの開発 • 今日は CakePHP 担当 2 自己紹介

Slide 3

Slide 3 text

池添 誠(いけぞえ まこと) • 開発グループ コンテンツユニット所属 • 2015年にウィルゲートに新卒入社(3年目) • クラウドソーシングサービスのサグーワークスの開発 • 今日は CakePHP 担当 3 自己紹介 テストコード いいぞ

Slide 4

Slide 4 text

岡田 正平(おかだ しょうへい) • 開発グループ ソリューションユニット所属 • 2015年にウィルゲートに新卒入社(3年目) • webコンサルティングツールの開発 • 今日は Laravel 担当 4 自己紹介

Slide 5

Slide 5 text

岡田 正平(おかだ しょうへい) • 開発グループ ソリューションユニット所属 • 2015年にウィルゲートに新卒入社(3年目) • webコンサルティングツールの開発 • 今日は Laravel 担当 5 自己紹介 Vue.js いいぞ

Slide 6

Slide 6 text

1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 6 目次

Slide 7

Slide 7 text

1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 7 目次

Slide 8

Slide 8 text

• もともと CakePHP のみを利用していた • オフショア開発をやっていた時代にベトナムの開発チームから Laravel を使いたいという要望が出て採用 • 以降、ソリューションチームでは Laravel が主流に • 1つ1つのシステムが小粒なので毎回違う技術を選べる • Slim や FuelPHP を採用したシステムも • 「チーム移動時のコスト」 < 「多様性により得られる恩恵」 • 同じPHP なので、そこまで大きなギャップではない • 新たな知見を得られやすい 8 背景 - なぜフレームワークが混在しているか

Slide 9

Slide 9 text

• サグーワークスのリニューアル(2017年1月) • CakePHP 1.3 → CakePHP 3.2 にバージョンアップ • https://www.wantedly.com/companies/willgate2/post_a rticles/70451 • 新しいコンサルティングツール開発(現在開発中) • Laravel 5.4 を採用 • 社内に双方の最新メジャーバージョンの知見 • → 「比較・考察は価値のある情報になるのでは?」 9 背景 – 今回の勉強会開催の理由

Slide 10

Slide 10 text

10

Slide 11

Slide 11 text

11 徹底比較!!

Slide 12

Slide 12 text

注意:対象バージョン • 特に断りのない限り、メインのプロダクトで採用されている を対象とします。 ※2017年9月13日現在の最新バージョンは CakePHP 3.5 および Laravel 5.5 CakePHP 3.2 Laravel 5.4 12

Slide 13

Slide 13 text

注意:スライドの内容 • 公式サイト等からの引用については枠線で囲い 斜字体で表記します 例) • 実際に利用したうえでの私見や考察には 「【私見】」や「【考察】」と明記します 13 The Model layer represents the part of your application that implements the business logic. モデル層はビジネスロジックを実装するアプリケーションの部品を表しま す。

Slide 14

Slide 14 text

1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 14 目次

Slide 15

Slide 15 text

• ディレクトリ 15 Model 層の比較 The Model layer represents the part of your application that implements the business logic. モデル層はビジネスロジックを実装するアプリケーションの部品を表しま す。 . ├── src/ : : │ ├── Model/ │ │ ├── Behavior/ │ │ ├── Entity/ │ │ └── Table/ : :

Slide 16

Slide 16 text

• 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つの利点を混成させるためです。

Slide 17

Slide 17 text

• 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. エンティティーは、個々のレコードを意味し、 行/レコードレベルの振る 舞いや機能の定義を可能にします。

Slide 18

Slide 18 text

• Behavior • 【考察】 • 処理の種類ごとに記述する場所が規約で決められている • どこに書くべきか、悩まずに記述できる • 組み合わせやすい分類になっている • 共通処理は Behavior • テーブル単位の操作の Table • レコード単位の操作は Entity 18 Model 層の比較 Behaviors provide a convenient way to package up behavior that is common across many models. ビヘイビアーは、多くのモデルで共通の振る舞いをまとめる便利な方法を 提供します。

Slide 19

Slide 19 text

• “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.

Slide 20

Slide 20 text

• 明示的に Model と言っているのは Eloquent ORM のみ • php artisan make:model の説明 「Create a new Eloquent model class」 • 【考察】 • ORM 即ち Model という意味ではない • Eloquent model class にビジネスロジックを 記述してもよい • Eloquent model class を単なる ORM とみなし 他の階層構造にビジネスロジックを記述してもよい 20 Model 層の比較

Slide 21

Slide 21 text

• Eloquent ORM • 【私見】「Laravel 強み」としてよく挙げられる • 【考察】比較的シンプルな記述ができるのが理由か • 読み方がよく議論になる • 【私見】では「エロクワント」と読む 21 Model 層の比較 The Eloquent ORM included with Laravel provides a beautiful, simple ActiveRecord implementation for working with your database.

Slide 22

Slide 22 text

実現したいこと • 異なるテーブルのレコード 「クライアントお問い合わせ」 「ユーザお問い合わせ」 • どちらも問い合わせ内容を body というカラムに格納 • 保存する前に body 内に含まれる特殊文字を HTML エンティティに変換したい 22 Model 層の比較 - コード比較 case 1 ※これくらいの処理は本来、ミューテータを使えば良い

Slide 23

Slide 23 text

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 も同様に記述

Slide 24

Slide 24 text

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 関数に記述する

Slide 25

Slide 25 text

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() を記述する

Slide 26

Slide 26 text

パターン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); } }

Slide 27

Slide 27 text

パターン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 を作成

Slide 28

Slide 28 text

パターン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 を登録

Slide 29

Slide 29 text

パターン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の定義から 処理を辿れない

Slide 30

Slide 30 text

パターン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, ], ]; }

Slide 31

Slide 31 text

パターン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” イベントを登録

Slide 32

Slide 32 text

パターン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 を定義

Slide 33

Slide 33 text

パターン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 を定義

Slide 34

Slide 34 text

パターン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 の対応を登録

Slide 35

Slide 35 text

パターン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 など

Slide 36

Slide 36 text

実現したいこと • クライアントと担当コンサルタントの多対多関係 • 担当コンサルタントの一括更新 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

Slide 37

Slide 37 text

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]);

Slide 38

Slide 38 text

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]); データ取得・更新の処理

Slide 39

Slide 39 text

CakePHP Laravel ビジネスロジック Model 層に記述する 記述箇所は規定されていない (開発者の判断に委ねられてい る) Model 層の構造 Table/Entity/Behavior の 3つの概念に分かれている ActiveRecord 実装の ORM のみを 提供 考察 • 各々にどのような処理を 書くのかが定まっている →悩まず書ける • 簡単な処理であれば クラス定義は必要ない →コードを書く量が少ない • ロジックを Model に書いても 良いし、それ意外の場所に別の 名前で書いても良い →場面にあわせた設計思想の取 り入れができる • ORM に関する記述はシンプル になりやすい 39 【考察】Model 層比較

Slide 40

Slide 40 text

1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 40 目次

Slide 41

Slide 41 text

• ディレクトリ 41 View 層の比較 Views are responsible for generating the specific output required for the request. ビューはリクエストに対する出力を生成する役割を担います。 . ├── src/ : : │ ├── Template/ │ │ ├── Element/ : : : │ │ ├── Layout/ │ │ └── Pages/ │ └── View/ │ ├── Helper/ : :

Slide 42

Slide 42 text

• CakePHP Template • 「PHP 別の構文」(原文:alternative PHP syntax) 42 View 層の比較 CakePHP のテンプレートファイルは既定の拡張子を .ctp (CakePHP Template) としており、 制御構造や出力のために PHP 別の構文 を利用す ることができます。 条件分岐 繰り返し = $message ?> = $item['name'] ?>

Slide 43

Slide 43 text

• CakePHP Template • 「PHP 別の構文」(原文:alternative PHP syntax) • つまりPHP 43 View 層の比較 CakePHP のテンプレートファイルは既定の拡張子を .ctp (CakePHP Template) としており、 制御構造や出力のために PHP 別の構文 を利用す ることができます。 条件分岐 繰り返し = $message ?> = $item['name'] ?>

Slide 44

Slide 44 text

• 4つの概念に分かれる • Layout • View • Element • Helper 44 View 層の比較

Slide 45

Slide 45 text

• Layout 45 アプリケーションの多くのインターフェイスをくるむ表示コードを入れる テンプレートファイルです。ほとんどのビューはレイアウトの中に描画さ れます。 View 層の比較

Slide 46

Slide 46 text

• Layout 46 View 層の比較 アプリケーションの多くのインターフェイスをくるむ表示コードを入れる テンプレートファイルです。ほとんどのビューはレイアウトの中に描画さ れます。 サイド バー メインコンテンツ メニューバー

Slide 47

Slide 47 text

• View 47 View 層の比較 テンプレートは実行中のアクション固有のページの一部分です。 アプリ ケーションの応答の中心となります。

Slide 48

Slide 48 text

• View 48 View 層の比較 テンプレートは実行中のアクション固有のページの一部分です。 アプリ ケーションの応答の中心となります。 サイド バー メインコンテンツ View メニューバー

Slide 49

Slide 49 text

• Element 49 View 層の比較 小さな、再利用可能なちょっとしたコードです。エレメントは通常、 ビューの中で描画されます。

Slide 50

Slide 50 text

• Element 50 View 層の比較 小さな、再利用可能なちょっとしたコードです。エレメントは通常、 ビューの中で描画されます。 メニューバーエレメント

Slide 51

Slide 51 text

• Element 51 View 層の比較 小さな、再利用可能なちょっとしたコードです。エレメントは通常、 ビューの中で描画されます。 サイド バー

Slide 52

Slide 52 text

• Element 52 View 層の比較 小さな、再利用可能なちょっとしたコードです。エレメントは通常、 ビューの中で描画されます。 バナーエレメント

Slide 53

Slide 53 text

• Element 53 View 層の比較 小さな、再利用可能なちょっとしたコードです。エレメントは通常、 ビューの中で描画されます。 タブエレメント

Slide 54

Slide 54 text

• Element 54 View 層の比較 小さな、再利用可能なちょっとしたコードです。エレメントは通常、 ビューの中で描画されます。 案件一覧エレメント

Slide 55

Slide 55 text

• Helper 55 View 層の比較 これらのクラスはビューレイヤーの様々な場所で必要とされるロジックを カプセル化します。

Slide 56

Slide 56 text

• Helper 56 View 層の比較 これらのクラスはビューレイヤーの様々な場所で必要とされるロジックを カプセル化します。 案件ヘルパー 案件ヘルパー

Slide 57

Slide 57 text

• 【考察】 • 処理の種類ごとに記述する場所が規約で決められている • どこに書くべきか、悩まずに記述できる • 組み合わせやすい分類になっている 57 View 層の比較

Slide 58

Slide 58 text

• 表示のためのロジックを切り離すもの • ディレクトリ • 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 :

Slide 59

Slide 59 text

• Blade • シンプルかつ強力 • タグを使わずに記述 • ヘルパー等は別途実装するかパッケージインストールが必要 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

Slide 60

Slide 60 text

• 継承等の機能も Blade 自体が提供 60 View 層の比較 - コード比較 case 1 @yield('title')
@yield('content')
@extends('layouts.master') @section('title') ここにタイトル @endsection @section('content') ここにコンテンツ @endsection views/layouts/master.blade.php views/index.blade.php

Slide 61

Slide 61 text

• Layout の場合は記述を省略できる 61 View 層の比較 - コード比較 case 1 = $this->fetch('title'); ?>
= $this->fetch('content'); ?>
extend('layout/master'); $this->assign('title', 'ここにタイトル'); // viewの出力はすべて content に出力されるので不要 //$this->start('content'); ?> ここにコンテンツ end(); ?> Layout/top.ctp View/top/index.ctp

Slide 62

Slide 62 text

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', ] );

Slide 63

Slide 63 text

63 【考察】View 層比較 CakePHP Laravel View 層の構造 • Layout / View / Element / Helper の4層に分かれる • 表示の制御に携わる部分は 全て Blade が担う • CakePHP の Helper に 該当するものは実装または インストールが必要 考察 • Model 層と同様、 各々にどのような処理を 書くのかが定まっている →迷わず書ける • 共通処理の実装をどこに書くかは 規定されていない →ヘルパーの実装・Facade・ blade 拡張など実現方法は多岐にわ たる • Blade template の記法がシンプル

Slide 64

Slide 64 text

1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 64 目次

Slide 65

Slide 65 text

• ディレクトリ 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. コントローラーはリクエストを解釈して、適切なモデルが 呼ばれるのを 確認して、正しいレスポンスまたはビューを書き出します。コントロー ラーはモデルとビューの 中間層とみなすことができます。

Slide 66

Slide 66 text

• Component • ルーティング • フォールバックメソッド • デフォルトで /Controller名/action名 のルーティングが 読み込まれる 66 Controller 層の比較 コンポーネントはコントローラー間で共有されるロジックのパッケージで す。

Slide 67

Slide 67 text

• ドキュメント内に「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/ │ │ : : :

Slide 68

Slide 68 text

• メソッドインジェクション • メソッドの引数に型情報を与えることで クラスの依存性解決を自動的に行う • ¥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; // } }

Slide 69

Slide 69 text

69 【考察】Controller 層比較 CakePHP Laravel 特徴 • Component • 共通処理を記述 • デフォルトで /Controller名/action名 の ルーティングが読み込まれる • メソッドインジェクション • 引数に型情報を 与えることで依存性解決 考察 機能に関しての違いがあるが 基本的な役割は2つのフレームワーク間で変わらない

Slide 70

Slide 70 text

1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 70 目次

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

• Utility • 例) • Hash 配列操作をサポート • Text 文字列操作をサポート • Number 数値操作をサポート • Debug Kit 72 その他特徴 DebugKit は、CakePHP アプリケーションを簡単にデバッグするための ツールバーを提供する コアチームがサポートしているプラグインです。

Slide 73

Slide 73 text

Debug Kit 73 その他特徴

Slide 74

Slide 74 text

Debug Kit 74 その他特徴

Slide 75

Slide 75 text

Debug Kit 75 その他特徴

Slide 76

Slide 76 text

• 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; }

Slide 77

Slide 77 text

• 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');

Slide 78

Slide 78 text

• Laravel を取り巻くサービス・プロダクトが豊富 78 その他特徴

Slide 79

Slide 79 text

• Laravel を取り巻くサービス・プロダクトが豊富 • Homestead • Vagrant を利用した開発環境 • Laracasts • Laravel および PHP に関する チュートリアル動画を配信しているサイト • Laravel Mix • webpack の設定の wrapper (npm パッケージ) • デフォルトで Vue.js や SASS を利用可能 • など 79 その他特徴

Slide 80

Slide 80 text

1. 背景 2. Model 層の比較 3. View 層の比較 4. Controller 層の比較 5. その他特徴 6. 全体考察・まとめ 80 目次

Slide 81

Slide 81 text

81 【考察】全体考察・まとめ CakePHP Laravel 特徴 「設定より規約」にもとづいて 少ないコードで機能を実現する 拡張のための機能を提供し コードを美しく保つ 長所 • 規約に則れば絶対的なコード記述量が 少なくて済む • 「正しい書き方」を公式が 提示してくれている • 「特有の書き方」「暗黙の了解」 を強制される場面が少ない • ORM や View テンプレートの記述が 比較的シンプル • 拡張するための仕組みが 提供されている 短所 • 「正しい書き方」を把握していないと いびつな造りになるおそれがある • 自力で拡張するためには CakePHP の 実装レベルの理解が必要になる • クラスの階層構造などの設計を 自力でできないと道に迷ってしまう • 設定を明示的に書くことが多いため 絶対的な記述量は多くなりがち

Slide 82

Slide 82 text

82 【考察】全体考察・まとめ CakePHP Laravel 特徴 「設定より規約」にもとづいて 少ないコードで機能を実現する 拡張のための機能を提供し コードを美しく保つ 長所 • 規約に則れば絶対的なコード記述量が 少なくて済む • 「正しい書き方」を公式が 提示してくれている • 「特有の書き方」「暗黙の了解」 を強制される場面が少ない • ORM や View テンプレートの記述が 比較的シンプル • 拡張するための仕組みが 提供されている 短所 • 「正しい書き方」を把握していないと いびつな造りになるおそれがある • 自力で拡張するためには CakePHP の 実装レベルの理解が必要になる • クラスの階層構造などの設計を 自力でできないと道に迷ってしまう • 設定を明示的に書くことが多いため 絶対的な記述量は多くなりがち 規約に則り、記述を減らすことで早く書きたい → CakePHP 自力で進み方を決め、柔軟に拡張していきたい → Laravel