diff --git a/README.md b/README.md
index d16da13..88d179c 100644
--- a/README.md
+++ b/README.md
@@ -20,15 +20,16 @@ includes:
For more details, see the [software requirements specification](docs/SOFTWARE_SPECS.md).
-The code for the admin website is found in a separate repository.
+This repository contains the code for the client website and the API. The code for the admin website is found in a
+separate repository.
## Main features
- MVC pattern
- Semantic URL routing
- Email-based password recovery
-- Email notification on order
-- Testing with phpUnit
+- Email notification on checkout
+- Integration testing with phpUnit
- Mobile-responsive website
- Utilizes Webpack for efficient code bundling and compatibility with older browsers.
- Product review system with nested comments
@@ -36,6 +37,7 @@ The code for the admin website is found in a separate repository.
- Pagination
- SEO optimized
- REST API
+- API testing with Guzzler and phpUnit
## Documentation
@@ -58,3 +60,17 @@ Attribution-ShareAlike
- https://github.com/kevinisaac/php-mvc
4. The filesystem was inspired by https://github.com/php-pds/sklseleton
5. Additional references are included within the code itself.
+
+# Todo
+
+Add `X-TEST-ENV` to the header of your request and set its value to `testing` if you want to use the testing database.
+This is required when running tests for API. Without this key-value pair, the production database will be used.
+
+USE DOCKER PHP
+
+- read guzzle documentation. read base_uri
+- test database is being used
+- add variable to .env
+
+line 18 in Reviews API is redundant
+use correct namespace
\ No newline at end of file
diff --git a/src/controllers/Orders.php b/src/controllers/Orders.php
new file mode 100644
index 0000000..1cc1205
--- /dev/null
+++ b/src/controllers/Orders.php
@@ -0,0 +1,78 @@
+validateURL()) {
+ $url = Utility::getURL();
+ $parts = explode('/', $url);
+ // Check if the last part of the URL is a valid integer
+ $lastPart = end($parts);
+ if (is_numeric($lastPart)) {
+ return (int)$lastPart;
+ } else {
+ return null;
+ }
+ }
+ return null;
+ }
+
+
+ private function handleInvalidURL(): void
+ {
+ if (!$this->validateURL()) {
+ (new Error())->handlePageNotFoundError();
+ die();
+ }
+ }
+
+ public function index(): void
+ {
+ $this->handleInvalidURL();
+
+ $order_id = $this->getOrderIDFromURL();
+ if ($order_id === null) {
+ (new Error())->handlePageNotFoundError();
+ return;
+ }
+
+ $order = Order::getByID($order_id);
+ if (!$order) {
+ (new Error())->handlePageNotFoundError();
+ return;
+ }
+
+ $order_products = Order::getOrderProducts($order->getOrderID());
+
+ $this->view_data['order'] = $order;
+ $this->view_data['line_items'] = $order_products;
+
+ $this->view(
+ 'orders',
+ $this->view_data,
+ 'Order #' . $order_id,
+ enableIndexing: false
+ );
+ }
+}
diff --git a/src/controllers/Profile.php b/src/controllers/Profile.php
index f6c7892..e518acb 100644
--- a/src/controllers/Profile.php
+++ b/src/controllers/Profile.php
@@ -145,7 +145,7 @@ public function cancelOrder(): void
}
// Cancel the order
- $order->deleteOrder();
+ $order->cancelOrder();
}
private function handleProfileEditSubmission(): void
diff --git a/src/models/Order.php b/src/models/Order.php
index c20cd86..07377be 100644
--- a/src/models/Order.php
+++ b/src/models/Order.php
@@ -260,21 +260,15 @@ public static function getByID(int $order_id): ?Order
}
/**
- * Deletes the order and associated line items from the database.
+ * Cancels the order and associated line items from the database.
*/
- public function deleteOrder(): void
+ public function cancelOrder(): void
{
$conn = self::connect();
$conn->beginTransaction();
try {
- // Delete line items first
- $query = "DELETE FROM order_product WHERE order_id = :order_id";
- $stm = $conn->prepare($query);
- $stm->execute(['order_id' => $this->order_id]);
-
- // Delete the order itself
- $query = "DELETE FROM `order` WHERE order_id = :order_id";
+ $query = "UPDATE `order` SET status = 'cancelled' WHERE order_id = :order_id";
$stm = $conn->prepare($query);
$stm->execute(['order_id' => $this->order_id]);
diff --git a/src/models/OrderProduct.php b/src/models/OrderProduct.php
index 2c79e13..5c4d7be 100644
--- a/src/models/OrderProduct.php
+++ b/src/models/OrderProduct.php
@@ -87,29 +87,36 @@ public function validate(): array
return $errors;
}
- public static function getByID(int $order_id, int $product_id): ?OrderProduct
+ public static function getByID(int $order_id, int $product_id = null): ?OrderProduct
{
- $query = <<< EOL
- select * from order_product
- where order_id = :order_id and product_id = :product_id
- EOL;
+ $query = 'SELECT * FROM order_product WHERE order_id = :order_id';
+ $params = ['order_id' => $order_id];
- $result = self::query($query, ['order_id' => $order_id, 'product_id' => $product_id]);
- if (empty($result)) {
- return null;
- }
- $result = $result[0];
+ if ($product_id !== null) {
+ $query .= ' AND product_id = :product_id';
+ $params['product_id'] = $product_id;
+ }
- return new OrderProduct(
- product_id: $result->product_id,
- cup_size: $result->cup_size,
- milk_type: $result->milk_type,
- quantity: $result->quantity,
- unit_price: (float)$result->unit_price,
- order_id: $result->order_id,
- );
+ $result = self::query($query, $params);
+ if (empty($result)) {
+ return null;
}
+ // Assuming there's only one product for a given order if product_id is not provided
+ if ($product_id === null) {
+ $result = $result[0];
+ }
+
+ return new OrderProduct(
+ product_id: $result->product_id,
+ cup_size: $result->cup_size,
+ milk_type: $result->milk_type,
+ quantity: $result->quantity,
+ unit_price: (float)$result->unit_price,
+ order_id: $result->order_id,
+ );
+ }
+
public function getOrderID(): int
{
return $this->order_id;
diff --git a/src/views/Orders.php b/src/views/Orders.php
new file mode 100644
index 0000000..a51e937
--- /dev/null
+++ b/src/views/Orders.php
@@ -0,0 +1,48 @@
+
+
+
+ Order #= filter_var($order->getOrderID(), FILTER_SANITIZE_NUMBER_INT); ?>
+
+ Order Details
+ Order ID: = filter_var($order->getOrderID(), FILTER_SANITIZE_NUMBER_INT); ?>
+ Date: = htmlspecialchars($order->getCreatedDate()->format('Y-m-d H:i:s')) ?>
+ Status: = htmlspecialchars(ucfirst($order->getStatus()->value)) ?>
+ Total Price: $= htmlspecialchars(number_format($order->calculateTotalPrice(), 2)) ?>
+
+
+
+ Order Items
+
+
+ Product Name |
+ Quantity |
+ Milk Type |
+ Cup Size |
+ Unit Price |
+
+
+
+ = htmlspecialchars($item->getProductName()) ?> |
+ = filter_var($item->getQuantity(), FILTER_SANITIZE_NUMBER_INT) ?> |
+ = htmlspecialchars($item->getMilkType()) ?> |
+ = htmlspecialchars($item->getCupSize()) ?> |
+ $= (number_format($item->getUnitPrice(), 2)) ?> |
+
+
+
+
+
diff --git a/src/views/Profile.php b/src/views/Profile.php
index 09fd683..3987139 100644
--- a/src/views/Profile.php
+++ b/src/views/Profile.php
@@ -100,7 +100,7 @@
$totalPrice = htmlspecialchars(number_format($order->calculateTotalPrice(), 2));
// Determine button states
- $cancelDisabled = $order->getStatus()->value === 'completed' ? 'disabled' : '';
+ $cancelDisabled = ($order->getStatus()->value === 'completed' || $order->getStatus()->value === 'cancelled') ? 'disabled' : '';
echo <<< EOL
@@ -112,17 +112,22 @@
|
EOL;
}
+
?>
+
+
+
@@ -169,9 +174,10 @@
+
-
+
\ No newline at end of file