php-ddd/notification

Fowler 的通知模式的 PHP 实现

v1.0.2 2014-12-27 22:12 UTC

This package is not auto-updated.

Last update: 2024-09-14 16:13:36 UTC


README

构建状态Scrutinizer 代码质量代码覆盖率SensioLabs Insight 通知

PHP 5.3+ 库,用于在验证中用通知替换抛出异常。

"如果你正在验证某些数据,通常你不应该使用异常来表示验证失败。" -- Martin Fowler

安装

可以通过 Composerphp-ddd/notification 的形式安装

$ composer require php-ddd/notification

用法

假设我们有一段这样的代码

use Exception;

class PurchaseOrder
{
    /**
     * @var Items[]
     */
    private $items = array();
    
    /**
     * @var ShippingInformation
     */
    private $shippingInformation;
    
    /**
     * Check if we can validate the purchase order
     *
     * @throw Exception an Exception containing the reason why we can't validate the Order
     */
    public function canValidate()
    {
        if (empty($this->items)) {
            throw new Exception('There is nothing to purchase.');
        }
        
        foreach($this->items as $item) {
            if ($item->isProductExpires()) {
                throw new Exception(sprintf('The item %s is no longer available.', (string)$item));
            }
        }
        
        if (!$this->shippingInformation->isComplete()) {
            throw new Exception('You should first complete your shipping information');
        }
    }
}

我们想避免使用 Exception,因为此方法的目标是知道我们是否可以验证采购订单,而不是进行验证。
这类方法应该返回一个布尔值,表示我们是否可以进行验证。
但返回布尔值而不抛出异常意味着我们失去了关于为什么我们不能购买此订单的信息。
通过引入通知模式,我们可以同时拥有这两种信息。

use PhpDDD\Notification;

class PurchaseOrder
{
    /**
     * @var Items[]
     */
    private $items = array();
    
    /**
     * @var ShippingInformation
     */
    private $shippingInformation;
    
    /**
     * Check if we can validate the purchase order
     *
     * @param Notification $notification
     *
     * @return bool whether we can validate this order or not
     */
    public function canValidate(Notification $notification)
    {
        if (empty($this->items)) {
            $notification->addError('There is nothing to purchase.');
        }
        
        foreach($this->items as $item) {
            if ($item->isProductExpires()) {
                $notification->addError(sprintf('The item %s is no longer available.', (string)$item));
            }
        }
        
        if (!$this->shippingInformation->isComplete()) {
            $notification->addError('You should first complete your shipping information');
        }
        
        return $notification->hasError();
    }
}

// Elsewhere
use Exception;

$order = new PurchaseOrder();
// ...
$notification = new Notification();
if (!$order->canValidate($notification)) {
    throw new Exception($notification->firstMessage());
}

请注意,这会改变你代码的行为。你应该阅读 Martin Fowler 的博客文章,以了解如何在不破坏代码的情况下进行此操作。

有时,你可能不想知道为什么我们不能验证。在这种情况下,创建通知对象对你的上下文是不相关的。
在这种情况下,只需按如下方式更新你的代码

use PhpDDD\Notification;

class PurchaseOrder
{
    /**
     * @var Items[]
     */
    private $items = array();
    
    /**
     * @var ShippingInformation
     */
    private $shippingInformation;
    
    /**
     * Check if we can validate the purchase order
     *
     * @param Notification|null $notification
     *
     * @return bool whether we can validate this order or not
     */
    public function canValidate(Notification $notification = null)
    {
        if (null === $notification) {
            $notification = new Notification();
        }
        
        if (empty($this->items)) {
            $notification->addError('There is nothing to purchase.');
        }
        
        foreach($this->items as $item) {
            if ($item->isProductExpires()) {
                $notification->addError(sprintf('The item %s is no longer available.', (string)$item));
            }
        }
        
        if (!$this->shippingInformation->isComplete()) {
            $notification->addError('You should first complete your shipping information');
        }
        
        return $notification->hasError();
    }
}

// Elsewhere
$order = new PurchaseOrder();
// ...
if (!$order->canValidate()) {
    return;
}