Php 如何在流明中使用干燥和服务层?
我正在Lumen框架中创建api,最近我阅读了有关DRY和服务层的内容。直到今天,我没有在我的代码中使用任何这些,所有的逻辑都在控制器中。所以我想开始使用它,但我有一些问题 这是我的控制器(userscoontroller.php)的一部分,因为整个代码太长。Php 如何在流明中使用干燥和服务层?,php,laravel,dry,lumen,service-layer,Php,Laravel,Dry,Lumen,Service Layer,我正在Lumen框架中创建api,最近我阅读了有关DRY和服务层的内容。直到今天,我没有在我的代码中使用任何这些,所有的逻辑都在控制器中。所以我想开始使用它,但我有一些问题 这是我的控制器(userscoontroller.php)的一部分,因为整个代码太长。 我在控制器、中间件等中使用了太多json响应,我想通过创建新类来统一它,但我不知道如何正确使用它。我的意思是,在ResponderService.php中返回json响应可能不会在其他地方停止执行,比如控制器。或者我应该创建这个作为助手
<?php
namespace App\Services;
use App\User;
class UserService
{
public function getUserById($id)
{
$user = User::find($id);
if (!$user) {
return response()->json([
'error' => 'User not found'
], 404);
}
if ($user->role === 'admin') {
return response()->json([
'error' => 'You cant edit admin'
], 403);
}
return $user;
}
}
<?php
namespace App\Services;
class ResponderService
{
private function base($data, $status_code)
{
$data['status_code'] = $status_code;
return response()->json($data, $status_code);
}
public function error($message, $status_code)
{
$data['error'] = $message;
$data['status'] = 'error';
$this->base($data, $status_code);
}
}
我认为在您的场景中使用异常没有任何问题
<?php
namespace App\Services;
use App\User;
class UserService
{
public function getUserById($id)
{
$user = User::find($id);
if (!$user) {
throw UserNotFoundException('User not found');
}
if ($user->role === 'admin') {
throw EditAdminException("You can't edit admin.");
}
return $user;
}
}
如果找不到用户
,Laravel将处理抛出illighted\Database\Eloquent\ModelNotFoundException
这样,您就不必担心为异常已经可以为您做的事情创建ResponderService
如果您想标准化资源的响应,您可以利用作为API转换层的雄辩资源:
最后,如果发现要从多个位置删除资源,并且不想复制响应,可以将响应放在事件中:
文档显示了处理事件的复杂方式,但我个人只会在您的模型开始感到臃肿时才这样做
您可以将此作为创建事件和观察者类的更简单的替代方法:
public static function boot()
{
parent::boot();
static::deleted(function ($model) {
return response()->json([], 204);
});
}
这种方法只适用于您的用户模型。顺便说一句,我是通过查看雄辩\模型
上的HasEvents
特征来发现的
现在,所有这些都说明了,我实际上会将所有删除逻辑放在UserService
中,并将方法从getUserById
重命名为deleteById
。另一种选择有点奇怪,因为你说如果用户是管理员,你不想通过id获取用户
实际上,您试图做的是封装删除用户的逻辑,因此只需将其全部移动到服务的方法中,或者更好的做法是在模型上使用delete
事件,并将所有逻辑放在那里。这样你甚至不需要引入服务
编辑
基于您在下面的评论,我认为您可能误解了如何在Laravel中使用异常
在一个全新的Laravel项目中,app\execptions\Handler
中有一个类,它捕获应用程序中所有未处理的异常。该类首先检查异常是否为ModelNotFoundException
,然后返回json响应
否则,它将捕获的异常传递给其父级的render
方法
因此,基本上,当您想要创建自定义异常时,只需创建一个扩展exception
并实现handle
方法的类
下面是一个示例异常类:
<?php
namespace App\Exceptions;
use Exception;
class TicketNotPayableException extends Exception
{
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render()
{
return response()->json([
'errors' => [
[
'title' => 'Ticket Not Payable Exception',
'description' =>
'This ticket has already been paid.'
],
],
'status' => '409'
], 409);
}
}
为什么异常不能与DRY原则“兼容”?@Philipp我可能错了,但我认为当我使用异常时,我需要重复try/catch代码。看看我的代码:@hafer我建议你把这个问题贴在干版上,因为我的状态像固体或酸性,这都是精神上的问题。(也许不是酸,至少我是说酸)。谢谢你的回答。我想要响应器服务,因为我在代码中有其他地方使用它,而不仅仅是在UserController中,所以我认为最好使用$this->responder->notFound('User not found')
而不是return response()->json(['error'=>'User not found',404)
。例外情况是可以的,但如果我错了,请纠正我。请看我的代码:。现在我的控制器中只有destroy方法,但将来我还需要edit方法,在那里我需要重复destroy方法中的try/catch代码。我认为在这种情况下使用异常是没有意义的。您不需要这些try-catch块,因为异常将冒泡并由Laravel处理,然后当Laravelexecptions\Handler
捕获异常时,您在自定义异常的render
方法中定义的任何逻辑都将被触发。我会用更好的解释来更新我的答案。现在我明白了,它就像我预期的那样工作,谢谢。
<?php
namespace App\Services;
use App\User;
class UserService
{
public function getUserById($id)
{
$user = User::findOrFail($id);
if ($user->role === 'admin') {
throw EditAdminException("You can't edit admin.");
}
return $user;
}
}
public static function boot()
{
parent::boot();
static::deleted(function ($model) {
return response()->json([], 204);
});
}
<?php
namespace App\Exceptions;
use Exception;
class TicketNotPayableException extends Exception
{
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render()
{
return response()->json([
'errors' => [
[
'title' => 'Ticket Not Payable Exception',
'description' =>
'This ticket has already been paid.'
],
],
'status' => '409'
], 409);
}
}