• 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



  • 相关阅读:
    leetcode回溯46
    多线程第五节_AQS
    leetcode1254
    leetcode214最大路径和
    leetcode200dfs岛屿的数量
    leetcode51n皇后
    多线程第三节_mesi
    ElasticSearch基本使用姿势二
    我的 Java 学习&面试网站又又又升级了!
    SpringBoot + JWT + Redis 开源知识社区系统
  • 原文地址:https://www.cnblogs.com/dzkjz/p/12381947.html
Copyright © 2020-2023  润新知