iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0
Modern Web

全端成長之旅系列 第 22

Day.22 Laravel with DDD Part.3

  • 分享至 

  • xImage
  •  

今天分享一些 DDD 抽象類別的實作。

ValueObject

這邊使用 __set__get 模式方法來時做出一個只能 new 而不能改值得物件
不過實際的類別要是使用 public setters 那就另當別論了。
以 PHP 來說,這部分只能依靠團隊共識跟 Code review 來補足了。


use ArrayAccess;

abstract class ValueObject implements ArrayAccess
{
    protected $props = [];

    const SETTER_ACCESS_MESSAGE = 'The value of the ValueObject cannot be modified';

    public function __construct(array $props)
    {
        $this->props = $props;
    }

    public function __set($key, $value)
    {
        throw new Exception(static::SETTER_ACCESS_MESSAGE);
    }

    public function __get($key)
    {
        return $this->props[$key] ?? null;
    }

    public function offsetSet($offset, $value)
    {
        throw new Exception(static::SETTER_ACCESS_MESSAGE);
    }

    public function offsetExists($offset)
    {
        return isset($this->props[$offset]);
    }

    public function offsetUnset($offset)
    {
        throw new Exception(static::SETTER_ACCESS_MESSAGE);
    }

    public function offsetGet($offset)
    {
        return $this->props[$offset] ?? null;
    }

    public function toArray()
    {
        return $this->props;
    }
}

使用範例


class Color extends ValueObject
{
    // ...
}

Entity

Entity 繼承了 ValueObject 並把 setters 打開

abstract class Entity extends ValueObject
{
    public function __set($key, $value)
    {
        $this->props[$key] = $value;
        
        return $value;
    }

    public function offsetSet($offset, $value)
    {
        $this->props[$offset] = $value;
    }

    public function offsetUnset($offset)
    {
        unset($this->props[$offset]);
    }
}

使用範例

Entity 的子類別可以依照所需再次複寫這些方法,例如:


<?php

class User
{
    public function __construct($props)
    {
        $this->props = $props;
    }
    
    public function __set($key, $value)
    {
        if ($key === 'email') {
            $this->setEmail($value);
        } else {
            $this->props[$key] = $value;
        }
    
        return $value;
    }

    public function setEmail($value)
    {
        var_dump('Check email format ...');

        $this->props['email'] = $value;
        
        return $this;
    }

    public function toArray()
    {
        return $this->props;
    }
}

$user = new User([
    'name' => 'Petter'
]);

$user->email = 'example@mail.com';
var_dump($user->toArray());

// output:
// string(22) "Check email format ..."
// array(2) {
//   ["props"]=>
//   array(1) {
//     ["name"]=>
//     string(6) "Petter"
//   }
//   ["email"]=>
//   string(16) "example@mail.com"
// }

這時候的 setters 是否要設為 public,就看自己的開發團隊共識。

Aggregate

Aggregate 實際上是 Entity 的子類因此沒有抽象類,延續上一個案例的 User 類別
它的 Aggregate 可能像是這樣:


use User;

class UserAggregate extends User
{
    public function __set($key, $value)
    {
        if ($key === 'group') {
            $this->setGroup($value);
        } else {
            parent::__set($key, $value);
        }
    }
    
    public function setGroup($group)
    {
        var_dump('Check something ...');

        $this->props['group'] = $group;
        
        return $this;
    }
}

$user = new UserAggregate([
    'name' => 'Petter'
]);

$user->email = 'example@mail.com';
$user->group = 'MyGroup';
var_dump($user->toArray());

// output:
// string(22) "Check email format ..."
// string(19) "Check something ..."
// array(3) {
//   ["props"]=>
//   array(1) {
//     ["name"]=>
//     string(6) "Petter"
//   }
//   ["email"]=>
//   string(16) "example@mail.com"
//   ["group"]=>
//   string(7) "MyGroup"
// }

基本上就是變成丟進建構子的 $props 屬性變多了,然後對增加的那些屬性新增 getters/setters。


上一篇
Day.21 Laravel with DDD Part.2
下一篇
Day.23 Laravel with DDD Part.4
系列文
全端成長之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言