Php Laravel模式-作业与服务的使用

Php Laravel模式-作业与服务的使用,php,laravel,laravel-5,model-view-controller,service-layer,Php,Laravel,Laravel 5,Model View Controller,Service Layer,我想知道大多数开发人员是如何使用这两个Laravel工具的 在Laravel中,您可以使用服务或作业处理业务逻辑(让我们只讨论不可排队的作业,只讨论在同一流程中运行的作业) 例如,用户想要创建一个实体,比如说一本书,您可以通过服务或分派作业来处理实体创建 使用作业可能是这样的: class PostBook extends Job { ... public function handle(Book $bookEntity) { // Business lo

我想知道大多数开发人员是如何使用这两个Laravel工具的

在Laravel中,您可以使用服务或作业处理业务逻辑(让我们只讨论不可排队的作业,只讨论在同一流程中运行的作业)

例如,用户想要创建一个实体,比如说一本书,您可以通过服务或分派作业来处理实体创建

使用作业可能是这样的:

class PostBook extends Job
{
    ...
    public function handle(Book $bookEntity)
    {
        // Business logic here.
    }
    ...
}

class BooksController extends Controller
{
    public function store(Request $request)
    {
        ...
        dispatch(new PostBook($request->all()));
        ...
    }
}
class BookService
{
    public function store(Request $request)
    {
        // Business logic here.
    }
}

class BooksController extends Controller
{
    public function store(Request $request)
    {
        ...
        // I could inject the service instead.
        $bookService = $this->app()->make(App\Services\BookService::class);
        $bookService->store($request);
        ...
    }
}
使用服务,可能是这样的:

class PostBook extends Job
{
    ...
    public function handle(Book $bookEntity)
    {
        // Business logic here.
    }
    ...
}

class BooksController extends Controller
{
    public function store(Request $request)
    {
        ...
        dispatch(new PostBook($request->all()));
        ...
    }
}
class BookService
{
    public function store(Request $request)
    {
        // Business logic here.
    }
}

class BooksController extends Controller
{
    public function store(Request $request)
    {
        ...
        // I could inject the service instead.
        $bookService = $this->app()->make(App\Services\BookService::class);
        $bookService->store($request);
        ...
    }
}
问题是,你通常如何选择一种或另一种方式?为什么

在这个问题上肯定有两个“学派”,但我想了解每一个学派的优缺点。

任何东西都可以处理“业务逻辑”,所以似乎真正要问的是,在不重复代码的情况下重复相同的业务逻辑哪个选项更好

一个作业类通常只做一件事,这是由它的
handle()
方法定义的。很难从比较中排除排队作业,因为同步运行它们通常会破坏目的,即在当前请求完成并向用户显示响应后处理缓慢、昂贵或不可靠的操作(如调用web API)

如果期望所有作业都是同步的,那么这与为业务逻辑定义一个函数没有多大区别。这实际上非常接近于调度同步作业的功能:在调用堆栈的某个地方,它最终运行
call\u user\u func([$job,'handle'])
来调用作业对象上的单个方法。更重要的是,同步作业缺少重试可能由于外部原因(如网络故障)而失败的作业的机制

另一方面,服务是封装组件逻辑的简单方法,它们可以做一件以上的事情。在这种情况下,组件可能被认为是应用程序的一部分,可以换成不同的实现,而无需修改使用它的代码。框架中包含的一个完美示例是
文件系统
服务(最常用的访问方式是
存储
外观)

考虑一下,如果您没有通过将书籍插入数据库来存储书籍,而是通过发布到外部API来存储书籍。您可能有一个BookRepository服务,它不仅有一个
store()
方法,而且还有一个
get()
update()
list()
delete()
,或任何其他方法。所有这些请求都共享用于向外部web服务进行身份验证的逻辑(如向请求添加头),并且BookRepository类可以封装该可重用逻辑。您可以在计划的artisan命令、web控制器、api控制器、作业、中间件等内部使用此服务类,而无需重复代码


使用此示例,您可以创建一个用于存储新书的作业,这样当API响应缓慢时,您就不会让用户等待(当出现故障时,它可以重试)。在内部,作业在运行时调用服务的
store()
方法。服务完成的工作由作业安排。

从概念上讲,作业更多地用于异步操作,如队列或crontab命令。服务(层)是封装业务逻辑的设计模式。在我看来,这通常是web应用程序同步操作的方式。有关代码示例的次要说明:我不会将
请求
对象传递给服务。请求是用户执行HTTP请求时收到的对象。如果直接将其传递给服务,则意味着您不能在控制台命令或(排队)作业中使用相同的服务,因为您错过了请求。我认为,控制器应该将请求转换为模型或DTO(数据传输对象),并使用这些作为参数调用服务函数。