繼昨天的優化
今天就來為 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 增加一些新功能