diff --git a/index.php b/index.php index 1ae4ad6..5870efe 100644 --- a/index.php +++ b/index.php @@ -5,12 +5,14 @@ use ProductList\Http\Request; use ProductList\Http\RequestHandler; use ProductList\Http\Route; -$request = new Request($_SERVER); +$request = new Request($_SERVER, $_GET, $_POST); $handler = new RequestHandler($request); $handler->registerRoutes([ - new Route('GET', 'products', ['ProductList\View\Product', 'list']), - new Route('DELETE', 'products', ['ProductList\View\Product', 'delete']), + new Route('GET', 'test', ['ProductList\View\Product', 'test']), + new Route('GET', 'product', ['ProductList\View\Product', 'get']), + new Route('DELETE', 'product', ['ProductList\View\Product', 'delete']), + new Route('POST', 'product', ['ProductList\View\Product', 'post']), new Route('GET', 'add-product', function() { readfile('static/add-product.html'); }), new Route('GET', '', function() { readfile('static/index.html'); }), ]); diff --git a/src/Http/Request.php b/src/Http/Request.php index 342e3fe..217a988 100644 --- a/src/Http/Request.php +++ b/src/Http/Request.php @@ -5,7 +5,8 @@ class Request { private $method; private $uri; - private $queryString; + private $queryParams; + private $formParams; public function getMethod() { @@ -17,19 +18,25 @@ class Request return $this->uri; } - public function getQueryString() + public function getQueryParams() { - return $this->queryString; + return $this->queryParams; } - public function __construct(array $params) + public function getFormParams() { - $uri_base = trim($params['REQUEST_URI'], '?'.$params['QUERY_STRING']); + return $this->formParams; + } + + public function __construct(array $params, array $queryParams, array $formParams) + { + $uri_base = strtok($params['REQUEST_URI'], '?'); $uri_base = trim(urldecode($uri_base), '/'); $this->uri = explode('/', $uri_base); $this->method = $params['REQUEST_METHOD']; - parse_str($params['QUERY_STRING'], $this->queryString); + $this->queryParams = $queryParams; + $this->formParams = $formParams; } } diff --git a/src/Http/RequestHandler.php b/src/Http/RequestHandler.php index 87b0244..87ebe1f 100644 --- a/src/Http/RequestHandler.php +++ b/src/Http/RequestHandler.php @@ -20,7 +20,12 @@ class RequestHandler { foreach ($this->routes as $route) { if ($route->matches($this->request)) { - $route->execute($this->request); + try { + $route->execute($this->request); + } catch (\Exception $e) { + http_response_code(500); + echo $e->getMessage(); + } return; } } diff --git a/src/View/Product.php b/src/View/Product.php index a2124dd..ed1b230 100644 --- a/src/View/Product.php +++ b/src/View/Product.php @@ -3,21 +3,25 @@ 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 +class Product extends View { - public static function list(Request $request) + public static function get(Request $request) { + header('Content-Type: application/json'); echo json_encode(ProductModel::selectAll()); } public static function delete(Request $request) { - $queryString = $request->getQueryString(); + $queryParams = $request->getQueryParams(); - if (array_key_exists('id', $queryString)) { - $ids = explode(',', $queryString['id']); + if (array_key_exists('id', $queryParams)) { + $ids = explode(',', $queryParams['id']); $ids = array_map('intval', $ids); foreach($ids as $id) { @@ -44,7 +48,70 @@ class Product } } - public static function add(Request $request) + public static function post(Request $request) { + $params= $request->getFormParams(); + $expected = [ + 'sku', + 'name', + 'price', + 'productType', + 'weight', + 'size', + 'height', + 'width', + 'length' + ]; + if (self::expectArgs($expected, $params)) { + $product = null; + $type = $params['productType']; + + 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; + } + + //try { + $product->insert(); + //} catch (\Exception $e) { + + //} + } + } + + public static function test(Request $request) + { + $params= $request->getQueryParams(); + if (self::expectArgs(['testarg'], $params)) { + echo var_dump($params); + } } } diff --git a/src/View/View.php b/src/View/View.php new file mode 100644 index 0000000..7a19ecb --- /dev/null +++ b/src/View/View.php @@ -0,0 +1,22 @@ + 0) { + http_response_code(400); + + $missing = join("', '", $missing); + + echo "Missing parameters '$missing'"; + + return false; + } + return true; + } +} diff --git a/static/add-product.html b/static/add-product.html index 5024d2e..9f5816a 100644 --- a/static/add-product.html +++ b/static/add-product.html @@ -1,16 +1,83 @@ - - - - Product Add - - - - + + + + Product Add + + + +
+
+
+ + + + + + + + + + + + + +
+
+
+ + +
+
+ + + +
+
+
+ + + diff --git a/static/add-product.js b/static/add-product.js new file mode 100644 index 0000000..94ca8d7 --- /dev/null +++ b/static/add-product.js @@ -0,0 +1,29 @@ +let currentTypeForm = document.getElementById($('#productType').val()); +currentTypeForm.querySelectorAll('input').forEach(input => input.required = true); +currentTypeForm.classList.remove('hidden'); + +$('#productType').on('change', e => { + const newTypeForm = document.getElementById(e.target.value); + + currentTypeForm.classList.add('hidden'); + newTypeForm.classList.remove('hidden'); + + currentTypeForm.querySelectorAll('input').forEach(input => input.required = false); + newTypeForm.querySelectorAll('input').forEach(input => input.required = true); + + currentTypeForm = newTypeForm; +}); + +$('#product_form').on('submit', e=> { + e.preventDefault(); + + $.ajax( + 'product', + { + method: 'POST', + data: $('#product_form').serializeArray(), + success: _ => window.location.href = '/', + error: jqXHR => alert(jqXHR.responseText), + } + ); +}); diff --git a/static/index.html b/static/index.html index 58e02f0..9d3b2d1 100644 --- a/static/index.html +++ b/static/index.html @@ -1,20 +1,21 @@ - - - - Product List - - - -
-
- - + + + + Product List + + + +
+
+ + + diff --git a/static/index.js b/static/index.js index 420a03b..70b7db8 100644 --- a/static/index.js +++ b/static/index.js @@ -1,45 +1,40 @@ -const productsList = document.getElementById('products'); - const loadItems = () => { - const xhttp = new XMLHttpRequest(); + $.ajax( + 'product', + { + success: data => { + const boxes = data.map(product => + `
+ +

+ ${product.sku}
+ ${product.name}
+ ${product.price} $
+ ${product.attribute} +

+
` + ); - xhttp.onload = function() { - const products = JSON.parse(this.responseText); - - const boxes = products.map(product => - `
- -

- ${product.sku}
- ${product.name}
- ${product.price} $
- ${product.attribute} -

-
` - ) - - productsList.innerHTML = boxes.join('\n'); - } - - xhttp.open('GET', 'products', true); - xhttp.send(); + $('#products').html(boxes.join('\n')); + }, + error: jqXHR => alert(jqXHR.responseText), + } + ) } + loadItems(); -const deleteSelected = () => { - const checkboxes = document.querySelectorAll('input[class="delete-checkbox"]:checked'); - let values = []; - checkboxes.forEach(checkbox => values.push(checkbox.value)); +$('#delete-product-btn').on('click', () => { + let values = []; + const checkboxes = document.querySelectorAll('input[class="delete-checkbox"]:checked'); + checkboxes.forEach(checkbox => values.push(checkbox.value)); - const xhttp = new XMLHttpRequest(); - - xhttp.onload = function() { - loadItems(); - } - - xhttp.open('DELETE', `products?id=${values.join(',')}`, true); - xhttp.send(); -} - -const deleteButton = document.getElementById('delete-product-btn'); -deleteButton.addEventListener('click', deleteSelected); + $.ajax( + `product?id=${values.join(',')}`, + { + method: 'DELETE', + success: loadItems, + error: jqXHR => alert(jqXHR.responseText), + } + ) +}); diff --git a/static/index.css b/static/stylesheet.css similarity index 81% rename from static/index.css rename to static/stylesheet.css index cfb7d85..94ddda0 100644 --- a/static/index.css +++ b/static/stylesheet.css @@ -14,16 +14,15 @@ body { margin: 0 1em; } -#buttons a { +.header-button { align-self: center; + margin: 0 2em; } #buttons button { font-family: cursive; padding: .5em 1em; font-size: 1rem; - margin: 0 2em; - align-self: center; background-color: white; border: 2px solid black; box-shadow: 2px 2px black; @@ -56,3 +55,23 @@ body { position: absolute; top: 0px; } + +.hidden { + display: none; +} + +#main { + margin: 2em; +} + +.form-section { + margin: 2em; +} + +td:nth-child(2) { + padding-left: 2em; +} + +#productType { + margin-left: 2em; +}