Whip Monstrous Code Into Shape - 01 Form Request

Whip Monstrous Code Into Shape - 01 Form Request

file

最近在看 laracast 的视频,有一个系列是 “Whip Monstrous Code Into Shape”,英语差,也不知道怎么翻译比较好,大概意思是随着业务逻辑的增长,我们的模型或者控制器都会变得臃肿不堪,这个系列介绍了一些方法可以帮助我们把这些代码组织成有一个逻辑清晰的结构('whipping convoluted code into shape.')。

在看这个视频之前,我们公司正在用 laravel 重写一个之前用 c# 写的 erp 系统,这个 erp 系统开发的时间很早,迭代了几次,导致逻辑非常复杂,所以我开发的过程非常痛苦,模型和控制器越来越臃肿,结构也混乱。在看了这个系列后就感觉有种突然恍然大悟的感觉:原来可以这样做啊!

其实里面用到的技术都是很基本的,只是可能在我们开发的时候根本就没有考虑到要如何组织代码会比较好,所以我把这个系列里面讲到一些 idea 都记录下来,一方面自己可以很好的巩固这些知识,也希望能带给大家一些启发。

使用 Form Request

举个简单的场景,比如需要存储一篇文章,我之前的做法是这样:数据验证放在 Form Request里面,然后在控制器中创建文章并保存到数据库,我相信很多开发者可能都是这样做。对于简单的表来说没有多大的问题,假如有一个有30个字段的表呢?并且30个字段可能只有15个是从 request 里面获取的,剩下的 15个是需要逻辑处理并填充进去的?这个时候该怎么做?为了避免控制器太臃肿,通常我会把这些放到一个服务(service)里面。

public function store(CreatePostRequest $request)
{
    $creator = new PostCreator();
    $post = $creator->create($request->all());
    return response()->json($post);
}

其实这种方法也还好,不过 Jeffrey 给出了一个新的思路:我们可以把存储逻辑放在 Form Request里面,而不仅仅只是用作数据验证。

首先,我们把 Form request 命名成 PublishPostForm,这样或许会更直观的理解这个类:这就是用户请求的一个发表文章的表单,只不过这个表单里面加了我们的数据验证规则,接着在 PublishPostForm 里面定义保存文章的方法。


class PublishPostForm extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'body' => 'required'
        ];
    }

    /**
     * 创建文章的逻辑
     * @return Post
     */
    public function persist()
    {
        return Post::create($this->all());
    }
}

然后在控制器中我们只要调用 persist 方法就行。

public function store(PublishPostForm $form)
{
    $post = $form->persist();
    return response()->json($post);
}

这种方法跟前一种比较起来其实很相似,都是把存储逻辑从控制器中分离出来,但是仔细想想,在 Form Request 里面处理相较于一个额外的 Service 还是有点好处:

  • 首先 Form Request 本来就是继承自 Request,你可以很容易在里面通过 $this->field 访问 request 里面的数据,但是使用 creator, 你就不得不把 $request 在 creator 里面传递来传递去;
  • 逻辑更清晰,用户提交了一个文章表单,然后把这个表单保存(persist)在数据库中,就是那么简单

这就是第一部分的内容,Jeffrey 在这个系列里面说过很多次,这个系列只是提供一些 idea,并不意味着一定是最好的方法或者必须这样做。所以咯,充分发挥想象力吧,我觉得对于开发者来说,怎么简单、易维护就怎么来,千万别让这些条条框框限制了你的思想,共勉。

本帖已被设为精华帖!
本帖由 Summer 于 7年前 加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 9
Summer

$form->persist(); 不错。

7年前 评论

@Summer 我发现老外命名的变量和方法都很贴切,我们自己命名一个方法变量得查有道查半天,而且还丑陋 果然英语还是很重要 :smile:

7年前 评论
Summer

@oustn Jeff 和 Taylor 在讲他们开发的一半时间是用来命名的。。。

7年前 评论
Summer

大家都要查半天,其实。哈哈

7年前 评论

@Summer 原来大手子也是这样,哈哈,还以为跟 jeff 的视频一样随手一写就是一个很好的命名呢

7年前 评论

@Summer 哈哈哈哈

7年前 评论

不赞成这样做~写到服务里面才是正道

大型项目基本保证三层:模型(数据读取/存储)-服务(业务逻辑)-控制(交互)

7年前 评论

@eddy8 也对, Jeffrey 在这个视频讲过很多次,他提供的都是一些 idea,并不存在 100% 适用或者哪种情况一定最好的情况,整个视频基本上没讲什么技术方面的,都是一些模式,能给我们更多一些参考。

不过我觉得写在服务里面才是正道的说法,我觉得可能比较死板一点,如何适合自己的系统才是正道。

就拿 MVC 来讲,真正大型项目可能模型层与控制器层之间会加一个仓储,在控制器层与仓储中间会加一个服务,在控制器和表现层中间会加一个 present ,这样一下就6层了。就单单数据存储这个来说,我觉得放在仓储层可能还更适合。如果对于比较小的项目,说不定直接放在控制器最简单。so,没有最好,只有最适合。

7年前 评论

@Summer 这个话题要是能前后关联就更好了

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!