CakePHPでBootstrapを組み込むには、いくつかのパターンがあります。今回は、よく知られている、プラグインを利用して行います
Cakeのインストールと初期設定
Composerで最新版をインストールします
1 2 |
$ mkdir test $ composer create-project --prefer-dist cakephp/app test @stable |
とりあえずテーブル作成
テストのためのテーブルを作成しておきます
1 2 3 4 5 6 7 8 |
CREATE TABLE `products` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `price` int(11) NOT NULL, `modified` datetime DEFAULT NULL, `created` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
簡単に初期設定
config/app.php
1 2 3 4 5 |
'App' => [ 'namespace' => 'App', 'encoding' => env('APP_ENCODING', 'UTF-8'), 'defaultLocale' => env('APP_DEFAULT_LOCALE', 'ja_JP'), 'defaultTimezone' => env('APP_DEFAULT_TIMEZONE', 'Asia/Tokyo'), |
1 2 3 |
'username' => 'ユーザ名', 'password' => 'パスワード', 'database' => 'データベース名', |
bakeで作っておく
1 2 3 |
cd test chmod +x /bin/cake bin/cake bake all products |
プラグインのインストール
CakePHPのプラグインをインストールします。これを使って簡単に組み込めるようにします
利用するのはよく使われている以下のプラグインです
friendsofcake/bootstrap-ui
プラグインのインストール
1 |
composer require friendsofcake/bootstrap-ui dev-develop |
2018年8月時点ではmasterではBootstrapバージョン3に対応したものです。developではバージョン4に対応しています。今回はバージョン4対応のために「dev-develop」を利用します
プラグインの有効化
最下部に追加します
config/bootstrap.php
1 |
\Cake\Core\Plugin::load('BootstrapUI'); |
設定
プラグインのための設定を行います。「AppView.php」の継承元を変更する、「trait」を利用するなどの方法が紹介されていますが、ここではもっと簡単にやってみます
src/View/AppView.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class AppView extends View { /** * Initialization hook method. * * Use this method to add common initialization code like loading helpers. * * e.g. `$this->loadHelper('Html');` * * @return void */ public function initialize() { $this->loadHelper('Html', ['className' => 'BootstrapUI.Html']); $this->loadHelper('Form', ['className' => 'BootstrapUI.Form']); $this->loadHelper('Flash', ['className' => 'BootstrapUI.Flash']); $this->loadHelper('Paginator', ['className' => 'BootstrapUI.Paginator']); } } |
Templateファイルを修正していく
プラグインのレイアウトファイルを利用することでデザインを変更することができますが、使えるレイアウトファイルが限られているので、とりあえず、デフォルトのレイアウトファイルをがっつり変更します
レイアウトファイル
src/Template/Layout/default.ctp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<!DOCTYPE html> <html lang="ja"> <head> <?= $this->Html->charset() ?> <?= $this->Html->meta('icon') ?> <title><?= $this->fetch('title') ?></title> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous"> <!-- Original CSS --> <?= $this->Html->css('style.css') ?> <?= $this->fetch('meta') ?> <?= $this->fetch('css') ?> <?= $this->fetch('script') ?> </head> <body> <?= $this->element("menu/default") ?> <?= $this->element("content") ?> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script> </body> |
CSS, JSの読み込み方法はもっと別の方法がありますが、コピペで済むのでこれで対応します
メニュー用エレメントの作成
画面上部のグローバルメニューとして作成するエレメントファイルです。フォルダも含めて作成します
src/Template/Element/menu/default.ctp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-primary"> <?=$this->Html->link("Title", "/products/index", ["class"=>"navbar-brand"]); ?> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item"> <?=$this->Html->link("商品一覧", "/products/index", ["class"=>"nav-link text-white"]);?> </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle text-white" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 商品一覧 </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> <?=$this->Html->link("一覧", "/products/index", ["class"=>"dropdown-item"]);?> <?=$this->Html->link("新規追加", "/products/add", ["class"=>"dropdown-item"]);?> </div> </li> </ul> <form class="form-inline my-2 my-lg-0"> <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search"> <button class="btn btn-dark my-2 my-sm-0" type="submit">Search</button> </form> <ul class="navbar-nav"> <li class="nav-item"> <?=$this->Html->link("ログイン", "/products/index", ["class"=>"nav-link text-white"]);?> </li> </ul> </div> </nav> |
メインコンテンツ表示のためのエレメントファイル
レイアウトファイルから読み込まれるメインの部分です
src/Template/Element/content.ctp
1 2 3 4 5 6 7 8 9 10 11 |
<div class="container"> <div class="container-fluid"> <div class="row main"> <div class="col-md-12"> <?= $this->Flash->render("auth") ?> <?= $this->Flash->render() ?> <?= $this->fetch('content') ?> </div> </div> </div> </div> |
簡単な独自CSS定義
Cakeで用意されているCSSを削除して、簡単なCSSを定義します
webroot/css/style.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@charset "utf-8"; body { padding-top: 4rem; } .main { padding: 1rem 0; background-color: #fff; } .main .page-header { margin-top: 0; } table.table thead a { color: white; } table.table tbody a { color: #4285F4; } |
Productsの一覧用Viewファイル
src/Template/Products/index.ctp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<h1>商品一覧</h1> <nav aria-label="pager"> <ul class="pagination"> <?= $this->Paginator->numbers([ 'before' => $this->Paginator->first("<<"), 'after' => $this->Paginator->last(">>"), ]) ?> </ul> </nav> <table class="table table-striped"> <thead class="bg-dark"> <tr> <th scope="col"><?= $this->Paginator->sort('id') ?></th> <th scope="col"><?= $this->Paginator->sort('name') ?></th> <th scope="col"><?= $this->Paginator->sort('price') ?></th> <th scope="col"><?= $this->Paginator->sort('modified') ?></th> <th scope="col"><?= $this->Paginator->sort('created') ?></th> <th scope="col" class="actions text-white"><?= __('Actions') ?></th> </tr> </thead> <?php foreach ($products as $product): ?> <tr> <td><?= $this->Number->format($product->id) ?></td> <td><?= h($product->name) ?></td> <td><?= $this->Number->format($product->price) ?></td> <td><?= h($product->modified) ?></td> <td><?= h($product->created) ?></td> <td class="actions"> <?= $this->Html->link(__('表示'), ['action' => 'view', $product->id]) ?> <?= $this->Html->link(__('編集'), ['action' => 'edit', $product->id]) ?> <?= $this->Form->postLink(__('削除'), ['action' => 'delete', $product->id], ['confirm' => __('Are you sure you want to delete # {0}?', $product->id)]) ?> </td> </tr> <?php endforeach; ?> </table> |
この時点での商品一覧の実行結果
データは適宜追加しておきます
商品の新規追加画面のViewファイル
src/Template/Products/add.ctp
1 2 3 4 5 6 7 8 9 |
<h1>商品追加</h1> <div class="products form large-9 medium-8 columns content"> <?= $this->Form->create($product) ?> <?php echo $this->Form->control('name'); ?> <?php echo $this->Form->control('price'); ?> <?= $this->Form->submit(__('Submit'), ["class"=>"btn btn-dark"]) ?> <?= $this->Form->end() ?> </div> |
新規登録画面の実行結果
フラッシュメッセージも対応しています
これで一応対応できていることは確認できます。後は、Bootstrapのルールに従って作成していきます
Flashメッセージのエレメントファイル
Bootstrapバージョン4の導入とは異なりますが、プラグインで導入したエレメントファイルをオーバーライドする方法を紹介します。導入したプラグインで利用されているFlashメッセージのエレメントファイルは以下のファイルです
1 |
vendor/friendsofcake/bootstrap-ui/src/Template/Element/Flash/default.ctp |
このファイルを「src」内にコピーすると表示スタイルを変更できます。以下の場所にコピーします
1 |
src/Template/Plugin/BootstrapUI/Element/Flash/ |
フォルダを作成して、プラグインのエレメントファイルをコピーします
1 2 |
mkdir -p src/Template/Plugin/BootstrapUI/Element/Flash/ cp vendor/friendsofcake/bootstrap-ui/src/Template/Element/Flash/default.ctp src/Template/Plugin/BootstrapUI/Element/Flash/ |
コピーしたファイルを編集するとFlashメッセージのHTMLなどを修正することができます