关于Repository可以参考:
不过你不一定需要Repository,具体使用中,视情况而定:
Repository 模式和 Eloquent 的 ORM 在本质上是冲突的,只能二选一,否则就是白费力气;
本身用 repository 不会变的更方便,了解这个模式的初衷,主要是用来将数据存储和业务逻辑分离,具体数据持久化到哪里,领域服务并不用关心,这也隔离了后续持久化变更问题,还有一点很重要的是了解一下 DDD (领域驱动设计) 估计会更好的理解这个模式,关于提到复杂查询,我在项目中更倾向于将 cmd 和 query 分开(cqrs 架构),对于领域服务而言,不存在过于复杂的查询,repository 基本够用,但对于后台这种是需要复杂查询的,query 查询走 db builder 或者裸写都可以,你方便怎么来就怎么来,也不会对业务带来影响,甚至你的数据还可能来自 es 呢
但为了了解Repository,我们在本项目中尝试使用:
1.在app文件夹下,创建Repositories文件夹,并在该文件夹内新建一个QuestionRepository:
将QuestionController中数据查询的逻辑移入本类的方法中,这些方法都必须使用便于理解的名字命名。
1 class QuestionRepository 2 { 3 4 /** 5 * 根据提供的数据,使用Eloquent创建question,存储到数据库中并且返回该实例 6 * @param array $data 7 * @return mixed 8 */ 9 public function create(array $data) 10 { 11 $question = Question::create($data); 12 return $question; 13 } 14 }
然后在QuestionController构造函数中,通过依赖注入的方式,将QuestionRepository 注入到QuestionController 中并赋值给QuestionController中的属性,
1 /** 2 * @var QuestionRepository 3 */ 4 private $questionRepository; 5 6 public function __construct(QuestionRepository $questionRepository) 7 { 8 $this->middleware( 9 'auth', 10 [ 11 'except' => 12 [ 13 'index', 14 'show', 15 ]//非注册用户只能查看不能编辑添加更改删除 16 ] 17 ); 18 19 $this->questionRepository = $questionRepository; 20 } 21
后续调用QuestionRepository中的方法,取代之前QuestionController 对数据层的操作即可。
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 = $this->questionRepository->create($data); 20 21 //使用我们再question model里面添加的topics方法获得 topics关联,再使用attach方法 22 23 $question->topics()->attach($topics); 24 25 return redirect()->route('questions.show', $question); 26 } 27
代码不多的时候,看起来多此一举,但是这样在思维上做到了数据和操作控制分离,代码多了之后可能会比较方便。
比如将QuestionController之中的normalizeTopics移入到QuestionRepository中:
最后代码:
1 <?php 2 3 namespace AppRepositories; 4 5 use AppModelsQuestion; 6 use AppTopic; 7 8 class QuestionRepository 9 { 10 11 /** 12 * 根据提供的数据,使用Eloquent创建question,存储到数据库中并且返回该实例 13 * @param array $data 14 * @return mixed 15 */ 16 public function create(array $data) 17 { 18 $question = Question::create($data); 19 return $question; 20 } 21 22 /** 23 * @param array $topics 24 * @return array 25 */ 26 public function normalizeTopics(array $topics) 27 { 28 //返回topic的id序列,如果不是数字,则强制认为是数据库中的topic的id, 29 //这样虽然会漏掉用户如果设置的topic就是数字的情况,但是因为是测试,所以暂时忽略 30 $normalizedTopics = collect($topics)->map(function ($topic) { 31 if (is_numeric($topic))//是数字 32 { 33 //在数据库中找id 34 $num_topic = Topic::query()->find($topic); 35 if (isset($num_topic) && $num_topic->count() > 0) //在数据库中找得到id 36 { 37 //因为是找到了 且是从question处提交,其内部的question_count应该增加1个 38 $num_topic->increment('questions_count'); 39 //返回id 40 return (int)$num_topic->id; 41 } 42 } 43 //否则创建一个新的topic 44 //再之前先判断是否找得到,因为有时候重复提交,select2在提交的数据中不为数字,但是实际上数据库中已经有值 45 $already = Topic::query()->select('id', 'name')->where('name', '=', $topic); 46 47 if ($already->count() > 0) { 48 //因为是找到了 且是从question处提交,其内部的question_count应该增加1个 49 $already->increment('questions_count'); 50 //返回id 51 return $already->first()->id; 52 } 53 $data_of_topic = [ 54 'name' => $topic,//目前view中topic只有一个选择框,没有设置content的输入框 55 'questions_count' => 1,//因为是找到了 且是从question处提交,其内部的question_count应该初始化为1个 56 ]; 57 //入库 58 $newTopic = Topic::create($data_of_topic); 59 //返回id 60 return $newTopic->id; 61 })->toArray(); 62 63 return $normalizedTopics; 64 } 65 }
1 <?php 2 3 namespace AppHttpControllers; 4 5 use AppHttpRequestsQuestionStoreRequest; 6 use AppModelsQuestion; 7 use AppRepositoriesQuestionRepository; 8 use IlluminateHttpRequest; 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 * 37 * @return IlluminateHttpResponse 38 */ 39 public function index() 40 { 41 // 42 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 78 $question->topics()->attach($topics); 79 80 return redirect()->route('questions.show', $question); 81 } 82 83 84 /** 85 * @param Question $question 86 * @return IlluminateContractsViewFactory|IlluminateViewView 87 */ 88 public function show(Question $question) 89 { 90 //使用关系关联加载,with方法会将分类之下的商品一起查询出来,而且不会出现N+1影响性能的问题 91 $question->with('topics')->get(); 92 93 return view('questions.show', compact('question')); 94 } 95 96 /** 97 * Show the form for editing the specified resource. 98 * 99 * @param int $id 100 * @return IlluminateHttpResponse 101 */ 102 public function edit($id) 103 { 104 // 105 } 106 107 /** 108 * Update the specified resource in storage. 109 * 110 * @param IlluminateHttpRequest $request 111 * @param int $id 112 * @return IlluminateHttpResponse 113 */ 114 public function update(Request $request, $id) 115 { 116 // 117 } 118 119 /** 120 * Remove the specified resource from storage. 121 * 122 * @param int $id 123 * @return IlluminateHttpResponse 124 */ 125 public function destroy($id) 126 { 127 // 128 } 129 130 131 }