91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

php中怎么實現事件溯源

發布時間:2021-07-06 17:58:57 來源:億速云 閱讀:153 作者:Leah 欄目:編程語言

php中怎么實現事件溯源,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

事件溯源(Event Sourcing)是領域驅動設計(Domain Driven Design)設計思想中的架構模式之一。領域驅動設計是面向業務的一種建模方式。它幫助開發者建立更貼近業務的模型。

在傳統的應用程序中,我們將狀態儲存在數據庫中,當狀態發生改變時,我們即時更新數據庫中相對應的狀態值。事件溯源則采用一種截然不同的模式,它的核心是事件,所有的狀態都來源于事件,我們通過播放事件來獲取應用中的狀態,所以它叫事件溯源。

在本文中,我們將運用事件溯源模式編寫一個簡化的購物車,以此分解事件溯源的幾個重要組成概念。我們也將使用 Spatie 的事件溯源庫來避免重復造輪。

在我們的案例中,用戶可以添加,刪除以及查看購物車內容,同時它具備兩個業務邏輯:

購物車不可添加超過 3 種產品。當用戶添加第 4 種產品時,系統將自動發出一個預警郵件。

要求以及聲明

本文使用 Laravel 框架。本文使用特定版本 spatie/laravel-event-sourcing:4.9.0 以避免不同版本之間的語法問題。本文并非手把手的分步教程,你必須有一定 Laravel 基礎才可以理解本文,請避免咬文嚼字,關注架構模式的組成結構。本文的重點是闡述事件溯源的核心思想,此庫中對事件溯源的實現方式并非唯一方案。

領域事件(Domain Event)

事件溯源中的事件被稱為領域事件,與傳統的事務事件不同,它有以下幾個特點:

它與業務息息相關,所以它的命名往往夾帶業務名詞,而不應該與數據庫掛鉤。比如購物車增添商品,對應的領域事件應該是 ProductAddedToCart, 而不是 CartUpdated。它是指發生過的事情,所以它一定是過去式,比如 ProductAddedToCart 而不是 ProductAddToCart。領域事件只可追加,不可以刪除或者更改,如果需要刪除,我們需要使用具備刪除效果的領域事件,比如 ProductRemovedFromCart。

根據以上信息,我們構建三種領域事件:

ProductAddedToCart:

<?php
use Spatie\EventSourcing\StoredEvents\ShouldBeStored;
class ProductAddedToCart extends ShouldBeStored
{
    public int $productId;
    public int $amount;
    public function __construct(int $productId, int $amount)
    {
        $this->productId = $productId;
        $this->amount = $amount;
    }
}


ProductRemovedFromCart:

<?php
use Spatie\EventSourcing\StoredEvents\ShouldBeStored;
class ProductRemovedFromCart extends ShouldBeStored
{
    public int $productId;
    public function __construct(int $productId)
    {
        $this->productId = $productId;
    }
}


CartCapacityExceeded:

<?php
use Spatie\EventSourcing\StoredEvents\ShouldBeStored;
class CartCapacityExceeded extends ShouldBeStored
{
    public array $currentProducts;
    public function __construct(array $currentProducts)
    {
        $this->currentProducts = $currentProducts;
    }
}

事件 ProductAddedToCart 和 ProductRemovedFromCart 分別代表商品加入購物車以及被從購物車中移除,事件 CartCapacityExceeded 代表購物車中商品超標,這是我們前面提到的業務邏輯之一。

聚合(Aggregate)

在領域驅動設計中,聚合(Aggregate)是指一組緊密相關的類,他們自成一體形成一個有邊界的組織,邊界外部的對象只可以通過聚合根(Aggregate Root)與此聚合交互,聚合根是聚合中的一種特殊的類。我們可以將聚合想象中一個家庭戶口本,對此戶口本進行任何操作,都必須通過戶主(聚合根)。

聚合具有以下幾個特點:

它確保核心業務的不變性。也就是說我們在聚合做驗證,對違反業務邏輯的操作拋出異常。它是領域事件的產生地。領域事件在聚合根中產生。也就是說我們可在領域事件已完成業務要求。它自成一體,具有明顯的邊界,也就是說,只能通過聚合根調用聚合中的方法。

聚合是服務于業務邏輯的主要以及最直接的部分,我們使用它直觀地為我們的業務建立模型。

綜上所述,讓我們構建一個 CartAggregateRoot 聚合根:

<?php
use Spatie\EventSourcing\AggregateRoots\AggregateRoot;
class CartAggregateRoot extends AggregateRoot
{
    public function addItem(int $productId, int $amount)
    {
    }
    public function removeItem(int $productId)
    {
    }
}

CartAggregateRoot 具備兩個方法 addItem 和 removeItem,分別代表添加以及移除商品。

另外我們還需要加些屬性來記錄購物車內容:

<?php
use Spatie\EventSourcing\AggregateRoots\AggregateRoot;
class CartAggregateRoot extends AggregateRoot
{
    private array $products;
    public function addItem(int $productId, int $amount)
    {
    }
    public function removeItem(int $productId)
    {
    }
}

private array $products; 將記錄購物車中的商品,那么我們什么時候可以為其賦值呢?在事件溯源中,這是在事件發生以后,所以我們首先需要發布領域事件:

<?php
use Spatie\EventSourcing\AggregateRoots\AggregateRoot;
class CartAggregateRoot extends AggregateRoot
{
    private array $products;
    public function addItem(int $productId, int $amount)
    {
        $this->recordThat(
            new ProductAddedToCart($productId, $amount)
        );
    }
    public function removeItem(int $productId)
    {
        $this->recordThat(
            new ProductRemovedFromCart($productId)
        );
    }
}

在調用 addItem 和 removeItem 事件時,我們分別發布 ProductAddedToCart 和 ProductRemovedFromCart 事件,與此同時,我們通過 apply 魔術方法為 $products 賦值:

<?php
use Spatie\EventSourcing\AggregateRoots\AggregateRoot;
class CartAggregateRoot extends AggregateRoot
{
    private array $products;
    public function addItem(int $productId, int $amount)
    {
        $this->recordThat(
            new ProductAddedToCart($productId, $amount)
        );
    }
    public function removeItem(int $productId)
    {
        $this->recordThat(
            new ProductRemovedFromCart($productId)
        );
    }
    public function applyProductAddedToCart(ProductAddedToCart $event)
    {
        $this->products[] = $event->productId;
    }
    public function applyProductRemovedFromCart(ProductRemovedFromCart $event)
    {
        $this->products[] = array_filter($this->products, function ($productId) use ($event) {
            return $productId !== $event->productId;
        });
    }
}

apply* 是 Spatie 的事件溯源庫自帶的魔術方法,當我們使用 recordThat 發布事件時,apply* 會被自動調用,它確保狀態的改動是在事件發布以后。

現在 CartAggregateRoot 已通過事件獲取了需要的狀態,現在我們可以加入第一條業務邏輯:購物車不可添加超過 3 種產品。

修改 CartAggregateRoot::addItem,當用戶添加第 4 種產品時,發布相關領域事件 CartCapacityExceeded:

public function addItem(int $productId, int $amount)
{
    if (count($this->products) >= 3) {
        $this->recordThat(
            new CartCapacityExceeded($this->products)
        );
        return;
    }
    $this->recordThat(
        new ProductAddedToCart($productId, $amount)
    );
}

現在我們已經完成了聚合根工作,雖然代碼很簡單,但是根據模擬業務而建立的模型非常直觀。

加入商品時,我們調用:

CartAggregateRoot::retrieve(Uuid::uuid4())->addItem(1, 100);

加入商品時,我們調用:

CartAggregateRoot::retrieve($uuid)->removeItem(1);

放映機(Projector)

UI 界面是應用中不可缺少的部分,比如向用戶展示購物車中的內容,通過重播聚合根或許會有性能問題。此時我們可以使用放映機(Projector)。

放映機實時監控領域事件,我們通過它可以建立服務于 UI 的數據庫表。放映機的特點是它可以重塑,當我們發現代碼中的 bug 影響到 UI 數據時,我們可以重塑此放映機建立的表單。

讓我們寫一個服務于用戶的放映機 CartProjector:

<?php
use Spatie\EventSourcing\EventHandlers\Projectors\Projector;
class CartProjector extends Projector
{
    public function onProductAddedToCart(ProductAddedToCart $event)
    {
        $projection = new ProjectionCart();
        $projection->product_id = $event->productId;
        $projection->saveOrFail();
    }
    public function onProductRemovedFromCart(ProductRemovedFromCart $event)
    {
        ProjectionCart::where('product_id', $event->productId)->delete();
    }
}

放映機 CartProjector

會根據監聽的事件來增加或者刪除表單 projection_carts,ProjectionCart 是一個普通的 Laravel 模型,我們僅使用它來操作數據庫。

當我們的 UI 需要展示購物車中的內容時,我們從 projection_carts 讀取數據,這和讀寫分離有異曲同工之妙。

反應機(Reactor)

反應機(Reactor)和放映機一樣,實時監控領域事件。不同的是反應機不可以重塑,它的用途是用來執行帶有副作用的操作,所以它不可以重塑。

我們使用它來實現我們的第二個業務邏輯:當用戶添加第 4 個產品時,系統將自動發出一個預警郵件。

<?php
use Spatie\EventSourcing\EventHandlers\Reactors\Reactor;
class WarningReactor extends Reactor
{
    public function onCartCapacityExceeded(CartCapacityExceeded $event)
    {
        Mail::to('admin@corporation.com')->send(new CartWarning());
    }
}

關于php中怎么實現事件溯源問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

定远县| 黄山市| 江油市| 靖边县| 遂平县| 揭东县| 垣曲县| 固原市| 友谊县| 内黄县| 昭苏县| 高淳县| 浦东新区| 贵港市| 岫岩| 客服| 茌平县| 武冈市| 龙川县| 桃园县| 离岛区| 保山市| 绥宁县| 罗山县| 托克托县| 溧水县| 镇雄县| 黄山市| 文安县| 兰坪| 鹤山市| 唐山市| 金川县| 华容县| 高雄县| 许昌市| 靖州| 东海县| 剑川县| 鸡泽县| 绍兴县|