侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

在Laravel中优化Actions的限制和不足

Laravel  /  管理员 发布于 2年前   486

在过去的一年多时间里, 基于Action(行动)的方法在Laravel世界中越来越受欢迎. 

我是这个方法的忠实粉丝,并在较早的时候就采用了它。

然而, 随着时间的推移, 我发现我把所有可以想象到的东西都放在Actions命名空间下, 而目录也越来越拥挤. 

我从试图简化我的过程到把所有东西都提取到动作中--而每次找到正确的动作都变得越来越复杂。

我决定做点什么,找到一种方法,让我仍能从这种方法中受益,但又不至于把所有东西都归类为行动。


由于以前使用过各种架构模式,我回想了一些对我很有效的模式。

我是CQRS(Command Query Responsibility Segregation)的忠实粉丝。

然而,我不喜欢手动添加我所有的映射的方法,这样我就可以靠在命令总线或查询总线上。

但是我可以采取我喜欢的这种模式,靠着Laravels容器来做我需要的事情。


所以我决定把我归类为Actions的东西拆成更接近CQRS的方法。

命令是我想要执行的写动作,而查询是我的读动作。让我们看一下这些变化的例子。

namespace App\Actions;
 
final class CreateNewUserAction
{
    public function handle(NewUser $user): Model|User
    {
        return DB::transaction(
            callback: static fn () => User::query()->create($user->toArray()),
            attempts: 2,
        );
    }
}

这是一个典型的写动作的例子。

它将接受一个DTO作为其有效载荷,并在数据库事务中执行一个写入查询。

这对我来说很有效,但作为一个命令,它看起来像什么呢?

namespace App\Commands\Users;
 
final class CreateNewUser
{
    public function handle(NewUser $user): Model|User
    {
        return DB::transaction(
            callback: static fn () => User::query()->create($user->toArray()),
            attempts: 2,
        );
    }
}

这是同样的事情,但在不同的命名空间下,所以我的代码中有更好的分离。

你可以用类似的方法来处理动作,并创建嵌套的命名空间--但你不会得到与你分割读写操作时一样的意图分离。

接下来让我举一个更复杂的例子。


如果你看过我的Laravel业务流程建模教程,你就会明白这个过程。

让我们假设我们有一个流程,我们想为我们的用户创建一个新的团队。

我们为此采取的步骤如下:

1.创建一个新的团队模型.
2.将我们的用户作为一个团队成员。
3.给我们的用户发电子邮件,通知他们。
4.设置一个团队所需的任何额外资源,也许是计费。

如果你在控制器中看,这是一个很大的问题,如果你使用动作,甚至命令和查询--你最终会有很多东西被拉到一个地方,命名变得混乱,而且你没有获得多少好处。

相反,我使用不同的方法,建立了一个流程。

我们在应用程序中做的很多事情都是流程,是为实现一个结果而需要做的事情的顺序列表。

这也没什么不同。

首先,看一下底层代码--我们想要实现的抽象过程。

abstract class Process
{
    protected array $tasks = [];
 
    public function run(object $payload): mixed
    {
        return Pipeline::send(
            passable: $payload,
        )->through(
            pipes: $this->tasks,
        )->thenReturn();
    }
}

我们要做的就是创建一个我们想要运行的任务集合--这意味着进程可以共享任务而不需要代码重复。

然后,我们通过管道门面运行所有这些。

不过,这与命令和查询有什么关系呢?让我们深入了解一下我们的例子。

final class TeamCreationProcess extends Process
{
    protected array $tasks = [
        CreateNewTeam::class,
        AssignNewTeamMember::class,
        NotifyTeamOwnerOfNewMember::class,
        SetupBillingForTeam::class,
    ];
}

在我们的控制器中,我们所需要做的就是:

final class StoreController
{
    public function __construct(
        private readonly TeamCreationProcess $process,
    ) {}
 
    public function __invoke(StoreRequest $request): Responsable
    {
        $this->process->run($request->payload());
 
        return new MessageResponse(
            message: 'Your team has been created',
        );
    }
}

很干净,对吗?

让我们看一下这些任务中的几个,看看我们在命令和查询方面的倚重。

final class CreateNewTeam
{
    public function __construct(
        private readonly NewTeamCreation $command,
    ) {}
 
    public function __invoke(object $payload, Closure $next): mixed
    {
        $this->command->handle($payload);
 
        return $next($payload);
    }
}

我们的任务可以调用我们的命令,而不是实现同样的逻辑。

你可以在这里添加写入动作。

然而,通过仍然使用一个命令--你可以从API、Web和CLI轻松地创建一个新的团队,而不需要把它包裹在一个过程中。

如果你有一个简单的CLI命令,你很可能想避免一个过程--你想要一个快速的动作。


我现在使用的方法来自于在构建不同类型的应用程序时学到的经验,虽然创建多个类来实现一件事可能有点费力,但随着你的应用程序的发展,你会对这样做表示感谢。

通过将我们需要的东西分解成一个过程,我们可以随着时间的推移通过添加额外的步骤来微调这个过程--而不影响正在发生的事情。

我不知道这种方法是否有一个架构术语,但这是我非常喜欢的一种方法。


我的FormRequest负责创建我想通过的有效载荷。

我的流程负责我想运行的任务。

我的任务负责调用正确的读或写操作,而我的读和写操作只需要担心读或写数据。

这都是小的、构建良好的、可单元测试的代码片断,很容易复制和重构,而不会对我的整个应用产生不利影响。


转:

https://laravel-news.com/going-past-actions-in-laravel

  • 上一条:
    Laravel 10.9版本发布
    下一条:
    用redis中的Zset(有序集合)实现热度排行版及场景示例
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • Laravel 11.14版本发布 - 新的字符串助手和ServeCommand改进(0个评论)
    • Laravel 11.12版本发布 - Artisan的`make`命令自动剪切`.php `扩展(0个评论)
    • Laravel的轻量型购物车扩展包:binafy/laravel-cart(0个评论)
    • Laravel 11.11版本发布 - 查看模型中的第三方关系:show(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-07
    • 2017-08
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2020-10
    • 2020-11
    • 2021-01
    • 2021-02
    • 2021-03
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客