WEBOPIXEL

Laravel5.4でシンプルなCMSを作るチュートリアル

Posted: 2017.06.14 / Category: PHP / Tag: 

Laravel5.4でシンプルなCMSを作るのをだらだらとメモしていきます。

Sponsored Link

インストール

コンポーザーでLaravelをインストールしましょう。
バージョン指定しないと現在(2017年6月)の最新バージョンである5.4がインストールされます。

$ composer create-project --prefer-dist laravel/laravel SimpleCMS

インストールにしばらく時間が掛かりますが、終わったらカレントを移動します。

$ cd SimpleCMS

ビルドインサーバーを起動してとりあえず動くか確認してみましょう。

$ php artisan serve

ブラウザでhttp://localhost:8000/にアクセスしてLaravelって表示されれば成功。

初期設定

configのapp.phpは言語の設定だけ変更。

config/app.php

return [
	// ...
	'timezone' => 'Asia/Tokyo',
	'locale' => 'ja',

データベースは今回はSQLiteを使うので.envを編集。
DB_CONNECTION=sqliteを追記して既存のMySQLの設定部分は削除します。

.env

DB_CONNECTION=sqlite

#DB_CONNECTION=mysql
#DB_HOST=127.0.0.1
#DB_PORT=3306
#DB_DATABASE=homestead
#DB_USERNAME=homestead
#DB_PASSWORD=secret

touchコマンドでsqliteファイルを作成。

$ touch database/database.sqlite

設定を変更したら、ビルドインサーバーを再起動しましょう。

ユーザー認証関係

ユーザー登録とか認証とかは一発でできます。

$ php artisan make:auth

migrateでデータベースにテーブルを作成。

$ php artisan migrate

ブラウザでhttp://localhost:8000/registerにアクセスしてユーザー登録してみましょう。
ユーザー登録できたらログアウト・ログインを試してみて動いてるか確認してみます。できてますよね。

Postモデルの作成

make:modelでモデルファイルを作成。-mオプションでマイグレーションファイルも一緒に作成します。

$ php artisan make:model Post -m

作成したマイグレーションファイルにtitle,bodyを追記します。
XXXXには作成日のタイムスタンプが自動的に入ります。

database/migrations/XXXX_XX_XX_XXXXXX_create_posts_table.php

public function up()
{
	Schema::create('posts', function (Blueprint $table) {
		$table->increments('id');
		$table->string('title');
		$table->text('body');
		$table->timestamps();
	});
}

migratepostsテーブルを作成します。

$ php artisan migrate

Postモデルにguardedを設定します。

app/Post.php

class Post extends Model
{
    protected $guarded = ['id', 'created_at'];
}

ダミーデータの作成

シーダーを使ってダミーデータを作成します。

$ php artisan make:seeder PostsTableSeeder

database/seeds/PostsTableSeeder.php

public function run()
{
	DB::table('posts')->insert([
		[
			'title' => '最初の記事',
			'body' => '最初の記事のテキストです。',
			'created_at' => '2017-05-02 14:28:19',
			'updated_at' => '2017-05-02 14:28:19'
		],[
			'title' => '2番目の記事',
			'body' => '2番目の記事のテキストです。',
			'created_at' => '2017-05-03 14:28:19',
			'updated_at' => '2017-05-03 14:28:19'
		]
		// ...
	]);
}

今回は配列でそのまま入れてますが、大量のデータが必要な場合はFakerという機能があるのでそちらを使用してたほうがいいかもしれません。

あとはDatabaseSeeder.phpに登録して、

database/seeds/DatabaseSeeder.php

public function run()
{
	$this->call(PostsTableSeeder::class);
}

db:seedコマンドでデータベースに投入します。

$ php artisan db:seed --class=PostsTableSeeder

管理画面用Postsコントローラーの作成

管理画面用のコントローラーを作成します。
make:controllerコマンドでコントローラーの雛形を作成。

$ php artisan make:controller Admin/PostsController --resource

各アクションを実装していきます。

app/Http/Controllers/Admin/PostsController.php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Post;

class PostsController extends Controller
{
    // バリデーションのルール
    public $validateRules = [
        'title' => 'required',
        'body' => 'max:500'
    ];
    public function index()
    {
        $posts = Post::orderBy('id', 'desc')->paginate(20);
        return view('admin.posts.index', compact('posts'));
    }
    public function create()
    {
        return view('admin.posts.create');
    }
    public function store(Request $request)
    {
        $this->validate($request, $this->validateRules);
        Post::create($request->all());
        \Session::flash('flash_message', '記事を作成しました。');
        return redirect('admin/posts');
    }
    public function show($id)
    {
        $post = Post::findOrFail($id);
        return view('admin.posts.show', compact('post'));
    }
    public function edit($id)
    {
        $post = Post::findOrFail($id);
        return view('admin.posts.edit', compact('post'));
    }
    public function update(Request $request, $id)
    {
        $this->validate($request, $this->validateRules);

        $post = Post::findOrFail($id);
        $post->update($request->all());

        \Session::flash('flash_message', '記事を更新しました。');
        return redirect('admin/posts');
    }
    public function destroy($id)
    {
        $post = Post::findOrFail($id);
        $post->delete($id);
        \Session::flash('flash_message', '記事を削除しました。');
        return redirect('admin/posts');
    }
}

ビューを作る前に

Laravel5.4にはフォームヘルパー的な機能はデフォルトで入っていないのでlaravelcollectiveをインストールします。

$ composer require laravelcollective/html

設定ファイルのprovidersaliasesに追記します。

config/app.php

return [
    'providers' => [
        // ...
        Collective\Html\HtmlServiceProvider::class,
    ],
    'aliases' => [
        // ...
        'Form' => Collective\Html\FormFacade::class,
        'Html' => Collective\Html\HtmlFacade::class,
    ],
];

コントローラーでバリデーションの設定もしたので日本語で表示できるようにしてみましょう。
5.3用ですが下記ファイルをダウンロードして、resources/lang/ja/に入れます。

oppara/validation.php

attributesの日本語も設定しましょう。
今回はtitleとbodyだけですね。

resources/lang/ja/validation.php

'attributes' => [
	'title' => 'タイトル',
	'body' => '内容'
],

管理画面用Postsビューの作成

次は管理画面表示部分のビューを作成しましょう。
最初にレイアウトファイルを作成します。
今回は単純にresources/views/layouts/app.blade.phpをリネームしてadmin.blade.phpとした。

index.blade.php

一覧ページです。

resources/views/admin/posts/index.blade.php

@extends('layouts.admin')
@section('content')

<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="panel panel-default">
                <div class="panel-heading">記事一覧</div>
                <div class="panel-body">
                    @if (Session::has('flash_message'))
                        <div class="alert alert-success">{{ Session::get('flash_message') }}</div>
                    @endif

                    <div class="mb10">
                        {!! link_to('admin/posts/create', '新規作成', ['class' => 'btn btn-primary']) !!}
                    </div>

                    <table class="table table-striped table-bordered table-hover">
                        <thead>
                        <tr>
                            <th>ID</th>
                            <th>タイトル</th>
                            <th>作成日</th>
                            <th>編集</th>
                        </tr>
                        </thead>
                        @foreach($posts as $post)
                            <tr>
                                <td>{{ $post->id }}</td>
                                <td>{{ $post->title }}</td>
                                <td>{{ $post->created_at->format('Y年m月d日') }}</td>
                                <td>
                                    {!! link_to_action('Admin\PostsController@show', '表示', [$post->id]) !!}
                                    {!! link_to_action('Admin\PostsController@edit', '編集', [$post->id]) !!}
                                    {!! Form::model($post,
                                    ['url' => [
                                        'admin/posts', $post->id],
                                        'method' => 'delete',
                                        'class' => 'delete-from'
                                    ]) !!}
                                        {!! Form::submit('削除', [
                                            'onclick' => "return confirm('本当に削除しますか?')",
                                            'class' => 'text-link'
                                            ]) !!}
                                    {!! Form::close() !!}
                                </td>
                            </tr>
                        @endforeach
                    </table>
                    {!! $posts->render() !!}
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

show.blade.php

詳細ページです。

resources/views/admin/posts/show.blade.php

@extends('layouts.admin')
@section('content')

<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="panel panel-default">
                <div class="panel-heading">記事詳細</div>
                <div class="panel-body">
                    <div>
                        <h1>{{ $post->title }}</h1>
                        <p>{{ $post->body }}</p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

fields.blade.php

入力フォームは新規と編集ページ共通なので独立させます。

resources/views/admin/posts/fields.blade.php

<div class="form-group">
    {!! Form::label('title', 'タイトル:', ['class' => 'col-sm-2 control-label']) !!}
    <div class="col-sm-10">
        {!! Form::text('title', null, ['class' => 'form-control']) !!}
    </div>
</div>

<div class="form-group">
    {!! Form::label('body', '内容:', ['class' => 'col-sm-2 control-label']) !!}
    <div class="col-sm-10">
        {!! Form::textarea('body', null, ['class' => 'form-control']) !!}
    </div>
</div>

<div class="form-group">
    <div class="col-sm-10 col-sm-offset-2">
        {!! Form::submit('保存', ['class' => 'btn btn-primary']) !!}
        {!! link_to('admin/posts', '一覧へ戻る', ['class' => 'btn btn-default']) !!}
    </div>
</div>

create.blade.php

作成画面です。先ほどのフォームをインクルードします。

resources/views/admin/posts/create.blade.php

@extends('layouts.admin')
@section('content')

<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="panel panel-default">
                <div class="panel-heading">新規作成</div>
                <div class="panel-body">

                    @if ($errors->any())
                        <div class="alert alert-danger">
                            <ul>
                                @foreach ($errors->all() as $error)
                                    <li>{{ $error }}</li>
                                @endforeach
                            </ul>
                        </div>
                    @endif

                    {!! Form::open(['url' => 'admin/posts',
                                'class' => 'form-horizontal',
                                'id' => 'post-input']) !!}

                    @include('admin.posts.fields')

                    {!! Form::close() !!}
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

edit.blade.php

編集画面は作成画面とほとんど同じですね。

resources/views/admin/posts/edit.blade.php

@extends('layouts.admin')
@section('content')

<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="panel panel-default">
                <div class="panel-heading">編集</div>
                <div class="panel-body">

                    @if ($errors->any())
                        <div class="alert alert-danger">
                            <ul>
                                @foreach ($errors->all() as $error)
                                    <li>{{ $error }}</li>
                                @endforeach
                            </ul>
                        </div>
                    @endif

                    {!! Form::model($post,
                    ['url' => [
                        'admin/posts', $post->id],
                        'method' => 'PATCH',
                        'class' => 'form-horizontal',
                        'id' => 'post-input'

                    ]) !!}
                    @include('admin.posts.fields')

                    {!! Form::close() !!}
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

ルーターの作成

ルーターの設定をしてアクセスできるようにします。
管理画面なのでadminプレフィクスを付けました。
middlewareauthを指定してすべて認証が必要なようにします。

routes/web.php

Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function()
{
	Route::resource('posts', 'Admin\PostsController');
});

/admin/postsにアクセスして動作を確認してみてください。
作成・編集など一通りの動作ができるようになったので管理画面の方は完了です。

フロントの作成

フロントに表示されるページを作成します。
編集機能はいらないので、一覧・詳細ページを作成します。
app/Http/Controllers/Admin/PostsController.phpをコピーしてapp/Http/Controllers/PostsController.phpに配置します。

app/Http/Controllers/PostsController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Post;

class PostsController extends Controller
{
    public function index()
    {
        $posts = Post::orderBy('id', 'desc')->paginate(20);
        return view('posts.index', compact('posts'));
    }
    public function show($id)
    {
        $post = Post::findOrFail($id);
        return view('posts.show', compact('post'));
    }
}

基本index、show以外を削除してパスを変更しただけです。
ルーターも追記しましょう。

routes/web.php

Route::resource('posts', 'PostsController', ['only' => [
    'index', 'show'
]]);

ビューもコントローラーと同じように/resources/views/posts/index.blade.php/resources/views/posts/show.blade.phpにコピーして作成します。
ほぼ同じなので割愛いたします。

とりあえず以上です。
ここまでのものはGitHubに置いてあります。

参考サイト:
Laravel 5.4 TOC
ララ帳