Skip to content

Commit

Permalink
Merge pull request #233 from Divyeshhhh/json-schema-validation-in-rev…
Browse files Browse the repository at this point in the history
…iews

use json schema validation in reviews api controller
  • Loading branch information
creme332 authored Jul 28, 2024
2 parents e2adcd4 + 3dcf91f commit ef41d66
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 121 deletions.
39 changes: 0 additions & 39 deletions resources/schemas/Review.json

This file was deleted.

39 changes: 39 additions & 0 deletions resources/schemas/common/review.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/common/review.json",
"title": "Review",
"description": "A review object",
"type": "object",
"properties": {
"review_id": {
"type": "integer",
"description": "Unique identifier for review"
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5,
"description": "Rating of the product"
},
"created_date": {
"type": "string",
"format": "date-time",
"description": "The date and time when the review was created"
},
"text": {
"type": "string",
"minLength": 2,
"maxLength": 2000,
"description": "The text of the review"
},
"client_id": {
"type": "integer",
"description": "Identifier for the client who wrote the review"
},
"product_id": {
"type": "integer",
"description": "Identifier for the product being reviewed"
}
},
"additionalProperties": false
}
2 changes: 1 addition & 1 deletion resources/schemas/products/update.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/products/update.json",
"title": "Create Product",
"title": "Update Product",
"properties": {
"name": {
"$ref": "https://example.com/common/product.json#/properties/name"
Expand Down
26 changes: 26 additions & 0 deletions resources/schemas/reviews/create.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/reviews/create.json",
"title": "Create Review",
"properties": {
"rating": {
"$ref": "https://example.com/common/review.json#/properties/rating"
},
"text": {
"$ref": "https://example.com/common/review.json#/properties/text"
},
"client_id": {
"$ref": "https://example.com/common/review.json#/properties/client_id"
},
"product_id": {
"$ref": "https://example.com/common/review.json#/properties/product_id"
}
},
"required": [
"rating",
"text",
"client_id",
"product_id"
],
"additionalProperties": false
}
20 changes: 20 additions & 0 deletions resources/schemas/reviews/update.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/reviews/update.json",
"title": "Update Review",
"properties": {
"rating": {
"$ref": "https://example.com/common/review.json#/properties/rating"
},
"text": {
"$ref": "https://example.com/common/review.json#/properties/text"
},
"client_id": {
"$ref": "https://example.com/common/review.json#/properties/client_id"
},
"product_id": {
"$ref": "https://example.com/common/review.json#/properties/product_id"
}
},
"additionalProperties": false
}
80 changes: 35 additions & 45 deletions src/controllers/api/Reviews.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

namespace Steamy\Controller\API;

use Opis\JsonSchema\{Errors\ErrorFormatter};
use Exception;
use Steamy\Core\Utility;
use Steamy\Model\Review;
use \Steamy\Model\Product as ProductModel;

class Reviews
{
Expand Down Expand Up @@ -70,54 +71,38 @@ public function getReviewByID(): void
public function createReview(): void
{
// Retrieve POST data
$postData = $_POST;

// TODO: Implement validation for required fields and data types
// Check if required fields are present
$requiredFields = [
'product_id',
'client_id',
'text',
'rating',
];

if (empty($postData)) {
$data = (object)json_decode(file_get_contents("php://input"), true);

// Validate against JSON schema
$result = Utility::validateAgainstSchema($data, "reviews/create.json");

if (!($result->isValid())) {
$errors = (new ErrorFormatter())->format($result->error());
$response = [
'error' => $errors
];
http_response_code(400);
echo json_encode(['error' => "Missing fields: " . implode(', ', $requiredFields)]);
echo json_encode($response);
return;
}

foreach ($requiredFields as $field) {
if (empty($postData[$field])) {
// Required field is missing, return 400 Bad Request
http_response_code(400);
echo json_encode(['error' => "Missing required field: $field"]);
return;
}
}
// Create a new Review object
$newReview = new Review(
null, // review_id will be auto-generated
(int)$postData['product_id'],
(int)$postData['client_id'],
$postData['text'],
(int)$postData['rating']
(int)$data->product_id,
(int)$data->client_id,
$data->text,
(int)$data->rating
);

$errors = $newReview->validate();

if (!empty($errors)) {
http_response_code(400);
echo json_encode(['error' => ($errors)]);
return;
}

// Save the new review to the database
if ($newReview->save()) {
try {
$newReview->save();
// Review created successfully, return 201 Created
http_response_code(201);
echo json_encode(['message' => 'Review created successfully', 'review_id' => $newReview->getReviewID()]);
} else {
echo json_encode(['message' => 'Review created successfully', 'review_id' => $newReview->getReviewID()]
);
} catch (Exception $e) {
// Failed to create review, return 500 Internal Server Error
http_response_code(500);
echo json_encode(['error' => 'Failed to create review']);
Expand All @@ -132,13 +117,18 @@ public function updateReview(): void
$reviewId = (int)Utility::splitURL()[3];

// Retrieve PUT request data
$putData = json_decode(file_get_contents("php://input"), true);
$data = (object)json_decode(file_get_contents("php://input"), true);

// Check if PUT data is valid
if (empty($putData)) {
// Invalid JSON data
http_response_code(400); // Bad Request
echo json_encode(['error' => 'Invalid JSON data']);
// Validate against JSON schema
$result = Utility::validateAgainstSchema($data, "reviews/update.json");

if (!($result->isValid())) {
$errors = (new ErrorFormatter())->format($result->error());
$response = [
'error' => $errors
];
http_response_code(400);
echo json_encode($response);
return;
}

Expand All @@ -154,7 +144,7 @@ public function updateReview(): void
}

// Update review in the database
$success = $review->updateReview($putData);
$success = $review->updateReview((array)$data);

if ($success) {
// Review updated successfully
Expand Down Expand Up @@ -186,7 +176,7 @@ public function deleteReview(): void
}

// Attempt to delete the review
if ($review->deleteReview($reviewId)) {
if ($review->deleteReview()) {
// Review successfully deleted
http_response_code(204); // No Content
} else {
Expand Down
40 changes: 16 additions & 24 deletions src/models/Review.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,9 @@ public function updateReview(array $newReviewData): bool
return $this->update($newReviewData, ['review_id' => $this->review_id], $this->table);
}

/**
* Deletes a review with the specified ID from the database.
*
* @param int $reviewId The ID of the review to delete.
* @return bool True if the deletion was successful, false otherwise.
*/
public static function deleteReview(int $reviewId): bool
public function deleteReview(): bool
{
$query = "DELETE FROM review WHERE review_id = :review_id";
$params = ['review_id' => $reviewId];
return self::query($query, $params);
return $this->delete($this->review_id, $this->table, 'review_id');
}

public function getReviewID(): int
Expand Down Expand Up @@ -225,34 +217,34 @@ public function setCreatedDate(DateTime $created_date): void
/**
* Saves review to database if attributes are valid. review_id and created_date attributes
* are automatically set by database and any set values are ignored.
* The review_id of the current object is updated after a successful insertion.
* @return bool
* @throws Exception
*/
public function save(): bool
{
// If attributes of the object are invalid, exit
if (count($this->validate()) > 0) {
return false;
$validation_errors = $this->validate();
if (count($validation_errors) > 0) {
throw new Exception(json_encode($validation_errors));
}

// Get data to be inserted into the review table
$reviewData = $this->toArray();

// Remove review_id as it is auto-incremented in database
// let database handle review_id and creation date
unset($reviewData['review_id']);

unset($reviewData['created_date']); // let database handle creation date
unset($reviewData['created_date']);

// Perform insertion to the review table
try {
$inserted_id = $this->insert($reviewData, 'review');
if ($inserted_id === null) {
return false;
}
$this->review_id = $inserted_id;
return true;
} catch (Exception) {
return false;
$inserted_id = $this->insert($reviewData, 'review');

if ($inserted_id === null) {
throw new Exception("Insertion failed for some unknown reason");
}

$this->review_id = $inserted_id;
return true;
}

public function validate(): array
Expand Down
Loading

0 comments on commit ef41d66

Please sign in to comment.