Laravel Vuejs 实战:开发知乎 (17)实现提交答案

1.添加路由 并 处理AnswerController内逻辑:

路由:向web.php中添加:

  1 #region 回答路由CRUD
  2 
  3 //查看回答 以及 回答的form 都是在questions详细内容页面
  4 
  5 //提交回答
  6 Route::post('questions/{question}/answers', 'AnswerController@store')->name('answers.store');
  7 
  8 //更新回答
  9 
 10 
 11 //删除回答
 12 
 13 
 14 #endregion
 15 
  1 <?php
  2 
  3 /*
  4 |--------------------------------------------------------------------------
  5 | Web Routes
  6 |--------------------------------------------------------------------------
  7 |
  8 | Here is where you can register web routes for your application. These
  9 | routes are loaded by the RouteServiceProvider within a group which
 10 | contains the "web" middleware group. Now create something great!
 11 |
 12 */
 13 
 14 Route::get('/', function () {
 15     return view('welcome');
 16 });
 17 
 18 Auth::routes(['verify' => true]);
 19 
 20 Route::get('/home', 'HomeController@index')->name('home');
 21 
 22 Route::resource('questions', 'QuestionController');
 23 
 24 
 25 #region 回答路由CRUD
 26 
 27 //查看回答 以及 回答的form 都是在questions详细内容页面
 28 
 29 //提交回答
 30 Route::post('questions/{question}/answers', 'AnswerController@store')->name('answers.store');
 31 
 32 //更新回答
 33 
 34 
 35 //删除回答
 36 
 37 
 38 #endregion
 39 
 40 
web.php

AnswerController.php最后更新见文末

2.在question详情内页 添加提交回答的form

最后更新见文末 show.blade.php

3.提交后由于要给Question和User模型内赋值 answer_id 所以在$fillable属性里加上'answer_id':

不赋值!见后文Pointing up根据 一对多关系处说明。不存所以表里之前的字段要删除,也就更不可能赋值了

在处理一对多的时候

Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理

Laravel One to Many Eloquent Relationship Tutorial

多对多的时候:

Laravel中的 Pivot 表与多对多关系s

一对多关系,在创建answer模型的时候,需要更新user 和 question 里面的 answer_id,

不需要更新!见后文Pointing up根据 一对多关系处说明。不存所以表里之前的字段要删除,也就更不可能需要更新了

之前忘了在anwers 的 migration里加外键;

【模型之间通过模型关联方法 已经默认配置了外键 讲解:一对多

laravel模型表建立外键约束的使用:

模型:

  1 //表->posts
  2 class Post extends Model
  3 {
  4     //关联用户:
  5     public function user(){
  6         //belongsTo,第一个参数:外键表,第二个:当前表的外键,第三个:外渐表的主键。
  7         //如果第二个是名词+id,第三个是:id。后面的两个参数可以省略:
  8         // return $this->belongsTo('AppUser');
  9         return $this->belongsTo('AppUser','user_id','id');
 10     }
 11 }
 12 

视图中的调用:下面的会输出:posts表中user_id对应的user表中的id的name值

  1 <a href="#">{{$post->user->name}}</a></p>


现在加上,执行命令:

  1 php artisan make:migration add_foreign_key_relationship_to_answers_table --table=answers

注意是answers表;

  1 <?php
  2 
  3 use IlluminateDatabaseMigrationsMigration;
  4 use IlluminateDatabaseSchemaBlueprint;
  5 use IlluminateSupportFacadesSchema;
  6 
  7 class AddForeignKeyRelationshipToAnswersTable extends Migration
  8 {
  9     /**
 10      * Run the migrations.
 11      *
 12      * @return void
 13      */
 14     public function up()
 15     {
 16         Schema::table('answers', function (Blueprint $table) {
 17             //
 18             $table->foreign('user_id')->references('id')->on('users');
 19             $table->foreign('question_id')->references('id')->on('questions');
 20         });
 21     }
 22 
 23     /**
 24      * Reverse the migrations.
 25      *
 26      * @return void
 27      */
 28     public function down()
 29     {
 30         Schema::table('answers', function (Blueprint $table) {
 31             //
 32             $table->dropForeign('answers_user_id_foreign');
 33             $table->dropForeign('answers_question_id_foreign');
 34         });
 35     }
 36 }
 37 
 38 
2020_02_29_143522_add_foreign_key_relationship_to_answers_table.php

注意foreign key的命名:answers_user_id_foreign  查阅: Foreign Key Constraints 

然后执行:

  1 php artisan migrate


Pointing up根据 一对多关系:

主表不存子表的id:用户不存回答的id,问题不存回答的id,

子表存储主表的id:回答存储用户的id,回答存储问题的id,并设置外键,可以使用save saveMany associate再save方法;批注 2020-02-29 225253

具体请查阅: Laravel One to Many Eloquent Relationship Tutorial

所以我们需要移除之前再Quesiton和User表中的answer_id字段;代码省略

多对多的表:

新建立第三个表  还要使用attach sync detach方法操作更新

以上都必须设置模型关联

具体请查阅:Laravel Many to Many Eloquent Relationship Tutorial


show.blade.php:

  1 @extends('layouts.app')
  2 @section('content')
  3     <div class="container">
  4         <div class="row">
  5             <div class="col-md-8 col-md offset-2">
  6                 {{--问题--}}
  7                 <div class="card">
  8                     <div class="card-header">
  9                         {{ $question->title }}
 10 
 11                         @foreach(['success','warning','danger'] as $info)
 12                             @if(session()->has($info))
 13                                 <div class="alert alert-{{$info}}">{{ session()->get($info) }}</div>
 14                             @endif
 15                         @endforeach
 16 
 17                         @can('update',$question)
 18                             <a href="{{ route('questions.edit',$question) }}" class="btn btn-warning">编辑</a>
 19                         @endcan
 20 
 21                         @can('destroy',$question)
 22                             <form action="{{ route('questions.destroy',$question) }}" method="post">
 23                                 @csrf
 24                                 @method('DELETE')
 25                                 <button type="submit" class="btn btn-danger">删除</button>
 26                             </form>
 27                         @endcan
 28 
 29                         @forelse($question->topics as $topic)
 30                             <button class="btn btn-secondary float-md-right m-1">{{ $topic->name }}</button>
 31                         @empty
 32                             <p class="text text-warning float-md-right"> "No Topics"</p>
 33                         @endforelse
 34 
 35                         <p class="text text-info float-md-right"> 已有{{ count($question->answers) }}个回答</p>
 36 
 37                     </div>
 38                     <div class="card-body">
 39                         {!! $question->content !!}
 40                     </div>
 41                 </div>
 42 
 43 
 44                 {{--回答提交form--}}
 45 
 46                 <div class="card mt-2">
 47                     <div class="card-header">
 48                         提交回答
 49                     </div>
 50                     <div class="card-body">
 51                         <form action="{{ route('answers.store',$question) }}" method="post">
 52                         @csrf
 53                         <!-- 回答编辑器容器 -->
 54                             <script id="container" name="content" type="text/plain"
 55                                     style=" 100%;height: 200px">{!! old('content') !!}</script>
 56                             <p class="text text-danger"> @error('content') {{ $message }} @enderror </p>
 57                             <!--提交按钮-->
 58                             <button type="submit" class="btn btn-primary mt-2 float-md-right">提交回答</button>
 59                         </form>
 60                     </div>
 61                 </div>
 62 
 63                 {{--展示答案--}}
 64                 @forelse($question->answers as $answer)
 65                     <div class="card mt-4">
 66                         <div class="card-header">
 67                             <div class="float-left">
 68                                 <img src="{{ $answer->user->avatar }}" class="img-thumbnail imgWrap"
 69                                      style="height: 50px" alt="{{ $answer->user->name }}">
 70                                 <span class="text text-info">{{ $answer->user->name }}</span>
 71                             </div>
 72                             <span class="float-right text text-info m-auto">{{ $answer->updated_at }}</span>
 73                         </div>
 74 
 75                         <div class="card-body">
 76                             {!!  $answer->content  !!}
 77                         </div>
 78                     </div>
 79 
 80                 @empty
 81 
 82                 @endforelse
 83             </div>
 84         </div>
 85     </div>
 86 @endsection
 87 @section('footer-js')
 88     @include('questions._footer_js')
 89 @endsection
show.blade.php

QuestionController.php:

  1 <?php
  2 
  3 namespace AppHttpControllers;
  4 
  5 use AppHttpRequestsQuestionStoreRequest;
  6 use AppModelsQuestion;
  7 use AppRepositoriesQuestionRepository;
  8 
  9 
 10 class QuestionController extends Controller
 11 {
 12 
 13     /**
 14      * @var QuestionRepository
 15      */
 16     private $questionRepository;
 17 
 18     public function __construct(QuestionRepository $questionRepository)
 19     {
 20         $this->middleware(
 21             'auth',
 22             [
 23                 'except' =>
 24                     [
 25                         'index',
 26                         'show',
 27                     ]//非注册用户只能查看不能编辑添加更改删除
 28             ]
 29         );
 30 
 31         $this->questionRepository = $questionRepository;
 32     }
 33 
 34 
 35     /** Display a listing of the resource.
 36      * @return IlluminateContractsViewFactory|IlluminateViewView
 37      */
 38     public function index()
 39     {
 40         //
 41         $questions = $this->questionRepository->getQuestionPublished();
 42         return view('questions.index', compact('questions'));
 43     }
 44 
 45 
 46     /**
 47      * @return IlluminateContractsViewFactory|IlluminateViewView
 48      */
 49     public function create()
 50     {
 51         //
 52         return view('questions.create');
 53     }
 54 
 55 
 56     /**
 57      * @param QuestionStoreRequest $request
 58      * @return IlluminateHttpRedirectResponse
 59      */
 60     public function store(QuestionStoreRequest $request)//依赖注入QuestionStoreRequest实例
 61     {
 62         //
 63 //        $data = $request->validate([
 64 //            'title' => 'required|min:8',
 65 //            'content' => 'required|min:28',
 66 //        ]);
 67         //存储topics
 68         $topics = $this->questionRepository->normalizeTopics($request->get('topics'));
 69         //初始化question要用到的数据
 70         $data = $request->all();
 71         $data['user_id'] = auth()->user()->id;
 72 
 73 //        $question=Question::create($data); 被下方代码取代
 74         $question = $this->questionRepository->create($data);
 75 
 76         //使用我们再question model里面添加的topics方法获得 topics关联,再使用attach方法
 77         $question->topics()->attach($topics);
 78 
 79         return redirect()->route('questions.show', $question);
 80     }
 81 
 82 
 83     /**
 84      * @param Question $question
 85      * @return IlluminateContractsViewFactory|IlluminateViewView
 86      */
 87     public function show(Question $question)
 88     {
 89         //使用关系关联加载,with方法会将分类之下的主题一起查询出来,而且不会出现N+1影响性能的问题
 90         $question->with('topics')->get();
 91         //使用关系关联加载,with方法会将分类之下的回答一起查询出来,而且不会出现N+1影响性能的问题
 92         $question->with('answers')->get();
 93 
 94         return view('questions.show', compact('question'));
 95     }
 96 
 97 
 98     /**判断权限 返回视图
 99      * @param Question $question
100      * @return IlluminateContractsViewFactory|IlluminateHttpRedirectResponse|IlluminateViewView
101      */
102     public function edit(Question $question)
103     {
104         if (auth()->user()->can('update', $question)) //判断当前用户是否有权编辑更新该question实例
105         {
106             //返回编辑视图
107             return view('questions.edit', compact('question'));
108         } else {
109             //返回警告 没有权限
110             return redirect()->back()->with('warning', '你不能编辑不属于你的问题!');
111         }
112     }
113 
114 
115     /** Update the specified resource in storage.
116      * @param QuestionStoreRequest $questionStoreRequest
117      * @param Question $question
118      * @return IlluminateHttpRedirectResponse
119      */
120     public function update(QuestionStoreRequest $questionStoreRequest, Question $question)
121     {
122         //更新前 判断下权限
123         if (!(auth()->user()->can('update', $question))) {
124             //返回警告 没有权限
125             return redirect()->back()->with('warning', '你不能编辑不属于你的问题!');
126         }
127         //取得更新的字段 使用Eloquent提供的update方法执行问题更新
128         $question->update([
129             'title' => $questionStoreRequest->get('title'),
130             'content' => $questionStoreRequest->get('content'),
131         ]);
132 
133 
134         //topics的操作这时候看起来有点臃肿 可以使用TopicController来管理,暂时省略
135         //存储topics
136         $topics = $this->questionRepository->normalizeTopics($questionStoreRequest->get('topics'));
137         //使用我们再question model里面添加的topics方法获得 topics关联,
138         //再使用sync方法同步tag 【删除的会被删除掉,没删除的就保留,新的就增加】
139         $question->topics()->sync($topics);
140 
141         //更新完成,跳转回去
142         return redirect()->back();
143     }
144 
145 
146     /**Remove the specified resource from storage.
147      * @param Question $question
148      * @return IlluminateHttpRedirectResponse
149      * @throws Exception
150      */
151     public function destroy(Question $question)
152     {
153         //
154         if (auth()->user()->can('destroy', $question)) {
155             $question->delete();
156             return redirect()->route('questions.index')->with('success', "删除成功!");
157         }
158         return redirect()->back()->with('danger', "你不能删除不属于你的问题!");
159     }
160 
161 
162 }
163 
QuestionController.php

AnswerController.php:

  1 <?php
  2 
  3 namespace AppHttpControllers;
  4 
  5 use AppAnswer;
  6 use AppModelsQuestion;
  7 use IlluminateHttpRequest;
  8 
  9 class AnswerController extends Controller
 10 {
 11 
 12     /**
 13      * AnswerController constructor.
 14      */
 15     public function __construct()
 16     {
 17         //只有登录用户才能回答问题 但是可以查看 和查看提交创建页面,引导用户去注册
 18         $this->middleware(['auth',])->except(['index', 'create', 'show']);
 19     }
 20 
 21     /**
 22      * Display a listing of the resource.
 23      *
 24      * @return IlluminateHttpResponse
 25      */
 26     public function index()
 27     {
 28         //
 29     }
 30 
 31     /**
 32      * Show the form for creating a new resource.
 33      *
 34      * @return IlluminateHttpResponse
 35      */
 36     public function create()
 37     {
 38         //
 39     }
 40 
 41 
 42     /** Store a newly created resource in storage.
 43      * @param Request $request
 44      * @param Question $question
 45      * @return IlluminateHttpRedirectResponse
 46      */
 47     public function store(Request $request, Question $question)
 48     {
 49         //
 50 
 51 
 52         //初始化回答数据
 53         $data = $request->validate([
 54             'content' => 'required|min:30',
 55         ]);
 56         $data['user_id'] = auth()->user()->id;
 57 
 58         $data['question_id'] = $question->id;
 59 
 60         //创建回答入库
 61         $answer = Answer::create($data);
 62         //更新问题里的数据
 63         $question->increment('answers_count');
 64         //更新用户里的数据
 65         auth()->user()->increment('answers_count');
 66         return redirect()->back()->with('success', "回答成功!");
 67     }
 68 
 69     /**
 70      * Display the specified resource.
 71      *
 72      * @param AppAnswer $answer
 73      * @return IlluminateHttpResponse
 74      */
 75     public function show(Answer $answer)
 76     {
 77         //
 78     }
 79 
 80     /**
 81      * Show the form for editing the specified resource.
 82      *
 83      * @param AppAnswer $answer
 84      * @return IlluminateHttpResponse
 85      */
 86     public function edit(Answer $answer)
 87     {
 88         //
 89     }
 90 
 91     /**
 92      * Update the specified resource in storage.
 93      *
 94      * @param IlluminateHttpRequest $request
 95      * @param AppAnswer $answer
 96      * @return IlluminateHttpResponse
 97      */
 98     public function update(Request $request, Answer $answer)
 99     {
100         //
101     }
102 
103     /**
104      * Remove the specified resource from storage.
105      *
106      * @param AppAnswer $answer
107      * @return IlluminateHttpResponse
108      */
109     public function destroy(Answer $answer)
110     {
111         //
112     }
113 }
114 
AnswerController.php


Answer.php

  1 <?php
  2 
  3 namespace App;
  4 
  5 use AppModelsQuestion;
  6 use IlluminateDatabaseEloquentModel;
  7 use IlluminateDatabaseEloquentSoftDeletes;
  8 
  9 class Answer extends Model
 10 {
 11     #region 支持软删除添加
 12     use SoftDeletes;
 13     protected $dates = ['deleted_at'];
 14 
 15     #endregion
 16 
 17     protected $fillable = ['user_id', 'question_id', 'content'];
 18 
 19     /** 一个回答只有一个回答主人
 20      * @return IlluminateDatabaseEloquentRelationsBelongsTo
 21      */
 22     public function user()
 23     {
 24         return $this->belongsTo(User::class);
 25     }
 26 
 27     /** 一个回答只针对一个问题
 28      * @return IlluminateDatabaseEloquentRelationsBelongsTo
 29      */
 30     public function question()
 31     {
 32         return $this->belongsTo(Question::class);
 33     }
 34 
 35 }
 36 
Answer.php

原文地址:https://www.cnblogs.com/dzkjz/p/12386754.html