前書き
laravelにAdminLTEを導入する時は通常はLaravel-AdminLTEをcomposer requireすると思うが、諸事情でgithubからzipダウンロードして導入することになった。その際に認証機能の導入でlaravel/ui
とlaravel-adminlte
との融合に苦労したのでまとめておく。
tl;dr
- zipダウンロードしてview書き換えるのは結構大変
- なので別で
laravel/ui
+laravel-adminlte
を導入したプロジェクトを作る - そしてview部分だけコピペで導入するという裏技的な対処で切り抜けた。
開発環境
- docker-compose
- php-fpm
- nginx
- mysql
- laravel7
やり方
参考のために、laravel/uiとlaravel-adminlteのプロジェクトを作る
参考にするために、普通にcomposer requireとartisanコマンドで実装するプロジェクトを作成します。
laravel/ui
+laravel-adminlte
での認証機能の導入は他の記事を参考にしてください。
認証機能が実装できたら次に進みます。
AdminLTEをzipで導入
それでは本題のプロジェクトの作業に取り掛かります。
githubからzipダウンロードします。
解凍したら/AdminLTE-3.0.5/dist/
配下のファイルと/AdminLTE-3.0.5/plugins
フォルダをlaravelの/public/
配下にコピーします。
$ cp -r /AdminLTE-3.0.5/dist/* public/vendor/AdminLTE/3.0.5/
$ cp -r /AdminLTE-3.0.5/plugins/* public/vendor/AdminLTE/3.0.5/
laravel/uiインストール
laravel/uiをインストールしますが、叩くコマンドが違います。
$ composer require laravel/ui
$ php artisan ui:auth //デフォルトでbootstrapで作成する
公式のやり方だとphp artisan ui bootstrap --auth
してnpm run dev
で/public/app.css
と/public/app.js
を作るように書いてますが、artisanコマンドのヘルプに沿った上のやり方だとなぜかnpm run dev
を求められない。
ビューを書き換え
ここが一番苦労した。
laravel/ui
+laravel-adminlte
のプロジェクトのコードからview部分だけを導入する
headタグ内のスタイルシート、javascriptの引用先や@extendsの参照先などに気を付けて書き換える。
@extends('auth.auth-page', ['auth_type' => 'login'])
@section('adminlte_css_pre')
<link rel="stylesheet" href="{{ asset('vendor/icheck-bootstrap/icheck-bootstrap.min.css') }}">
@stop
@php( $login_url = View::getSection('login_url') ?? config('adminlte.login_url', 'login') )
@php( $register_url = View::getSection('register_url') ?? config('adminlte.register_url', 'register') )
@php( $password_reset_url = View::getSection('password_reset_url') ?? config('adminlte.password_reset_url', 'password/reset') )
@if (config('adminlte.use_route_url', false))
@php( $login_url = $login_url ? route($login_url) : '' )
@php( $register_url = $register_url ? route($register_url) : '' )
@php( $password_reset_url = $password_reset_url ? route($password_reset_url) : '' )
@else
@php( $login_url = $login_url ? url($login_url) : '' )
@php( $register_url = $register_url ? url($register_url) : '' )
@php( $password_reset_url = $password_reset_url ? url($password_reset_url) : '' )
@endif
@section('auth_header', __('ログイン'))
@section('auth_body')
<form action="{{ $login_url }}" method="post">
{{ csrf_field() }}
{{-- Email field --}}
<div class="input-group mb-3">
<input type="email" name="email" class="form-control {{ $errors->has('email') ? 'is-invalid' : '' }}"
value="{{ old('email') }}" placeholder="メールアドレス" autofocus>
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-envelope"></span>
</div>
</div>
@if($errors->has('email'))
<div class="invalid-feedback">
<strong>{{ $errors->first('email') }}</strong>
</div>
@endif
</div>
{{-- Password field --}}
<div class="input-group mb-3">
<input type="password" name="password" class="form-control {{ $errors->has('password') ? 'is-invalid' : '' }}"
placeholder="パスワード">
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock"></span>
</div>
</div>
@if($errors->has('password'))
<div class="invalid-feedback">
<strong>{{ $errors->first('password') }}</strong>
</div>
@endif
</div>
{{-- Login field --}}
<div class="row">
<div class="col-7">
<div class="icheck-primary">
<input type="checkbox" name="remember" id="remember">
<label for="remember">ログイン状態を記憶する</label>
</div>
</div>
<div class="col-5">
<button type=submit class="btn btn-block btn-flat btn-primary">
<span class="fas fa-sign-in-alt"></span>
ログイン
</button>
</div>
</div>
</form>
@stop
@section('auth_footer')
{{-- Password reset link --}}
@if($password_reset_url)
<p class="my-0">
<a href="{{ $password_reset_url }}">
パスワードをお忘れの方
</a>
</p>
@endif
{{-- Register link --}} //登録機能は提供しないのでコメントアウト
{{-- @if($register_url)
<p class="my-0">
<a href="{{ $register_url }}">
{{ __('adminlte::adminlte.register_a_new_membership') }}
</a>
</p>
@endif --}}
@stop
{{-- 認証画面レイアウト --}}
@extends('layout.master')
@php( $dashboard_url = View::getSection('dashboard_url') ?? '/' )
@if (config('adminlte.use_route_url', false))
@php( $dashboard_url = $dashboard_url ? route($dashboard_url) : '' )
@else
@php( $dashboard_url = $dashboard_url ? url($dashboard_url) : '' )
@endif
@section('adminlte_css')
@stack('css')
@yield('css')
@stop
@section('classes_body'){{ ($auth_type ?? 'login') . '-page' }}@stop
@section('body')
<div class="{{ $auth_type ?? 'login' }}-box">
{{-- Logo --}}
<div class="{{ $auth_type ?? 'login' }}-logo">
<img src="{{ asset(config('adminlte.logo_img')) }}" height="50">
<b>AdminLTE</b>
</div>
{{-- Card Box --}}
<div class="card card-outline card-primary">
{{-- Card Header --}}
@hasSection('auth_header')
<div class="card-header">
<h3 class="card-title float-none text-center">
@yield('auth_header')
</h3>
</div>
@endif
{{-- Card Body --}}
<div class="card-body {{ $auth_type ?? 'login' }}-card-body">
@yield('auth_body')
</div>
{{-- Card Footer --}}
@hasSection('auth_footer')
<div class="card-footer">
@yield('auth_footer')
</div>
@endif
</div>
</div>
@stop
@section('adminlte_js')
@stack('js')
@yield('js')
@stop
{{-- 認証画面レイアウト --}}
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
{{-- Base Meta Tags --}}
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
{{-- Custom Meta Tags --}}
@yield('meta_tags')
{{-- Title --}}
<title>AdminLTE 3 | Dashboard</title>
{{-- Custom stylesheets (pre AdminLTE) --}}
@yield('adminlte_css_pre')
<!-- Tell the browser to be responsive to screen width -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Font Awesome -->
<link rel="stylesheet" href={{ asset('/vendor/AdminLTE/3.0.5/plugins/fontawesome-free/css/all.min.css') }}>
<!-- Ionicons -->
<link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
<!-- Tempusdominus Bbootstrap 4 -->
<link rel="stylesheet" href={{ asset('vendor/AdminLTE/3.0.5/plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css') }}>
<!-- iCheck -->
<link rel="stylesheet" href={{ asset('vendor/AdminLTE/3.0.5/plugins/icheck-bootstrap/icheck-bootstrap.min.css') }}>
<!-- JQVMap -->
<link rel="stylesheet" href={{ asset('vendor/AdminLTE/3.0.5/plugins/jqvmap/jqvmap.min.css') }}>
<!-- Theme style -->
<link rel="stylesheet" href={{ asset('vendor/AdminLTE/3.0.5/css/adminlte.min.css') }}>
<!-- overlayScrollbars -->
<link rel="stylesheet" href={{ asset('vendor/AdminLTE/3.0.5/plugins/overlayScrollbars/css/OverlayScrollbars.min.css') }}>
<!-- Daterange picker -->
<link rel="stylesheet" href={{ asset('vendor/AdminLTE/3.0.5/plugins/daterangepicker/daterangepicker.css') }}>
<!-- summernote -->
<link rel="stylesheet" href={{ asset('vendor/AdminLTE/3.0.5/plugins/summernote/summernote-bs4.css') }}>
<!-- Google Font: Source Sans Pro -->
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">
{{-- Custom Stylesheets (post AdminLTE) --}}
@yield('adminlte_css')
</head>
<body class="@yield('classes_body')" @yield('body_data')>
{{-- Body Content --}}
@yield('body')
<!-- jQuery -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/jquery/jquery.min.js") }}></script>
<!-- jQuery UI 1.11.4 -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/jquery-ui/jquery-ui.min.js") }}></script>
<!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip -->
<!-- Bootstrap 4 -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/bootstrap/js/bootstrap.bundle.min.js") }}></script>
<!-- ChartJS -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/chart.js/Chart.min.js") }}></script>
<!-- Sparkline -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/sparklines/sparkline.js") }}></script>
<!-- JQVMap -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/jqvmap/jquery.vmap.min.js") }}></script>
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/jqvmap/maps/jquery.vmap.usa.js") }}></script>
<!-- jQuery Knob Chart -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/jquery-knob/jquery.knob.min.js") }}></script>
<!-- daterangepicker -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/moment/moment.min.js") }}></script>
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/daterangepicker/daterangepicker.js") }}></script>
<!-- Tempusdominus Bootstrap 4 -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js") }}></script>
<!-- Summernote -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/summernote/summernote-bs4.min.js") }}></script>
<!-- overlayScrollbars -->
<script src={{ asset("vendor/AdminLTE/3.0.5/plugins/overlayScrollbars/js/jquery.overlayScrollbars.min.js") }}></script>
<!-- AdminLTE App -->
<script src={{ asset("vendor/AdminLTE/3.0.5/js/adminlte.js") }}></script>
<!-- AdminLTE dashboard demo (This is only for demo purposes) -->
<script src={{ asset("vendor/AdminLTE/3.0.5/js/pages/dashboard.js") }}></script>
<!-- AdminLTE for demo purposes -->
<script src={{ asset("vendor/AdminLTE/3.0.5/js/demo.js") }}></script>
{{-- Custom Scripts --}}
@yield('adminlte_js')
</body>
</html>