zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31
    知也atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31无涯 - I
  • 原文地址:https://www.cnblogs.com/dzkjz/p/12386754.html
Copyright ? 2011-2022 开发猿


http://www.vxiaotou.com