imanghafoori / laravel-terminator
一个最小化但功能强大的包,让你有机会重构你的控制器。
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 "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"