管理画面用のフレームワークであるAdminLTEの構造を見てみたので、今度は、PHPのフレームワークであるLaravel5.1に組み込んで見たいと思います。
なお、Laravelの基本的な知識はあるものとして話を進めます。
##準備
###laravelのインストール
laravelのインストールはComposerで行うことにします。そもそも、Composerが入っていない人は準備して下さい。
composer create-project laravel/laravel test
###AdminLTEの導入
AdminLTEのCSSやJSを設置する場所は、laravelのpublicフォルダになるかと思います。
AdminLTEをダウンロードしてきて直接展開してもいいですし、bowerでインストールしてもいいです。
ここでは、bowerを利用します。Bowerが入っていない人は準備して下さい。
cd test/public
bower install admin-lte
そうすると、public/bower_components/admin-lte以下にファイルが展開されます。
主なフォルダとしては、
- dist AdminLTEの本体系CSS,JS
- bootstrap ベースとなっているBootstrap3.x系ファイル
- plugins jQueryなどなど
それ以外は、サンプルだったりするので、消してもいいかなと思います。
これで、とりあえずファイルの準備は完了です。
##Laravelと統合
ここでいうLaravelとの統合とは、Laravelのテンプレートエンジンであるbladeとパーシャル機能を使った部品化です。
###テンプレート化への前準備
bladeでテンプレート化する前に、そもそもLaravelでAdminLTEで作成した画面が正しく表示されるようにします。
基本編で用意した最低構成のファイルをコピーして、resources/views/以下にadminlte.blade.phpとして保存します。
また、このページがhttp://localhost:8000/admin 等で呼び出しできるようにRouteを設定します。
Route::get('admin',function(){
return view('adminlte');
});
アクセスしてみると、表示はされるものの、CSS等が適用されておらず、表示が崩れています。
これは、admin.blade.phpから、adminLTE等のCSS,JSが正しく参照されていないからです。
<head>および<body>の最後のCSSやJSの参照パスをpublic/bower-components/admin-let/以下を参照するように修正します。
以下が、正しく適用したものです。
CDN参照のものはそのままで、ローカルリソースに対して、{{asset("bower_components/admin-lte/~")}}をつけてやる感じです。なお、asset()はpublicフォルダとして解釈されます。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>adminLTE test</title>
<!-- for responsive -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- bootstrap -->
<link href="{{asset("bower_components/admin-lte/bootstrap/css/bootstrap.min.css")}}" rel="stylesheet" type="text/css" />
<!-- font awesome -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<!-- ionicons -->
<link href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css" />
<!-- adminLTE style -->
<link href="{{asset("bower_components/admin-lte/dist/css/AdminLTE.min.css")}}" rel="stylesheet" type="text/css" />
<link href="{{asset("bower_components/admin-lte/dist/css/skins/skin-blue.min.css")}}" rel="stylesheet" type="text/css" />
</head>
<body class="skin-blue">
<div class="wrapper">
<!-- トップメニュー -->
<header class="main-header">
<!-- ロゴ -->
<a href="" class="logo">管理画面</a>
<!-- トップメニュー -->
<nav class="navbar navbar-static-top" role="navigation">
<ul class="nav navbar-nav">
<li><a href="">顧客管理</a></li>
</ul>
</nav>
</header><!-- end header -->
<!-- サイドバー -->
<aside class="main-sidebar">
<section class="sidebar">
<ul class="sidebar-menu">
<!-- メニューヘッダ -->
<li class="header">機能一覧</li>
<!-- メニュー項目 -->
<li><a href="">新規登録</a></li>
</ul>
</section>
</aside><!-- end sidebar -->
<!-- content -->
<div class="content-wrapper">
<!-- コンテンツヘッダ -->
<section class="content-header">
<h1>ページタイトル</h1>
</section>
<!-- メインコンテンツ -->
<section class="content">
<!-- コンテンツ1 -->
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">ボックスタイトル</h3>
</div>
<div class="box-body">
<p>ボックスボディー</p>
</div>
</div>
</section>
</div><!-- end content -->
<!-- フッター -->
<footer class="main-footer">
<div class="pull-right hidden-xs">Version1.0</div>
<strong>Copyright © 2015</strong>, All rights reserved.
</footer><!-- end footer -->
</div><!-- end wrapper -->
<!-- JS -->
<!-- jquery -->
<script src="{{asset("bower_components/admin-lte/plugins/jQuery/jQuery-2.1.4.min.js")}}" type="text/javascript"></script>
<!-- bootstrap -->
<script src="{{asset("bower_components/admin-lte/bootstrap/js/bootstrap.min.js")}}" type="text/javascript"></script>
<!-- adminLTE -->
<script src="{{asset("bower_components/admin-lte/dist/js/app.min.js")}}" type="text/javascript"></script>
</body>
</html>
http://localhost:8000/admin にアクセスすると、
と、表示されればOKです。
###テンプレート化する
ベースとなるファイルで正しく表示ができるようになったので、これを分解して、テンプレート化します。
テンプレートの構造は、
- layout.blade.php
を主ファイルとし、共通部分を
- header.blade.php
- sidebar.blade.php
- footer.blade.php
に分散させます。
####layout.blade.phpを作る
layout.blade.phpをviews以下に作成し、先ほど動作を確認したadminlte.blade.phpのコードをコピペします。
adminlte.blade.phpをlayoutにリネームしても大丈夫です。
####header部分を置き換える
layout.blade.phpの<header>...</header>部分をカットし、header.blade.phpとしてペースト・保存します。
<!-- トップメニュー -->
<header class="main-header">
<!-- ロゴ -->
<a href="" class="logo">管理画面</a>
<!-- トップメニュー -->
<nav class="navbar navbar-static-top" role="navigation">
<ul class="nav navbar-nav">
<li><a href="">顧客管理</a></li>
</ul>
</nav>
</header><!-- end header -->
さらに、layout.blade.phpの<header>...</header>があった部分を、
@include('header')
のように分離したheader部分を読み込むように置き換えます。
同様に、sidebar, footerなども置き換えます。
####sidebarを置き換える
サイドバーの位置にあるコードをカットし、sidebar.blade.phpとして保存します。
<!-- サイドバー -->
<aside class="main-sidebar">
<section class="sidebar">
<ul class="sidebar-menu">
<!-- メニューヘッダ -->
<li class="header">機能一覧</li>
<!-- メニュー項目 -->
<li><a href="">新規登録</a></li>
</ul>
</section>
</aside><!-- end sidebar -->
サイトバーがあった位置、<aside class="main-sidebar">...</aside class="main-sidebar">を
@include('sidebar')
に置き換えます。
####footerを置き換える
フッターの位置にあるコードをカットし、footer.blade.phpとして保存します。
<!-- フッター -->
<footer class="main-footer">
<div class="pull-right hidden-xs">Version1.0</div>
<strong>Copyright © 2015</strong>, All rights reserved.
</footer><!-- end footer -->
フッターがあった<footer>...</footer>を、
@include('footer')
に置き換えます。
####contentを置き換える
content部分は動的に変わるところなので、include()ではなく、yield('content')に置き換えます。
header等は、関連記述全体を置き換えましたが、contentでは<div class="content-wrapper"></div>部は残しています。
これで、テンプレート化は終了です。
layout.blade.php全体を見てみます。共通部分が外部ファイルへ切りだされ、動的部分は@yield('content')となりました。
<!doctype html>
<head>
<meta charset="utf-8">
<title>adminLTE test</title>
<!-- for responsive -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- bootstrap -->
<link href="{{asset("bower_components/admin-lte/bootstrap/css/bootstrap.min.css")}}" rel="stylesheet" type="text/css" />
<!-- font awesome -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<!-- ionicons -->
<link href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css" />
<!-- adminLTE style -->
<link href="{{asset("bower_components/admin-lte/dist/css/AdminLTE.min.css")}}" rel="stylesheet" type="text/css" />
<link href="{{asset("bower_components/admin-lte/dist/css/skins/skin-blue.min.css")}}" rel="stylesheet" type="text/css" />
</head>
<body class="skin-blue">
<div class="wrapper">
<!-- ヘッダー -->
@include('header')
<!-- サイドバー -->
@include('sidebar')
<!-- content -->
<div class="content-wrapper">
<!-- コンテンツ -->
@yield('content')
</div><!-- end content -->
<!-- フッター -->
@include('footer')
</div><!-- end wrapper -->
<!-- JS -->
<!-- jquery -->
<script src="{{asset("bower_components/admin-lte/plugins/jQuery/jQuery-2.1.4.min.js")}}" type="text/javascript"></script>
<!-- bootstrap -->
<script src="{{asset("bower_components/admin-lte/bootstrap/js/bootstrap.min.js")}}" type="text/javascript"></script>
<!-- adminLTE -->
<script src="{{asset("bower_components/admin-lte/dist/js/app.min.js")}}" type="text/javascript"></script>
</body>
</html>
だいぶ見通しがいい感じになりました。
###表示してみる
では、作成したテンプレートを利用してコンテンツを表示してみます。
とりあえず、さきほど@yield('content')に置き換えた部分を、下記のようにsample.blade.phpとして保存します。
@extends('layout')
@section('content')
<!-- コンテンツヘッダ -->
<section class="content-header">
<h1>ページタイトル</h1>
</section>
<!-- メインコンテンツ -->
<section class="content">
<!-- コンテンツ1 -->
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">ボックスタイトル</h3>
</div>
<div class="box-body">
<p>ボックスボディー</p>
</div>
</div>
</section>
@endsection
layout.blade.phpをレイアウトとして読み込むように@extends('layout')とし、@yield('content')に置き換わる部分を@section('content')...@sectionendで囲いました。
そして、ルートを適切に書き換えます。sample.blade.phpを見に行くようにします。
Route::get('admin',function(){
return view('sample');
});
/admimにアクセスしてみます。
見た目はまったく変わっていませんが、テンプレート化された状態で表示されています。
###ファイルをまとめる
Laravelのプロジェクトを作成するたび、こんな操作をしてられません。とりあえず、views直下に作成したファイル群をファイルにまとめます。後は、まとめたファイルをgithub等で管理し、都度cloneするなり、各種自動化ツールで、取得するようにすればいいでしょう(もちろん手動でもいいですが)。
ここでは、views以下にadminlteというフォルダを作って、そこに集約します。
修正が必要なファイルは2つ。
- layout.blade.php
- sample.blade.php
です。
####テンプレートの修正
まず、layout.blade.php側でinclude()の記述を修正します。
@include('header') => @include('adminlte.header')
頭に、adminlte.を付与します。headerだけでなく、sidebar,footerについても行います。
####テンプレート利用側の修正
sample.blade.phpの頭でextends()を修正します。
@extends('layout') => @extends('adminlte.layout')
とします。
完了したら、/adminにアクセスして、表示に問題がないか確認して下さい。
##応用
いくつかの機能がLaravelで正しく動くか試してみます。
###ページネーション
LaravelはBootstrap3互換のページネーションタグを出力しますが、それがAdminLTEで動くかの動作確認をしてみたいと思います。
結論から言えばとりあえずは動きました。ただ、AdminLTEが用意しているページネーションのスタイルに完全に合わせるためには、Laravel側でページネーションをカスタマイズする必要があります。
ちなみに、表示している顧客データはダミー情報生成ツールFakerで生成した架空のものですが、偶然実名と一致することもあるでしょうから、モザイクかけときます。
標準でmigrateできるUserを利用し、Seederを使ってデータを生成しました。
で、コントローラーで、
public function index()
{
//
$query = User::query();
$users = $query->paginate(10);
return view('users')->with('users',$users);
などとし、Viewで、テンプレートを使い、
@extends('adminlte.layout')
@section('content')
<!-- コンテンツヘッダ -->
<section class="content-header">
<h1>顧客管理</h1>
</section>
<!-- メインコンテンツ -->
<section class="content">
<!-- コンテンツ1 -->
<div class="box">
<div class="box-header with-border">
{{-- <h3 class="box-title">顧客一覧</h3> --}}
<form class="form-inline" style="margin:15px;">
<div class="form-group">
<label>検索:</label>
<input type="text" name="keyword" class="form-control" style="width:200px;">
</div>
<div class="form-group">
<input type="submit" value="検索" class="btn btn-primary">
</div>
</form>
</div>
<div class="box-body">
<table class="table table-bordered">
<tr>
<th>ID</th>
<th>氏名</th>
<th>email</th>
</tr>
@foreach($users as $user)
<tr>
<td>{{$user->id}}</td>
<td>{{$user->name}}</td>
<td>{{$user->email}}</td>
</tr>
@endforeach
</table>
</div>
<div class="box-footer clearfix">
{!! $users->render() !!}
</div>
</div>
</section>
@endsection
としています。ポイントはboxのheaer,footer等をちゃんと利用することでしょうか。
残念ながら一部直接styleを追加して補正しています。。。まあ、仕方ないでしょう。
補正してるところは、
- 検索用のFormに15pxのマージン追加。
- 検索用のinput typeの長さを200pxに。
です。
###Chart.js
AdminLTEでは、いくつかのChartプラグインが最初から含まれているようですが、ここでは簡単に試せるchart.jsを見てみます。
結論から言えば、少し癖があるものの動きまし。とはいえ、Laravel依存なのはchart.jsへのPathくらいですが。
但し、幾つかやること・注意点があります。
####chart.jsを読み込む
読み込みを共通に行っているlaytou.blade.phpにChart.jsを読み込むための記述をします。
また、javascriptを記述する専用の@include('scripts')を各種JSの読み込み後に入れました(下記は抜粋部)。
<!-- JS -->
<!-- jquery -->
<script src="{{asset("bower_components/admin-lte/plugins/jQuery/jQuery-2.1.4.min.js")}}" type="text/javascript"></script>
<!-- bootstrap -->
<script src="{{asset("bower_components/admin-lte/bootstrap/js/bootstrap.min.js")}}" type="text/javascript"></script>
<!-- adminLTE -->
<script src="{{asset("bower_components/admin-lte/dist/js/app.min.js")}}" type="text/javascript"></script>
<!-- chart.js -->
<script src="{{asset("bower_components/admin-lte/plugins/chartjs/Chart.min.js")}}" type="text/javascript"></script>
@include('scripts')
####canvasの配置
Chart.jsでは、canvasに描画されるので、HTMLにChart描画用のcanvasを配置します。
ここではid="line"と配置しています。
@extends('adminlte.layout')
@section('content')
<!-- コンテンツヘッダ -->
<section class="content-header">
<h1>チャート表示</h1>
</section>
<!-- メインコンテンツ -->
<section class="content">
<!-- コンテンツ1 -->
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">LineChart</h3>
</div>
<div class="box-body">
<div class="chart">
<canvas id="line" height="200" width="800"></canvas>
</div>
</div>
</div>
</section>
@endsection
Canvasを<div class="chart">...</div>で囲ってやることで、Windowsサイズに合わせてリサイズされるようになるようです(まあ、ただ伸び縮みしてるだけですが)。ただ、その伸び縮みロジックがいまいち???な感じです。縦横を均等ではなく、一定の比率を取ってやるほうがちゃんと機能するようです。詳細は機械があれば調べますが。。。
####JSを書く
描画用のJavascriptと記述します。ここでは、scripts.blade.phpに切り出したので、そこに書きます。
<script>
$(function(){
//動的要素
var axis = ["A","B","C","D"];
var data = [10,20,30,20];
//描画設定
var lineChartData = {
labels:axis,
datasets:[
{
fillColor:"rgba(220,220,220,0.5)",
strokeColor:"rgba(220,220,220.1)",
pointColor:"rgba(220,220,220,1)",
pointStrokeColor:"#FFF",
data:data
}
]
};
//特定のルート時のみ適用
var url = window.location;
if(url.pathname == "/chart"){
var ctx = $("#line")[0].getContext("2d");
new Chart(ctx).Line(lineChartData);
}
});
</script>
基本はchart.jsのページ等を参考に書くだけです。あと、今回は、layout.blade.phpに@include('scripts')としたので、関係無いページでもJSが実行されます。存在しないIDを参照するとエラーになるので、特定のルート(ここでは/chart)の時だけ、描画処理を行うように記述しています。
動的要素のところをAPIから取得すれば、汎用性が上がります。LaravelでAPIつくるのはここに書いてます。
###Form
いよいよLaraveとは無関係ですが、この流れでFormのチェックもしておきます。Form関連はBootstrapとほぼ同じようです。
コードは下記の通り。
<form>タグの位置をbox-headerやbox-footerの位置を考慮しながら置くと、いい感じになるようです。
@extends('adminlte.layout')
@section('content')
<!-- header -->
<section class="content-header">
<h1>Formのテスト</h1>
</section>
<!-- body -->
<section class="content">
<!-- box col-12 -->
<div class="box box-primary">
<div class="box-header with-border">
Simple From
</div>
<form>
<div class="box-body">
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control">
</div>
<div class="form-group has-error">
<label>Password</label>
<input type="text" class="form-control">
<span class="help-block">パスワードがおかしいです。</span>
</div>
<div class="form-group">
<label>Select</label>
<select class="form-control">
<option>option1</option>
<option>option2</option>
<option>option3</option>
</select>
</div>
<div class="form-group">
<label>File Upload</label>
<input type="file">
</div>
<div class="checkbox">
<label>
<input type="checkbox"><b>remember</b>
</label>
</div>
<p><b>Radio</b></p>
<div class="radio-inline">
<label>
<input type="radio" name="gender" value="man"><b>男</b>
</label>
</div>
<div class="radio-inline">
<label>
<input type="radio" name="gender" value="woman"><b>女</b>
</label>
</div>
<div class="form-group">
<label>TextArea</label>
<textarea class="form-control" rows="3"></textarea>
</div>
</div>
<div class="box-footer">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</section>
@endsection
###参考
基本的な流れはここを参考にしました。
参考になりました。