Laravel5.1 搭建博客 --文章的增删改查

教程源于:Laravel学院

继文件上传后呢,咱来搞一搞文章的事情。


1 更改数据表

我们需要改改数据表的结构 因为涉及到重命名列名 所以咱需要引入一个包:Doctrine

composer require "doctrine/dbal"

1.1 新建迁移文件

php artisan make:migration restructure_posts_table --table=posts

1.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(){
    // js
    gulp.src("vendor/bower_dl/jquery/dist/jquery.js")
        .pipe(gulp.dest("resources/assets/js/"));
    // bootstrap
    gulp.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"));

    // awesome
    gulp.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"));

    // 拷贝 datatables
    var 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/'));

    // 拷贝selectize
    gulp.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/"));

    // 拷贝 pickadate
    gulp.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'
    );

    // 编译 Less
    mix.less('admin.less', 'public/assets/css/admin.css');
});

运行Gulp:

gulp copyfiles
gulp

4.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(RequestsPostCreateRequest $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(RequestsPostCreateRequest $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>
@stop

5.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(RequestsPostUpdateRequest $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