一、前言
上一节教程中完成了用户管理,这节教程将大概完成发表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