Php 如何在流明中使用干燥和服务层?

Php 如何在流明中使用干燥和服务层?,php,laravel,dry,lumen,service-layer,Php,Laravel,Dry,Lumen,Service Layer,我正在Lumen框架中创建api,最近我阅读了有关DRY和服务层的内容。直到今天,我没有在我的代码中使用任何这些,所有的逻辑都在控制器中。所以我想开始使用它,但我有一些问题 这是我的控制器(userscoontroller.php)的一部分,因为整个代码太长。 我在控制器、中间件等中使用了太多json响应,我想通过创建新类来统一它,但我不知道如何正确使用它。我的意思是,在ResponderService.php中返回json响应可能不会在其他地方停止执行,比如控制器。或者我应该创建这个作为助手

我正在Lumen框架中创建api,最近我阅读了有关DRY和服务层的内容。直到今天,我没有在我的代码中使用任何这些,所有的逻辑都在控制器中。所以我想开始使用它,但我有一些问题

这是我的控制器(userscoontroller.php)的一部分,因为整个代码太长。

  • 我在控制器、中间件等中使用了太多json响应,我想通过创建新类来统一它,但我不知道如何正确使用它。我的意思是,在ResponderService.php中返回json响应可能不会在其他地方停止执行,比如控制器。或者我应该创建这个作为助手
  • ResponderService.php

    <?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处理,然后当Laravel
    execptions\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);
        }
    }