読者です 読者をやめる 読者になる 読者になる

@半径とことこ60分

人間の認知範囲なんてそんなもんさと、鳥が囀った

プログラマーじゃないけどLaravel4入門(9)blogをつくる

laravel4

フロントエンド

まだ、ブロックに最新記事やカテゴリ一覧を表示するモジュール(的なもの)を作れていないのですが、ここらあたりでフロントエンドにかかってみようと思います。

実装すべきは、

  • トップページ
    1. 指定記事数を最新記事から順に表示
    2. 各記事に公開日、カテゴリ表示
    3. 長文は readmore を表示し省略
    4. 各記事タイトルに各記事ページへのリンク
    5. カテゴリにカテゴリ内記事トップへのリンク
  • 各記事ページ
    1. 全文表示
    2. Previous、Next 記事へのリンク

というところでしょう。

ただ、現在のところ、記事のタイムスタンプは created_at と updated_at しかありませんので published_at を追加しないといけません。updated_at は、Eloquent が自動的に更新してくれるようですが、下書きをしておいて後日公開ということを考えれば、公開日が必要になりますね。

articles テーブルに公開日カラムを追加する

$ php artisan migrate:make AddPublishedatToArticleTable

 app/database/migrations/****_AddPublishedatToArticleTable.php

public function up()
{
  Schema::table('articles', function($table)
  {
    $table->datetime('published_at');
  });
}

$ php artisan migrate

あわせて、views/backend/articles の index、edit 各 blade を変更します。コードは ausnichts/laravel4-blog · GitHub にあります。

で、公開日の入力は、当然「公開」をチェックした時ということになり、データを保存する時点で、新規の場合はチェックされていれば、編集の場合は非公開から公開に変更された場合に、その時の時間を書き込めばいいということになります。

app/controllers/backend/ArticlesController.php

public function store()
{
  $validator = Validator::make($data = Input::all(), Article::$rules);
  if ($validator->fails())
  {
    return Redirect::back()->withErrors($validator)->withInput();
  }
  $data['is_published'] = isset($data['is_published']) ? true : false;
  if( $data['is_published'] ) $data['published_at'] = date( 'Y-m-d H:i:s' );
  Article::create($data);
  Notification::success('Article was successfully added');
  return Redirect::action('ArticlesController@index');
}

public function update($id)
{
(略)

  $data['is_published'] = isset($data['is_published']) ? true : false;
  if ( !$article->is_published && $data['is_published'] ) $data['published_at'] = date( 'Y-m-d H:i:s' );
  $article->update($data);

(略)
}

ルーティング

フロントエンドのルーティングは、トップページ、各記事、カテゴリ内記事トップを振り分ける必要があります。routes.php で定義すればすむことですが、RESTフルコントローラーというものを試してみようと思います。

まず、app/routes.php

// FRONT SECTION
Route::controller('/', 'BlogController');

を追加します。で、これはあとから気づいたのですが、このルーティングは最下行に追加しないと、すべてのアクセスがこのルーティングに引っかかり、そんなページ内よと全てエラーになってしまいます。

app/controllers/BlogController.php

class BlogController extends BaseController {

  public function getIndex()
  {
    $articles = Article::where('is_published', '=', TRUE)->orderBy('published_at', 'DESC')->paginate(5);
    $categories = Category::all();
    $blocks = Block::where('is_published', '=', TRUE)->orderBy('order', 'ASC')->get();
    return View::make('index', compact('articles', 'categories', 'blocks'));
  }

  public function getArticle($id)
  {
    $article = Article::find($id);

    // get previous article
    $previous = Article::where('published_at', '=', Article::where('published_at', '<', $article->published_at)->max('published_at'))->first();

    // get next article
    $next = Article::where('published_at', '=', Article::where('published_at', '>', $article->published_at)->min('published_at'))->first();

    $categories = Category::all();
    $blocks = Block::where('is_published', '=', TRUE)->orderBy('order', 'ASC')->get();

    return View::make('article', compact('article', 'previous', 'next', 'categories', 'blocks'));
  }

  public function getCategoryArticles($id)
  {
    $articles = Article::where('category_id', $id)->orderBy('published_at', 'DESC')->paginate(5);
    $blocks = Block::where('is_published', '=', TRUE)->orderBy('order', 'ASC')->get();
    return View::make('index', compact('articles', 'blocks'));
  }

}

これだけで、トップURLにアクセスすれば index が呼ばれ、各記事は article/(id) を、カテゴリ内記事トップは category-articles/(id) を呼べばいいようです。

次ページ(previous)、前ページ(next)はこれがベストかどうか分かりませんが、今のところ問題はないようです。また、カテゴリ内記事トップからタイトルをクリックして各記事を表示した場合の previous、next が全ての記事の previous、next になってしまいます。何か方法を考えなくてはなりません。

フロントビュー

レイアウトは Bootstrap のテンプレートを使います。

Blog Template for Bootstrap

コードは ausnichts/laravel4-blog · GitHub にありますが、master.blade.php に Bladeレイアウトを定義し、index.blade.php で content と sidebar をオーバーライドしています。

先々、ブログタイトルや description などのメタデータも設定編集ができるようにしなくてはなりませんね。

app/views/index.blade.php

@extends('master')
@section('content')
@if($articles->count())
  @foreach($articles as $article)
    <div class="blog-post">
      <p class="blog-post-meta">{{ date('Y-m-d', strtotime($article->created_at)) }}</p>
      <h2 class="blog-post-title"><a href="{{ URL::to('article', array('id'=>$article->id)) }}">{{ $article->title }}</a></h2>
      <p class="blog-post-meta"><a href="{{ URL::to('category-articles', array('id'=>$article->category->id)) }}" class="btn btn-default btn-xs" role="button">{{ $article->category->category }}</a></p>
      {{ $article->content }}
    </div><!-- /.blog-post -->
  @endforeach
  {{ $articles->links() }}
@else
  <p>No message found</p>
@endif
@stop

@section('sidebar')
@foreach($blocks as $block)
@unless($block->type)
    <div class="sidebar-module sidebar-module-inset">
      <h4>{{ $block->title }}</h4>
      {{ $block->value }}
    </div>@endunless
@endforeach
@stop

ブロックのモジュール対応と readmore 処理が未完成になっています。article.blade.php ausnichts/laravel4-blog · GitHub にあります。

で、こんな感じになりました。英語のダミーデータでは雰囲気が分かりませんのでこちらを利用させていただきました。


すぐ使えるダミーテキスト - 日本語 Lorem ipsum

 

f:id:ausnichts:20140917161223p:plain

f:id:ausnichts:20140917161249p:plain