imanghafoori/laravel-terminator

一个最小化但功能强大的包,让你有机会重构你的控制器。

v1.3.7 2023-02-15 18:25 UTC

This package is auto-updated.

Last update: 2024-09-04 14:14:44 UTC


README

💎 "告诉而不是询问原则" 为你的 Laravel 控制器

这个包有什么好处?

简短回答:这个包以你从未见过的方式帮助你清理控制器代码

Latest Stable Version Build Status Quality Score License Total Downloads

**专为每个 Laravel "Clean Coder" 制作 ❤️**

安装

composer require imanghafoori/laravel-terminator

不需要添加任何服务提供者。

兼容性

  • Laravel +5.1 及以上
  • Php 7.0 及以上

何时使用它?

代码异味:👃

  • 当你看到一个端点,你必须发送多种类型的响应时...那么这个包将大大帮助你。

示例

考虑一个典型的登录端点,它可能在不同的情况下返回 5 种类型的响应

  • 1- 用户已登录,因此重定向。
  • 2- 登录成功
  • 3- 凭证无效错误
  • 4- 凭证错误
  • 5- 登录尝试过多错误

MVC 框架强制我们“从控制器返回响应”的事实阻止我们在一定程度上简化控制器。因此,我们决定打破这个牢笼,给自己带来自由。

想法是:应用中的任何类都应该能够发送回响应。

记住

控制器是控制器,它们不是响应器!!!

控制器,“控制”代码的执行流程,向其他对象发送命令,告诉它们该做什么。它们的职责不是向客户端返回“响应”,这也是 terminator 包的哲学。

考虑下面的代码

// BAD code : Too many conditions
// BAD code : In a single method
// BAD code : (@_@)   (?_?)
// (It is not that bad, since it is a simplified example)
class AuthController {
  public function login(Request $request)
  {
           
           $validator = Validator::make($request->all(), [
              'email' => 'required|max:255||string',
              'password' => 'required|confirmed||string',
          ]);
          
          if ($validator->fails()) {
              return redirect('/some-where')->withErrors($validator)->withInput(); // return response 1
          }
          
         
          // 2 - throttle Attempts
          if ($this->hasTooManyLoginAttempts($request)) {
              $this->fireLockoutEvent($request);
              return $this->sendLockoutResponse($request);   // return response 2
          }
        
         
          // 3 - handle valid Credentials
          if ($this->attemptLogin($request)) {
              return $this->sendLoginResponse($request);   // return response 3
          }
        

          // 4 - handle invalid Credentials
          $this->incrementLoginAttempts($request);
          return $this->sendFailedLoginResponse($request); // return response 4
          
          
          //These if blocks can not be extracted out. Can they ?
  }
}

问题

使用当前方法,这是我们能重构的最大程度。为什么?因为控制器在请求响应,而不是告诉该做什么。

我们不希望一个方法中有许多 if 条件,因为这会使方法难以理解和推理。

// Good code
// Good code
// Good code

class LoginController
{
    public function Login(Request $request)
    {
        // Here we are telling what to do (not asking them)
        // No response, just commands, Nice ???
        
        $this->validateRequest();          // 1
        $this->throttleAttempts();         // 2
        $this->handleValidCredentials();   // 3 
        $this->handleInvalidCredentials(); // 4
        
    }
    
    // private functions may sit here
    
    ...
    
}

注意

使用 "respondWith()" 不会阻止框架的正常执行流程被中断。所有的中间件和 Laravel 的其他正常终止过程都将像往常一样发生。因此,它是生产就绪的!🐬

重构步骤:🔨

1 - 首先,你应该从你的控制器中消除“return”语句,如下所示

use \ImanGhafoori\Terminator\Facades\Responder;

class AuthController {
    public function login(Request $request)
    {
           // 1 - Validate Request
           $validator = Validator::make($request->all(), [
              'email' => 'required|max:255||string',
              'password' => 'required|confirmed||string',
          ]);
          
          if ($validator->fails()) {
               $response = redirect('/some-where')->withErrors($validator)->withInput();
               respondWith($response);  // <-- look here
          }
          
         
          // 2 - throttle Attempts
          if ($this->hasTooManyLoginAttempts($request)) {
              $this->fireLockoutEvent($request);
              $response = $this->sendLockoutResponse($request);
              respondWith($response); // <-- look here "no return!"
          }
          
         
          // 3 - handle valid Credentials
          if ($this->attemptLogin($request)) {
               $response = $this->sendLoginResponse($request);
               respondWith($response);  // <-- look here  "no return!"
          }
          

          // 4 - handle invalid Credentials
          $this->incrementLoginAttempts($request);
          $response = $this->sendFailedLoginResponse($request) 
         
          respondWith($response);  // <-- look here "no return!"
    }
}

你是否看到“return”关键字现在变成了普通的函数调用?!

2 - 现在我们已经消除了“return”语句,那么剩下的就简单了,现在可以将每个 if 块提取到方法中,如下所示

class LoginController
{
    public function Login(Request $request)
    {
        $this->validateRequest();         
        $this->throttleAttempts();       
        $this->handleValidCredentials();  
        $this->handleInvalidCredentials(); 
        
    }
    ...
}

Terminator API

这个包为你暴露了 2 个全局辅助函数和 1 个 Facade

  • respondWith()
  • sendAndTerminate()
  • \ImanGhafoori\Terminator\TerminatorFacade::sendAndTerminate()
$response = response()->json($someData);

respondWith($response);

// or 
respondWith()->json($someData);


// or an alias function for 'respondWith()' is 'sendAndTerminate':

sendAndTerminate($response);


// or use facade:
\ImanGhafoori\Terminator\TerminatorFacade::sendAndTerminate($response);

实际上,sendAndTerminate()(或其别名“respondWith”)函数可以接受你通常从典型控制器返回的任何内容。

关于可测试性

让我提一下,“sendAndTerminate 或 respondWith”辅助函数(如其他 Laravel 辅助函数)可以轻松模拟,并且根本不影响可测试性。

// Sample Mock
TerminatorFacade::shouldRecieve('sendAndTerminate')->once()->with($someResponse)->andReturn(true);

事实上,它们使你的应用更容易测试,因为如果你的响应形状发生变化,测试不会失败。

这个魔法是如何实现的,兄弟?!

你可能想知道这个魔法背后是如何工作的。简而言之,它使用的只是标准的laravel "renderable exception"。

我们强烈建议您查看这个包的简单源代码,以了解其中发生了什么。它只有几行代码。

更多来自作者

Laravel HeyMan

💎 允许您编写表达式的代码来授权、验证和认证。

Laravel AnyPass

💎 一个最小化但实用的包,帮助您在本地环境中使用任何密码登录。

Laravel Widgetize

💎 一个最小化但功能强大的包,为您的laravel应用提供更好的结构和缓存机会。

Laravel MasterPass

💎 一个简单的包,让您可以轻松地冒充您的用户。

⭐️ 您的星标使我们做得更多 ⭐️

一如既往,如果您觉得这个包很有用,并希望鼓励我们维护和改进它,请按星标按钮表达您的意愿。

I believe in standardizing automobiles. I do not believe in standardizing human beings.

"Albert Einstein"