Laravelでブログを作成する方法【チュートリアル】
Laravelの勉強として、ブログを作成したので、その方法をまとめました。以下の英語記事を参考に作成し、いくつかバグのあるコードを修正しました。
» Creating a Blog Using Laravel 4 Part 1: Models and Seeding – CodeHeaps
類似記事も書いています。以下の記事のほうが難易度が低いです。
» 【保存版】Laravelで掲示板を作成する方法【チュートリアル】
記事の対象者
- PHPの基礎がわかる人
- Laravelの基本がわかる人
- やる気がある人
ブログの機能一覧
- 記事一覧の表示
- 続きを読むボタンの表示
- 記事の検索機能
- コメント機能
- ログイン機能
- 会員登録機能
- ユーザーは自分の記事のCRUD処理ができる
- 会員はコメントの承認/非承認を選択できる
もくじ
- 【1】LaravelのDBセットアップ
- 【2】Laravelのマイグレーション
- 【3】Eloquent ORMを使ったモデル作成
- 【4】データベースにダミーデータの送信
- 【5】各種コントローラーの作成
- 【6】ルーティングの設定
- 【7】ユーザー認証
- 【8】ビューの作成
それでは、まとめていきます( ◜◡‾)
【1】LaravelのDBセットアップ
DBのセットアップ
編集ファイル:app/config/database.php
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'classified',
'username' => 'root',
'password' => 'root',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
【2】Laravelのマイグレーション
postsテーブルのマイグレーション
$ php artisan migrate:make create_posts_table
Created Migration: 2014_10_09_142812_create_posts_table
Generating optimized class loader
Compiling common classes
Compiling views
生成されたファイルに以下を記述します。
<?php
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class CreatePostsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function($table){
$table->increments('id');
$table->unsignedInteger('author_id');
$table->string('title');
$table->string('read_more');
$table->text('content');
$table->unsignedInteger('comment_count');
$table->timestamps();
$table->engine = 'MyISAM';
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('posts');
}
}
解説:$table->engine=’MyISAM’
上記はMySQLの検索機能を利用するために設定しています。
その後、マイグレートします。
$ php artisan migrate
commentsテーブルのマイグレーション
$ php artisan migrate:make create_comments_table
Created Migration: 2014_10_09_143901_create_comments_table
Generating optimized class loader
Compiling common classes
Compiling views
生成されたファイルに以下を記述します。
<?php
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class CreateCommentsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('comments', function($table){
$table->increments('id');
$table->unsignedInteger('post_id');
$table->string('commenter');
$table->string('email');
$table->text('comment');
$table->boolean('approved');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('comments');
}
}
解説:post_id
post_idはcommmentsテーブルとpostsテーブルを紐づけます。
また、approvedフィールドでは、あとで解説するusersテーブルと連携します。
その後、マイグレートをします。
$ php artisan migrate
【3】Eloquent ORMを使ったモデル作成
Eloquent ORMでモデルを作成する
規約に従うため、モデル名は『テーブル名の単数形』を使います。
それでは、Postモデルを作っていきます。
新規作成ファイル:app/models/Post.php
<?php
class Post extends Eloquent{
protected $fillable = ['title', 'content'];
public function comments(){
return $this->hasMany('Comment');
}
public function user(){
return $this->belongsTo('User');
}
}
つぎにCommentモデルを作成します。
新規作成ファイル:app/models/Comment.php
<?php
class Comment extends Eloquent{
protected $fillable = ['commenter', 'email', 'comment'];
public function post(){
return $this->belongsTo('Post');
}
public function getApprovedAttribute($approved){
return (intval($approved) == 1) ? 'yes' : 'no';
}
public function setApprovedAttribute($approved){
$this->attributes['approved'] = ($approved === 'yes') ? 1 : 0;
}
}
【4】データベースにダミーデータの送信
シードコマンドでDBにダミーデータを送信する
artisan db:seed
というコマンドでDBにダミーデータを挿入することができます。
まずは、PostCommentSeederを以下のとおりに作成します。
新規作成ファイル:app/database/seeds/PostCommentSeeder.php
<?php
class PostCommentSeeder extends Seeder{
public function run(){
$content = 'この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。';
for( $i = 1 ; $i <= 20 ; $i++) {
$post = new Post;
$post->title = "$i 番目の投稿";
$post->author_id = 1;
$post->read_more = substr($content, 0, 120);
$post->content = $content;
$post->save();
$maxComments = mt_rand(3, 15);
for ($j=0; $j <= $maxComments; $j++) {
$comment = new Comment;
$comment->commenter = '名無し';
$comment->comment = substr($content, 0, 120);
$comment->email = '[email protected]';
$comment->approved = 1;
$post->comments()->save($comment);
$post->increment('comment_count');
}
}
}
}
以下のコマンドで実行します。
php artisan db:seed --class= PostCommentSeeder
※注意
php artisan db:seed
だと、デフォルトのシード(DatabaseSeeder.php
)が実行されてしまいます。
【5】各種コントローラーの作成
BlogControllerを作成する
BlogControllerでは、主に以下の処理を行ないます。
- トップページの保存
- 記事の検索
- 検索結果の表示
- ユーザーログイン/ログアウト
尚、記事とコメントのCRUD処理はPostControllerとCommentControllerで処理します。それでは、BlogControllerをつくっていきます( ◜◡‾)
新規作成ファイル:app/controllers/BlogController.php
<?php
class BlogController extends BaseController{
public function __construct(){
// 再度ログインすることを防ぐ処理
$this->beforeFilter('guest', ['only' => ['getLogin']]);
$this->beforeFilter('auth', ['only' => ['getLogout']]);
}
public function getIndex(){
$posts = Post::orderBy('id', 'desc')->paginate(10);
$posts->getFactory()->setViewName('pagination::simple');
$this->layout->title = 'Laravelでブログ作成';
$this->layout->main = View::make('home')->nest('content', 'index', compact('posts'));
}
public function getSearch(){
$searchTerm = Input::get('s');
$posts = Post::where('title', 'LIKE', '%'.$searchTerm.'%')->paginate(10);
$posts->getFactory()->setViewName('pagination::slider');
$posts->appends(['s'=>$searchTerm]);
$this->layout->with('title', '検索:'.$searchTerm);
$this->layout->main = View::make('home')->nest('content', 'index', ($posts->isEmpty()) ? ['notFound'=>true] : compact('posts'));
}
public function getLogin(){
$this->layout->title = 'login';
$this->layout->main = View::make('login');
}
public function postLogin(){
$credentials = [
'username'=>Input::get('username'),
'password'=>Input::get('password')
];
$rules = [
'username'=>'required',
'password'=>'required'
];
$validator = Validator::make($credentials, $rules);
if ($validator->passes()) {
if (Auth::attempt($credentials)) {
return Redirect::to('admin/dash-board');
}else{
return Redirect::back()->withInput()->with('failure', '正しいユーザー名/パスワードを入力してください。');
}
}else{
return Redirect::back()->withErrors($validator)->withInput();
}
}
public function getLogout(){
Auth::logout();
return Redirect::to('/');
}
}
getIndexファンクションに関して
Postモデルを利用してクエリを行ないます。
同時に、Paginatorを使い1ページに10件の投稿を表示しています。
getSearchファンクションに関して
検索キーワード(searchTerms)に応じて、ポストモデルからクエリを行ないます。
検索結果の1ページ目はpaginateに紐づきますが、それ以外のページは$post->appendsによって、情報の紐付けを行なっています。
nestに関して
使い方は以下です。
nest(partial viewの名前, viewへのパス, 送信したいデータ)
compactに関して
参考:PHP関数「compact」と「extract」を試してみる
PostControllerを作成する
新規作成ファイル:app/controllers/PostController.php
<?php
class PostController extends BaseController{
public function listPost(){
// AuthユーザーIDを取得する
$id = Auth::user()->id;
// ユーザーIDとauthorIDの等しい記事を取得する
$posts = Post::where('author_id', '=', $id)->get();
// $posts = Post::orderBy('id', 'desc')->paginate(10);
$this->layout->title = '記事一覧';
$this->layout->main = View::make('dash')->nest('content', 'posts.list', compact('posts'));
}
// ※ルートとモデルの結合:解説あり
public function showPost(Post $post){
$comments = $post->comments()->where('approved', '=', 1)->get();
$this->layout->title = $post->title;
// nestを使うことで、homeビューの中にindexビューを埋込みます
$this->layout->main = View::make('home')->nest('content', 'posts.single', compact('post', 'comments'));
}
public function newPost(){
$this->layout->title = '新規投稿';
$this->layout->main = View::make('dash')->nest('content', 'posts.new');
}
public function editPost(Post $post){
$this->layout->title = '記事の編集';
$this->layout->main = View::make('dash')->nest('content', 'posts.edit', compact('post'));
}
public function deletePost(Post $post){
$post->delete();
return Redirect::route('post.list') ->with('success', '記事が削除されました');
}
public function savePost(){
$post = [
'title' => Input::get('title'),
'content' => Input::get('content'),
];
$rules = [
'title' => 'required',
'content' => 'required',
];
$valid = Validator::make($post, $rules);
if ($valid->passes()) {
$post = new Post($post);
$post->author_id = Auth::user()->id;
$post->comment_count = 0;
$post->read_more = (strlen($post->content) > 120) ? sbstr($post->content, 0, 120) : $post->content;
$post->save();
return Redirect::to('admin/dash-board')->with('success', '投稿が保存されました');
}else{
return Redirect::back()->withErrors($valid)->withInput();
}
}
public function updatePost(Post $post){
$data = [
'title' => Input::get('title'),
'content' => Input::get('content'),
];
$rules = [
'title' => 'required',
'content' => 'required',
];
$valid = Validator::make($data, $rules);
if ($valid->passes()) {
$post->title = $data['title'];
$post->content = $data['content'];
$post->read_more = (strlen($post->content) > 120) ? sbstr($post->content, 0, 120) : $post->content;
// 同じ投稿を再度送信することを避ける
// getDirty:Get the attributes that have been changed since last sync.
if (count($post->getDirty()) > 0) {
$post->save();
return Redirect::back()->with('success', '投稿が更新されました');
}else{
return Redirect::back()->with('success', '更新内容がありません');
}
}else{
return Redirect::back()->withErrors($valid)->withInput();
}
}
}
ルートとモデルの結合に関して解説します。
たとえば、以下のプログラムをご覧ください。
<?php
//ファイル場所:app/routes.php
Route::model('post', 'Post');
Route::get('post/{post}',function(Post $post)
{
echo $post->title;
});
このプログラム書いた上で、postIDを渡してルートにアクセスします。
すると、Postモデルが自動的にIDに対応した情報をもってきてくれます。
Laravelの便利な機能のうちのひとつです( ◜◡‾)
次のステップへ進みます。
CommentControllerを作成する
新規作成ファイル:app/controller/CommentController.php
<?php
class CommentController extends BaseController{
public function listComment(){
$comments = Comment::orderBy('id', 'desc')->paginate(20);
$this->layout->title = 'コメント一覧';
$this->layout->main = View::make('dash')->nest('content', 'comments.list', compact('comments'));
}
public function newComment(Post $post){
$comment = [
'commenter' => Input::get('commenter'),
'email' => Input::get('email'),
'comment' => Input::get('comment'),
];
$rules = [
'commenter' => 'required',
'email' => 'required|email',
'comment' => 'required',
];
$valid = Validator::make($comment, $rules);
if ($valid->passes()) {
$comment = new Comment($comment);
$comment->approved = 'no';
$post->comments()->save($comment);
return Redirect::to(URL::previous().'#reply')->with('success', 'コメントが送信されました。現在は承認待ちです。');
}else{
return Redirect::to(URL::previous().'#reply')->withErrors($valid)->withInput();
}
}
public function showComment(Comment $comment){
if (Request::ajax()) {
return View::make('comments.show', compact('comment'));
}
}
public function deleteComment(Comment $comment){
$post = $comment->post;
$status = $comment->approved;
$comment->delete();
($status === 'yes') ? $post->decrement('comment_count') : '';
return Redirect::back()->with('success', 'コメントが削除されました');
}
public function updateComment(Comment $comment){
$comment->approved = Input::get('status');
$comment->save();
$comment->post->comment_count = Comment::where('post_id', '=', $comment->post->id)->where('approved', '=', 1)->count();
$comment->post->save();
return Redirect::back()->with('success', 'Comment'. (($comment->approved === 'yes') ? 'Approved' : 'Disapproved'));
}
}
ここまでで、以下が完了しました。
- Laravelの初期セットアップ
- Laravelのマイグレーション
- Eloquent ORMを使ったモデル作成
- データベースにダミーデータの送信
- 各種コントローラーの作成
【6】ルーティングの設定
つぎはルーティングを作っていきます。ルーティングを作成する前に、さらっと基礎を復習します。以下をご覧ください。
<?php
// GETリクエストはつぎのように処理します
Route::get('index',function(){
echo 'これが index pageです';
});
Route::get('login',function(){
echo 'これがログインぺーじです.';
});
// POSTリクエストはつぎのように処理します。
Route::post('login', function() {
echo 'POSTリクエストです';
});
コントローラーのリクエストは次のように行ないます。
Route::get('users', 'UsersController@getIndex');
上記のように記述した場合、 /users へのすべてのリクエストがUserControllerのgetIndexファンクションで処理されます。
ルーターでパラメータを渡すには以下のように記述します。
<?php
// パラメータ{id}がわたされます
Route::any('post/{id}',function($id){
echo "$id がわたされています。";
});
// ルートとモデルの結合
Route::model('post','Post'); // {post}でわたされたパラメータがPostモデルで処理されます
binds a model to the route parameter {post}
以上で、基本的な処理の解説はおわりです。
あわせて以下の記事をご覧いただくと、理解が深まります。
» 【アメリカで人気なPHPフレームワーク】Laravelの使い方メモ
それでは、開発を進めていきましょう。
ブログのルーターを作成する
編集ファイル:app/routes.php
<?php
// モデルとの結合
Route::model('post', 'Post');
Route::model('comment', 'Comment');
Route::model('user', 'User');
// ユーザーのルート設定
Route::get('/post/{post}/show', ['as' => 'post.show', 'uses' => 'PostController@showPost']);
Route::post('/post/{post}/comment', ['as' => 'comment.new', 'uses' => 'CommentController@newComment']);
// アドミンのルート設定
Route::group(['prefix' => 'admin', 'before' => 'auth'], function(){
// ルートの取得
Route::get('dash-board', function(){
$layout = View::make('master');
$layout->title = '管理パネル';
$layout->main = View::make('dash')->with('content', '管理パネルへようこそ<(_ _)>');
return $layout;
});
Route::get('/post/list', ['as' => 'post.list', 'uses' => 'PostController@listPost']);
Route::get('/post/new', ['as' => 'post.new', 'uses' => 'PostController@newPost']);
Route::get('/post/{post}/edit', ['as' => 'post.edit', 'uses' => 'PostController@editPost']);
Route::get('/post/{post}/delete', ['as' => 'post.delete', 'uses' => 'PostController@deletePost']);
Route::get('/comment/list', ['as' => 'comment.list', 'uses' => 'CommentController@listComment']);
Route::get('/comment/{comment}/show', ['as' => 'comment.show', 'uses' => 'CommentController@showComment']);
Route::get('/comment/{comment}/delete', ['as' => 'comment.delete', 'uses' => 'CommentController@deleteComment']);
// 投稿のルート設定
Route::post('/post/save', ['as' => 'post.save', 'uses' => 'PostController@savePost']);
Route::post('/post/{post}/update', ['as' => 'post.update', 'uses' => 'PostController@updatePost']);
Route::post('/comment/{comment}/update', ['as' => 'comment.update', 'uses' => 'CommentController@updateComment']);
});
// ホームのルート設定
Route::controller('/', 'BlogController');
// ビューコンポーサー
// サイドバーに最近の投稿を表示するためのルーティング
View::composer('sidebar', function ($view) {
$view->recentPosts = Post::orderBy('id', 'desc')->take(5)->get();
});
【7】ユーザー認証
AdminのルートをAuthenticationで保護する
Laravelには、『auth』『guest』認証が含まれています。
authとは
ユーザーがログインしている場合はTrueを返す
guestとは
ユーザーがログインしていない場合はTrueを返す
今回作成したルートプログラムにはauthファンクションを利用していることがわかるかと思います。
それでは、ユーザー認証をつくっていきます。
マイグレーションする
以下のコマンドを実行します。
$ php artisan migrate:make create_users_table --table='users'
Created Migration: 2014_10_11_072228_create_users_table
Generating optimized class loader
作成されたファイルを以下のように編集します。
編集ファイル:app/database/misrations/[実行日] create_users_table.php
<?php
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class CreateUsersTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function(Blueprint $table)
{
$table->create();
$table->increments('id');
$table->string('username');
$table->string('password');
$table->string('email');
$table->string('photo');
$table->string('remember_token')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function(Blueprint $table)
{
Schema::drop('users');
});
}
}
その後、マイグレートします。
$ php artisan migrate
これで、usersテーブルが完成しました。
ユーザーのダミーデータを生成する
ブログのコンテンツ/コメントを生成した方法とほぼ同じです。
編集ファイル:app/database/seeds/DatbaseSeeder.php
上記ファイルを以下のように変更します。
<?php
class DatabaseSeeder extends Seeder {
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Eloquent::unguard();
$this->call('UserTableSeeder');
}
}
つぎに、UserTableSeederを作成します。
新規作成ファイル:app/database/seeds/UserTableSeeder.php
<?php
class UserTableSeeder extends Seeder {
public function run()
{
$user = array(
'username' => 'hogehoge',
'password' => Hash::make('admin'),
'created_at' => DB::raw('NOW()'),
'updated_at' => DB::raw('NOW()'),
);
DB::table('users')->insert($user);
}
}
上記ファイルを実行します。
$ php artisan db:seed
usersテーブルに新規のユーザーが追加されたかと思います。
加えて、Userモデルを以下のように編集します。
編集ファイル:app/models/User.php
<?php
use IlluminateAuthUserTrait;
use IlluminateAuthUserInterface;
use IlluminateAuthRemindersRemindableTrait;
use IlluminateAuthRemindersRemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = array('password', 'remember_token');
protected $fillable = array('username', 'email');
public function posts(){
return $this->hasMany('Post');
}
}
ここまでで、以下が完了しました。
- Laravelの初期セットアップ
- Laravelのマイグレーション
- Eloquent ORMを使ったモデル作成
- データベースにダミーデータの送信
- 各種コントローラーの作成
- ルーティングの設定
- ユーザー認証
つぎはビューを作っていきます。
【8】ビューの作成
マスターのレイアウトの作成
新規作成ファイル:app/views/master.blade.php
<!DOCTYPE html>
<html class="no-js" lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
@section('title')
<title>{{{$title}}}</title>
@show
{{ HTML::style('assets/css/foundation.css') }}
{{ HTML::style('assets/css/custom.css') }}
{{ HTML::script('./assets/js/vendor/custom.modernizr.js') }}
</head>
<body>
<div class="row main">
<div class="small-12 large-12 column" id="masthead">
<header>
<nav class="top-bar" data-topbar>
<ul class="title-area">
<!-- Title Area -->
<li class="name"></li>
<li class="toggle-topbar menu-icon"><a href="#"><span>メニュー</span></a></li>
</ul>
<section class="top-bar-section">
<ul class="left">
<li class="{{(strcmp(URL::full(), URL::to('/')) == 0) ? 'active' : ''}}"><a href="{{URL::to('/')}}">ホーム</a></li>
</ul>
<ul class="right">
@if(Auth::check())
<!-- if文の解説:現在ページのliクラスにactiveを付加する -->
<li class="{{ (strpos(URL::current(), URL::to('admin/dash-board'))!== false) ? 'active' : '' }}">
{{HTML::link('admin/dash-board','ダッシュボード')}}
</li>
<li class="{{ (strpos(URL::current(), URL::to('logout'))!== false) ? 'active' : '' }}" >
{{HTML::link('logout','ログアウト')}}
</li>
@else
<li class="{{ (strpos(URL::current(), URL::to('login'))!== false) ? 'active' : '' }}">
{{HTML::link('login','ログイン')}}
</li>
@endif
</ul>
</section>
</nav>
<div class="sub-header">
<hgroup>
<h1>{{HTML::link('/','Laravelブログ')}}</h1>
<h2>Laravelでブログ作成</h2>
</hgroup>
</div>
</header>
</div>
<div class="row">
{{$main}}
</div>
<div class="row">
<div class="small-12 large-12 column">
<footer class="site-footer"></footer>
</div>
</div>
</div>
{{ HTML::script('./assets/js/vendor/jquery.js') }}
{{ HTML::script('./assets/js/foundation.min.js') }}
<script>
$(document).foundation();
</script>
</body>
</html>
※注意:マスターレイアウトをすべてのコントローラーで継承する方法
BaseControllerに以下の記述を追加することで実現可能です。
protected $layout='master';
プログラミングの前半部分でfoundation.cssを読み込んでいることがわかるかと思います。
CSS部分を多少カスタマイズしたファイルはgithubで配布しています。
以下のリンクからDLしてご利用ください<(_ _)>
Laravel ブログ foundation
つづいて、その他のビューを作成していきます。
尚、ビューファイルの全体構造としては、以下のとおりになります。
■ commentsフォルダ ∟ commentform.blade.php ∟ list.blade.php ∟ show.blade.php ■ postsフォルダ ∟ edit.blade.php ∟ list.blade.php ∟ new.blade.php ∟ single.blade.php ■ usrsフォルダ ∟ login.blade.php ∟ newaccount.blade.php ■ dash.blade.php ■ home.blade.php ■ index.blade.php ■ master.blade.php ■ sidebar.blade.php
これから上記のファイルの全コードを書いていくわけですが、とても簡単なので解説は省きます。一点だけ、注意点があります。
コードの場所:app/views/dash.blade.php
<div class="small-9 large-9 column">
<div class="content">
<!-- foundationのReveal Modal pluginがajaxをサポートしています -->
<!-- 最後のdiv要素はAjaxでコンテンツを出力しますが、これはfoundationのReveal Modal pluginが利用されています -->
@if(Session::has('success'))
<div data-alert class="alert-box round">
{{Session::get('success')}}
<a href="#" class="close">×</a>
</div>
@endif
{{$content}}
</div>
<div id="comment-show" class="reveal-modal small" data-reveal>
{{-- Ajaxを利用 --}}
</div>
</div>
ここの部分だけ少し特殊になっています。
foundationにはreveal-modalというプラグインが入っており、上記のコードを書くだけで、コメントをAjaxで表示/非表示ができるようです。
もっと詳しく知りたいって人は以下のリンクからどうぞ。
Reveal Modal | Foundation Docs
残りのビューファイルは以下からDLしてご利用ください。
manabubannai/laravel_cms
以上です。参考になれば幸いです( ◜◡‾)
photo credit: moominsean via photopin cc
※P.S:無料メルマガで発信中:過去の僕は「ブログ発信で5億円」を稼ぎました。次は「30億円」を目指します。挑戦しつつ、裏側の思考を「メルマガ」から発信します。不満足なら1秒で解約できます。無料登録は「こちら」です。