Validate forms
This commit is contained in:
parent
16b4d686e3
commit
6ce3d64649
|
@ -0,0 +1 @@
|
||||||
|
.phan/
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
require 'autoload.php';
|
require 'autoload.php';
|
||||||
|
ini_set('display_errors', true);
|
||||||
|
ini_set('error_log', '/tmp/php.log');
|
||||||
|
|
||||||
use ProductList\Http\Request;
|
use ProductList\Http\Request;
|
||||||
use ProductList\Http\RequestHandler;
|
use ProductList\Http\RequestHandler;
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
namespace ProductList\Exception;
|
||||||
|
|
||||||
|
class DuplicateException extends \Exception {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
namespace ProductList\Exception;
|
||||||
|
|
||||||
|
class InvalidFieldException extends \Exception
|
||||||
|
{
|
||||||
|
public function __construct($field, $code = 0, Throwable $previous = null)
|
||||||
|
{
|
||||||
|
http_response_code(400);
|
||||||
|
parent::__construct("The field '$field' is invalid.", $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace ProductList\Model;
|
namespace ProductList\Model;
|
||||||
|
|
||||||
|
use ProductList\Exception\InvalidFieldException;
|
||||||
|
|
||||||
class Book extends Product
|
class Book extends Product
|
||||||
{
|
{
|
||||||
private $weight;
|
private $weight;
|
||||||
|
@ -14,6 +16,11 @@ class Book extends Product
|
||||||
$variationId = null
|
$variationId = null
|
||||||
) {
|
) {
|
||||||
parent::__construct($sku, $name, $price, $productId, $variationId);
|
parent::__construct($sku, $name, $price, $productId, $variationId);
|
||||||
|
|
||||||
|
if (empty($weight) || !is_numeric($weight)) {
|
||||||
|
throw new InvalidFieldException('Weight');
|
||||||
|
}
|
||||||
|
|
||||||
$this->weight = $weight;
|
$this->weight = $weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +31,8 @@ class Book extends Product
|
||||||
$row['name'],
|
$row['name'],
|
||||||
$row['price'],
|
$row['price'],
|
||||||
$row['weight'],
|
$row['weight'],
|
||||||
$row['product_id'],
|
$row['productId'],
|
||||||
$row['variation_id']
|
$row['variationId']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +49,15 @@ class Book extends Product
|
||||||
|
|
||||||
private static function getSelectAllQuery() : string
|
private static function getSelectAllQuery() : string
|
||||||
{
|
{
|
||||||
return 'SELECT '.PRODUCT.'.*, '.BOOK.'.id as variation_id, size
|
return '
|
||||||
FROM '.PRODUCT.' LEFT JOIN '.BOOK.' ON '.PRODUCT.'.id = '.BOOK.'.product_id';
|
SELECT
|
||||||
|
'.PRODUCT.'.*,
|
||||||
|
'.BOOK.'.id as variationId,
|
||||||
|
weight
|
||||||
|
FROM
|
||||||
|
'.PRODUCT.'
|
||||||
|
LEFT JOIN
|
||||||
|
'.BOOK.' ON '.PRODUCT.'.id = '.BOOK.'.product_id';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function insert($conn = null) : int
|
public function insert($conn = null) : int
|
||||||
|
@ -81,7 +95,7 @@ class Book extends Product
|
||||||
$stmt->bind_param('i', $variationId);
|
$stmt->bind_param('i', $variationId);
|
||||||
|
|
||||||
if ($stmt->execute() === false) {
|
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);
|
parent::delete($conn);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace ProductList\Model;
|
namespace ProductList\Model;
|
||||||
|
|
||||||
|
use ProductList\Exception\InvalidFieldException;
|
||||||
|
|
||||||
class DVD extends Product
|
class DVD extends Product
|
||||||
{
|
{
|
||||||
private $size;
|
private $size;
|
||||||
|
@ -14,6 +16,11 @@ class DVD extends Product
|
||||||
$variationId = null
|
$variationId = null
|
||||||
) {
|
) {
|
||||||
parent::__construct($sku, $name, $price, $productId, $variationId);
|
parent::__construct($sku, $name, $price, $productId, $variationId);
|
||||||
|
|
||||||
|
if (empty($size) || !is_numeric($size)) {
|
||||||
|
throw new InvalidFieldException('Size');
|
||||||
|
}
|
||||||
|
|
||||||
$this->size = $size;
|
$this->size = $size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +31,8 @@ class DVD extends Product
|
||||||
$row['name'],
|
$row['name'],
|
||||||
$row['price'],
|
$row['price'],
|
||||||
$row['size'],
|
$row['size'],
|
||||||
$row['product_id'],
|
$row['productId'],
|
||||||
$row['variation_id']
|
$row['variationId']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +49,15 @@ class DVD extends Product
|
||||||
|
|
||||||
private static function getSelectAllQuery() : string
|
private static function getSelectAllQuery() : string
|
||||||
{
|
{
|
||||||
return 'SELECT '.PRODUCT.'.*, '.DVD.'.id as variation_id, size
|
return '
|
||||||
FROM '.PRODUCT.' LEFT JOIN '.DVD.' ON '.PRODUCT.'.id = '.DVD.'.product_id';
|
SELECT
|
||||||
|
'.PRODUCT.'.*,
|
||||||
|
'.DVD.'.id as variationId,
|
||||||
|
size
|
||||||
|
FROM
|
||||||
|
'.PRODUCT.'
|
||||||
|
LEFT JOIN
|
||||||
|
'.DVD.' ON '.PRODUCT.'.id = '.DVD.'.product_id';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function insert($conn = null) : int
|
public function insert($conn = null) : int
|
||||||
|
@ -66,7 +80,7 @@ class DVD extends Product
|
||||||
$this->setVariationId($conn->insert_id);
|
$this->setVariationId($conn->insert_id);
|
||||||
return $conn->insert_id;
|
return $conn->insert_id;
|
||||||
} else {
|
} 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);
|
$stmt->bind_param('i', $variationId);
|
||||||
|
|
||||||
if ($stmt->execute() === false) {
|
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);
|
parent::delete($conn);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace ProductList\Model;
|
namespace ProductList\Model;
|
||||||
|
|
||||||
|
use ProductList\Exception\InvalidFieldException;
|
||||||
|
|
||||||
class Furniture extends Product
|
class Furniture extends Product
|
||||||
{
|
{
|
||||||
private $height;
|
private $height;
|
||||||
|
@ -8,7 +10,7 @@ class Furniture extends Product
|
||||||
private $length;
|
private $length;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
$SKU,
|
$sku,
|
||||||
$name,
|
$name,
|
||||||
$price,
|
$price,
|
||||||
$height,
|
$height,
|
||||||
|
@ -17,7 +19,20 @@ class Furniture extends Product
|
||||||
$productId = null,
|
$productId = null,
|
||||||
$variationId = null
|
$variationId = null
|
||||||
) {
|
) {
|
||||||
parent::__construct($SKU, $name, $price, $productId, $variationId);
|
parent::__construct($sku, $name, $price, $productId, $variationId);
|
||||||
|
|
||||||
|
if (empty($height) || !is_numeric($height)) {
|
||||||
|
throw new InvalidFieldException('Height');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($width) || !is_numeric($width)) {
|
||||||
|
throw new InvalidFieldException('Width');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($length) || !is_numeric($length)) {
|
||||||
|
throw new InvalidFieldException('Length');
|
||||||
|
}
|
||||||
|
|
||||||
$this->height = $height;
|
$this->height = $height;
|
||||||
$this->width = $width;
|
$this->width = $width;
|
||||||
$this->length = $length;
|
$this->length = $length;
|
||||||
|
@ -32,8 +47,8 @@ class Furniture extends Product
|
||||||
$row['height'],
|
$row['height'],
|
||||||
$row['width'],
|
$row['width'],
|
||||||
$row['length'],
|
$row['length'],
|
||||||
$row['product_id'],
|
$row['productId'],
|
||||||
$row['variation_id']
|
$row['variationId']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,9 +77,17 @@ class Furniture extends Product
|
||||||
|
|
||||||
private static function getSelectAllQuery() : string
|
private static function getSelectAllQuery() : string
|
||||||
{
|
{
|
||||||
return 'SELECT '.PRODUCT.'.*, '.FURNITURE.'.id as variation_id, size
|
return '
|
||||||
FROM '.PRODUCT.'
|
SELECT
|
||||||
LEFT JOIN '.FURNITURE.' ON '.PRODUCT.'.id = '.FURNITURE.'.product_id';
|
'.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
|
public function insert($conn = null) : int
|
||||||
|
@ -107,7 +130,7 @@ class Furniture extends Product
|
||||||
$stmt->bind_param('i', $variationId);
|
$stmt->bind_param('i', $variationId);
|
||||||
|
|
||||||
if ($stmt->execute() === false) {
|
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);
|
parent::delete($conn);
|
||||||
|
|
|
@ -2,33 +2,49 @@
|
||||||
namespace ProductList\Model;
|
namespace ProductList\Model;
|
||||||
|
|
||||||
use ProductList\Exception\NotFoundException;
|
use ProductList\Exception\NotFoundException;
|
||||||
|
use ProductList\Exception\InvalidFieldException;
|
||||||
|
use ProductList\Exception\DuplicateException;
|
||||||
|
|
||||||
abstract class Product implements \JsonSerializable
|
abstract class Product implements \JsonSerializable
|
||||||
{
|
{
|
||||||
use Model;
|
use Model;
|
||||||
private $variationId;
|
private $variationId;
|
||||||
private $SKU;
|
private $sku;
|
||||||
private $name;
|
private $name;
|
||||||
private $price;
|
private $price;
|
||||||
private $productId;
|
private $productId;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
$SKU,
|
$sku,
|
||||||
$name,
|
$name,
|
||||||
$price,
|
$price,
|
||||||
$productId = null,
|
$productId = null,
|
||||||
$variationId = 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->productId = $productId;
|
||||||
$this->variationId = $variationId;
|
$this->variationId = $variationId;
|
||||||
$this->SKU = $SKU;
|
|
||||||
|
|
||||||
|
$this->sku = $sku;
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->price = $price;
|
$this->price = $price;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSKU()
|
public function getSKU()
|
||||||
{
|
{
|
||||||
return $this->SKU;
|
return $this->sku;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
|
@ -74,7 +90,7 @@ abstract class Product implements \JsonSerializable
|
||||||
$stmt->bind_param('i', $productId);
|
$stmt->bind_param('i', $productId);
|
||||||
|
|
||||||
if ($stmt->execute() === false) {
|
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
|
public static function fromRow($row) : self
|
||||||
{
|
{
|
||||||
if ($row['size'] !== null) {
|
switch ($row['productType']) {
|
||||||
|
case 'dvd':
|
||||||
return DVD::fromRow($row);
|
return DVD::fromRow($row);
|
||||||
} elseif ($row['weight'] !== null) {
|
case 'book':
|
||||||
return Book::fromRow($row);
|
return Book::fromRow($row);
|
||||||
} elseif ($row['height'] !== null) {
|
case 'furniture':
|
||||||
return Furniture::fromRow($row);
|
return Furniture::fromRow($row);
|
||||||
} else {
|
default:
|
||||||
throw new \Exception("Product without a type");
|
throw new \Exception("Product without a type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getSelectAllQuery() : string
|
private static function getSelectAllQuery() : string
|
||||||
{
|
{
|
||||||
return 'SELECT '.PRODUCT.'.id as product_id,
|
return '
|
||||||
COALESCE('.DVD.'.id, '.BOOK.'.id, '.FURNITURE.'.id) as variation_id,
|
SELECT
|
||||||
name, sku, price, size, weight, width, height, length
|
'.PRODUCT.'.id as productId,
|
||||||
FROM '.PRODUCT.'
|
name,
|
||||||
LEFT JOIN '.DVD.' ON '.PRODUCT.'.id = '.DVD.'.product_id
|
sku,
|
||||||
LEFT JOIN '.BOOK.' ON '.PRODUCT.'.id = '.BOOK.'.product_id
|
price,
|
||||||
LEFT JOIN '.FURNITURE.' ON '.PRODUCT.'.id = '.FURNITURE.'.product_id';
|
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
|
public function insert($conn = null) : int
|
||||||
|
@ -140,12 +175,20 @@ abstract class Product implements \JsonSerializable
|
||||||
);
|
);
|
||||||
$stmt->bind_param('ssd', $SKU, $name, $price);
|
$stmt->bind_param('ssd', $SKU, $name, $price);
|
||||||
|
|
||||||
|
try {
|
||||||
if ($stmt->execute() === true) {
|
if ($stmt->execute() === true) {
|
||||||
$this->setProductId($conn->insert_id);
|
$this->setProductId($conn->insert_id);
|
||||||
return $conn->insert_id;
|
return $conn->insert_id;
|
||||||
} else {
|
} else {
|
||||||
throw new \Exception("Unable to insert object");
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jsonSerialize() : mixed
|
public function jsonSerialize() : mixed
|
||||||
|
|
|
@ -3,9 +3,6 @@ namespace ProductList\View;
|
||||||
|
|
||||||
use ProductList\Http\Request;
|
use ProductList\Http\Request;
|
||||||
use ProductList\Model\Product as ProductModel;
|
use ProductList\Model\Product as ProductModel;
|
||||||
use ProductList\Model\DVD;
|
|
||||||
use ProductList\Model\Furniture;
|
|
||||||
use ProductList\Model\Book;
|
|
||||||
use ProductList\Exception\NotFoundException;
|
use ProductList\Exception\NotFoundException;
|
||||||
|
|
||||||
class Product extends View
|
class Product extends View
|
||||||
|
@ -38,7 +35,7 @@ class Product extends View
|
||||||
|
|
||||||
} catch (NotFoundException $e) {
|
} catch (NotFoundException $e) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
echo $e->getMessage();
|
echo "The selected(s) object(s) is(are) not available anymore.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,55 +60,12 @@ class Product extends View
|
||||||
'length'
|
'length'
|
||||||
];
|
];
|
||||||
if (self::expectArgs($expected, $params)) {
|
if (self::expectArgs($expected, $params)) {
|
||||||
$product = null;
|
$params['productId'] = null;
|
||||||
$type = $params['productType'];
|
$params['variationId'] = null;
|
||||||
|
|
||||||
switch($type) {
|
$product = ProductModel::fromRow($params);
|
||||||
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();
|
$product->insert();
|
||||||
//} catch (\Exception $e) {
|
|
||||||
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function test(Request $request)
|
|
||||||
{
|
|
||||||
$params= $request->getQueryParams();
|
|
||||||
if (self::expectArgs(['testarg'], $params)) {
|
|
||||||
echo var_dump($params);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ $('#delete-product-btn').on('click', () => {
|
||||||
const checkboxes = document.querySelectorAll('input[class="delete-checkbox"]:checked');
|
const checkboxes = document.querySelectorAll('input[class="delete-checkbox"]:checked');
|
||||||
checkboxes.forEach(checkbox => values.push(checkbox.value));
|
checkboxes.forEach(checkbox => values.push(checkbox.value));
|
||||||
|
|
||||||
|
if(values.length) {
|
||||||
$.ajax(
|
$.ajax(
|
||||||
`product?id=${values.join(',')}`,
|
`product?id=${values.join(',')}`,
|
||||||
{
|
{
|
||||||
|
@ -37,4 +38,7 @@ $('#delete-product-btn').on('click', () => {
|
||||||
error: jqXHR => alert(jqXHR.responseText),
|
error: jqXHR => alert(jqXHR.responseText),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
alert('Please select a product.');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue