diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e87ac62 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,18 @@ +# Change Log +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## xx.yy.zz +### Fixed +- {description_of_fixed} + +### Added +- {description_of_added} + +### Changed +- {description_of_added} + +### Removed +- {description_of_removed} \ No newline at end of file diff --git a/README.md b/README.md index 39f637e..bbd50ce 100644 --- a/README.md +++ b/README.md @@ -135,3 +135,15 @@ Lint code using [PSR-2](http://www.php-fig.org/psr/psr-2/) coding style ```bash composer lint ``` + +## Debugging + +### Setting up xDebug with PhpStorm + +Increase your composer's timeout limit by adding these lines to your +`~/.bashrc` file + +``` +export COMPOSER_PROCESS_TIMEOUT=1200 +export COMPOSER_DISABLE_XDEBUG_WARN=1 +``` diff --git a/composer.json b/composer.json index 6889682..4a7bfaf 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,6 @@ "ext-pdo_sqlite": "*", "phramework/phramework": "^1.3", "phramework/jsonapi": "1.0.0-RC19", - "ext-pdo_sqlite": "*", "phramework/basic-authentication": "^0.0.0" }, "require-dev": { diff --git a/db/db_changes/170605_vm_create_table_review.sql b/db/db_changes/170605_vm_create_table_review.sql new file mode 100644 index 0000000..8c3c6b1 --- /dev/null +++ b/db/db_changes/170605_vm_create_table_review.sql @@ -0,0 +1,52 @@ +CREATE TABLE review( + `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `score` INTEGER NOT NULL CHECK (`score` BETWEEN 1 AND 10), + `status` INTEGER NOT NULL CHECK (`status` BETWEEN 0 AND 1), + `user_exist` INTEGER NOT NULL CHECK (`user_exist` BETWEEN 0 AND 1) +); + +CREATE TABLE article_review( + `article_id` INTEGER NOT NULL, + `review_id` INTEGER NOT NULL, + `status` INTEGER NOT NULL CHECK (`status` BETWEEN 0 AND 1), + PRIMARY KEY (article_id,review_id), + FOREIGN KEY (article_id) REFERENCES article(id), + FOREIGN KEY (review_id) REFERENCES review(id) +); + +CREATE TABLE user_review( + `user_id` INTEGER NOT NULL, + `review_id` INTEGER NOT NULL, + `status` INTEGER NOT NULL CHECK (`status` BETWEEN 0 AND 1), + PRIMARY KEY (user_id,review_id), + FOREIGN KEY (user_id) REFERENCES user(id), + FOREIGN KEY (review_id) REFERENCES review(id) +); + +ALTER TABLE 'user_review' RENAME TO 'user-review'; +ALTER TABLE "article_review" RENAME TO "article-review"; + +DROP TABLE review; +DROP TABLE "article-review"; +DROP TABLE "user-review"; + +CREATE TABLE review ( + `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `score` INTEGER NOT NULL CHECK (`score` BETWEEN 1 AND 10), + `status` INTEGER NOT NULL CHECK (`status` BETWEEN 0 AND 1), + `user_id` INTEGER REFERENCES user (id) +); + +CREATE TABLE 'article-review'( + `article_id` INTEGER NOT NULL REFERENCES article(id), + `review_id` INTEGER NOT NULL REFERENCES review(id), + `status` INTEGER NOT NULL CHECK (`status` BETWEEN 0 AND 1), + constraint article_review PRIMARY KEY (article_id,review_id) +); + +CREATE TABLE `user-review`( + `user_id` INTEGER NOT NULL REFERENCES user(id), + `review_id` INTEGER NOT NULL REFERENCES review(id), + `status` INTEGER NOT NULL CHECK (`status` BETWEEN 0 AND 1), + CONSTRAINT user_review PRIMARY KEY (user_id,review_id) +); diff --git a/public/index.php b/public/index.php index 041adc6..5999cb8 100644 --- a/public/index.php +++ b/public/index.php @@ -95,6 +95,36 @@ 'byIdRelationships', Phramework::METHOD_ANY ], + [ + 'review/', //URI + NS . 'ReviewController', //Class + 'GET', //Class method + Phramework::METHOD_GET, //HTTP Method + ], + [ + 'review/{id}', + NS . 'ReviewController', + 'GETById', + Phramework::METHOD_GET + ], + [ + 'review/', + NS . 'ReviewController', + 'POST', + Phramework::METHOD_POST + ], + [ + 'review/{id}', + NS . 'ReviewController', + 'PATCH', + Phramework::METHOD_PATCH + ], + [ + 'review/{id}/relationships/{relationship}', + NS . 'ReviewController', + 'byIdRelationships', + Phramework::METHOD_ANY + ], ]); //Initialize API with settings and routing diff --git a/src/Controllers/ReviewController.php b/src/Controllers/ReviewController.php new file mode 100644 index 0000000..899fd27 --- /dev/null +++ b/src/Controllers/ReviewController.php @@ -0,0 +1,155 @@ + + */ +class ReviewController extends \Phramework\Examples\JSONAPI\Controller +{ + /** + * Get collection + * `/review/` handler + * @param \stdClass $params Request parameters + * @param string $method Request method + * @param array $headers Request headers + */ + public static function GET(\stdClass $params, string $method, array $headers) + { + static::handleGET( + $params, + Review::class, + [], + [] + ); + } + + /** + * Get a resource + * `/review/{id}/` handler + * @param \stdClass $params Request parameters + * @param string $method Request method + * @param array $headers Request headers + * @param string $id Resource id + */ + public static function GETById(\stdClass $params, string $method, array $headers, string $id) + { + static::handleGETById( + $params, + $id, + Review::class, + [], + [] + ); + } + + /** + * Post new resource + * @param \stdClass $params Request parameters + * @param string $method Request method + * @param array $headers Request headers + */ + public static function POST(\stdClass $params, string $method, array $headers) + { + static::handlePOST( + $params, + $method, + $headers, + Review::class + ); + } + + /** + * Update a resource + * @param $params + * @param $method + * @param $headers + * @param string $id + */ + public static function PATCH( + \stdClass $params, + string $method, + array $headers, + string $id + ) { + static::handlePATCH( + $params, + $method, + $headers, + $id, + Review::class + ); + } + + /** + * Delete a resource + * @param $params + * @param $method + * @param $headers + * @param string $id + */ + public static function DELETE( + \stdClass $params, + string $method, + array $headers, + string $id + ) { + static::handleDELETE( + $params, + $method, + $headers, + $id, + Review::class + ); + } + + /** + * Manage resource's relationships + * `/article/{id}/relationships/{relationship}/` handler + * @param \stdClass $params Request parameters + * @param string $method Request method + * @param array $headers Request headers + * @param string $id Resource id + * @param string $relationship Relationship + */ + public static function byIdRelationships( + $params, + $method, + $headers, + string $id, + string $relationship + ) { + static::handleByIdRelationships( + $params, + $method, + $headers, + $id, + $relationship, + Review::class, + [Phramework::METHOD_GET], + [], + [] + ); + } +} diff --git a/src/Models/Article.php b/src/Models/Article.php index 3d4399c..bf1702a 100644 --- a/src/Models/Article.php +++ b/src/Models/Article.php @@ -170,6 +170,31 @@ public static function getRelationshipTag( return $ids; } + /** + * Get all articles with given review id + * @param string $reviewId + * @return string[] + */ + public static function getRelationshipReview( + string $reviewId, + Fields $fields = null, + $flags = Resource::PARSE_DEFAULT + ) { + $ids = Database::executeAndFetchAllArray( + 'SELECT "article-review"."article_id" + FROM "article-review" + JOIN "article" + ON "article"."id" = "article-review"."article_id" + WHERE + "article-review"."review_id" = ? + AND "article-review"."status" <> 0 + AND "article"."status" <> 0', + [$reviewId] + ); + + return $ids; + } + /** * Get all articles with given creator id * @param string $userId @@ -224,6 +249,18 @@ public static function getRelationships() ] ], Relationship::FLAG_DEFAULT | Relationship::FLAG_DATA + ), + 'review' => new Relationship( + Review::class, + Relationship::TYPE_TO_MANY, + null, //source data attribute + (object) [ //source data callback + Phramework::METHOD_GET => [ + Review::class, + 'getRelationshipArticle' + ] + ], + Relationship::FLAG_DEFAULT | Relationship::FLAG_DATA ) ]; } diff --git a/src/Models/Review.php b/src/Models/Review.php new file mode 100644 index 0000000..faddfa6 --- /dev/null +++ b/src/Models/Review.php @@ -0,0 +1,236 @@ + + */ +class Review extends \Phramework\Examples\JSONAPI\Model +{ + protected static $type = 'review'; + protected static $endpoint = 'review'; + protected static $table = 'review'; + + /** + * @param Page $page + * @param Filter $filter + * @param Sort $sort + * @param Fields $fields + * @param mixed ...$additionalParameters + * @return Resource[] + */ + public static function get( + Page $page = null, + Filter $filter = null, + Sort $sort = null, + Fields $fields = null, + ...$additionalParameters + ) { + $query = static::handleGet( + 'SELECT + {{fields}}, + "user_id" + FROM "review" + WHERE "status" <> ? + {{filter}} + {{sort}} + {{page}}', + $page, + $filter, + $sort, + $fields, + true + ); + + $records = Database::executeAndFetchAll( + $query, + [ + '0' + ] + ); + + array_walk( + $records, + [static::class, 'prepareRecord'] + ); + + return static::collection($records, $fields); + } + + /** + * Defines model's validator for POST requests + * also may be used for PATCH requests and to validate filter directive values + * @return ValidationModel + */ + public static function getValidationModel() + { + return new ValidationModel( + new ObjectValidator( //attributes + (object) [ //properties + 'score' => new UnsignedIntegerValidator(1, 10), + 'status' => (new UnsignedIntegerValidator(0, 1)) + ->setDefault(1) + ], + ['score'], //required attributes, + false //additional properties + ), + new ObjectValidator( //relationships + (object) [ + 'reviewer' => User::getIdValidator() + ], + [], //required relationships, + false //additional properties + ) + ); + } + + public static function getPatchValidationModel() + { + return new ValidationModel( + new ObjectValidator( //attributes + (object) [ //properties + 'score' => new UnsignedIntegerValidator(1, 10), + 'status' => new UnsignedIntegerValidator(0, 1) + ], + [], //required attributes, + false + ), + new ObjectValidator( //relationships + (object) [ + 'reviewer' => User::getIdValidator() + ], + [], //required relationships + false + ) + ); + } + + /** + * @return string[] + */ + public static function getMutable() + { + return ['score', 'status']; // 'user_id', --> do I need to add this? + } + + /** + * @return string[] + */ + public static function getFields() + { + return ['score']; // 'user_id', --> do I need to add this? + } + + /** + * Get all reviews with given article id + * @param string $articleId + * @return string[] + */ + public static function getRelationshipArticle( + string $articleId, + Fields $fields = null, + $flags = Resource::PARSE_DEFAULT + ) { + $ids = Database::executeAndFetchAllArray( + 'SELECT "article-review"."article_id" + FROM "article-review" + JOIN "article" + ON "article"."id" = "article-review"."article_id" + WHERE + "article-review"."article_id" = ? + AND "article-review"."status" <> 0 + AND "article"."status" <> 0', + [$articleId] + ); + + return $ids; + } + +// /** +// * Get all articles with given creator id +// * @param string $userId +// * @return string[] +// */ +// public static function getRelationshipUser( +// string $userId, +// Fields $fields = null, +// $flags = Resource::PARSE_DEFAULT +// ) : array { +// $ids = Database::executeAndFetchAllArray( +// 'SELECT "article"."id" +// FROM "article" +// WHERE +// "article"."creator-user_id" = ? +// AND "article"."status" <> 0', +// [$userId] +// ); +// +// return $ids; +// } + + /** + * @return string[] + */ + public static function getSortable() + { + return ['id', 'status']; + } + + /** + * @return \stdClass + */ + public static function getRelationships() + { + return (object) [ +// 'creator' => new Relationship( +// User::class, +// Relationship::TYPE_TO_ONE, +// 'creator-user_id', //source data attribute +// null, //source data callback +// Relationship::FLAG_DEFAULT | Relationship::FLAG_DATA +// ), + 'article' => new Relationship( + Article::class, + Relationship::TYPE_TO_MANY, + null, //source data attribute + (object) [ //source data callback + Phramework::METHOD_GET => [ + Article::class, + 'getRelationshipReview' + ] + ], + Relationship::FLAG_DEFAULT | Relationship::FLAG_DATA + ) + ]; + } +}