LoginSignup
134
166

More than 5 years have passed since last update.

管理画面を作る:AdminLTE Laravel組込み編

Last updated at Posted at 2015-07-25

管理画面用のフレームワークである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 &copy; 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 にアクセスすると、

adminlte

と、表示されれば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 &copy; 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にアクセスしてみます。

adminlte

見た目はまったく変わっていませんが、テンプレート化された状態で表示されています。

ファイルをまとめる

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で生成した架空のものですが、偶然実名と一致することもあるでしょうから、モザイクかけときます。

adminlte

標準で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くらいですが。

adminlte

但し、幾つかやること・注意点があります。

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とほぼ同じようです。

adminlte

コードは下記の通り。
<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

参考

基本的な流れはここを参考にしました。
参考になりました。

134
166
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
134
166