修改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 IlluminateHttpRedirectResponse 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数组值。如图:
由于当前显示的页面中不够完善,我们想看到添加的question的topics信息,所以在QuestionController.php的show方法更改如下以提供view需要的数据:
1 /** 2 * @param Question $question 3 * @return IlluminateContractsViewFactory|IlluminateViewView 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方法的介绍:
然后修改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 100%; 27 } 28 </style> 29 @endsection
最后效果如下: