Laravel Vuejs 实战:开发知乎 (11)实现选择话题整个流程

修改QuestionController.php如下:

1.处理Topic:

  1 /**
  2  * @param array $topics
  3  * @return array
  4  */
  5 private function normalizeTopics(array $topics)
  6 {
  7     //返回topic的id序列,如果不是数字,则强制认为是数据库中的topic的id,
  8     //这样虽然会漏掉用户如果设置的topic就是数字的情况,但是因为是测试,所以暂时忽略
  9     $normalizedTopics = collect($topics)->map(function ($topic) {
 10         if (is_numeric($topic))//是数字
 11         {
 12             //在数据库中找id
 13             $num_topic = Topic::query()->find($topic);
 14             if (isset($num_topic) && $num_topic->count() > 0) //在数据库中找得到id
 15             {
 16                 //因为是找到了 且是从question处提交,其内部的question_count应该增加1个
 17                 $num_topic->increment('questions_count');
 18                 //返回id
 19                 return (int)$num_topic->id;
 20             }
 21         }
 22         //否则创建一个新的topic
 23         //再之前先判断是否找得到,因为有时候重复提交,select2在提交的数据中不为数字,但是实际上数据库中已经有值
 24         $already = Topic::query()->select('id', 'name')->where('name', '=', $topic);
 25 
 26         if ($already->count() > 0) {
 27             //因为是找到了 且是从question处提交,其内部的question_count应该增加1个
 28             $already->increment('questions_count');
 29             //返回id
 30             return $already->first()->id;
 31         }
 32         $data_of_topic = [
 33             'name' => $topic,//目前view中topic只有一个选择框,没有设置content的输入框
 34             'questions_count' => 1,//因为是找到了 且是从question处提交,其内部的question_count应该初始化为1个
 35         ];
 36         //入库
 37         $newTopic = Topic::create($data_of_topic);
 38         //返回id
 39         return $newTopic->id;
 40     })->toArray();
 41 
 42     return $normalizedTopics;
 43 }
 44 

2.更新关联:

  1  /**
  2      * @param QuestionStoreRequest $request
  3      * @return \Illuminate\Http\RedirectResponse
  4      */
  5     public function store(QuestionStoreRequest $request)//依赖注入QuestionStoreRequest实例
  6     {
  7         //
  8 //        $data = $request->validate([
  9 //            'title' => 'required|min:8',
 10 //            'content' => 'required|min:28',
 11 //        ]);
 12         //存储topics
 13         $topics = $this->normalizeTopics($request->get('topics'));
 14         //初始化question要用到的数据
 15         $data = $request->all();
 16         $data['user_id'] = auth()->user()->id;
 17 
 18         $question = Question::create($data);
 19         //使用我们再question model里面添加的topics方法获得 topics关联,再使用attach方法
 20 
 21         $question->topics()->attach($topics);
 22 
 23         return redirect()->route('questions.show', $question);
 24     }
 25 

参考模型关联的官方文档:我们使用了attach方法,更多关于attach,detach,sync方法的介绍可以看:Laravel 模型关联attach,save,sync方法参数类型验证laravel 多对多关联 attach detach sync

代码:$question->topics()->attach($topics); 解析:

根据Question.php模型下的topics方法,关联信息的表是questions_topics,如果不设置,会有一个默认值

  1 public function topics()
  2 {
  3     return $this->belongsToMany(
  4         Topic::class,
  5         'questions_topics' //表名我设置的是questions_topics,可能不是系统自动解析的question_topic
  6     )->withTimestamps();//withTimestamps操作questions_topics表中create_at及updated_at字段的
  7 }
  8 

操作questions_topics表,使用attach方法,向表中添加question_id 对应的 $topics数组里的id数组值。如图:批注 2020-02-29 003329

由于当前显示的页面中不够完善,我们想看到添加的question的topics信息,所以在QuestionController.php的show方法更改如下以提供view需要的数据:

  1 /**
  2  * @param Question $question
  3  * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
  4  */
  5 public function show(Question $question)
  6 {
  7     //使用关系关联加载,with方法会将分类之下的商品一起查询出来,而且不会出现N+1影响性能的问题
  8     $question->with('topics')->get();
  9 
 10     return view('questions.show', compact('question'));
 11 }
 12 
 13 

关于with方法的介绍:

预加载

Laravel的Eloquent ORM 关联关系中的with用法

然后修改show.blade.php文件如下:

  1 @extends('layouts.app')
  2 
  3 @section('content')
  4 
  5     <div class="container">
  6         <div class="row">
  7             <div class="col-md-8 col-md offset-2">
  8                 <div class="card">
  9                     <div class="card-header">
 10                         {{ $question->title }}
 11                         @forelse($question->topics as $topic)
 12                             <button class="btn btn-secondary float-md-right m-1">{{ $topic->name }}</button>
 13                         @empty
 14                             <p class="text text-warning float-md-right"> "No Topics"</p>
 15                         @endforelse
 16                     </div>
 17                     <div class="card-body">
 18                         {!! $question->content !!}
 19                     </div>
 20                 </div>
 21             </div>
 22         </div>
 23     </div>
 24     <style scoped>
 25         .card-body img {
 26             width: 100%;
 27         }
 28     </style>
 29 @endsection

最后效果如下:

批注 2020-02-29 005052

posted @ 2020-02-29 00:52  dzkjz  阅读(390)  评论(0编辑  收藏  举报