简体   繁体   English

Laravel 中的瘦控制器

[英]Skinny Controllers in Laravel

I am trying to improve my Laravel code design by moving code away from the controllers as much as possible.我正在尝试通过将代码尽可能远离控制器来改进我的 Laravel 代码设计。

In my AuthController I have a store function for logging in the user, where can I move the logic in this function?在我的AuthController ,我有一个store function 用于登录用户,我可以在哪里移动这个 function 中的逻辑?

So far I have implemented a FormRequest for validation and UserResource for the response fields.到目前为止,我已经实现了用于验证的FormRequest和用于响应字段的UserResource I was thinking of creating a file in /Services called AuthService and moving authentication logic there, unless there is a better design pattern?我正在考虑在/Services中创建一个名为AuthService的文件并在那里移动身份验证逻辑,除非有更好的设计模式? Or maybe logic for authentication can be moved to the User 's model?或者可以将身份验证逻辑移至User的 model?

public function store(StoreAuthRequest $request)
{
    $user = User::where('email', $request->input('email'))->first();

    if(!$user || !Hash::check($request->input('password'), $user->password)) {
        return response([
            'message' => 'Bad credentials'
        ], 401);
    }

    $token = $user->createToken('AppToken')->plainTextToken;

    return response([
        'user' => new UserResource($user),
        'token' => $token
    ], 201);
}

I would recommend to never mixup what a "service" is/means.我建议永远不要混淆“服务”是什么/意味着什么。 In Laravel a Service (not a ServiceProvider , but a literal folder called Services in the app folder) is a class that allows the developer to communicate with external services, it is not a "logic" class that drives something, like logic for logging in.在 Laravel 中, Service (不是ServiceProvider ,而是app文件夹中名为Services的文字文件夹)是一个 class ,它允许开发人员与外部服务进行通信,它不是驱动某些东西的“逻辑” class ,例如用于登录的逻辑.

What I have done, after working so many years with Laravel, is to "mix" a little bit of DDD (Domain Driven Development), what I have done is just add a Domain folder inside app , and you put ALL your logic in there.在与 Laravel 合作多年后,我所做的就是“混合”一点 DDD(领域驱动开发),我所做的只是在app中添加一个Domain文件夹,然后将所有逻辑放入其中.

For example, imagine we have a Doctors app, this would be the heriarchy:例如,假设我们有一个 Doctors 应用程序,这将是层次结构:

  • app应用程序
    • Console安慰
    • Domain领域
    • Exceptions例外情况
    • Http Http
    • Models楷模
    • Providers供应商
  • bootstrap自举
  • config配置
  • database数据库
  • resources资源
  • etc.等等

So, intead of having stuff inside a app/Services , just put code inside Domain , like this (following our example):因此,不要将内容放在app/Services中,只需将代码放在Domain中,就像这样(按照我们的示例):

  • Domain领域
    • Common ( App\Domain\Common )通用( App\Domain\Common
      • Enums枚举
      • Events事件
      • Listeners听众
      • Jobs职位
      • Servicies服务项目
    • Doctor ( App\Domain\Doctor )医生( App\Domain\Doctor
    • Facility ( App\Domain\Facility )设施( App\Domain\Facility
    • Patient ( App\Domain\Patient )患者( App\Domain\Patient

So, the idea is to put true logic inside this Domain folder (and further organize them), so you can then NOT mix logic or stuff togheter.所以,我们的想法是将真正的逻辑放在这个Domain文件夹中(并进一步组织它们),这样你就不能将逻辑或东西混合在一起。

To wrap it up, you would then have controllers like this:总结一下,您将拥有这样的控制器:

class PatientController extends Controller
{
    public function store(PatientRequest $request)
    {
        return \App\Domain\Patient\Entity::store(
            $request->input('name'),
            $request->input('email'),
            $request->input('age')
        );
    }
}

All the logic for "registering" (manipulating something from the Patient) model, is on the Entity class. “注册”的所有逻辑(从患者那里操作一些东西)model,都在Entity class 上。


I have also taken a different approach by following something similar to having "modules", so everything is in a "modules" folder and that logic is just in there.我还采取了一种不同的方法,遵循类似于拥有“模块”的方法,因此所有内容都在“模块”文件夹中,逻辑就在那里。 I got that idea from Ryuta Hamasaki: Modularising the Monolith , but this may be way more advance.我从Ryuta Hamasaki 那里得到了这个想法:Modularising the Monolith ,但这可能更先进。

You can write the validator directly in the controller. Because this line of code has no possibility of being reused.验证器可以直接写在controller。因为这行代码没有被复用的可能。

Example:例子:

public function store(Request $request)
{
    $request->validate([
        'email' => ['required', 'email'],
        'password' => ['required'],
    ]);
    $user = User::query()
        ->where('email', $request->email)
        ->first();
    // PHP 8.x
    if (! Hash::check($request->password, $user?->password)) {
        // Throw an exception
    }
    
    return response()->json([
        'token' => $user->createToken(...)->plainTextToken,
        'user' => new UserResource($user), // or UserResource::make($user)
    ])
}

End.结尾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM