一、前言
上一节教程中完成了用户管理,这节教程将大概完成发表Markdown格式文章并展示的功能。
二、Let's go
1.数据库迁移
articlestagsarticle_tag
$ php artisan migrate:make create_articles_table --create=articles $ php artisan migrate:make create_tags_table --create=tags $ php artisan migrate:make create_article_tag_table --create=article_tag
*_create_articles_table.php
Schema::create('articles', function(Blueprint $table)
{
$table->increments('id');
$table->string('title');
$table->string('summary')->nullable();
$table->text('content');
$table->text('resolved_content');
$table->integer('user_id');
$table->softDeletes();
$table->timestamps();
});
*_create_tags_table.php
Schema::create('tags', function(Blueprint $table)
{
$table->increments('id');
$table->string('name')->unique();
$table->integer('count')->default(0);
$table->softDeletes();
$table->timestamps();
});
*_create_article_tag_table.php
Schema::create('article_tag', function(Blueprint $table)
{
$table->increments('id');
$table->integer('article_id');
$table->integer('tag_id');
});
$ php artisan migrate
2.创建Article和Tag模型
ArticleTag
$ php artisan generate:model article $ php artisan generate:model tag
User.php
public function articles()
{
return $this->hasMany('Article');
}
一个用户会有多篇文章。
Article.php
use IlluminateDatabaseEloquentSoftDeletingTrait;
class Article extends Eloquent {
use SoftDeletingTrait;
protected $fillable = ['title', 'content'];
public function tags()
{
return $this->belongsToMany('Tag');
}
public function user()
{
return $this->belongsTo('User');
}
}
一篇文章会有多个标签并属于一个用户。
Tag.php
use IlluminateDatabaseEloquentSoftDeletingTrait;
class Tag extends Eloquent {
use SoftDeletingTrait;
protected $fillable = ['name'];
public function articles()
{
return $this->belongsToMany('Article');
}
}
一个标签会有多篇文章。
belongsToMany
3.发表文章视图
nav.blade.php
<li><a href="{{ URL::to('article/create') }}"><span ></span> Publish Article</a></li>
这时候登录会发现多了一个选项:

$ php artisan generate:view articles.create
articles/create.blade.php
@extends('_layouts.default')
@section('main')
<div >
<div >
<h1>Publish Article</h1>
<hr/>
@if ($errors->has())
<div data-am-alert>
<p>{{ $errors->first() }}</p>
</div>
@endif
{{ Form::open(array('url' => 'article', 'class' => 'am-form')) }}
<div >
<label for="title">Title</label>
<input name="title" type="text" value="{{ Input::old('title') }}"/>
</div>
<div >
<label for="content">Content</label>
<textarea name="content" rows="20">{{ Input::old('content') }}</textarea>
<p >
<button type="button" ><span ></span> Preview</button>
</p>
</div>
<div >
<label for="tags">Tags</label>
<input name="tags" type="text" value="{{ Input::old('tags') }}"/>
<p >Separate multiple tags with a comma ","</p>
</div>
<p><button type="submit" ><span ></span> Publish</button></p>
{{ Form::close() }}
</div>
</div>
<div >
<div >
<div >
<h4 ></h4>
<span data-am-modal-close
>×</span>
</div>
<div >
</div>
</div>
</div>
<script>
$(function() {
$('#preview').on('click', function() {
$('.am-popup-title').text($('#title').val());
$.post('preview', {'content': $('#content').val()}, function(data, status) {
$('.am-popup-bd').html(data);
});
$('#preview-popup').modal();
});
});
</script>
@stop
routes.php
$ php artisan generate:controller ArticleController
appcontrollersArticleController.phproutes.php
Route::resource('article', 'ArticleController');
对应路由如下:

ArticleController.phpcreate
public function __construct()
{
$this->beforeFilter('auth', array('only' => array('create', 'store', 'edit', 'update', 'destroy')));
}
public function create()
{
return View::make('articles.create');
}
Publish Article

4.文章预览
MarkdownMarkdowncomposer.jsonrequire
"maxhoffmann/parsedown-laravel": "dev-master"
composer updateconfig/app.php
'providers' => array(
...
'MaxHoffmannParsedownParsedownServiceProvider'
),
'aliases' => array(
...
'Markdown' => 'MaxHoffmannParsedownParsedownFacade',
),
ArticleController.php
public function preview() {
return Markdown::parse(Input::get('content'));
}
routes.php
Route::post('article/preview', array('before' => 'auth', 'uses' => 'ArticleController@preview'));
Route::resource('article', 'ArticleController');
Preview

出现预览界面:

5.添加文章
ArticleController.php
public function store()
{
$rules = [
'title' => 'required|max:100',
'content' => 'required',
'tags' => array('required', 'regex:/^w+$|^(w+,)+w+$/'),
];
$validator = Validator::make(Input::all(), $rules);
if ($validator->passes()) {
$article = Article::create(Input::only('title', 'content'));
$article->user_id = Auth::id();
$resolved_content = Markdown::parse(Input::get('content'));
$article->resolved_content = $resolved_content;
$tags = explode(',', Input::get('tags'));
if (str_contains($resolved_content, '<p>')) {
$start = strpos($resolved_content, '<p>');
$length = strpos($resolved_content, '</p>') - $start - 3;
$article->summary = substr($resolved_content, $start + 3, $length);
} else if (str_contains($resolved_content, '</h')) {
$start = strpos($resolved_content, '<h');
$length = strpos($resolved_content, '</h') - $start - 4;
$article->summary = substr($resolved_content, $start + 4, $length);
}
$article->save();
foreach ($tags as $tagName) {
$tag = Tag::whereName($tagName)->first();
if (!$tag) {
$tag = Tag::create(array('name' => $tagName));
}
$tag->count++;
$article->tags()->save($tag);
}
return Redirect::route('article.show', $article->id);
} else {
return Redirect::route('article.create')->withInput()->withErrors($validator);
}
}
public function show($id)
{
return View::make('articles.show')->with('article', Article::find($id));
}
tagsregex,Articleresolved_contentresolved_contentresolved_content
$ php artisan generate:view articles.show
articles/show.blade.php
@extends('_layouts.default')
@section('main')
<article >
<div >
<div >
<br/>
<div >
<h1 >{{{ $article->title }}}</h1>
<p >Author: <a >{{{ $article->user->nickname }}}</a> Datetime: {{ $article->updated_at }}</p>
</div>
<div >
<blockquote>
Tags:
@foreach ($article->tags as $tag)
<a >{{ $tag->name }}</a>
@endforeach
</blockquote>
</p>
<p>{{ $article->resolved_content }}</p>
</div>
<br/>
</div>
</div>
</article>
@stop
完成之后看看效果吧,先编辑文章:

发布后跳转到显示文章页面:

6.小结
User