Laravel 5.4 を活用した記事管理アプリケーションの作成手順

データベース設計からフロントエンドまで含めた、記事(Article)機能の CRUD リソースを作成するプロセスを解説します。

  1. データベースマイグレーションの定義 まずはプロジェクトにデータベーススキーマを構築します。Artisan ツールを使用して新しいテーブルを作成します。
php artisan make:migration create_articles_schema

生成されたファイルは database/migrations ディレクトリに保存され、タイムスタンプを含む一意の名前が付けられています。以下の内容でスキーマを定義してください。

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateArticlesSchema extends Migration
{
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title', 100)->nullable(false);
            $table->text('body')->nullable();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('articles');
    }
}

マイグレーションを実行して実際にテーブルを生成します。エラーが発生した場合(デフォルトの User テーブル関連など)、既存のインデックス設定を確認し調整が必要です。

php artisan migrate
  1. オブジェクト指向のリポジトリモデル(ORM)設定 Laravel の Eloquent ORM を利用してデータアクセス層を抽象化します。
php artisan make:model Article

生成されたクラスには明示的にテーブル名を設定します(デフォルトでは複数形を使いますが、ここでは単数形を使用するため)。

namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $table = 'articles';
    
    // フィールド名のマッピングや検証ルールを定義可能
    protected $fillable = ['title', 'body'];
}
  1. ルートとコントローラーの実装 MVC パターンの核心となるコントローラーを作成します。
php artisan make:controller ArticleController --resource

routes/web.php にリソースルーティングを設定します。

<?php

Route::resource('articles', 'ArticleController');

メインロジックの記述 コントローラー内でメソッドを実装します。変数名を変更し、コード構造を見やすくしています。

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Article;

class ArticleController extends Controller
{
    /**
     * 一覧表示
     */
    public function index(Request $request)
    {
        $list = Article::orderBy('created_at', 'desc')->get();
        return view('articles.list', compact('list'));
    }

    /**
     * 新規登録フォーム
     */
    public function create()
    {
        return view('articles.form');
    }

    /**
     * 登録処理
     */
    public function store(Request $request)
    {
        $params = $request->all();
        $record = new Article;
        $record->fill($params);

        if ($record->save()) {
            return redirect()->route('articles.index');
        } else {
            return back()->withInput()->withErrors('処理中に問題が発生しました');
        }
    }

    /**
     * 詳細表示
     */
    public function show($identifier)
    {
        $detail = Article::findOrFail($identifier);
        return view('articles.detail', compact('detail'));
    }

    /**
     * 編集画面表示
     */
    public function edit($identifier)
    {
        $item = Article::findOrFail($identifier);
        return view('articles.form', compact('item'));
    }

    /**
     * 更新処理
     */
    public function update(Request $request, $identifier)
    {
        $target = Article::findOrFail($identifier);
        $data = $request->only(['title', 'body']);
        
        if ($target->update($data)) {
            return redirect()->route('articles.show', $identifier);
        }
        
        return back()->withInput()->withErrors('更新失敗');
    }

    /**
     * 削除処理
     */
    public function destroy($identifier)
    {
        $deleteTarget = Article::findOrFail($identifier);
        $deleteTarget->delete();
        return redirect()->route('articles.index');
    }
}
  1. Blade テンプレートの構築 デザインレイアウトとして共通の親テンプレートを作成し、個別ページでこれを継承します。

共通レイアウト (resources/views/layouts/master.blade.php)

&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;記事管理システム&lt;/title&gt;
    &lt;link href="/css/bootstrap.css" rel="stylesheet"&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;nav class="navbar navbar-inverse"&gt;
        &lt;div class="container"&gt;
            &lt;a class="navbar-brand" href="/"&gt;Admin Panel&lt;/a&gt;
        &lt;/div&gt;
    &lt;/nav&gt;
    &lt;div class="container"&gt;
        @yield('content')
    &lt;/div&gt;
    &lt;script src="//code.jquery.com/jquery.min.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

新規作成フォーム (resources/views/articles/form.blade.php) POST と PUT メソッドを適切にハンドリングします。

&lt;!-- master.blade.php から拡張 --&gt;
@extends('layouts.master')
        
@section('content')
&lt;div class="panel panel-default"&gt;
  &lt;div class="panel-heading"&gt;@if(isset($item))編集&lt;else&gt;新規作成&lt;/endif&gt;&lt;/div&gt;
  
  &lt;div class="panel-body"&gt;
    @if ($errors-&gt;any())
      &lt;div class="alert alert-danger"&gt;
        &lt;ul&gt;
          @foreach ($errors-&gt;all() as $error)
            &lt;li&gt;{{ $error }}&lt;/li&gt;
          @endforeach
        &lt;/ul&gt;
      &lt;/div&gt;
    @endif
    
    &lt;form action="@if(isset($item)){{ url('articles/'.$item->id) }}@else{{ url('articles') }}@endif" method="POST"&gt;
      &lt;input type="hidden" name="_token" value="{{ csrf_token() }}"&gt;
      
      &lt;!-- 編集時はメソッド偽装が必要 --&gt;
      @if(isset($item))
        &lt;input type="hidden" name="_method" value="PUT"&gt;
      @endif
      
      件名:&lt;input type="text" name="title" class="form-control" value="{{ old('title', isset($item) ? $item->title : '') }}" required&gt;&lt;br&gt;
      本文:&lt;textarea name="body" rows="10" class="form-control"&gt;{{ old('body', isset($item) ? $item->body : '') }}&lt;/textarea&gt;&lt;br&gt;
      
      &lt;button type="submit" class="btn btn-success"&gt;保存&lt;/button&gt;
      &lt;button type="reset" class="btn btn-default"&gt;クリア&lt;/button&gt;
    &lt;/form&gt;
  &lt;/div&gt;
&lt;/div&gt;
@endsection

リスト表示 (resources/views/articles/list.blade.php)

@extends('layouts.master')
        
@section('content')
&lt;h3&gt;記事一覧&lt;/h3&gt;
&lt;a href="{{ route('articles.create') }}" class="btn btn-primary mb-3"&gt;記事追加&lt;/a&gt;

&lt;table class="table table-bordered"&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;ID&lt;/th&gt;
      &lt;th&gt;タイトル&lt;/th&gt;
      &lt;th&gt;操作&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    @forelse ($list as $row)
    &lt;tr&gt;
      &lt;td&gt;{{ $row->id }}&lt;/td&gt;
      &lt;td&gt;{{ $row->title }}&lt;/td&gt;
      &lt;td&gt;
        &lt;a href="{{ route('articles.edit', $row->id) }}" class="btn btn-xs btn-warning"&gt;編集&lt;/a&gt;
        
        &lt;form action="{{ route('articles.destroy', $row->id) }}" method="POST" style="display:inline;"&gt;
          &lt;input type="hidden" name="_method" value="DELETE"&gt;
          &lt;input type="hidden" name="_token" value="{{ csrf_token() }}"&gt;
          &lt;button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('削除してもよろしいですか?');"&gt;削除&lt;/button&gt;
        &lt;/form&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    @empty
    &lt;tr&gt;&lt;td colspan="3"&gt;データはありません&lt;/td&gt;&lt;/tr&gt;
    @endforelse
  &lt;/tbody&gt;
&lt;/table&gt;
@endsection

詳細表示 (resources/views/articles/detail.blade.php)

@extends('layouts.master')
        
@section('content')
&lt;div class="well"&gt;
  &lt;h2&gt;{{ $detail->title }}&lt;/h2&gt;
  &lt;hr&gt;
  &lt;div class="text"&gt;{{ nl2br(e($detail->body)) }}&lt;/div&gt;
  
  &lt;div style="margin-top:20px;"&gt;
    &lt;a href="{{ route('articles.edit', $detail->id) }}"&gt;この項目を編集&lt;/a&gt; | 
    &lt;a href="{{ route('articles.index') }}"&gt;一覧に戻る&lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;
@endsection

タグ: Laravel 5.4 Eloquent ORM Blade Template crud RESTful Routes

6月16日 00:20 投稿