/** * Validate a bundle against an order, and trigger an exception if the bundle is not valid. * Bundles will be marked as invalid if: * - The order has a discount code assigned to it and the bundle is set to not work in conjunction with * discount codes * - An order does not have the minimum number of items needed for the bundle * * @param Bundle $bundle * @param Order\Order $order * @throws \LogicException Throws exception if product row ID not set in count arrays * * @return bool */ public function validate(Bundle $bundle, Order\Order $order) { if (!$bundle->inTimeRange()) { $this->_error('ms.discount.bundle.validation.time', ['%name%' => $bundle->getName()]); } list($expectedCounts, $currentCounts) = $this->_getCounts($bundle); $this->validateAllowsCodes($bundle, $order); foreach ($order->items as $item) { foreach ($bundle->getProductRows() as $row) { if (!array_key_exists($row->getID(), $expectedCounts) || !array_key_exists($row->getID(), $currentCounts)) { throw new \LogicException('Expected counts arrays to have a value with a key of `' . $row->getID() . '` but it doesn\'t'); } // Do not increment current counts beyond the expected count if ($currentCounts[$row->getID()] >= $expectedCounts[$row->getID()]) { continue; } // If the item fits the requirements of the product row, increment the current count if ($this->itemIsApplicable($item, $row)) { $currentCounts[$row->getID()]++; $item->id = $item->id ?: uniqid(); $this->_alreadyInBundle[] = $item->id; break; } } } foreach ($expectedCounts as $key => $value) { if ($currentCounts[$key] != $value) { $this->_error('ms.discount.bundle.validation.items', ['%name%' => $bundle->getName()]); } } return true; }