2121final class Cart implements Countable, CartInterface
2222{
2323 /**
24- * @var ProductInterface[]
24+ * @var array<string, ItemDtoInterface[]>
2525 */
2626 private array $ items = [];
2727
28- /**
29- * @var array<string, int>
30- */
31- private array $ quantity = [];
32-
3328 private array $ meta = [];
3429
3530 public function __construct (
@@ -51,14 +46,16 @@ public function withMeta(array $meta): self
5146 return $ self ;
5247 }
5348
54- public function withItem (ProductInterface $ product , int $ quantity = 1 ): self
49+ public function withItem (ProductInterface $ product , int $ quantity = 1 , int | string | null $ price = null ): self
5550 {
5651 $ self = clone $ this ;
5752
5853 $ productId = $ self ->productId ($ product );
54+ if (!isset ($ self ->items [$ productId ])) {
55+ $ self ->items [$ productId ] = [];
56+ }
5957
60- $ self ->quantity [$ productId ] = $ self ->getQuantity ($ product ) + $ quantity ;
61- $ self ->items [$ productId ] = $ product ;
58+ $ self ->items [$ productId ][] = new ItemDto ($ product , $ quantity , $ price );
6259
6360 return $ self ;
6461 }
@@ -80,29 +77,28 @@ public function getItems(): array
8077 {
8178 $ items = [];
8279 foreach ($ this ->items as $ item ) {
83- $ count = $ this ->getQuantity ($ item );
84- for ($ i = 0 ; $ i < $ count ; ++$ i ) {
85- $ items [] = $ item ;
80+ foreach ($ item as $ datum ) {
81+ $ items [] = $ datum ->items ();
8682 }
8783 }
8884
89- return $ items ;
90- }
91-
92- /**
93- * @return ProductInterface[]
94- */
95- public function getUniqueItems (): array
96- {
97- return $ this ->items ;
85+ return array_merge (...$ items );
9886 }
9987
10088 public function getTotal (Customer $ customer ): string
10189 {
10290 $ result = 0 ;
103- foreach ($ this ->items as $ item ) {
104- $ price = $ this ->math ->mul ($ this ->getQuantity ($ item ), $ item ->getAmountProduct ($ customer ));
105- $ result = $ this ->math ->add ($ result , $ price );
91+ $ prices = [];
92+ foreach ($ this ->items as $ productId => $ _items ) {
93+ foreach ($ _items as $ item ) {
94+ $ product = $ item ->product ();
95+ $ prices [$ productId ] = $ item ->getPrice ()
96+ ?? $ prices [$ productId ]
97+ ?? $ item ->product ()->getAmountProduct ($ customer );
98+
99+ $ price = $ this ->math ->mul ($ this ->getQuantity ($ product ), $ prices [$ productId ]);
100+ $ result = $ this ->math ->add ($ result , $ price );
101+ }
106102 }
107103
108104 return (string ) $ result ;
@@ -115,24 +111,26 @@ public function count(): int
115111
116112 public function getQuantity (ProductInterface $ product ): int
117113 {
118- return $ this ->quantity [$ this ->productId ($ product )] ?? 0 ;
114+ /** @var ItemDtoInterface[] $items */
115+ $ quantity = 0 ;
116+ $ items = $ this ->items [$ this ->productId ($ product )] ?? [];
117+ foreach ($ items as $ item ) {
118+ $ quantity += $ item ->count ();
119+ }
120+
121+ return $ quantity ;
119122 }
120123
121124 /**
122125 * @throws CartEmptyException
123126 */
124127 public function getBasketDto (): BasketDtoInterface
125128 {
126- $ items = array_map (
127- fn (ProductInterface $ product ): ItemDtoInterface => new ItemDto ($ product , $ this ->getQuantity ($ product )),
128- $ this ->getUniqueItems ()
129- );
130-
131- if ($ items === []) {
129+ if ($ this ->items === []) {
132130 throw new CartEmptyException ('Cart is empty ' , ExceptionInterface::CART_EMPTY );
133131 }
134132
135- return new BasketDto ($ items , $ this ->getMeta ());
133+ return new BasketDto (array_merge (... array_values ( $ this -> items )) , $ this ->getMeta ());
136134 }
137135
138136 private function productId (ProductInterface $ product ): string
0 commit comments