diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea415ee --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.phan/ diff --git a/index.php b/index.php index 5870efe..63cc209 100644 --- a/index.php +++ b/index.php @@ -1,5 +1,7 @@ weight = $weight; } @@ -24,8 +31,8 @@ class Book extends Product $row['name'], $row['price'], $row['weight'], - $row['product_id'], - $row['variation_id'] + $row['productId'], + $row['variationId'] ); } @@ -42,8 +49,15 @@ class Book extends Product private static function getSelectAllQuery() : string { - return 'SELECT '.PRODUCT.'.*, '.BOOK.'.id as variation_id, size - FROM '.PRODUCT.' LEFT JOIN '.BOOK.' ON '.PRODUCT.'.id = '.BOOK.'.product_id'; + return ' + SELECT + '.PRODUCT.'.*, + '.BOOK.'.id as variationId, + weight + FROM + '.PRODUCT.' + LEFT JOIN + '.BOOK.' ON '.PRODUCT.'.id = '.BOOK.'.product_id'; } public function insert($conn = null) : int @@ -81,7 +95,7 @@ class Book extends Product $stmt->bind_param('i', $variationId); if ($stmt->execute() === false) { - throw new \Exception("Unable to delete product with id '$id'"); + throw new \Exception("Unable to delete product with id '$variationId'"); } parent::delete($conn); diff --git a/src/Model/DVD.php b/src/Model/DVD.php index 6e05e39..a8cb60c 100644 --- a/src/Model/DVD.php +++ b/src/Model/DVD.php @@ -1,6 +1,8 @@ size = $size; } @@ -24,8 +31,8 @@ class DVD extends Product $row['name'], $row['price'], $row['size'], - $row['product_id'], - $row['variation_id'] + $row['productId'], + $row['variationId'] ); } @@ -42,8 +49,15 @@ class DVD extends Product private static function getSelectAllQuery() : string { - return 'SELECT '.PRODUCT.'.*, '.DVD.'.id as variation_id, size - FROM '.PRODUCT.' LEFT JOIN '.DVD.' ON '.PRODUCT.'.id = '.DVD.'.product_id'; + return ' + SELECT + '.PRODUCT.'.*, + '.DVD.'.id as variationId, + size + FROM + '.PRODUCT.' + LEFT JOIN + '.DVD.' ON '.PRODUCT.'.id = '.DVD.'.product_id'; } public function insert($conn = null) : int @@ -66,7 +80,7 @@ class DVD extends Product $this->setVariationId($conn->insert_id); return $conn->insert_id; } else { - throw new Exception("Unable to insert object"); + throw new \Exception("Unable to insert object"); } } @@ -81,7 +95,7 @@ class DVD extends Product $stmt->bind_param('i', $variationId); if ($stmt->execute() === false) { - throw new \Exception("Unable to delete product with id '$id'"); + throw new \Exception("Unable to delete product with id '$variationId'"); } parent::delete($conn); diff --git a/src/Model/Furniture.php b/src/Model/Furniture.php index 91d558d..51902b9 100644 --- a/src/Model/Furniture.php +++ b/src/Model/Furniture.php @@ -1,6 +1,8 @@ height = $height; $this->width = $width; $this->length = $length; @@ -32,8 +47,8 @@ class Furniture extends Product $row['height'], $row['width'], $row['length'], - $row['product_id'], - $row['variation_id'] + $row['productId'], + $row['variationId'] ); } @@ -62,9 +77,17 @@ class Furniture extends Product private static function getSelectAllQuery() : string { - return 'SELECT '.PRODUCT.'.*, '.FURNITURE.'.id as variation_id, size - FROM '.PRODUCT.' - LEFT JOIN '.FURNITURE.' ON '.PRODUCT.'.id = '.FURNITURE.'.product_id'; + return ' + SELECT + '.PRODUCT.'.*, + '.FURNITURE.'.id as variationId, + height, + width, + length + FROM + '.PRODUCT.' + LEFT JOIN '.FURNITURE.' ON + '.PRODUCT.'.id = '.FURNITURE.'.product_id'; } public function insert($conn = null) : int @@ -107,7 +130,7 @@ class Furniture extends Product $stmt->bind_param('i', $variationId); if ($stmt->execute() === false) { - throw new \Exception("Unable to delete product with id '$id'"); + throw new \Exception("Unable to delete product with id '$variationId'"); } parent::delete($conn); diff --git a/src/Model/Product.php b/src/Model/Product.php index bf9f427..ba05bc6 100644 --- a/src/Model/Product.php +++ b/src/Model/Product.php @@ -2,33 +2,49 @@ namespace ProductList\Model; use ProductList\Exception\NotFoundException; +use ProductList\Exception\InvalidFieldException; +use ProductList\Exception\DuplicateException; abstract class Product implements \JsonSerializable { use Model; private $variationId; - private $SKU; + private $sku; private $name; private $price; private $productId; public function __construct( - $SKU, + $sku, $name, $price, $productId = null, $variationId = null ) { + if (empty($sku)) { + throw new InvalidFieldException('SKU'); + } + + if (empty($name)) { + throw new InvalidFieldException('Name'); + } + + if (empty($price) || !is_numeric($price)) { + throw new InvalidFieldException('Price'); + } + $this->productId = $productId; $this->variationId = $variationId; - $this->SKU = $SKU; + + + $this->sku = $sku; $this->name = $name; $this->price = $price; } public function getSKU() { - return $this->SKU; + return $this->sku; } public function getName() @@ -74,7 +90,7 @@ abstract class Product implements \JsonSerializable $stmt->bind_param('i', $productId); if ($stmt->execute() === false) { - throw new \Exception("Unable to delete product with id '$id'"); + throw new \Exception("Unable to delete product with id '$productId'"); } } @@ -102,26 +118,45 @@ abstract class Product implements \JsonSerializable public static function fromRow($row) : self { - if ($row['size'] !== null) { - return DVD::fromRow($row); - } elseif ($row['weight'] !== null) { - return Book::fromRow($row); - } elseif ($row['height'] !== null) { - return Furniture::fromRow($row); - } else { - throw new \Exception("Product without a type"); + switch ($row['productType']) { + case 'dvd': + return DVD::fromRow($row); + case 'book': + return Book::fromRow($row); + case 'furniture': + return Furniture::fromRow($row); + default: + throw new \Exception("Product without a type"); } } private static function getSelectAllQuery() : string { - return 'SELECT '.PRODUCT.'.id as product_id, - COALESCE('.DVD.'.id, '.BOOK.'.id, '.FURNITURE.'.id) as variation_id, - name, sku, price, size, weight, width, height, length - FROM '.PRODUCT.' - LEFT JOIN '.DVD.' ON '.PRODUCT.'.id = '.DVD.'.product_id - LEFT JOIN '.BOOK.' ON '.PRODUCT.'.id = '.BOOK.'.product_id - LEFT JOIN '.FURNITURE.' ON '.PRODUCT.'.id = '.FURNITURE.'.product_id'; + return ' + SELECT + '.PRODUCT.'.id as productId, + name, + sku, + price, + size, + weight, + width, + height, + length, + COALESCE('.DVD.'.id, '.BOOK.'.id, '.FURNITURE.'.id) as variationId, + CASE + WHEN '.DVD.'.id IS NOT NULL THEN "dvd" + WHEN '.BOOK.'.id IS NOT NULL THEN "book" + WHEN '.FURNITURE.'.id IS NOT NULL THEN "furniture" + END as productType + FROM + '.PRODUCT.' + LEFT JOIN '.DVD.' ON + '.PRODUCT.'.id = '.DVD.'.product_id + LEFT JOIN '.BOOK.' ON + '.PRODUCT.'.id = '.BOOK.'.product_id + LEFT JOIN '.FURNITURE.' ON + '.PRODUCT.'.id = '.FURNITURE.'.product_id'; } public function insert($conn = null) : int @@ -140,11 +175,19 @@ abstract class Product implements \JsonSerializable ); $stmt->bind_param('ssd', $SKU, $name, $price); - if ($stmt->execute() === true) { - $this->setProductId($conn->insert_id); - return $conn->insert_id; - } else { - throw new \Exception("Unable to insert object"); + try { + if ($stmt->execute() === true) { + $this->setProductId($conn->insert_id); + return $conn->insert_id; + } else { + throw new \Exception("Unable to insert object"); + } + } catch (\mysqli_sql_exception $e) { + if ($e->getCode() === 1062) { + throw new DuplicateException('The provided SKU is already registered.'); + } else { + throw $e; + } } } diff --git a/src/View/Product.php b/src/View/Product.php index ed1b230..0122f74 100644 --- a/src/View/Product.php +++ b/src/View/Product.php @@ -3,9 +3,6 @@ namespace ProductList\View; use ProductList\Http\Request; use ProductList\Model\Product as ProductModel; -use ProductList\Model\DVD; -use ProductList\Model\Furniture; -use ProductList\Model\Book; use ProductList\Exception\NotFoundException; class Product extends View @@ -38,7 +35,7 @@ class Product extends View } catch (NotFoundException $e) { http_response_code(404); - echo $e->getMessage(); + echo "The selected(s) object(s) is(are) not available anymore."; return; } } @@ -63,55 +60,12 @@ class Product extends View 'length' ]; if (self::expectArgs($expected, $params)) { - $product = null; - $type = $params['productType']; + $params['productId'] = null; + $params['variationId'] = null; - switch($type) { - case 'dvd': - $product = new DVD( - $params['sku'], - $params['name'], - $params['price'], - $params['size'], - ); - break; - case 'furniture': - $product = new Furniture( - $params['sku'], - $params['name'], - $params['price'], - $params['height'], - $params['width'], - $params['length'], - ); - break; - case 'book': - $product = new Book( - $params['sku'], - $params['name'], - $params['price'], - $params['weight'], - ); - break; - default: - http_response_code(400); - echo "Invalid 'productType' value '$type'"; - return; - } + $product = ProductModel::fromRow($params); - //try { - $product->insert(); - //} catch (\Exception $e) { - - //} - } - } - - public static function test(Request $request) - { - $params= $request->getQueryParams(); - if (self::expectArgs(['testarg'], $params)) { - echo var_dump($params); + $product->insert(); } } } diff --git a/static/index.js b/static/index.js index 70b7db8..faa1eb0 100644 --- a/static/index.js +++ b/static/index.js @@ -29,12 +29,16 @@ $('#delete-product-btn').on('click', () => { const checkboxes = document.querySelectorAll('input[class="delete-checkbox"]:checked'); checkboxes.forEach(checkbox => values.push(checkbox.value)); - $.ajax( - `product?id=${values.join(',')}`, - { - method: 'DELETE', - success: loadItems, - error: jqXHR => alert(jqXHR.responseText), - } - ) + if(values.length) { + $.ajax( + `product?id=${values.join(',')}`, + { + method: 'DELETE', + success: loadItems, + error: jqXHR => alert(jqXHR.responseText), + } + ) + } else { + alert('Please select a product.'); + } });