diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..f83d22a --- /dev/null +++ b/CHANGELOG @@ -0,0 +1 @@ +CHANGELOG: https://www.mageplaza.com/releases/better-product-reviews/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9e08325 --- /dev/null +++ b/LICENSE @@ -0,0 +1,33 @@ +Copyright © 2016-present Mageplaza Co. Ltd. + +This License is entered by Mageplaza to govern the usage or redistribution of Mageplaza software. This is a legal agreement between you (either an individual or a single entity) and Mageplaza for Mageplaza software product(s) which may include extensions, templates and services. + +By purchasing, installing, or otherwise using Mageplaza products, you acknowledge that you have read this License and agree to be bound by the terms of this Agreement. If you do not agree to the terms of this License, do not install or use Mageplaza products. + +The Agreement becomes effective at the moment when you acquire software from our site or receive it through email or on data medium or by any other means. Mageplaza reserves the right to make reasonable changes to the terms of this license agreement and impose its clauses at any given time. + + 1. GRANT OF LICENSE: By purchasing a product of Mageplaza: + + 1. Customer will receive source code open 100%. + + 2. Customer will obtain a License Certificate which will remain valid until the Customer stops using the Product or until Mageplaza terminates this License because of Customer’s failure to comply with any of its Terms and Conditions. Each License Certificate includes a license serial which is valid for one live Magento installation only and unlimited test Magento installations. + + 3. You are allowed to customize our products to fit with your using purpose. + + 4. DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS + + 5. Installation and Use + + 6. For each new Software installation, you are obliged to purchase a separate License. You are not permitted to use any part of the code in whole or part in any other software or product or website. You are legally bound to preserve the copyright information intact including the text/link at bottom. + + 2. Distribution: You are not allowed to distribute Mageplaza software to third parties. Any distribution without our permission, including non commercial distribution is considered as violation of this Agreement and entails liability, according to the current law. You may not place the Software onto a server that allows access to the Software via a public network or the Internet for distribution purposes. + + 3. Rental: You may not give, sell, sub-license, rent, lease or lend any portion of the Software to anyone. + + 4. Compliance with Applicable Laws: You must comply with all applicable laws regarding use of software products. Mageplaza software and a portion of it are protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. Accordingly, customer is required to treat the software like any other copyrighted material. Any activity violating copyright law will be prosecuted according to the current law. We retain the right to revoke the license of any user holding an invalid license. + + 5. TERMINATION: Without prejudice to any other rights, Mageplaza may terminate this License at any time if you fail to comply with the terms and conditions of this License. In such event, it constitutes a breach of the agreement, and your license to use the program is revoked and you must destroy all copies of Mageplaza products in your possession. After being notified of termination of your license, if you continue to use Mageplaza software, you hereby agree to accept an injunction to prevent you from its further use and to pay all costs (including but not limited to reasonable attorney fees) to enforce our revocation of your license and any damages suffered by us because of your misuse of the Software. We are not bound to return you the amount spent for purchase of the Software for the termination of this License. + + 6. LIMITATION OF LIABILITY: In no event shall Mageplaza be liable for any damages (including, without limitation, lost profits, business interruption, or lost information) rising out of ‘Authorized Users’ use of or inability to use the Mageplaza products, even if Mageplaza has been advised of the possibility of such damages. In no event will Mageplaza be liable for prosecution arising from use of the Software against law or for any illegal use. + +The latest License: https://www.mageplaza.com/LICENSE.txt \ No newline at end of file diff --git a/Model/Resolver/CreateReview.php b/Model/Resolver/CreateReview.php new file mode 100644 index 0000000..6ab50d9 --- /dev/null +++ b/Model/Resolver/CreateReview.php @@ -0,0 +1,262 @@ +_rating = $ratingFactory; + $this->_review = $reviewFactory; + $this->_product = $productModel; + $this->_orderFactory = $orderFactory; + $this->_helperData = $helperData; + $this->_customerRepositoryInterface = $customerRepositoryInterface; + } + + /** + * Fetches the data from persistence models and format it according to the GraphQL schema. + * + * @param Field $field + * @param ContextInterface $context + * @param ResolveInfo $info + * @param array|null $value + * @param array|null $args + * + * @return mixed|Value + * @throws Exception + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (!isset($args['input']) || !is_array($args['input']) || empty($args['input'])) { + throw new GraphQlInputException(__('"input" value should be specified')); + } + + $data = $args['input']; + $productId = $args['productId']; + + if (!$this->_product->load($productId)->getId()) { + throw new GraphQlInputException(__('The Product does not exit.')); + } + + $storeId = isset($data['store_id']) ? $data['store_id'] : 1; + $customerId = $this->isUserGuest($context->getUserId(), $productId); + $avgValue = isset($data['avg_value']) ? (int) $data['avg_value'] : 5; + + if ($customerId === false || $avgValue > 5 || $avgValue <= 0) { + throw new GraphQlAuthorizationException(__('The current customer isn\'t authorized.')); + } + + $status = isset($data['status_id']) ? $data['status_id'] : Review::STATUS_PENDING; + $ratings = $this->getRatingCollection($storeId); + $object = $this->_review->create()->setData($data); + $object->unsetData('review_id'); + + if ($object->validate()) { + $object->setEntityId($object->getEntityIdByCode(Review::ENTITY_PRODUCT_CODE)) + ->setEntityPkValue($productId) + ->setStatusId($status) + ->setCustomerId($customerId) + ->setStoreId($storeId) + ->setStores([$storeId]) + ->save(); + foreach ($ratings as $ratingId => $rating) { + foreach ($rating->getOptions() as $option) { + if ((int) $option->getValue() === $avgValue) { + $this->_rating->create() + ->setRatingId($ratingId) + ->setReviewId($object->getId()) + ->setCustomerId($customerId) + ->addOptionVote($option->getId(), $productId); + } + } + } + $object->aggregate(); + $collection = $object->getCollection(); + $collection->getSelect()->join( + ['mp_detail' => $collection->getTable('review_detail')], + 'main_table.review_id = mp_detail.review_id', + ['mp_bpr_images', 'mp_bpr_recommended_product', 'mp_bpr_verified_buyer', 'mp_bpr_helpful'] + )->join( + ['mp_vote' => $collection->getTable('rating_option_vote')], + 'main_table.review_id = mp_vote.review_id', + ['avg_value' => 'mp_vote.value'] + )->where('main_table.review_id = ?', $object->getId())->group('main_table.review_id'); + + return $collection->getFirstItem(); + } + + return []; + } + + /** + * @param $storeId + * + * @return mixed + * @throws LocalizedException + */ + public function getRatingCollection($storeId) + { + return $this->_rating->create()->getResourceCollection()->addEntityFilter( + 'product' + )->setPositionOrder()->addRatingPerStoreName( + $storeId + )->setStoreFilter( + $storeId + )->setActiveFilter( + true + )->load()->addOptionToItems(); + } + + /** + * @param $currentUserId + * @param $productId + * + * @return bool|null + * @throws LocalizedException + */ + public function isUserGuest($currentUserId, $productId) + { + if ($this->_helperData->isEnabled() && $this->isEnableWrite($currentUserId, $productId)) { + $mpGroupArray = explode(',', $this->_helperData->getWriteReviewConfig('customer_group')); + try { + $customerGroup = $this->_customerRepositoryInterface->getById($currentUserId)->getGroupId(); + } catch (NoSuchEntityException $exception) { + $customerGroup = '0'; + } + + if (in_array($customerGroup, $mpGroupArray, true)) { + return $currentUserId ?: null; + } + } + + return false; + } + + /** + * @param $customerId + * @param $productId + * + * @return bool + */ + public function isEnableWrite($customerId, $productId) + { + if ((int) $this->_helperData->getWriteReviewConfig('enabled') !== CustomerRestriction::PURCHASERS_ONLY) { + return (bool) $this->_helperData->getWriteReviewConfig('enabled'); + } + + $result = false; + + if ($customerId) { + $orders = $this->_orderFactory->create()->getCollection() + ->addFieldToFilter('customer_id', $customerId) + ->addFieldToFilter('state', Order::STATE_COMPLETE); + foreach ($orders as $order) { + /** + * @var Order $order + */ + foreach ($order->getAllVisibleItems() as $item) { + /** @var Item $item */ + if ($productId == $item->getProductId()) { + $result = true; + break; + } + } + } + } + + return $result; + } +} diff --git a/Model/Resolver/Filter/DataProvider/Review.php b/Model/Resolver/Filter/DataProvider/Review.php new file mode 100644 index 0000000..ea1cf69 --- /dev/null +++ b/Model/Resolver/Filter/DataProvider/Review.php @@ -0,0 +1,107 @@ +collectionFactory = $collectionFactory; + $this->searchResultsFactory = $searchResultsFactory; + $this->collectionProcessor = $collectionProcessor; + $this->_helperData = $_helperData; + } + + /** + * Gets list of product data with full data set. Adds eav attributes to result set from passed in array + * + * @param SearchCriteriaInterface $searchCriteria + * + * @param $collection + * + * @return SearchResultsInterface + */ + public function getList( + SearchCriteriaInterface $searchCriteria, + $collection + ): SearchResultsInterface { + /** @var Collection $collection */ + if (!$collection) { + $collection = $this->collectionFactory->create()->addReviewDetailTable()->addAverageVotingTable(); + if ($this->_helperData->getReviewListingConfig('store_owner_answer')) { + $collection->addReviewReplyTable(); + } + } + $this->collectionProcessor->process($searchCriteria, $collection); + $searchResult = $this->searchResultsFactory->create(); + $searchResult->setSearchCriteria($searchCriteria); + $searchResult->setItems($collection->getItems()); + $searchResult->setTotalCount($collection->getSize()); + + return $searchResult; + } +} diff --git a/Model/Resolver/Filter/Query/Filter.php b/Model/Resolver/Filter/Query/Filter.php new file mode 100644 index 0000000..5dafa59 --- /dev/null +++ b/Model/Resolver/Filter/Query/Filter.php @@ -0,0 +1,100 @@ +searchResultFactory = $searchResultFactory; + $this->_review = $review; + $this->_helperData = $_helperData; + } + + /** + * Filter catalog product data based off given search criteria + * + * @param SearchCriteriaInterface $searchCriteria + * + * @param null $collection + * + * @return SearchResult + */ + public function getResult( + SearchCriteriaInterface $searchCriteria, + $collection = null + ): SearchResult { + $list = $this->_review->getList($searchCriteria, $collection); + + $listArray = []; + /** @var ReviewModel $item */ + foreach ($list->getItems() as $item) { + if (!$this->_helperData->getReviewListingConfig('store_owner_answer')) { + $item->setData('reply_enabled', 0); + $item->setData('reply_nickname', ''); + $item->setData('reply_content', ''); + $item->setData('reply_created_at', ''); + } + $listArray[$item->getId()] = $item->getData(); + $listArray[$item->getId()]['model'] = $item; + } + + return $this->searchResultFactory->create($list->getTotalCount(), $listArray); + } +} diff --git a/Model/Resolver/Filter/SearchResult.php b/Model/Resolver/Filter/SearchResult.php new file mode 100644 index 0000000..2d6f28d --- /dev/null +++ b/Model/Resolver/Filter/SearchResult.php @@ -0,0 +1,72 @@ +totalCount = $totalCount; + $this->itemsSearchResult = $itemsSearchResult; + } + + /** + * Return total count of search and filtered result + * + * @return int + */ + public function getTotalCount(): int + { + return $this->totalCount; + } + + /** + * Retrieve an array in the format of GraphQL-readable type containing product data. + * + * @return array + */ + public function getItemsSearchResult(): array + { + return $this->itemsSearchResult; + } +} diff --git a/Model/Resolver/Filter/SearchResultFactory.php b/Model/Resolver/Filter/SearchResultFactory.php new file mode 100644 index 0000000..4d27aab --- /dev/null +++ b/Model/Resolver/Filter/SearchResultFactory.php @@ -0,0 +1,61 @@ +objectManager = $objectManager; + } + + /** + * Instantiate SearchResult + * + * @param int $totalCount + * @param array $itemsSearchResult + * + * @return SearchResult + */ + public function create(int $totalCount, array $itemsSearchResult): SearchResult + { + return $this->objectManager->create( + SearchResult::class, + ['totalCount' => $totalCount, 'itemsSearchResult' => $itemsSearchResult] + ); + } +} diff --git a/Model/Resolver/FilterArgument.php b/Model/Resolver/FilterArgument.php new file mode 100644 index 0000000..25a8efc --- /dev/null +++ b/Model/Resolver/FilterArgument.php @@ -0,0 +1,62 @@ +config = $config; + } + + /** + * @return array + */ + public function getEntityAttributes(): array + { + $fields = []; + /** @var Field $field */ + foreach ($this->config->getConfigElement('Review')->getFields() as $field) { + $fields[$field->getName()] = ''; + } + + return array_keys($fields); + } +} diff --git a/Model/Resolver/Review/Product.php b/Model/Resolver/Review/Product.php new file mode 100644 index 0000000..4eb9f0b --- /dev/null +++ b/Model/Resolver/Review/Product.php @@ -0,0 +1,62 @@ +_product = $product; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + $productId = $value['entity_pk_value']; + + return $this->_product->load($productId); + } +} diff --git a/Model/Resolver/Reviews.php b/Model/Resolver/Reviews.php new file mode 100644 index 0000000..174de66 --- /dev/null +++ b/Model/Resolver/Reviews.php @@ -0,0 +1,286 @@ +searchCriteriaBuilder = $searchCriteriaBuilder; + $this->reviewCollection = $reviewCollection; + $this->_product = $product; + $this->filterQuery = $filterQuery; + $this->_helperData = $_helperData; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + $this->validateArgs($args); + $searchCriteria = $this->searchCriteriaBuilder->build('reviews', $args); + $searchCriteria->setCurrentPage($args['currentPage']); + $searchCriteria->setPageSize($args['pageSize']); + + if (!$this->_helperData->isEnabled()) { + return [ + 'total_count' => 0, + 'items' => [], + 'pageInfo' => [ + 'pageSize' => $args['pageSize'], + 'currentPage' => $args['currentPage'], + 'hasNextPage' => false, + 'hasPreviousPage' => false, + 'startPage' => 1, + 'endPage' => 1, + ] + ]; + } + + switch ($args['action']) { + case 'get_all_review': + $collection = null; + break; + case 'get_view_review': + $collection = $this->getViewReview($args); + break; + case 'get_by_productId': + $collection = $this->getByProductId($args); + break; + case 'get_by_productSku': + $collection = $this->getByProductSku($args); + break; + case 'get_by_customerId': + $collection = $this->getByCustomerId($args); + break; + default: + throw new GraphQlInputException(__('No find your function')); + } + $searchResult = $this->filterQuery->getResult($searchCriteria, $collection); + + //possible division by 0 + if ($searchCriteria->getPageSize()) { + $maxPages = ceil($searchResult->getTotalCount() / $searchCriteria->getPageSize()); + } else { + $maxPages = 0; + } + + $currentPage = $searchCriteria->getCurrentPage(); + if ($searchCriteria->getCurrentPage() > $maxPages && $searchResult->getTotalCount() > 0) { + throw new GraphQlInputException( + __( + 'currentPage value %1 specified is greater than the %2 page(s) available.', + [$currentPage, $maxPages] + ) + ); + } + + return [ + 'total_count' => $searchResult->getTotalCount(), + 'items' => $searchResult->getItemsSearchResult(), + 'pageInfo' => [ + 'pageSize' => $args['pageSize'], + 'currentPage' => $args['currentPage'], + 'hasNextPage' => $currentPage < $maxPages, + 'hasPreviousPage' => $currentPage > 1, + 'startPage' => 1, + 'endPage' => $maxPages, + ] + ]; + } + + /** + * @param $args + * + * @return Collection + * @throws GraphQlInputException + */ + protected function getViewReview($args) + { + if (!isset($args['reviewId'])) { + throw new GraphQlInputException(__('reviewId value is not null')); + } + $collection = $this->getReviewCollection(); + $collection->addFieldToFilter('main_table.review_id', $args['reviewId']); + + return $collection; + } + + /** + * @param $args + * + * @return Collection + * @throws GraphQlInputException + */ + protected function getByProductId($args) + { + if (!isset($args['productId'])) { + throw new GraphQlInputException(__('productId value is not null')); + } + $product = $this->_product->load($args['productId']); + + if (!$product->getId()) { + throw new GraphQlInputException(__('No element found matching the given condition.')); + } + + $collection = $this->getReviewCollection(); + $collection->addFieldToFilter('main_table.entity_pk_value', $args['productId']); + + return $collection; + } + + /** + * @param $args + * + * @return Collection + * @throws GraphQlInputException + */ + protected function getByProductSku($args) + { + if (!isset($args['productSku'])) { + throw new GraphQlInputException(__('Action value is not null')); + } + $product = $this->_product->loadByAttribute('sku', $args['productSku']); + + if (!$product) { + throw new GraphQlInputException(__('No element found matching the given condition.')); + } + + $collection = $this->getReviewCollection(); + $collection->addFieldToFilter('main_table.entity_pk_value', $product->getId()); + + return $collection; + } + + /** + * @param $args + * + * @return Collection + * @throws GraphQlInputException + */ + protected function getByCustomerId($args) + { + if (!isset($args['customerId'])) { + throw new GraphQlInputException(__('customerId value is not null')); + } + + $collection = $this->getReviewCollection(); + + if ($args['customerId'] === 0) { + $collection->addFieldToFilter('detail.customer_id', ['null' => true]); + } else { + $collection->addFieldToFilter('detail.customer_id', $args['customerId']); + } + + return $collection; + } + + /** + * @return Collection + */ + protected function getReviewCollection() + { + $collection = $this->reviewCollection->create()->addReviewDetailTable()->addAverageVotingTable(); + if ($this->_helperData->getReviewListingConfig('store_owner_answer')) { + $collection->addReviewReplyTable(); + } + + return $collection; + } + + /** + * @param array $args + * + * @throws GraphQlInputException + */ + protected function validateArgs(array $args) + { + if (!isset($args['action'])) { + throw new GraphQlInputException(__('Action value is not null')); + } + + if (isset($args['currentPage']) && $args['currentPage'] < 1) { + throw new GraphQlInputException(__('currentPage value must be greater than 0.')); + } + + if (isset($args['pageSize']) && $args['pageSize'] < 1) { + throw new GraphQlInputException(__('pageSize value must be greater than 0.')); + } + } +} diff --git a/README.md b/README.md index e0911d1..bfdae5f 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ -# Better Product Reviews GraphQl -This module provides type and resolver information for the GraphQl module to generate catalog reviews information endpoints. - -## How to install -Run the following command in Magento 2 root folder: - -``` -composer require mageplaza/module-better-product-reviews-graphql -php bin/magento setup:upgrade -php bin/magento setup:static-content:deploy -``` - -## How to use - -To start working with GraphQl in Magento, you need the following: -- Use Magento 2.3.x. Returns site to developer mode -- Install [chrome extension](https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij?hl=en) (currently does not support other browsers) -- Set **GraphQL endpoint** as `http:///graphql` in url box, click **Set endpoint**. (e.g. http://develop.mageplaza.com/graphql/ce232/graphql) -- Mageplaza-supported queries are fully written in the **Description** section of `Query.productreviews.Products` - -![](https://i.imgur.com/8OW0Y2G.png) +# Better Product Reviews GraphQl +This module provides type and resolver information for the GraphQl module to generate catalog reviews information endpoints. + +## How to install +Run the following command in Magento 2 root folder: + +``` +composer require mageplaza/module-better-product-reviews-graphql +php bin/magento setup:upgrade +php bin/magento setup:static-content:deploy +``` + +## How to use + +To start working with GraphQl in Magento, you need the following: +- Use Magento 2.3.x. Returns site to developer mode +- Install [chrome extension](https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij?hl=en) (currently does not support other browsers) +- Set **GraphQL endpoint** as `http:///graphql` in url box, click **Set endpoint**. (e.g. http://develop.mageplaza.com/graphql/ce232/graphql) +- Mageplaza-supported queries are fully written in the **Description** section of `Query.productreviews.Products` + +![](https://i.imgur.com/8OW0Y2G.png) diff --git a/USER-GUIDE.md b/USER-GUIDE.md new file mode 100644 index 0000000..988acb8 --- /dev/null +++ b/USER-GUIDE.md @@ -0,0 +1,54 @@ +## Documentation + +- Installation guide: https://www.mageplaza.com/install-magento-2-extension/#solution-1-ready-to-paste +- User Guide: https://docs.mageplaza.com/better-product-reviews/ +- Product page: https://www.mageplaza.com/magento-2-better-product-reviews/ +- FAQs: https://www.mageplaza.com/faqs/ +- Get Support: https://www.mageplaza.com/contact.html or support@mageplaza.com +- Changelog: https://www.mageplaza.com/releases/better-product-reviews/ +- License agreement: https://www.mageplaza.com/LICENSE.txt + +## How to install + +### Install ready-to-paste package (Recommended) + +- Installation guide: https://www.mageplaza.com/install-magento-2-extension/ + +## How to upgrade + +1. Backup + +Backup your Magento code, database before upgrading. + +2. Remove BetterProductReviewsGraphQl folder + +In case of customization, you should backup the customized files and modify in newer version. +Now you remove `app/code/Mageplaza/BetterProductReviewsGraphQl` folder. In this step, you can copy override BetterProductReviewsGraphQl folder but this may cause of compilation issue. That why you should remove it. + +3. Upload new version +Upload this package to Magento root directory + +4. Run command line: + +``` +php bin/magento setup:upgrade +php bin/magento setup:static-content:deploy +``` + + +## FAQs + + +#### Q: I got error: `Mageplaza_Core has been already defined` +A: Read solution: https://github.com/mageplaza/module-core/issues/3 + + +#### Q: My site is down +A: Please follow this guide: https://www.mageplaza.com/blog/magento-site-down.html + + +## Support + +- FAQs: https://www.mageplaza.com/faqs/ +- https://www.mageplaza.com/contact.html +- support@mageplaza.com diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4183ea8 --- /dev/null +++ b/composer.json @@ -0,0 +1,23 @@ +{ + "name": "mageplaza/module-better-product-reviews-graphql", + "description": "Magento 2 Better Product Reviews GraphQl Extension", + "type": "magento2-module", + "version": "1.0.0", + "license": "proprietary", + "authors": [ + { + "name": "Mageplaza", + "email": "support@mageplaza.com", + "homepage": "https://www.mageplaza.com", + "role": "Technical Support" + } + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Mageplaza\\BetterProductReviewsGraphQl\\": "" + } + } +} diff --git a/etc/di.xml b/etc/di.xml new file mode 100755 index 0000000..b86fd02 --- /dev/null +++ b/etc/di.xml @@ -0,0 +1,33 @@ + + + + + + + + \Mageplaza\BetterProductReviewsGraphQl\Model\Resolver\FilterArgument + + + + + diff --git a/etc/module.xml b/etc/module.xml new file mode 100755 index 0000000..53a7f43 --- /dev/null +++ b/etc/module.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/etc/schema.graphqls b/etc/schema.graphqls new file mode 100644 index 0000000..af9f4c6 --- /dev/null +++ b/etc/schema.graphqls @@ -0,0 +1,125 @@ +# Mageplaza +# +# NOTICE OF LICENSE +# +# This source file is subject to the Mageplaza.com license that is +# available through the world-wide-web at this URL: +# https://www.mageplaza.com/LICENSE.txt +# +# DISCLAIMER +# +# Do not edit or add to this file if you wish to upgrade this extension to newer +# version in the future. +# +# @category Mageplaza +# @package Mageplaza_BetterProductReviewsGraphQl +# @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/) +# @license https://www.mageplaza.com/LICENSE.txt + +type Query { + mpBprGetReview( + action: String! @doc(description: "Action in query.") + filter: ReviewsFilterInput @doc(description: "Identifies which product attributes to search for and return.") + reviewId: Int @doc(description: "Review ID use in the filter. Apply when action is get_view_review.") + productId: Int @doc(description: "Product ID use in the filter. Apply when action is get_by_productId.") + productSku: String @doc(description: "Product Sku use in the filter. Apply when action is get_by_productSku.") + customerId: Int @doc(description: "Customer ID use in the filter. Apply when action is get_by_customerId.") + pageSize: Int = 10 @doc(description: "How many items should show on the page.") + currentPage: Int = 1 @doc(description: "Allows to using paging it start with 1.") + ):ReviewsOutput @resolver(class: "\\Mageplaza\\BetterProductReviewsGraphQl\\Model\\Resolver\\Reviews") @doc(description: "The mpBprGetReview query searches for review that match the criteria specified in the filter.") +} + +type Mutation { + mpBprCreateReview ( + input: ReviewInput! + productId: Int! @doc(description: "Product ID used to add reviews.") + ): NewReview @resolver(class: "\\Mageplaza\\BetterProductReviewsGraphQl\\Model\\Resolver\\CreateReview") @doc(description:"Create a new Review") +} + +input ReviewsFilterInput { + created_at: FilterTypeInput @doc(description: "Timestamp indicating when the post was created."), + entity_id: FilterTypeInput @doc(description: "The Entity ID."), + status_id: FilterTypeInput @doc(description: "Status code."), + detail_id: FilterTypeInput @doc(description: "Review detail ID."), + title: FilterTypeInput @doc(description: "Review title."), + nickname: FilterTypeInput @doc(description: "User nickname"), + mp_bpr_helpful: FilterTypeInput @doc(description: "Mageplaza BPR Helpful.") +} +input ReviewInput { + title: String! @doc(description: "Review title."), + detail: String! @doc(description: "Review detail."), + nickname: String! @doc(description: "User nickname."), + mp_bpr_images: String @doc(description: "Mageplaza BPR Review Images (Json)."), + mp_bpr_recommended_product: String @doc(description: "Mageplaza BPR Recommended Product."), + mp_bpr_verified_buyer: String @doc(description: "Mageplaza BPR Verified Buyer."), + mp_bpr_helpful: Int @doc(description: "Mageplaza BPR Helpful."), + avg_value: String! @doc(description: "Average summaried rating.") +} + + +type ReviewsOutput { + total_count: Int @doc(description: "The number of posts returned."), + items: [Review] @doc(description: "An array of post that match the specified search criteria.") + pageInfo: PageInfo @doc(description: "An object that includes the page_info and currentPage values specified in the query.") +} + +type PageInfo { + pageSize: Int @doc(description: "How many items should show on the page.") + currentPage: Int @doc(description: "Allow page number to start with 1.") + hasNextPage: Boolean @doc(description: "Is next page") + hasPreviousPage: Boolean @doc(description: "Is previous page") + startPage: Int @doc(description: "Start page") + endPage: Int @doc(description: "End page") +} + +type Review { + review_id: Int @doc(description: "An ID that uniquely identifies the review."), + created_at: String @doc(description: "Timestamp indicating when the category was created."), + entity_id: Int @doc(description: "Review entity ID."), + entity_pk_value: Int @doc(description: "An ID that identifies the product."), + status_id: Int @doc(description: "An ID that identifies the status."), + detail_id: Int @doc(description: "An ID that identifies the review detail."), + title: String @doc(description: "The title of the review."), + detail: String @doc(description: "The detail of the review."), + nickname: String @doc(description: "The nickname of the reviewer."), + customer_id: Int @doc(description: "An ID that identifies the customer."), + mp_bpr_images: String @doc(description: "Mageplaza BPR Review Images (Json)."), + mp_bpr_recommended_product: String @doc(description: "Mageplaza BPR Recommended Product."), + mp_bpr_verified_buyer: String @doc(description: "Mageplaza BPR Verified Buyer."), + mp_bpr_helpful: Int @doc(description: "Mageplaza BPR Helpful."), + reply_enabled: Int @doc(description: "Mageplaza reply is enabled."), + reply_nickname: String @doc(description: "The nickname of the admin."), + reply_content: String @doc(description: "The content of the reply."), + reply_created_at: String @doc(description: "The timestamp indicating when the reply is created."), + avg_value: String @doc(description: "The avg rating of the review."), + products: Product @resolver(class: "Mageplaza\\BetterProductReviewsGraphQl\\Model\\Resolver\\Review\\Product") @doc(description: "The products assigned to a review.") +} + +type NewReview { + review_id: Int @doc(description: "An ID that uniquely identifies the review."), + created_at: String @doc(description: "Timestamp indicating when the category was created."), + entity_id: Int @doc(description: "Review entity ID."), + entity_pk_value: Int @doc(description: "An ID that identifies the product."), + status_id: Int @doc(description: "An ID that identifies the status."), + detail_id: Int @doc(description: "An ID that identifies the review detail."), + title: String @doc(description: "The title of the review."), + detail: String @doc(description: "The detail of the review."), + nickname: String @doc(description: "The nickname of the reviewer."), + customer_id: Int @doc(description: "An ID that identifies the customer."), + mp_bpr_images: String @doc(description: "Mageplaza BPR Review Images (Json)."), + mp_bpr_recommended_product: String @doc(description: "Mageplaza BPR Recommended Product."), + mp_bpr_verified_buyer: String @doc(description: "Mageplaza BPR Verified Buyer."), + mp_bpr_helpful: Int @doc(description: "Mageplaza BPR Helpful."), + avg_value: String @doc(description: "The avg rating of the review.") +} + +type Product { + entity_id: Int @doc(description: "The ID number assigned to the product."), + attribute_set_id: Int @doc(description: "The attribute set assigned to the product."), + type_id: String @doc(description: "Represent simple, virtual, downloadable, grouped or configirable product type."), + sku: String @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer."), + has_options: Int @doc(description: "Indicate whether a product option is available."), + required_options: Int @doc(description: "Indicate whether a product option is required."), + created_at: String @doc(description: "Timestamp indicating when the product was created."), + updated_at: String @doc(description: "Timestamp indicating when the product was updated.") +} diff --git a/i18n/en_US.csv b/i18n/en_US.csv new file mode 100644 index 0000000..2668bce --- /dev/null +++ b/i18n/en_US.csv @@ -0,0 +1,12 @@ +"""input"" value should be specified","""input"" value should be specified" +"The Product does not exit.","The Product does not exit." +"The current customer isn't authorized.","The current customer isn't authorized." +"No find your function","No find your function" +"currentPage value %1 specified is greater than the %2 page(s) available.","currentPage value %1 specified is greater than the %2 page(s) available." +"reviewId value is not null","reviewId value is not null" +"productId value is not null","productId value is not null" +"No element found matching the given condition.","No element found matching the given condition." +"Action value is not null","Action value is not null" +"customerId value is not null","customerId value is not null" +"currentPage value must be greater than 0.","currentPage value must be greater than 0." +"pageSize value must be greater than 0.","pageSize value must be greater than 0." diff --git a/registration.php b/registration.php new file mode 100755 index 0000000..a2fb6e3 --- /dev/null +++ b/registration.php @@ -0,0 +1,28 @@ +