一文详解Laravel中的事件溯源

一文详解Laravel中的事件溯源

事件溯源是一个在过去几年 PHP 社区越来越流行的术语,但对很多开发人员来说仍然是个谜。这些问题总是如何以及为什么,当然这是可以理解的。本教程的目的是通过一个实际的方式不仅仅是帮你理解什么是事件溯源,同样也会让你知道什么时候你可能会想使用它。

在传统应用程序中,我们的应用程序状态直接表示在我们所连接的数据库中。我们不能够完全理解它是怎么到那里的。我们只知道他是这样的。我们可以通过一些方法来进一步理解一点,使用审计模型更改的工具,这样我们就可以看到更改了什么,是谁做的。 这也是朝着正确方向迈出的一步。然而,我们仍然不明白这个关键的问题。【相关推荐:laravel视频教程】

为什么?为什么这个模型发生了变化?这改变的目的是什么?

这就是事件溯源发挥作用的地方,它保留了应用程序状态发生了什么以及为什么发生变化的历史视图。事件溯源允许你根据过去做出决定,从而你能够生成报告。但是在基本层面,他能让你知道为什么这个应用的状态改变了,这是通过事件完成的。

我将会构建一个基础的 Laravel 项目来引导你理解它是如何工作的。我们会将这个应用构建的简单些,以便你能理解时间溯源的逻辑而不是对于应用程序逻辑困惑。我们正在建立一个可以庆祝团队成员的应用程序。这就对了。简单而易于理解。我们与用户有团队,并且我们希望能够在团队中公开庆祝一些东西。

我们将新建一个 Laravel 项目,但我将使用 Jetstream,因为我想启用身份验证和团队结构和功能。 一旦你创建了这个项目, 请在你的IDE中打开它。(这里的正确答案当然是 PHPStorm ), 现在我们已经准备好在 Laravel 深入事件溯源。

我们希望为应用程序创建一个附加模型,这是唯一的一个。这是一个 Celebration 模型,你可以使用以下的Artisan命令创建它:

php artisan make:model Celebration -m

修改你的迁移文件 up 方法,它看起来应该像这样:

public function up(): void{    Schema::create('celebrations', static function (Blueprint $table): void {        $table->id();        $table->string('reason');        $table->text('message')->nullable();        $table            ->foreignId('user_id')            ->index()            ->constrained()            ->cascadeOnDelete();        $table            ->foreignId('sender_id')            ->index()            ->constrained('users')            ->cascadeOnDelete();        $table            ->foreignId('team_id')            ->index()            ->constrained()            ->cascadeOnDelete();        $table->timestamps();    });}

我们有一个庆祝的原因 reason,一个简单的句子,然后是我们可能希望与庆祝活动发送的可选消 message。除此之外,我们有三个关系,正在庆祝的用户,发送庆祝的用户,以及他们所在的团队。使用 Jetstream,一个用户可以属于多个团队,并且可能存在两个用户在同一个团队中的情况
,我们要确保我们在正确的团队中公开庆祝他们。

一旦我们有了这个设定,让我们看看模型本身:

declare(strict_types=1);namespace AppModels;use IlluminateDatabaseEloquentFactoriesHasFactory;use IlluminateDatabaseEloquentModel;use IlluminateDatabaseEloquentRelationsBelongsTo;use IlluminateDatabaseEloquentRelationsHasMany;final class Celebration extends Model{    use HasFactory;    protected $fillable = [        'reason',        'message',        'user_id',        'sender_id',        'team_id',    ];    public function user(): BelongsTo    {        return $this->belongsTo(            related: User::class,            foreignKey: 'user_id',        );    }    public function sender(): BelongsTo    {        return $this->belongsTo(            related: User::class,            foreignKey: 'sender_id',        );    }    public function team(): BelongsTo    {        return $this->belongsTo(            related: Team::class,            foreignKey: 'team_id',        );    }}

我们可以将这些关系映射到其他相关的模型上。尽管,默认情况下,我会将关联关系的另一端添加到每一个模型中,使它们的关联关系更加清楚,无论它是否严格需要这些关联关系。这是我养成的习惯,为了帮助他人理解模型本身。

现在我们有了从模型视角创建的我们的应用基础。我想我们需要一些安装一些对我们有帮助的软件包(依赖)。对于我的应用,我使用 Laravel Livewire 来控制 UI 。但是我并不会在本教程详细介绍这个包,因为我想确保我能专注于讲事件溯源这个方面。

与我创建的大多数项目一样,无论大小,我都为应用程序采用了模块化布局——一个领域驱动模型设计 ( Domain Driven Design ) 方法。这只是我做的事情,不要觉得你自己必须遵循这个,因为它是非常主观的。

我的下一步是设置我的域,对于这个演示,我只有一个域:文化。在文化中,我为我可能需要的一切创建了名称空间。但我会经历它,这样你就明白了过程

第一步是安装一个软件包,使我能够在Laravel中使用事件源。为此,我使用了一个 Spatie package包,它为我做了大量的后台工作

composer require spatie/laravel-event-sourcing

安装后,请确保按照包的安装说明进行操作,因为配置和迁移需要发布。正确安装后,运行迁移,使数据库处于正确状态。

php artisan migrate

现在我们可以开始思考我们要如何实现事件溯源。你可以通过两种方式实现这一点:投影仪来投影你的状态或聚合。

Projector 是一个位于你的应用程序中并处理你调度的事件的类。然后,这些将更改你的应用程序的状态。这不仅仅是简单地更新你的数据库。它位于中间,捕获一个事件,存储它,然后进行所需的更改 —— 然后 “投射” 应用程序的新状态

另一种方法,我的首选方法,聚合 – 这些是像投影仪一样为你处理应用程序状态的类。我们不是在我们的应用程序中自己触发事件,而是将其留给聚合为我们做。把它想象成一个中继,你要求中继做某事,它会为你处理。

在我们创建第一个聚合之前,需要在后台做一些工作。我非常喜欢为每个聚合创建一个事件存储,以便查询更快,并且该存储不会很快填满。这在包文档中进行了解释,但我将亲自引导你完成它,因为它在文档中并不是最清楚的。

第一步是创建模型和迁移,因为你将来需要一种方法来查询它以进行报告等。运行以下 artisan 命令来创建这些:

php artisan make:model CelebrationStoredEvent -m

以下代码是你在 up 方法中进行迁移所需的代码:

public function up(): void{    Schema::create('celebration_stored_events', static function (Blueprint $table): void {        $table->id();        $table->uuid('aggregate_uuid')->nullable()->unique();        $table        ->unsignedBigInteger('aggregate_version')        ->nullable()        ->unique();        $table->integer('event_version')->default(1);        $table->string('event_class');        $table->json('event_properties');        $table->json('meta_data');        $table->timestamp('created_at');        $table->index('event_class');        $table->index('aggregate_uuid');    });}

如你所见,我们为我们的活动收集了大量数据。现在模型要简单得多。它应该如下所示:

declare(strict_types=1);namespace AppModels;use SpatieEventSourcingStoredEventsModelsEloquentStoredEvent;final class CelebrationStoredEvent extends EloquentStoredEvent{    public $table = 'celebration_stored_events';}

当我们扩展 EloquentStoredEvent 模型时,我们需要做的就是改变它正在查看的表。模型的其余功能已经在父级上到位。

要使用这些模型,你必须创建一个存储库来查询事件。这是一个非常简单的存储库 —— 然而,这是一个重要的步骤。我将我的添加到我的域代码中,位于 src/Domains/Culture/Repositories/ 下,但您可以随意添加对您最有意义的位置:

declare(strict_types=1);namespace DomainsCultureRepositories;use AppModelsCelebrationStoredEvent;use SpatieEventSourcingStoredEventsRepositoriesEloquentStoredEventRepository;final class CelebrationStoredEventsRepository extends EloquentStoredEventRepository{    public function __construct(        protected string $storedEventModel = CelebrationStoredEvent::class,    ) {        parent::__construct();    }}

既然我们有了存储事件和查询它们的方法,我们可以继续我们的聚合本身。同样,我将我的存储在我的域中,但可以随意将你的存储在你的应用程序上下文中。

declare(strict_types=1);namespace DomainsCultureAggregates;use DomainsCultureRepositoriesCelebrationStoredEventsRepository;use SpatieEventSourcingAggregateRootsAggregateRoot;use SpatieEventSourcingStoredEventsRepositoriesStoredEventRepository;final class CelebrationAggregateRoot extends AggregateRoot{    protected function getStoredEventRepository(): StoredEventRepository    {        return app()->make(            abstract: CelebrationStoredEventsRepository::class,        );    }}

到目前为止,除了为我们连接到正确的事件存储之外,此聚合不会执行任何操作。要让它开始跟踪事件,我们首先需要创建它们。但在此之前,我们需要停下来想一想。我们希望在活动中存储哪些数据?我们想要存储我们需要的每一个属性吗?或者我们是否希望存储一个数组,就像它来自一个表单一样?我两种方法都不用,因为为什么要保持简单呢?我在所有事件中使用数据传输对象,以确保始终维护上下文并始终提供类型安全。

巧文书 巧文书

巧文书是一款AI写标书、AI写方案的产品。通过自研的先进AI大模型,精准解析招标文件,智能生成投标内容。

巧文书 61 查看详情 巧文书

我构建了一个软件包,让我做这件事更容易。可以通过以下 Composer 命令安装它:

composer require juststeveking/laravel-data-object-tools

和以前一样, 我默认将我的数据对象保存在我的领域, 但你可以添加到对你最有意义的地方。 我创建了一个名为 Celebration 的数据对象,可以传递给事件和聚合器:

declare(strict_types=1);namespace DomainsCultureDataObjects;use JustSteveKingDataObjectsContractsDataObjectContract;final class Celebration implements DataObjectContract{    public function __construct(        private readonly string $reason,        private readonly string $message,        private readonly int $user,        private readonly int $sender,        private readonly int $team,    ) {}    public function userID(): int    {        return $this->user;    }    public function senderID(): int    {        return $this->sender;    }    public function teamUD(): int    {        return $this->team;    }    public function toArray(): array    {        return [            'reason' => $this->reason,            'message' => $this->message,            'user_id' => $this->user,            'sender_id' => $this->sender,            'team_id' => $this->team,        ];    }}

当我升级到 PHP 8.2 时,这会容易得多,因为我可以创建只读类 – 是的,我的包已经支持它们。

现在我们有了我们的数据对象。我们可以回到我们想要存储的事件。我已经调用了我的CelebrationWasCreated,因为事件名称应该总是过去时。让我们看看这个事件:

declare(strict_types=1);namespace DomainsCultureEvents;use DomainsCultureDataObjectsCelebration;use SpatieEventSourcingStoredEventsShouldBeStored;final class CelebrationWasCreated extends ShouldBeStored{    public function __construct(        public readonly Celebration $celebration,    ) {}}

因为我们使用的是数据对象,所以我们的类保持干净。所以,现在我们有了一个事件——以及一个可以发送的数据对象,我们需要考虑如何触发它。这让我们回到了聚合本身,所以让我们在聚合上创建一个可以用于此目的的方法:

declare(strict_types=1);namespace DomainsCultureAggregates;use DomainsCultureDataObjectsCelebration;use DomainsCultureEventsCelebrationWasCreated;use DomainsCultureRepositoriesCelebrationStoredEventsRepository;use SpatieEventSourcingAggregateRootsAggregateRoot;use SpatieEventSourcingStoredEventsRepositoriesStoredEventRepository;final class CelebrationAggregateRoot extends AggregateRoot{    protected function getStoredEventRepository(): StoredEventRepository    {        return app()->make(            abstract: CelebrationStoredEventsRepository::class,        );    }    public function createCelebration(Celebration $celebration): CelebrationAggregateRoot    {        $this->recordThat(            domainEvent: new CelebrationWasCreated(                celebration: $celebration,            ),        );        return $this;    }}

在这一点上,我们有一种方法来要求一个类记录事件。但是,这一事件还不会持续下去 —— 那是以后的事。此外,我们不会以任何方式改变应用程序的状态。那么,我们该如何做这项活动采购工作呢?这一部分是关于 Livewire 中的实现的,我现在将向你介绍它。

我喜欢通过调度一个事件来管理这个过程,因为它更高效。如果你考虑如何与应用程序交互,你可以从 Web 访问它,通过 API 端点发送请求,或者发生 CLI 命令可能运行的事件 —— 可能是一个 Cron 作业。在所有这些方法中,通常,你需要即时响应,或者至少您不想等待。我将在我的 Livewire 组件上向你展示我为此使用的方法:

public function celebrate(): void{    $this->validate();    dispatch(new TeamMemberCelebration(        celebration: Hydrator::fill(            class: Celebration::class,            properties: [                'reason' => $this->reason,                'message' => $this->content,                'user' => $this->identifier,                'sender' => auth()->id(),                'team' => auth()->user()->current_team_id,            ]        ),    ));    $this->closeModal();}

在这一点上,我们有一种方法来要求一个类记录事件。但是,这一事件还不会持续下去 —— 那是以后的事。此外,我们不会以任何方式改变应用程序的状态。那么,我们该如何做这项活动采购工作呢?这一部分是关于 Livewire 中的实现的,我现在将向你介绍它。

我喜欢通过调度一个事件来管理这个过程,因为它更高效。如果你考虑如何与应用程序交互,你可以从 Web 访问它,通过 API 端点发送请求,或者发生 CLI 命令可能运行的事件 —— 可能是一个 Cron 作业。在所有这些方法中,通常,你需要即时响应,或者至少你不想等待。我将在我的 Livewire 组件上向你展示我为此使用的方法:

public function celebrate(): void{    $this->validate();    dispatch(new TeamMemberCelebration(        celebration: Hydrator::fill(            class: Celebration::class,            properties: [                'reason' => $this->reason,                'message' => $this->content,                'user' => $this->identifier,                'sender' => auth()->id(),                'team' => auth()->user()->current_team_id,            ]        ),    ));    $this->closeModal();}

当我验证来自组件的用户输入,可以分派处理一个新的作业,然后结束这个流程。我使用我的包将一个新的数据对象传递给作业。它有一个 Facade,可以让我用一系列属性来为类添加——到目前为止它工作得很好。那么这是怎么实现的呢?让我们来看看。

declare(strict_types=1);namespace AppJobsTeam;use DomainsCultureAggregatesCelebrationAggregateRoot;use DomainsCultureDataObjectsCelebration;use IlluminateBusQueueable;use IlluminateContractsQueueShouldQueue;use IlluminateFoundationBusDispatchable;use IlluminateQueueInteractsWithQueue;use IlluminateQueueSerializesModels;use IlluminateSupportStr;final class TeamMemberCelebration implements ShouldQueue{    use Queueable;    use Dispatchable;    use SerializesModels;    use InteractsWithQueue;    public function __construct(        public readonly Celebration $celebration,    ) {}    public function handle(): void    {        CelebrationAggregateRoot::retrieve(            uuid: Str::uuid()->toString(),        )->createCelebration(            celebration: $this->celebration,        )->persist();    }}

我们的工作将数据对象接受到它的构造函数中,然后在处理它时存储它。处理作业时,它使用 CelebrationAggregateRoot 按 UUID 检索聚合,然后调用我们之前创建的 createCelebration 方法。在它调用了这个方法之后 – 它在聚合本身上调用了 persist。这就是将为我们存储事件的内容。但是,同样,我们还没有改变我们的应用程序状态。我们所做的只是存储一个不相关的事件而不是创建我们想要创建的庆祝活动?那么我们缺少什么?

我们的事件也需要处理。在另一种方法中,我们使用投影仪来处理我们的事件,但我们必须手动调用它们。这是一个类似的过程,但是我们的聚合正在触发事件,我们仍然需要一个投影仪来处理事件并改变我们的应用程序状态。

让我们创建我们的投影仪,我称之为处理程序 —— 因为它们处理事件。但我会让你决定如何命名你的。

declare(strict_types=1);namespace DomainsCultureHandlers;use DomainsCultureEventsCelebrationWasCreated;use SpatieEventSourcingEventHandlersProjectorsProjector;use InfrastructureCultureActionsCreateNewCelebrationContract;final class CelebrationHandler extends Projector{    public function __construct(        public readonly CreateNewCelebrationContract $action,    ) {}    public function onCelebrationWasCreated(CelebrationWasCreated $event): void    {        $this->action->handle(            celebration: $event->celebration,        );    }}

我们的投影机 / 处理程序,无论你选择如何称呼它,都将从容器中为我们解析 – 然后它将寻找一个以 on 为前缀的方法,后跟事件名称本身。所以在我们的例子中,onCelebrationWasCreated。在我的示例中,我使用一个动作来执行事件中的实际逻辑 – 单个类执行一项可以轻松伪造或替换的工作。所以再一次,我们把树追到下一个班级。动作,这对我来说是这样的:

declare(strict_types=1);namespace DomainsCultureActions;use AppModelsCelebration;use DomainsCultureDataObjectsCelebration as CelebrationObject;use IlluminateDatabaseEloquentModel;use InfrastructureCultureActionsCreateNewCelebrationContract;final class CreateNewCelebration implements CreateNewCelebrationContract{    public function handle(CelebrationObject $celebration): Model|Celebration    {        return Celebration::query()->create(            attributes: $celebration->toArray(),        );    }}

这是当前执行的操作。如你所见,我的操作类本身实现了一个合同 / 接口。这意味着我将接口绑定到我的服务提供者中的特定实现。这使我可以轻松地创建测试替身 / 模拟 / 替代方法,而不会对需要执行的实际操作产生连锁反应。这不是严格意义上的事件溯源,而是通用编程。我们确实拥有的一个好处是我们的投影仪可以重放。因此,如果出于某种原因,我们离开了 Laravel Eloquent,也许我们使用了其他东西,我们可以创建一个新的操作 – 将实现绑定到我们的容器中,重放我们的事件,它应该都能正常工作。

在这个阶段,我们正在存储我们的事件并有办法改变我们的应用程序的状态 —— 但是我们做到了吗?我们需要告诉 Event Sourcing 库我们已经注册了这个 Projector/Handler 以便它知道在事件上触发它。通常我会为每个域创建一个 EventSourcingServiceProvider,这样我就可以在一个地方注册所有的处理程序。我的看起来如下:

declare(strict_types=1);namespace DomainsCultureProviders;use DomainsCultureHandlersCelebrationHandler;use IlluminateSupportServiceProvider;use SpatieEventSourcingFacadesProjectionist;final class EventSourcingServiceProvider extends ServiceProvider{    public function register(): void    {        Projectionist::addProjector(            projector: CelebrationHandler::class,        );    }}

剩下的就是确保再次注册此服务提供者。我为每个域创建一个服务提供者来注册子服务提供者 —— 但这是另一个故事和教程。

在这个阶段,我们正在存储我们的事件,并有一种办法改变我们的应用程序的状态——但是我们做到了吗?我们需要告诉 Event Sourcing 库,我们已经注册了 Projector/Handler 以便它知道在事件上触发它。通常,我会为每个域创建一个EventSourcingServiceProvider,以便可以在一个位置注册所有处理程序。如下:

declare(strict_types=1);namespace DomainsCultureProviders;use DomainsCultureHandlersCelebrationHandler;use IlluminateSupportServiceProvider;use SpatieEventSourcingFacadesProjectionist;final class EventSourcingServiceProvider extends ServiceProvider{    public function register(): void    {        Projectionist::addProjector(            projector: CelebrationHandler::class,        );    }}

剩下确保此服务提供者重新注册。我为每个域创建一个 Service Provider 来注册子服务提供者–但这是另一个故事和教程。

现在,当我们把它们放在一起时。我们可以要求我们的聚合创建一个庆祝活动,它将记录事件并将其保存在数据库中,并且作为副作用,我们的处理程序将被触发,随着新的变化改变应用程序的状态。

这似乎有点啰嗦,对吧?有没有更好的办法?可能,但在这一点上,我们知道何时更改了我们的应用程序状态。我们了解它们的制作原因。此外,由于我们的数据对象,我们知道谁进行了更改以及何时进行了更改。所以它可能不是最直接的方法,但它可以让我们更多地了解我们的应用程序。

你可以根据需要尽可能多地进行此操作,也可以将脚趾浸入事件溯源中,这是最有意义的。希望本教程为你展示了一条清晰实用的路径,让你从今天开始使用事件溯源。

如果看完后你觉得意犹未尽, Spatie 很大方的提供了一张 7 折优惠券,可以用在他们 Laravel 课程里的事件溯源部分,真是太棒了!访问 课程网站 并使用优惠券码 LARAVEL-NEWS-EVENT-SOURCING。

你曾经使用过事件溯源吗?你是怎么处理的?在评论区告诉我们!

原文地址:https://laravel-news.com/event-sourcing-in-laravel译文地址:https://learnku.com/laravel/t/71001

更多编程相关知识,请访问:编程视频!!

以上就是一文详解Laravel中的事件溯源的详细内容,更多请关注php中文网其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/339261.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
怎么查看小米10s电池状况_查看小米10s电池状况教程
上一篇 2026年11月8日 04:06:39
《明日方舟:终末地》雨天效果惊人:角色服装被打湿
下一篇 2025年11月28日 05:53:47

相关推荐

  • 聊聊怎么在大型Laravel项目中组织路由

    聊聊怎么在大型Laravel项目中组织路由聊聊怎么在大型Laravel项目中组织路由聊聊怎么在大型Laravel项目中组织路由聊聊怎么在大型Laravel项目中组织路由

    想象一下一个拥有 100 多个路由的 Laravel 项目,其中包括访客,用户,管理员等分离的模块。你真的要将所有内容写在一个文件中吗?那么如何将它们分组,并且为 URL 添加前缀呢?看看有哪些办法。 1. 分离 WEB 和 API 路由 这个简单,因为 Laravel 已经帮你做了。有如下两个文件…

    2026年11月8日 • 用户投稿
    000
  • 如何使用Composer解决Laravel项目中GoogleSheetsAPI的集成问题?revolution/laravel-google-sheets可以帮到你!

    最近在开发一个 Laravel 项目时,我遇到了一个需求:需要从 Google Sheets 中读取和写入数据。这个需求看似简单,但实际操作中却遇到了不少问题。首先,我需要找到一个可靠且易用的库来集成 Google Sheets API。其次,如何配置和使用这个库也让我头疼了一阵子。最后,我找到了 …

    2026年11月8日
    100
  • 126邮箱首页登录入口 126邮箱官网首页直接登录

    126邮箱首页登录入口 126邮箱官网首页直接登录126邮箱首页登录入口 126邮箱官网首页直接登录126邮箱首页登录入口 126邮箱官网首页直接登录126邮箱首页登录入口 126邮箱官网首页直接登录

    126邮箱首页登录入口位于官网左上角“登录”按钮,进入mail.126.com后点击该按钮,输入账号密码并完成安全验证即可登录。 126邮箱首页登录入口在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来126邮箱官网首页直接登录方式,感兴趣的网友一起随小编来瞧瞧吧! https://mail…

    2026年11月8日 • 用户投稿
    100
  • 分享Laravel邮件SPF检查器:Mail SPF Checker

    分享Laravel邮件SPF检查器:Mail SPF Checker分享Laravel邮件SPF检查器:Mail SPF Checker分享Laravel邮件SPF检查器:Mail SPF Checker分享Laravel邮件SPF检查器:Mail SPF Checker

    如何避免邮件进入垃圾邮箱?本篇文章就来给大家分享一个laravel邮件spf检查器:mail spf checker,看看它是怎么解决这个问题的! Laravel 「Mail SPF Checker」 是一个包,用来检查你是否可以通过给定的邮件服务器,并以给定的邮件地址名义来发送一份电子邮件: 当以…

    2026年11月8日 • 用户投稿
    200
  • PHP JSON 数组合并:添加时间戳信息

    本文档旨在指导开发者如何使用 PHP 处理从数据库获取的 JSON 数组数据,并为每个 JSON 对象添加基于时间戳计算出的“时间前”信息。通过示例代码,详细讲解如何遍历数组、计算时间差,并将计算结果合并到原始 JSON 数据中,最终生成包含时间信息的 JSON 数组。 核心思路 核心在于使用 fo…

    2026年11月8日
    100
  • 【整理分享】Laravel8优化数据库查询的18 个 小技巧

    【整理分享】Laravel8优化数据库查询的18 个 小技巧【整理分享】Laravel8优化数据库查询的18 个 小技巧【整理分享】Laravel8优化数据库查询的18 个 小技巧【整理分享】Laravel8优化数据库查询的18 个 小技巧

    laravel怎么优化数据库查询?下面本篇文章给大家整理分享18  laravel8 数据库查询优化的 小技巧,希望对大家有所帮助! 如果应用运行缓慢或存在大量数据库查询,请按照以下性能优化提示来缩短应用的加载时间。【相关推荐:laravel视频教程】 1. 检索大型数据集 本提示主要侧重于提高处理…

    2026年11月8日 • 用户投稿
    100
  • Laravel开发:如何使用Laravel Event Sourcing构建事件驱动的应用程序?

    laravel开发:如何使用laravel event sourcing构建事件驱动的应用程序? 事件驱动的应用程序是一种利用事件和事件处理器(Event Handler)来实现的应用程序。事件驱动的架构使得应用程序更加容易扩展和维护,并且更加灵活,在面对变化时更加容易适应。 Laravel是一种流…

    用户投稿 2026年11月8日
    000
  • PHP JSON数组合并:添加时间戳信息

    本文旨在提供一种在PHP中处理JSON数组,并向每个数组元素添加基于时间戳计算出的“时间距离现在”信息的实用方法。通过遍历JSON数组,计算时间差,并将结果合并到原始数组中,最终生成包含id、CreatedAt以及Time字段的JSON数据。 使用引用循环修改JSON数组 当需要修改数组本身,而不是…

    2026年11月8日
    000
  • 一文详解Laravel怎么快速创建简单事件流

    一文详解Laravel怎么快速创建简单事件流一文详解Laravel怎么快速创建简单事件流一文详解Laravel怎么快速创建简单事件流一文详解Laravel怎么快速创建简单事件流

    本篇文章给大家带来了关于laravel 事件流的相关知识,其中主要介绍了什么是事件流,又如何在 laravel 中创建一个简单的事件流,感兴趣的朋友一起来看一下吧,希望对大家有帮助。 简介 事件流为你提供了一种将事件发送到客户端而无需重新加载页面的方法。当对数据库进行实时更改时,这对于更新用户界面非…

    2026年11月8日 • 用户投稿
    000
  • 如何使用OpenTelemetry自动追踪Laravel应用中的性能问题?Composer可以帮你搞定!

    可以通过一下地址学习 Composer:学习地址 在开发 laravel 应用时,性能监控和追踪是确保应用高效运行的关键。然而,配置和管理这些工具通常会让人感到头疼。我在最近的一个项目中就遇到了这样的问题:如何在不增加太多复杂度的情况下,实现对应用性能的全面监控? 经过一番研究,我找到了 OpenT…

    2026年11月8日
    100
  • 浅析Laravel中isDirty()和wasChanged()的区别

    浅析Laravel中isDirty()和wasChanged()的区别浅析Laravel中isDirty()和wasChanged()的区别浅析Laravel中isDirty()和wasChanged()的区别浅析Laravel中isDirty()和wasChanged()的区别

    本篇文章带大家聊聊laravel数据模型中isdirty()和waschanged()的区别,希望对大家有所帮助! Laravel 数据模型中 `isDirty()` 和 `wasChanged()` 有区别吗? 答案:是有区别的。 相关代码: github.com/laravel/framewor…

    2026年11月8日 • 用户投稿
    200
  • 如何配置VSCode在Laravel中模拟API数据 Laravel Mock API接口开发插件方法

    如何配置VSCode在Laravel中模拟API数据 Laravel Mock API接口开发插件方法如何配置VSCode在Laravel中模拟API数据 Laravel Mock API接口开发插件方法如何配置VSCode在Laravel中模拟API数据 Laravel Mock API接口开发插件方法如何配置VSCode在Laravel中模拟API数据 Laravel Mock API接口开发插件方法

    在laravel中模拟api数据的核心是使用路由+控制器+faker生成假数据;2. 需在routes/api.php中注册mock路由并指向mockapicontroller;3. 在控制器中用faker类生成结构化假数据并以json格式返回;4. 利用vscode的rest client或thu…

    2026年11月8日 • 用户投稿
    000
  • 我的 Apple ID 官网登录 Apple ID 账户管理中心

    我的 Apple ID 官网登录 Apple ID 账户管理中心我的 Apple ID 官网登录 Apple ID 账户管理中心我的 Apple ID 官网登录 Apple ID 账户管理中心我的 Apple ID 官网登录 Apple ID 账户管理中心

    我的 Apple ID 官网登录入口地址是 https://appleid.apple.com,用户可在此管理个人资料、安全设置、支付信息及设备列表,支持iCloud同步、Find My定位、媒体服务管理和隐私设置,界面简洁且适配多语言多终端。 我的 Apple ID 官网登录入口地址在哪里?这是不…

    2026年11月8日 • 用户投稿
    000
  • 什么叫laravel控制器

    什么叫laravel控制器什么叫laravel控制器什么叫laravel控制器什么叫laravel控制器

    在laravel中,控制器(Controller)是一个类,用于实现一定的功能;控制器能将相关的请求处理逻辑组成一个单独的类。控制器中存放中一些方法,实现一定的功能,通过路由调用控制器,不再使用回调函数;控制器被存放在“app/Http/Controllers”目录中。 本教程操作环境:window…

    2026年11月8日 • 用户投稿
    000
  • 如何解决Laravel查询缓存问题?watson/rememberable可以帮你提升效率

    可以通过以下地址学习 Composer:学习地址 在开发 laravel 项目时,我遇到了一个普遍存在的问题:频繁的数据库查询导致程序性能下降。虽然我尝试了一些基本的缓存策略,但这些方法要么不够灵活,要么实施起来过于复杂。就在我苦恼之际,我发现了 watson/rememberable 这个库,它通…

    2026年11月8日
    100
  • 笔趣阁官方网站入口 笔趣阁在线阅读网站入口

    笔趣阁官方网站入口 笔趣阁在线阅读网站入口笔趣阁官方网站入口 笔趣阁在线阅读网站入口笔趣阁官方网站入口 笔趣阁在线阅读网站入口笔趣阁官方网站入口 笔趣阁在线阅读网站入口

    笔趣阁官方网站入口在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来笔趣阁在线阅读网站入口,感兴趣的网友一起随小编来瞧瞧吧! https://www.biquge.info/ Text-To-Pokemon口袋妖怪 输入文本生成自己的Pokemon,还有各种选项来定制自己的口袋妖怪 48 查…

    2026年11月8日 • 用户投稿
    200
  • 聊聊Laravel中怎么向About命令添加有用的信息

    聊聊Laravel中怎么向About命令添加有用的信息聊聊Laravel中怎么向About命令添加有用的信息聊聊Laravel中怎么向About命令添加有用的信息聊聊Laravel中怎么向About命令添加有用的信息

    怎么向about命令添加信息?下面本篇文章介绍一下向 laravel about 命令添加有用信息的方法,希望对大家有所帮助! Laravel 9.21 中发布的 Laravel about 命令为应用程序的重要配置提供了出色的概览。 它开箱即用,列出了环境详细信息、驱动程序的缓存状态和配置: 新的…

    2026年11月7日 • 用户投稿
    800
  • 笔趣阁小说官网入口 笔趣阁免费阅读网站直达

    笔趣阁小说官网入口 笔趣阁免费阅读网站直达笔趣阁小说官网入口 笔趣阁免费阅读网站直达笔趣阁小说官网入口 笔趣阁免费阅读网站直达笔趣阁小说官网入口 笔趣阁免费阅读网站直达

    笔趣阁小说官网入口在哪里?这是不少书友都在寻找的,接下来由PHP小编为大家带来笔趣阁免费阅读网站直达地址,喜欢看小说和漫画的读者一起随小编来了解吧! https://www.biquge.info/ 妙笔工坊 妙笔工坊是一个集短剧解说,AI视频生成,口播数字人,小说推文生成的ai智能工具 138 查…

    2026年11月7日 • 用户投稿
    100
  • 分享Laradock中Laravel Octane与WebSocket的nginx配置

    分享Laradock中Laravel Octane与WebSocket的nginx配置分享Laradock中Laravel Octane与WebSocket的nginx配置分享Laradock中Laravel Octane与WebSocket的nginx配置分享Laradock中Laravel Octane与WebSocket的nginx配置

    本篇文章给大家带来了关于laravel的相关知识,其中主要是记录一下laradock中laravel octane与websocket的nginx配置,感兴趣的朋友,下面一起来看一下,希望对大家有帮助。 docker 安装laradock,和Laravel Octane的安装这里就不过多赘述了。 前…

    2026年11月7日 • 用户投稿
    100
  • 如何解决PHP包中分发资产的管理问题?使用pixelfear/composer-dist-plugin可以!

    可以通过以下地址学习composer:学习地址 在开发一个名为foo/bar的php包时,我遇到了一个问题:如何管理编译后的css和js文件。这些文件体积较大,并且频繁更新,我不希望将它们提交到git仓库中,因为这会使仓库变得臃肿且难以管理。 最初,我尝试手动管理这些文件,但这不仅增加了工作量,还容…

    2026年11月7日
    000

发表回复

登录后才能评论
关注微信