imanghafoori/laravel-responder

该包已被弃用且不再维护。作者建议使用imanghafoori/laravel-terminator包代替。

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

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

This package is auto-updated.

Last update: 2024-01-04 12:34:18 UTC


README

💎 "告诉而非询问原则"适用于你的Laravel控制器

这个包有什么好处?

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

41775502-5406df86-7639-11e8-9211-3b618e0e4600.jpg

Latest Stable Version Build Status Quality Score License Total Downloads

**专为每一个Laravel“清洁程序员”制作❤️**

安装

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(); 
        
    }
    ...
}

终结器 API

此包为您公开了 2 个全局辅助函数和 1 个外观

  • 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"