Laravel Vuejs 实战:开发知乎 (12)使用 Repository 模式

关于Repository可以参考:

为什么你应该使用 Repository

推荐:好用的 Laravel Repository 包

Repository 模式作用和实现原理

PHP Laravel框架的 Repository 模式

关于 Repository 的设计模式

服务容器

不过你不一定需要Repository,具体使用中,视情况而定:

Laravel repository

Repository 模式和 Eloquent 的 ORM 在本质上是冲突的,只能二选一,否则就是白费力气;


本身用 repository 不会变的更方便,了解这个模式的初衷,主要是用来将数据存储和业务逻辑分离,具体数据持久化到哪里,领域服务并不用关心,这也隔离了后续持久化变更问题,还有一点很重要的是了解一下 DDD (领域驱动设计) 估计会更好的理解这个模式,关于提到复杂查询,我在项目中更倾向于将 cmd 和 query 分开(cqrs 架构),对于领域服务而言,不存在过于复杂的查询,repository 基本够用,但对于后台这种是需要复杂查询的,query 查询走 db builder 或者裸写都可以,你方便怎么来就怎么来,也不会对业务带来影响,甚至你的数据还可能来自 es 呢


但为了了解Repository,我们在本项目中尝试使用:

1.在app文件夹下,创建Repositories文件夹,并在该文件夹内新建一个QuestionRepository:

批注 2020-02-29 110847

将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 

批注 2020-02-29 112206

代码不多的时候,看起来多此一举,但是这样在思维上做到了数据和操作控制分离,代码多了之后可能会比较方便。

比如将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 }
QuestionRepository.php

  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 }
QuestionController.php



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