iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
0
自我挑戰組

單元測試開發購物車功能系列 第 7

Day07: 持續優化商品物件2

繼昨天的優化
今天就來為 Item 增加總計的功能

// tests/ItemTest.php

namespace Recca0120\Cart\Tests;

use Recca0120\Cart\Item;
use PHPUnit\Framework\TestCase;

class ItemTest extends TestCase
{
    /** @test */
    public function 測試商品屬性()
    {
        $attributes = [
            'name' => '商品01',
            'price' => 100,
            'quantity' => 2,
        ];

        $item = new Item($attributes);

        $this->assertEquals($attributes, $item->toArray());
    }

    /** @test */
    public function 使用mehtod來設定屬性()
    {
        $attributes = [
            'name' => '商品01',
            'price' => 100,
            'quantity' => 2,
        ];

        $item = new Item();

        $item->setName($attributes['name']);
        $this->assertSame($attributes['name'], $item->getName());

        $item->setPrice($attributes['price']);
        $this->assertSame($attributes['price'], $item->getPrice());

        $item->setQuantity($attributes['quantity']);
        $this->assertSame($attributes['quantity'], $item->getQuantity());

        $this->assertEquals($attributes, $item->toArray());
    }

    /** @test */
    public function 測試ArrayAccess()
    {
        $attributes = [
            'name' => '商品01',
            'price' => 100,
            'quantity' => 2,
        ];

        $item = new Item();

        $item['name'] = $attributes['name'];
        $this->assertSame($attributes['name'], $item['name']);

        $item['price'] = $attributes['price'];
        $this->assertSame($attributes['price'], $item['price']);

        $item['quantity'] = $attributes['quantity'];
        $this->assertSame($attributes['quantity'], $attributes['quantity']);

        $this->assertEquals($attributes, $item->toArray());
    }

    /** @test */
    public function 取得商品屬性()
    {
        $attributes = [
            'name' => '商品01',
            'price' => 100,
            'quantity' => 2,
        ];

        $item = new Item;
        $item['name'] = $attributes['name'];
        $item->price = $attributes['price'];
        $item->setQuantity($attributes['quantity']);

        $this->assertEquals($attributes, $item->toArray());
    }

    /** @test */
    public function 商品價格總計()
    {
        $attributes = [
            'name' => '商品01',
            'price' => 100,
            'quantity' => 2,
        ];

        $item = new Item($attributes);

        $this->assertEquals(200, $item->total());
        $this->assertEquals(200, $item->total);
        $this->assertEquals(200, $item['total']);
    }
}
// src/Item.php

namespace Recca0120\Cart;

use ArrayAccess;
use RuntimeException;

class Item implements ArrayAccess
{
    private $attributes = [];

    public function __construct($attributes = [])
    {
        $this->attributes = $attributes;
    }

    public function __get($key)
    {
        $key = $key === 'qty' ? 'quantity' : $key;
        
        // 判斷有無此 method,有的話則執行 method
        if (method_exists($this, $key) === true) {
            return call_user_func([$this, $key]);
        }

        return $this->attributes[$key];
    }

    public function __set($key, $value)
    {
        $key = $key === 'qty' ? 'quantity' : $key;

        $this->attributes[$key] = $value;

        return $this;
    }

    public function __isset($key)
    {
        $key = $key === 'qty' ? 'quantity' : $key;

        return isset($this->attributes[$key]);
    }

    public function __unset($key)
    {
        $key = $key === 'qty' ? 'quantity' : $key;

        unset($this->attributes[$key]);
    }

    public function __call($method, $paramters)
    {
        if (strpos($method, 'set') === 0) {
            return $this->__set(lcfirst(substr($method, 3)), $paramters[0]);
        }

        if (strpos($method, 'get') === 0) {
            return $this->__get(lcfirst(substr($method, 3)));
        }

        throw new RuntimeException('Call to undefined method '.__CLASS__.'::'.$method);
    }

    public function offsetGet($key)
    {
        return $this->__get($key);
    }

    public function offsetSet($key, $value)
    {
        return $this->__set($key, $value);
    }

    public function offsetExists($key)
    {
        return $this->__isset($key);
    }

    public function offsetUnset($key)
    {
        $this->__unset($key);
    }

    // 總計功能
    public function total()
    {
        return $this->attributes['price'] * $this->attributes['quantity'];
    }

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

改造到這邊,我們可以發現 Cart.php 的有地方可優化,所以就順手改造一下

// src/Cart.php

namespace Recca0120\Cart;

class Cart
{
    private $items = [];

    public function put($item)
    {
        array_push($this->items, $item);

        return $this;
    }

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

    public function total()
    {
        return array_sum(array_map(function ($item) {
            return $item['total'];
        }, $this->items));
    }
}

至此 Item 重構的差不多了,
明天就開始來為 Cart 增加一些新功能


上一篇
Day06: 持續優化商品物件
下一篇
Day08: 替購物車增加功能
系列文
單元測試開發購物車功能12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言