imanghafoori / laravel-responder
Requires
- php: >=7.1.3|8.*
- laravel/framework: 5.*|6.*|7.*|8.*|9.*|10.*
Requires (Dev)
- imanghafoori/laravel-makesure: ^1.0
- mockery/mockery: ^1.0
- orchestra/testbench: ~6.0
README
💎 "告诉而非询问原则"适用于你的Laravel控制器
这个包有什么好处?
简短回答: 这个包以你从未见过的方式帮助你清理控制器代码
**专为每一个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"