【问题标题】:Laravel responsibility in the classes类中的 Laravel 责任
【发布时间】:2019-12-10 13:43:26
【问题描述】:

我有一个关于 Laravel 的项目,需要进行重构。我已经阅读了关于服务提供者和依赖注入的内容并且有一些问题。 这是一个简短的结构:user 模型、event 模型、favorite user 模型等。此外,所有模型都有控制器。每个event 都有一个creatorclientuser 关系)。在每一堂课中,我都在注入适当的服务:User Service、Event service、Favorite user service 等。 让我们考虑这个例子——我想deleteuser

class UserController extends Controller
{
    /**
     * @var UserService $userService
     */
    protected $userService;

    /**
     * UserController constructor.
     * @param UserService $userService
     */
    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }
    protected function delete(int $id)
    {
        $user = User::find($id);
        if ($user) {
            $this->userService->setUser($user);
            $this->userService->delete();
        }
    }

在用户服务中,我正在处理用户删除 - 更新相应的字段。另外,我需要取消所有用户事件并删除喜欢的用户。 我的问题是我应该在哪里做?我应该在UserControllerUserService 中注入eventfavorite user 服务吗?或者也许有更好的方法来执行此操作。提前谢谢

【问题讨论】:

  • 没有“最好”的方法可以做到这一点,imo。确保您没有违反任何 OOP 原则。在我看来,你不是。我会在用户服务类中注入任何其他服务,但会使用接口而不是具体类来进行解析。 (程序到接口,而不是实现)使用事件似乎是一个从服务类中加载一些负担的好主意。但是,如果这就是它的全部复杂性,那对我来说似乎有点矫枉过正。

标签: laravel laravel-5 eloquent


【解决方案1】:

似乎您有很多取决于删除用户的操作,所以我会考虑使用事件并在每个侦听器内部处理它的细节。

class UserController extends Controller
{
    /**
     * @var UserService $userService
     */
    protected $userService;

    /**
     * UserController constructor.

     * @param UserService $userService
     */
    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }

    protected function delete(int $id)
    {
        if(!$this->userService->delete($id)) {
          // return some error;
        }

        event(new UserWasRemoved($id));
        // return success response
    }
class DeleteUserService {

    protected $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function delete($id){
       return $this->user->delete($id);
    }
}
// app/Providers/EventServiceProvider

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        UserWasRemoved::class => [
            CancelUserEvents::class,
            RemoveUserFavorites::class,
            // etc...
        ],
    ];
}

【讨论】:

    【解决方案2】:

    如果删除用户的代码很多,我将创建DeleteUserService 类,其中将包含删除用户所需的所有代码以及删除的效果。

    class DeleteUserService {
    
        public function __construct(int $userId)
        {
            $this->userId = $userId;
        }
    
        public function delete(){
             $this->deleteUser();
             $this->updateAppropriateFields();  // of course the name should be clearer
             $this->deleteEvents();
             $this->deleteFavoriteUser();
             ...
        }
    
        private function deleteUser(){...}
        private function updateAppropriateFields(){...}
        private function deleteEvents(){...}
        private function deleteFavoriteUser(){...}
        ...
    
    }
    

    在您的控制器中,您可以注入服务或在控制器方法中实例化一个新实例

    class UserController extends Controller
    {
        ...
        public function delete(int $id)
        {
            $user = User::findOrFail($id);
            $deleteService = new DeleteUserService($user->id);
            $deleteService->delete();
        }
    }
    

    将大型函数分解为一个或多个类总是一个好主意。

    【讨论】:

    • 这意味着我必须为每个“大”动作创建服务。但是重用现有代码呢?我应该在不同的动作中做一些相同的动作。例如,我需要在用户删除、事件删除和其他几个地方删除喜欢的用户。我该怎么办?在每个服务中创建相同的功能,还是将其放在不同的服务中?主要问题是模型之间的关系很多,不知道怎么用很多服务来管理。
    【解决方案3】:

    我建议您放弃使用此类服务​​的方法。你用服务实现的所有东西都已经在 Laravel 中实现了,只是更简单。您现在正在一个简单的现成逻辑之上实现更繁琐的逻辑。

    1. 为您的主题区域的每个对象(用户、事件、最喜欢的用户)添加模型类。在其中添加表的信息,属于它们的数据 - 当然除非您使用关系存储Eloquent Model Conventions。在这里我有一个问题要问你——最喜欢的用户实体是否需要一个单独的类?如果 User 和 FavoriteUser 具有相同的特征(即实现中的类成员),那么就不需要将它们分配到不同的类中,添加一个额外的 isFavourite() (bool) 属性就足够了——在班级和表格中。

    2. 如文档Defining Controllers 中所述,在控制器中为每个模型类实现必要的方法。根据客户端部分的类型,响应的返回可以是 RESTful API 的 JSON,也可以是带有传输数据 Views 的刀片模板。在这里,在控制器中,您应该实现一个删除模型的方法。

    如果不希望逻辑类似,即去掉UserController的all()、get()、post()、put()、delete()等类似的方法,对于EventController, ...(模型类除外 - 会有所不同),那么我建议您使用以下架构技巧(当然,这是可选的)。开发通用层——通用模型类、通用控制器类、通用模型存储库类(如果你在开发中使用它)。并且在控制器中,描述所有模型类的通用逻辑,all()、get()、post()、put()、delete()。然后从通用继承模型的每个具体类,从通用继承控制器的每个具体类 - 等等。但! 在模型的具体类中,有必要,例如,在一个数组中,列出关系存储表的属性,从中获取数据;还需要在变量中指定类的名称 - 以便控制器可以了解它应该使用哪个类。 并在控制器中以任何方式传递有关模型类的数据 - 例如,使用 DependencyInjection Dependency Injection & Controllers。 使用这种方法,具体控制器的类变得稀薄,其中代码的增加只是由于通用方法的重新定义或自定义方法的实现而发生。 这种方法的优点还在于不需要添加类似结构的路由。例如,一条通用路线就足够了

    Route::get('{entity}/{id}', function ($entity, $id) {
        $module = ucfirst($entity);
        Route::get("{$entity}/{$id}", "{$module}Controller@get");
    });
    

    而不是许多相同的类型

    Route::get('user/{id}', 'UserController@get');
    
    Route::get('event/{id}', 'EventController@get');
    

    等等。

    【讨论】:

    • 有一个标准 Laravel 结构的现有项目,包含模型、控制器等。我必须对其进行重构。正如我所说,有很多关系。你说不要使用服务,但我不明白如何从你的回答中实施所有需要我采取的行动。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-16
    • 2018-01-31
    • 2023-03-06
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    相关资源
    最近更新 更多