Validate forms

This commit is contained in:
Augusto Gunsch 2022-07-29 11:32:45 +02:00
parent 16b4d686e3
commit 6ce3d64649
No known key found for this signature in database
GPG Key ID: F7EEFE29825C72DC
10 changed files with 173 additions and 103 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.phan/

View File

@ -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;

View File

@ -0,0 +1,4 @@
<?php
namespace ProductList\Exception;
class DuplicateException extends \Exception {}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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']) {
return DVD::fromRow($row); case 'dvd':
} elseif ($row['weight'] !== null) { return DVD::fromRow($row);
return Book::fromRow($row); case 'book':
} elseif ($row['height'] !== null) { return Book::fromRow($row);
return Furniture::fromRow($row); case 'furniture':
} else { return Furniture::fromRow($row);
throw new \Exception("Product without a type"); default:
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,11 +175,19 @@ abstract class Product implements \JsonSerializable
); );
$stmt->bind_param('ssd', $SKU, $name, $price); $stmt->bind_param('ssd', $SKU, $name, $price);
if ($stmt->execute() === true) { try {
$this->setProductId($conn->insert_id); if ($stmt->execute() === true) {
return $conn->insert_id; $this->setProductId($conn->insert_id);
} else { return $conn->insert_id;
throw new \Exception("Unable to insert object"); } 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;
}
} }
} }

View File

@ -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);
} }
} }
} }

View File

@ -29,12 +29,16 @@ $('#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));
$.ajax( if(values.length) {
`product?id=${values.join(',')}`, $.ajax(
{ `product?id=${values.join(',')}`,
method: 'DELETE', {
success: loadItems, method: 'DELETE',
error: jqXHR => alert(jqXHR.responseText), success: loadItems,
} error: jqXHR => alert(jqXHR.responseText),
) }
)
} else {
alert('Please select a product.');
}
}); });