Skip to content

Instantly share code, notes, and snippets.

@vanthao03596
Last active February 19, 2021 09:39
Show Gist options
  • Save vanthao03596/0dd0df8081f7419e8f9fc269aec96d32 to your computer and use it in GitHub Desktop.
Save vanthao03596/0dd0df8081f7419e8f9fc269aec96d32 to your computer and use it in GitHub Desktop.
OOP
<?php

//=============================================================================
// DEFINE coefficient:
//=============================================================================

define('DEFAULT_WEIGHT_COEFFICIENT', 11);
define('DEFAULT_DIMENSION_COEFFICIENT', 11);
<?php

namespace App;

class Item
{
    protected float $weight;
    protected float $width;
    protected float $height;
    protected float $depth;
    protected float $amazonPrice;
    protected float $weightCoefficient = DEFAULT_WEIGHT_COEFFICIENT;
    protected float $dimensionCoefficient = DEFAULT_DIMENSION_COEFFICIENT;
    protected $feeByProductType;

    public function itemPrice()
    {
        return $this->amazonPrice + $this->shippingFee();
    }

    protected function shippingFee()
    {
        if ($this->feeByProductType) {
            return max($this->feeByWeight(), $this->feeByDimensions(), $this->feeByProductType);
        }
        return max($this->feeByWeight(), $this->feeByDimensions());
    }

    protected function feeByWeight()
    {
        return $this->weight * $this->weightCoefficient;
    }

    protected function feeByDimensions()
    {
        return $this->width * $this->height * $this->depth * $this->dimensionCoefficient;
    }

    public function withWeight($weight)
    {
        $this->weight = $weight;

        return $this;
    }

    public function withHeight($height)
    {
        $this->height = $height;

        return $this;
    }

    public function withWidth($width)
    {
        $this->width = $width;

        return $this;
    }

    public function withDepth($depth)
    {
        $this->depth = $depth;

        return $this;
    }

    public function withAmazonPrice($amazonPrice)
    {
        $this->amazonPrice = $amazonPrice;

        return $this;
    }

    public function withWeightCoefficient($weightCoefficient)
    {
        $this->weightCoefficient = $weightCoefficient;

        return $this;
    }

    public function withDimensionCoefficient($dimensionCoefficient)
    {
        $this->dimensionCoefficient = $dimensionCoefficient;

        return $this;
    }

    public static function make()
    {
        return new static();
    }
}

<?php

namespace App;

class Order
{
    /**
     * @var Item[]
     */
    protected $items = [];

    public function addItem(Item $item)
    {
        $this->items[] = $item;

        return $this;
    }

    public function calculateGrossPrice()
    {
        $total = 0;
        foreach ($this->items as $item) {
            $total += $item->itemPrice();
        }
        return $total;
    }

    public static function make()
    {
        return new static();
    }
}

$item1 = new Item(1, 1, 2, 3, 11);
$item2 = new Item(1, 1, 2, 3, 12);

// Order 1
$order = new Order();
$order->addItem($item1);
$order->addItem($item2);
$order->calculateGrossPrice();

// Order 2

Order::make()
    ->addItem($item1)
    ->addItem($item2)
    ->calculateGrossPrice();


// Order 3 fluent

Order::make()
    ->addItem(
        Item::make()
            ->withDepth(1)
            ->withHeight(2)
            ->withWeight(3)
            ->withWidth(3)
            ->withAmazonPrice(2)
    )
    ->addItem(
        Item::make()
            ->withDepth(1)
            ->withHeight(2)
            ->withWeight(3)
            ->withWidth(3)
            ->withAmazonPrice(3)
            ->withDimensionCoefficient(1)
            ->withWeightCoefficient(5)
    )
    ->calculateGrossPrice();
<?php

namespace Tests;

use App\Item;
use PHPUnit\Framework\TestCase;

class ItemTest extends TestCase
{
    protected Item $itemTest;

    protected function setUp(): void
    {
        parent::setUp();

        $this->itemTest = Item::make()
            ->withWidth(1)
            ->withHeight(2)
            ->withWeight(3)
            ->withDepth(4)
            ->withAmazonPrice(50);
    }

    public static function callMethod($obj, $name, array $args) {
        $class = new \ReflectionClass($obj);
        $method = $class->getMethod($name);
        $method->setAccessible(true);
        return $method->invokeArgs($obj, $args);
    }

    public function testWithAmazonPrice()
    {
        $item = Item::make();

        $item->withAmazonPrice(1);

        $this->assertEquals(1, $item->getAmazonPrice());
    }

    public function testWithWeight()
    {
        $item = Item::make();

        $item->withWeight(1);

        $this->assertEquals(1, $item->getWeight());
    }

    public function testWithDepth()
    {
        $item = Item::make();

        $item->withDepth(1);

        $this->assertEquals(1, $item->getDepth());
    }

    public function testWithWeightCoefficient()
    {
        $item = Item::make();

        $this->assertEquals(DEFAULT_WEIGHT_COEFFICIENT, $item->getWeightCoefficient());

        $item->withWeightCoefficient(1);

        $this->assertEquals(1, $item->getWeightCoefficient());
    }

    public function testWithDimensionCoefficient()
    {
        $item = Item::make();

        $this->assertEquals(DEFAULT_DIMENSION_COEFFICIENT, $item->getDimensionCoefficient());

        $item->withDimensionCoefficient(1);

        $this->assertEquals(1, $item->getDimensionCoefficient());
    }

    public function testWithHeight()
    {
        $item = Item::make();

        $item->withHeight(1);

        $this->assertEquals(1, $item->getHeight());
    }

    public function testWithWidth()
    {
        $item = Item::make();

        $item->withWidth(1);

        $this->assertEquals(1, $item->getWidth());
    }

    public function testMake()
    {
        $item = Item::make();

        $this->assertInstanceOf(Item::class, $item);
    }

    public function testFeeByDimensions()
    {
        $expected = $this->itemTest->getWidth() * $this->itemTest->getHeight() * $this->itemTest->getDepth() * $this->itemTest->getDimensionCoefficient();

        $feeByDimensions = static::callMethod(
            $this->itemTest,
            'feeByDimensions',
            []
        );

        $this->assertEquals($expected, $feeByDimensions);
    }

    public function testFeeByWeight()
    {
        $feeByWeight = static::callMethod(
            $this->itemTest,
            'feeByWeight',
            []
        );

        $expected = $this->itemTest->getWeight() * $this->itemTest->getWeightCoefficient();

        $this->assertEquals($expected, $feeByWeight);
    }

    public function testShippingFee()
    {
        $shippingFee = static::callMethod(
            $this->itemTest,
            'shippingFee',
            []
        );

        $this->assertEquals(88, $shippingFee);

        $this->itemTest->withFeeByProductType(100);

        $shippingFeeByProductType = static::callMethod(
            $this->itemTest,
            'shippingFee',
            []
        );

        $this->assertEquals(100, $shippingFeeByProductType);
    }

    public function testItemPrice()
    {
        $expected = 88 + $this->itemTest->getAmazonPrice();

        $this->assertEquals($expected, $this->itemTest->itemPrice());
    }


}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment