Laravel5.1 搭建博客 --文章的增删改查
教程源于:Laravel學院
繼文件上傳后呢,咱來搞一搞文章的事情。
?
1 更改數據表
我們需要改改數據表的結構 因為涉及到重命名列名 所以咱需要引入一個包:Doctrine:
composer require "doctrine/dbal"1.1 新建遷移文件
php artisan make:migration restructure_posts_table --table=posts1.2 編輯遷移文件
class RestructurePostsTable extends Migration {/*** Run the migrations.** @return void*/public function up(){Schema::table('posts', function (Blueprint $table) {// 在title字段后添加subtitle 文章的副標題$table->string('subtitle')->after('title');// 把content改為content_raw Markdown格式的文本$table->renameColumn('content', 'content_raw');// 在content字段后添加content_html 使用 Markdown 編輯內容但同時保存 HTML 版本$table->text('content_html')->after('content');// 在content_html字段后添加page_image 文章使用到縮略圖$table->string('page_image')->after('content_html');// 在page_image字段后添加meta_description 文章說明$table->string('meta_description')->after('page_image');// 在meta_description字段后添加is_draft 是否是草稿$table->boolean('is_draft')->after('meta_description');// 在is_draft字段后添加layout 并設置默認值 使用的布局$table->string('layout')->after('is_draft')->default('blog.layouts.post');});}/*** Reverse the migrations.** @return void*/public function down(){Schema::table('posts', function (Blueprint $table) {$table->dropColumn('subtitle');$table->dropColumn('content_html');$table->dropColumn('page_image');$table->dropColumn('meta_description');$table->dropColumn('is_draft');$table->dropColumn('layout');$table->renameColumn('content_raw', 'content');});} }1.3 運行遷移
運行命令后看眼數據庫是否已經修改成功:
php artisan migrate?
2 和Tag關聯
文章和標簽是多對多的關系,所以先創建遷移文件,然后記得運行遷移:
class CreatePostTagPivot extends Migration {/*** Run the migrations.** @return void*/public function up(){Schema::create('post_tag_pivot', function (Blueprint $table) {$table->increments('id');$table->integer('tag_id')->unsigned()->index();$table->integer('post_id')->unsigned()->index();});}/*** Reverse the migrations.** @return void*/public function down(){Schema::drop('post_tag_pivot');} }2.1 編輯Tag模型
class Tag extends Model {protected $fillable = ['tag', 'title', 'subtitle', 'page_image', 'meta_description', 'layout', 'reverse_direction'];// 定義關系public function posts(){return $this->belongsToMany(Post::class, 'post_tag_pivot');}/*** 批量創建需要的tag** @param array $tags*/public static function addNeededTags(array $tags){if (count($tags) === 0){return;}// 通過tag字段在$tags數組中查找,把找到的模型通過lists來獲取所有的tag字段$found = static::WhereIn('tag', $tags)->lists('tag')->all();foreach (array_diff($tags, $found) as $tag) {// 把不存在的tag進行創建 其他字段先自動填充static::create(['tag' => $tag,'title' => $tag,'subtitle' => 'Subtitle for '.$tag,'page_image' => '','meta_description' => '','reverse_direction' => false,]);}} }?
3 展示文章
我們一步步的來,首先先來展示我們的文章吧。
3.1 修改PostController的index方法
public function index(){return view('admin.post.index')->withPosts(Post::all());}3.2 修改post/index.blade.php
@extends('admin.layout')@section('content')<div class="container-fluid"><div class="row page-title-row"><div class="col-md-6"><h3>Post <small> >> Listing</small></h3></div><div class="col-md-6 text-right"><a href="/admin/post/create" class="btn btn-success btn-md"><i class="fa fa-plus-circle"></i> New Post</a></div></div><div class="row"><div class="col-sm-12">@include('admin.partials.error')@include('admin.partials.success')<table id="posts-table" class="table table-bordered table-striped"><thead><tr><td>Published</td><td>Title</td><td>Subtitle</td><td data-sortable="false">Published</td></tr></thead><tbody>@foreach($posts as $post)<tr><td data-order="{{ $post->published_at->timestamp }}">{{ $post->published_at->format('j-M-y g:ia') }}</td><td>{{ $post->title }}</td><td>{{ $post->subtitle }}</td><td><a href="/admin/post/{{ $post->id }}/edit" class="btn btn-xs btn-info"><i class="fa fa-edit"></i> Edit</a><a href="/blog/{{ $post->slug }}" class="btn btn-xs btn-warning"><i class="fa fa-eye"></i> View</a></td></tr>@endforeach</tbody></table></div></div></div> @endsection@section('scripts')<script>$(function () {$("#posts-table").DataTable({order: [[0, "desc"]]});});</script> @endsection?
4 創建文章
4.1 編輯create方法
public function create(){$data = $this->dispatch(new PostFormFields());return view('admin.post.create', $data);}在上面的代碼中我們使用到了一個任務,這個任務就是返回每個字段的默認值
4.2 創建Job
創建create方法中用到的job:
php artisan make:job PostFormFields在app/Jobs中找到剛剛創建的job編輯如下:
class PostFormFields extends Job implements SelfHandling {protected $id;protected $fieldList = ['title' => '','subtitle' => '','page_image' => '','content' => '','meta_description' => '','is_draft' => "0",'publish_date' => '','publish_time' => '','layout' => 'blog.layouts.post','tags' => [],];/*** Create a new job instance.** @return void*/public function __construct($id = null){$this->id = $id;}/*** Execute the job.** @return void*/public function handle(){$fields = $this->fieldList;if ($this->id){$fields = $this->fieldsFromModel($this->id, $fields);} else {$when = Carbon::now()->addHour();$fields['publish_date'] = $when->format('M-j-Y');$fields['publish_time'] = $when->format('g:i A');}foreach ($fields as $fieldName => $fieldValue) {$fields[$fieldName] = old($fieldName, $fieldValue);}return array_merge($fields, ['allTags' => Tag::lists('tag')->all()]);}/*** 取出模型中的數據** @param $id* @param array $fields* @return array*/protected function fieldsFromModel($id, array $fields){$post = Post::findOrFail($id);$fieldNames = array_keys(array_except($fields, ['tags']));$fields = ['id' => id];foreach ($fieldNames as $field) {$fields[$field] = $post->$field;}$fields['tags'] = $post->tags()->lists('tag')->all();return $fields;} }4.3 添加方法到Post模型
在job中我們使用了publishe_date和time,我們來實現這些get:
/*** 設置ContentRaw的同時設置ContentHTML。* * @param $value*/public function setContentRawAttribute($value){$this->attributes['content_raw'] = $value;$this->attributes['content_html'] = Markdown::convertToHtml($value);}/*** 使用content快捷的返回content_raw* * @param $value* @return mixed*/public function getContentAttribute($value){return $this->content_raw;}/*** 快捷返回publish_time* * @param $value* @return mixed*/public function getPublishTimeAttribute($value){return $this->published_at->format('g:i A');}/*** 快捷返回publish_date* * @param $value* @return mixed*/public function getPublishDateAttribute($value){return $this->published_at->format('M-j-Y');}4.4 下載需要用到的兩個前端資源
我們在create視圖中需要用到兩個前端資源:Selectize.js(下拉列表功能)和Pickadate.js(日期插件),我們來使用Bower下載:
bower install selectize --save bower install pickadate --save使用Gulp來整理前端資源:
var gulp = require('gulp'); var rename = require('gulp-rename'); var elixir = require('laravel-elixir');/*|--------------------------------------------------------------------------| Elixir Asset Management|--------------------------------------------------------------------------|| Elixir provides a clean, fluent API for defining some basic Gulp tasks| for your Laravel application. By default, we are compiling the Less| file for our application, as well as publishing vendor resources.|*//*** 拷貝操作*/ gulp.task("copyfiles", function(){// jsgulp.src("vendor/bower_dl/jquery/dist/jquery.js").pipe(gulp.dest("resources/assets/js/"));// bootstrapgulp.src("vendor/bower_dl/bootstrap/less/**").pipe(gulp.dest("resources/assets/less/bootstrap"));gulp.src("vendor/bower_dl/bootstrap/dist/js/bootstrap.js").pipe(gulp.dest("resources/assets/js/"));// font 不用編譯和合并 直接復制到public就可以gulp.src("vendor/bower_dl/bootstrap/fonts/**").pipe(gulp.dest("public/assets/fonts"));// awesomegulp.src("vendor/bower_dl/font-awesome/less/**").pipe(gulp.dest("resources/assets/less/fontawesome"));gulp.src("vendor/bower_dl/font-awesome/fonts/**").pipe(gulp.dest("public/assets/fonts"));// 拷貝 datatablesvar dtDir = 'vendor/bower_dl/datatables.net-plugins/integration/';gulp.src("vendor/bower_dl/datatables/media/js/jquery.dataTables.js").pipe(gulp.dest('resources/assets/js/'));gulp.src(dtDir + 'bootstrap/3/dataTables.bootstrap.css').pipe(rename('dataTables.bootstrap.less')).pipe(gulp.dest('resources/assets/less/others/'));gulp.src(dtDir + 'bootstrap/3/dataTables.bootstrap.js').pipe(gulp.dest('resources/assets/js/'));// 拷貝selectizegulp.src("vendor/bower_dl/selectize/dist/css/**").pipe(gulp.dest("public/assets/selectize/css"));gulp.src("vendor/bower_dl/selectize/dist/js/standalone/selectize.min.js").pipe(gulp.dest("public/assets/selectize/"));// 拷貝 pickadategulp.src("vendor/bower_dl/pickadate/lib/compressed/themes/**").pipe(gulp.dest("public/assets/pickadate/themes/"));gulp.src("vendor/bower_dl/pickadate/lib/compressed/picker.js").pipe(gulp.dest("public/assets/pickadate/"));gulp.src("vendor/bower_dl/pickadate/lib/compressed/picker.date.js").pipe(gulp.dest("public/assets/pickadate/"));gulp.src("vendor/bower_dl/pickadate/lib/compressed/picker.time.js").pipe(gulp.dest("public/assets/pickadate/")); });elixir(function(mix) {// 合并腳本文件mix.scripts(['js/jquery.js','js/bootstrap.js','js/jquery.dataTables.js','js/dataTables.bootstrap.js'],'public/assets/js/admin.js','resources/assets');// 編譯 Lessmix.less('admin.less', 'public/assets/css/admin.css'); });運行Gulp:
gulp copyfiles gulp4.5 創建create視圖
@extends("admin.layout") {{-- 樣式表 --}} @section('styles')<link rel="stylesheet" href="/assets/selectize/css/selectize.css"><link rel="stylesheet" href="/assets/selectize/css/selectize.bootstrap3.css"><link rel="stylesheet" href="/assets/pickadate/themes/default.css"><link rel="stylesheet" href="/assets/pickadate/themes/default.date.css"><link rel="stylesheet" href="/assets/pickadate/themes/default.time.css"> @endsection {{--content--}} @section("content")<div class="container-fluid"><div class="row page-title-row"><div class="col-md-12"><h3>Posts <small> >> Add New Post</small></h3></div></div><div class="row"><div class="col-sm-12"><div class="panel panel-default"><div class="panel-heading"><h3 class="panel-title">New Post Form</h3></div><div class="panel-body">@include('admin.partials.error')<form action="{{ route("admin.post.store") }}" method="POST" class="form-horizontal"><input type="hidden" name="_token" value="{{ csrf_token() }}">@include('admin.post._form')<div class="col-md-8"><div class="form-group"><div class="col-md-10 col-md-offset-2"><button class="btn btn-primary btn-lg" type="submit"><i class="fa fa-disk-o"></i>Save New Post</button></div></div></div></form></div></div></div></div></div> @endsection {{--scripts--}} @section('scripts')<script src="/assets/pickadate/picker.js"></script><script src="/assets/pickadate/picker.date.js"></script><script src="/assets/pickadate/picker.time.js"></script><script src="/assets/selectize/selectize.min.js"></script><script>$(function() {$("#publish_date").pickadate({format: "mmm-d-yyyy"});$("#publish_time").pickatime({format: "h:i A"});$("#tags").selectize({create: true});});</script> @endsection創建我們在上面用到的_form.blade.php:
<div class="row"><div class="col-md-8"><div class="form-group"><label for="title" class="col-md-2 control-label">Title</label><div class="col-md-10"><input type="text" class="form-control" name="title" autofocus id="title" value="{{ $title }}"></div></div><div class="form-group"><label for="subtitle" class="col-md-2 control-label">Subtitle</label><div class="col-md-10"><input type="text" class="form-control" name="subtitle" id="subtitle" value="{{ $subtitle }}"></div></div><div class="form-group"><label for="page_image" class="col-md-2 control-label">Page Image</label><div class="col-md-10"><div class="row"><div class="col-md-8"><input type="text" class="form-control" name="page_image" id="page_image" onchange="handle_image_change()" alt="Image thumbnail" value="{{ $page_image }}"></div><script>function handle_image_change() {$("#page-image-preview").attr("src", function () {var value = $("#page_image").val();if ( ! value) {value = {!! json_encode(config('blog.page_image')) !!};if (value == null) {value = '';}}if (value.substr(0, 4) != 'http' && value.substr(0, 1) != '/') {value = {!! json_encode(config('blog.uploads.webpath')) !!} + '/' + value;}return value;});}</script><div class="visible-sm space-10"></div><div class="col-md-4 text-right"><img src="{{ page_image($page_image) }}" class="img img_responsive" id="page-image-preview" style="max-height:40px"></div></div></div></div><div class="form-group"><label for="content" class="col-md-2 control-label">Content</label><div class="col-md-10"><textarea class="form-control" name="content" rows="14" id="content">{{ $content }}</textarea></div></div></div><div class="col-md-4"><div class="form-group"><label for="publish_date" class="col-md-3 control-label">Pub Date</label><div class="col-md-8"><input class="form-control" name="publish_date" id="publish_date" type="text" value="{{ $publish_date }}"></div></div><div class="form-group"><label for="publish_time" class="col-md-3 control-label">Pub Time</label><div class="col-md-8"><input class="form-control" name="publish_time" id="publish_time" type="text" value="{{ $publish_time }}"></div></div><div class="form-group"><div class="col-md-8 col-md-offset-3"><div class="checkbox"><label><input {{ checked($is_draft) }} type="checkbox" name="is_draft">Draft?</label></div></div></div><div class="form-group"><label for="tags" class="col-md-3 control-label">Tags</label><div class="col-md-8"><select name="tags[]" id="tags" class="form-control" multiple>@foreach ($allTags as $tag)<option @if (in_array($tag, $tags)) selected @endif value="{{ $tag }}">{{ $tag }}</option>@endforeach</select></div></div><div class="form-group"><label for="layout" class="col-md-3 control-label">Layout</label><div class="col-md-8"><input type="text" class="form-control" name="layout" id="layout" value="{{ $layout }}"></div></div><div class="form-group"><label for="meta_description" class="col-md-3 control-label">Meta</label><div class="col-md-8"><textarea class="form-control" name="meta_description" id="meta_description" rows="6">{{ $meta_description }}</textarea></div></div></div> </div>上面使用到了一個幫助函數,我們在helper.php中添加這個方法:
/*** 如果傳進來的參數是true 則返回checked,false放回空字符串。** @param $value* @return string*/ function checked($value) {return $value ? 'checked' : ''; }/*** Return img url for headers*/ function page_image($value = null) {if (empty($value)) {$value = config('blog.page_image');}if (! starts_with($value, 'http') && $value[0] !== '/') {$value = config('blog.uploads.webpath') . '/' . $value;}return $value; }4.6 創建表單請求類
class PostCreateRequest extends Request {/*** Determine if the user is authorized to make this request.** @return bool*/public function authorize(){return true;}/*** Get the validation rules that apply to the request.** @return array*/public function rules(){return ['title' => 'required','subtitle' => 'required','content' => 'required','publish_date' => 'required','publish_time' => 'required','layout' => 'required',];}/*** 返回創建模型所需要用的數據。** @return array*/public function postFillData(){$published_at = new Carbon($this->publish_date.' '.$this->publish_time);return ['title' => $this->title,'subtitle' => $this->subtitle,'page_image' => $this->page_image,'content_raw' => $this->get('content'),'meta_description' => $this->meta_description,'is_draft' => (bool)$this->is_draft,'published_at' => $published_at,'layout' => $this->layout,];} }4.7 實現store方法
public function store(Requests\PostCreateRequest $request){$post = Post::create($request->postFillData());$post->syncTags($request->get('tags', []));return redirect()->route('admin.post.index')->withSuccess('New Post Successfully Created.');}4.8 實現syncTags方法
在store方法中使用了Post模型的syncTags方法 用于同步標簽,在Post模型中創建這個方法:
public function syncTags(array $tags){Tag::addNeededTags($tags);if (count($tags)){$this->tags()->sync(Tag::whereIn('tag', $tags)->lists('id')->all());return;}$this->tags()->detach();}4.9 實現store方法
現在我們可以實現PostController上的store方法了:
public function store(Requests\PostCreateRequest $request){$post = Post::create($request->postFillData());$post->syncTags($request->get('tags', []));return redirect()->route('admin.post.index')->withSuccess('New Post Successfully Created.');}?
5 更新Post
5.1 創建edit視圖
@extends('admin.layout')@section('styles')<link href="/assets/pickadate/themes/default.css" rel="stylesheet"><link href="/assets/pickadate/themes/default.date.css" rel="stylesheet"><link href="/assets/pickadate/themes/default.time.css" rel="stylesheet"><link href="/assets/selectize/css/selectize.css" rel="stylesheet"><link href="/assets/selectize/css/selectize.bootstrap3.css" rel="stylesheet"> @stop@section('content')<div class="container-fluid"><div class="row page-title-row"><div class="col-md-12"><h3>Posts <small>? Edit Post</small></h3></div></div><div class="row"><div class="col-sm-12"><div class="panel panel-default"><div class="panel-heading"><h3 class="panel-title">Post Edit Form</h3></div><div class="panel-body">@include('admin.partials.error')@include('admin.partials.success')<form class="form-horizontal" role="form" method="POST" action="{{ route('admin.post.update', $id) }}"><input type="hidden" name="_token" value="{{ csrf_token() }}"><input type="hidden" name="_method" value="PUT">@include('admin.post._form')<div class="col-md-8"><div class="form-group"><div class="col-md-10 col-md-offset-2"><button type="submit" class="btn btn-primary btn-lg" name="action" value="continue"><i class="fa fa-floppy-o"></i>Save - Continue</button><button type="submit" class="btn btn-success btn-lg" name="action" value="finished"><i class="fa fa-floppy-o"></i>Save - Finished</button><button type="button" class="btn btn-danger btn-lg" data-toggle="modal" data-target="#modal-delete"><i class="fa fa-times-circle"></i>Delete</button></div></div></div></form></div></div></div></div>{{-- 確認刪除 --}}<div class="modal fade" id="modal-delete" tabIndex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button><h4 class="modal-title">Please Confirm</h4></div><div class="modal-body"><p class="lead"><i class="fa fa-question-circle fa-lg"></i>Are you sure you want to delete this post?</p></div><div class="modal-footer"><form method="POST" action="{{ route('admin.post.destroy', $id) }}"><input type="hidden" name="_token" value="{{ csrf_token() }}"><input type="hidden" name="_method" value="DELETE"><button type="button" class="btn btn-default" data-dismiss="modal">Close</button><button type="submit" class="btn btn-danger"><i class="fa fa-times-circle"></i> Yes</button></form></div></div></div></div></div>@stop@section('scripts')<script src="/assets/pickadate/picker.js"></script><script src="/assets/pickadate/picker.date.js"></script><script src="/assets/pickadate/picker.time.js"></script><script src="/assets/selectize/selectize.min.js"></script><script>$(function() {$("#publish_date").pickadate({format: "mmm-d-yyyy"});$("#publish_time").pickatime({format: "h:i A"});$("#tags").selectize({create: true});});</script> @stop5.2 生成edit方法
我們創建好edit視圖后要生成對應的方法:PostController下的edit方法。
public function edit($id){$data = $this->dispatch(new PostFormFields($id));return view('admin.post.edit', $data);}5.3 創建修改用的Request
php artisan make:request PostUpdateRequest我們的修改用的Request和創建用的Request很相像,所以直接繼承就好:
class PostUpdateRequest extends PostCreateRequest {}5.4 編輯update方法
public function update(Requests\PostUpdateRequest $request, $id){$data = $request->postFillData();$post = Post::findOrFail($id);$post->fill($data);$post->save();$post->syncTags($request->get('tags', []));if ($request->get('action') === 'continue'){return redirect()->back()->withSuccess('Post saved.');}return redirect()->route('admin.post.index')->withSuccess('Post saved.');}?
6 刪除Post
修改destroy方法:
public function destroy($id){$post = Post::findOrFail($id);// 刪除中間表的數據。$post->tags()->detach();$post->delete();return redirect()->route('admin.post.index')->withSuccess('Post deleted.');}?
轉載于:https://www.cnblogs.com/sun-kang/p/7702675.html
總結
以上是生活随笔為你收集整理的Laravel5.1 搭建博客 --文章的增删改查的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓8.1 字体 ——现在6.0,7.0
- 下一篇: 【ZJ选讲·字符串折叠】