mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
[Review] Fixes after PR review
This commit is contained in:
parent
a2167e3ae3
commit
c9a86d0b83
104 changed files with 1257 additions and 1360 deletions
|
|
@ -22,6 +22,7 @@ imports:
|
|||
- suites/legacy/products.yml
|
||||
- suites/legacy/promotions.yml
|
||||
- suites/legacy/reports.yml
|
||||
- suites/legacy/reviews.yml
|
||||
- suites/legacy/search.yml
|
||||
- suites/legacy/security.yml
|
||||
- suites/legacy/settings.yml
|
||||
|
|
|
|||
|
|
@ -16,5 +16,6 @@ default:
|
|||
- Sylius\Bundle\TaxonomyBundle\Behat\TaxonomyContext
|
||||
- Sylius\Bundle\WebBundle\Behat\WebContext
|
||||
- Sylius\Bundle\ChannelBundle\Behat\ChannelContext
|
||||
- Sylius\Bundle\ReviewBundle\Behat\ReviewContext
|
||||
filters:
|
||||
tags: "@legacy_products"
|
||||
|
|
|
|||
20
etc/behat/suites/legacy/reviews.yml
Normal file
20
etc/behat/suites/legacy/reviews.yml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# This file is part of the Sylius package.
|
||||
# (c) Paweł Jędrzejewski
|
||||
|
||||
default:
|
||||
suites:
|
||||
reviews:
|
||||
contexts:
|
||||
- Behat\MinkExtension\Context\MinkContext
|
||||
- Sylius\Bundle\ChannelBundle\Behat\ChannelContext
|
||||
- Sylius\Bundle\CoreBundle\Behat\CoreContext
|
||||
- Sylius\Bundle\CoreBundle\Behat\HookContext
|
||||
- Sylius\Bundle\MoneyBundle\Behat\MoneyContext
|
||||
- Sylius\Bundle\ProductBundle\Behat\ProductContext
|
||||
- Sylius\Bundle\ResourceBundle\Behat\FixtureContext
|
||||
- Sylius\Bundle\ReviewBundle\Behat\ReviewContext
|
||||
- Sylius\Bundle\TaxationBundle\Behat\TaxationContext
|
||||
- Sylius\Bundle\TaxonomyBundle\Behat\TaxonomyContext
|
||||
- Sylius\Bundle\WebBundle\Behat\WebContext
|
||||
filters:
|
||||
tags: "@legacy_reviews"
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
@products
|
||||
Feature: Products
|
||||
In order to know and pick the products
|
||||
As a visitor
|
||||
I want to be able to browse products
|
||||
|
||||
Background:
|
||||
Given there is default currency configured
|
||||
And there are following taxonomies defined:
|
||||
| code | name |
|
||||
| RTX1 | Category |
|
||||
And there are following users:
|
||||
| email | password | enabled |
|
||||
| bar@foo.com | foo1 | yes |
|
||||
And taxonomy "Category" has following taxons:
|
||||
| Clothing[TX1] > T-Shirts[TX2] |
|
||||
| Clothing[TX1] > PHP T-Shirts[TX3] |
|
||||
| Clothing[TX1] > Gloves[TX4] |
|
||||
And there are following channels configured:
|
||||
| code | name | currencies | locales | url |
|
||||
| WEB-US | mystore.us | EUR, GBP | en_US | |
|
||||
| WEB-EU | mystore.eu | USD | en_GB, fr_FR, de_DE | localhost |
|
||||
And there are following attributes:
|
||||
| name | type |
|
||||
| T-Shirt fabric | text |
|
||||
And the following products exist:
|
||||
| name | price | taxons | pricing calculator | calculator configuration | attributes | average_rating |
|
||||
| Super T-Shirt | 19.99 | T-Shirts | channel_based | WEB-EU:15.99 | T-Shirt fabric:Wool | 0 |
|
||||
| Black T-Shirt | 18.99 | T-Shirts | | | | 0 |
|
||||
| Sylius Tee | 12.99 | PHP T-Shirts | | | | 0 |
|
||||
| Symfony T-Shirt | 15.00 | PHP T-Shirts | | | | 5 |
|
||||
| Doctrine T-Shirt | 15.00 | PHP T-Shirts | | | | 0 |
|
||||
And channel "WEB-EU" has following configuration:
|
||||
| taxonomy |
|
||||
| Category |
|
||||
And channel "WEB-EU" has following products assigned:
|
||||
| product |
|
||||
| Super T-Shirt |
|
||||
| Symfony T-Shirt |
|
||||
And channel "WEB-US" has following products assigned:
|
||||
| product |
|
||||
| Sylius Tee |
|
||||
| Black T-Shirt |
|
||||
| Doctrine T-Shirt |
|
||||
And there are following reviews:
|
||||
| title | rating | comment | author | product | subject type |
|
||||
| Lorem ipsum | 5 | Lorem ipsum dolor sit | bar@foo.com | Symfony T-Shirt | product |
|
||||
|
||||
Scenario: Displaying product rating and reviews:
|
||||
Given I am on the store homepage
|
||||
And I follow "PHP T-Shirts"
|
||||
When I click "Symfony T-Shirt"
|
||||
Then I should see "Rating: 5"
|
||||
And I should see 1 review on the reviews list
|
||||
|
||||
@javascript
|
||||
Scenario: Adding review as logged in user
|
||||
Given I am logged in as "bar@foo.com"
|
||||
And I am on the product page for "Symfony T-Shirt"
|
||||
When I fill in "Title" with "Very good"
|
||||
And I fill in "Comment" with "Very good shirt."
|
||||
And I select the "5" radio button
|
||||
And I press "Submit"
|
||||
And I wait 3 seconds
|
||||
Then I should see "Product review has been successfully created."
|
||||
|
||||
@javascript
|
||||
Scenario: Adding review as guest
|
||||
Given I am on the product page for "Symfony T-Shirt"
|
||||
When I fill in "Title" with "Very good"
|
||||
And I fill in "Comment" with "Very good shirt."
|
||||
And I fill in "Email" with "guest@example.com"
|
||||
And I select the "5" radio button
|
||||
And I press "Submit"
|
||||
And I wait 3 seconds
|
||||
Then I should see "Product review has been successfully created."
|
||||
|
||||
@javascript
|
||||
Scenario: Trying to add review as guest
|
||||
Given I am on the product page for "Symfony T-Shirt"
|
||||
When I fill in "Title" with "Very good"
|
||||
And I fill in "Comment" with "Very good shirt."
|
||||
And I fill in "Email" with "bar@foo.com"
|
||||
And I select the "5" radio button
|
||||
And I press "Submit"
|
||||
And I wait 3 seconds
|
||||
Then I should see "This email is already registered. Please log in."
|
||||
63
features/legacy/frontend/product_reviews.feature
Normal file
63
features/legacy/frontend/product_reviews.feature
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
@legacy_products
|
||||
Feature: Product reviews
|
||||
In order to rate and learn more about the products
|
||||
As a Visitor
|
||||
I want to browse and post product reviews
|
||||
|
||||
Background:
|
||||
Given there is default currency configured
|
||||
And there are following users:
|
||||
| email | password | enabled |
|
||||
| bar@foo.com | foo1 | yes |
|
||||
And there are following channels configured:
|
||||
| code | name | currencies | locales | url |
|
||||
| WEB-EU | mystore.eu | USD | en_GB, fr_FR, de_DE | localhost |
|
||||
And the following products exist:
|
||||
| name | price | pricing calculator | calculator configuration | attributes |
|
||||
| Symfony T-Shirt | 15.00 | | | |
|
||||
And channel "WEB-EU" has following products assigned:
|
||||
| product |
|
||||
| Symfony T-Shirt |
|
||||
And there are following reviews:
|
||||
| title | rating | comment | author | product | subject type |
|
||||
| Lorem ipsum | 5 | Lorem ipsum dolor sit | bar@foo.com | Symfony T-Shirt | product |
|
||||
| Consectetur | 4 | Consectetur adipiscing | bar@foo.com | Symfony T-Shirt | product |
|
||||
| Proin nibh | 3 | Proin nibh augue | bar@foo.com | Symfony T-Shirt | product |
|
||||
|
||||
Scenario: Displaying product rating and reviews:
|
||||
When I am on the product page for "Symfony T-Shirt"
|
||||
Then I should see "Rating: 4"
|
||||
And I should see 3 review on the reviews list
|
||||
|
||||
@javascript
|
||||
Scenario: Adding review as logged in user
|
||||
Given I am logged in as "bar@foo.com"
|
||||
And I am on the product page for "Symfony T-Shirt"
|
||||
When I fill in "Title" with "Very good"
|
||||
And I fill in "Comment" with "Very good shirt."
|
||||
And I select the "5" radio button
|
||||
And I press "Submit"
|
||||
And I wait 3 seconds
|
||||
Then I should see "Product review has been successfully created."
|
||||
|
||||
@javascript
|
||||
Scenario: Adding review as guest
|
||||
Given I am on the product page for "Symfony T-Shirt"
|
||||
When I fill in "Title" with "Very good"
|
||||
And I fill in "Comment" with "Very good shirt."
|
||||
And I fill in "Email" with "guest@example.com"
|
||||
And I select the "5" radio button
|
||||
And I press "Submit"
|
||||
And I wait 3 seconds
|
||||
Then I should see "Product review has been successfully created."
|
||||
|
||||
@javascript
|
||||
Scenario: Trying to add review as guest
|
||||
Given I am on the product page for "Symfony T-Shirt"
|
||||
When I fill in "Title" with "Very good"
|
||||
And I fill in "Comment" with "Very good shirt."
|
||||
And I fill in "Email" with "bar@foo.com"
|
||||
And I select the "5" radio button
|
||||
And I press "Submit"
|
||||
And I wait 3 seconds
|
||||
Then I should see "This email is already registered, please login or use forgotten password."
|
||||
|
|
@ -1,80 +1,80 @@
|
|||
@legacy_products
|
||||
Feature: Products
|
||||
In order to know and pick the products
|
||||
As a visitor
|
||||
I want to be able to browse products
|
||||
In order to know and pick the products
|
||||
As a visitor
|
||||
I want to be able to browse products
|
||||
|
||||
Background:
|
||||
Given there is default currency configured
|
||||
And there are following taxonomies defined:
|
||||
| code | name |
|
||||
| RTX1 | Category |
|
||||
And taxonomy "Category" has following taxons:
|
||||
| Clothing[TX1] > T-Shirts[TX2] |
|
||||
| Clothing[TX1] > PHP T-Shirts[TX3] |
|
||||
| Clothing[TX1] > Gloves[TX4] |
|
||||
And there are following channels configured:
|
||||
| code | name | currencies | locales | url |
|
||||
| WEB-US | mystore.us | EUR, GBP | en_US | |
|
||||
| WEB-EU | mystore.eu | USD | en_GB, fr_FR, de_DE | localhost |
|
||||
And there are following attributes:
|
||||
| name | type |
|
||||
| T-Shirt fabric | text |
|
||||
And the following products exist:
|
||||
| name | price | taxons | pricing calculator | calculator configuration | attributes |
|
||||
| Super T-Shirt | 19.99 | T-Shirts | channel_based | WEB-EU:15.99 | T-Shirt fabric:Wool |
|
||||
| Black T-Shirt | 18.99 | T-Shirts | | | |
|
||||
| Sylius Tee | 12.99 | PHP T-Shirts | | | |
|
||||
| Symfony T-Shirt | 15.00 | PHP T-Shirts | | | |
|
||||
| Doctrine T-Shirt | 15.00 | PHP T-Shirts | | | |
|
||||
And channel "WEB-EU" has following configuration:
|
||||
| taxonomy |
|
||||
| Category |
|
||||
And channel "WEB-EU" has following products assigned:
|
||||
| product |
|
||||
| Super T-Shirt |
|
||||
| Symfony T-Shirt |
|
||||
And channel "WEB-US" has following products assigned:
|
||||
| product |
|
||||
| Sylius Tee |
|
||||
| Black T-Shirt |
|
||||
| Doctrine T-Shirt |
|
||||
And there are following reviews:
|
||||
| title | rating | comment | author | product | subject type |
|
||||
| Lorem ipsum | 5 | Lorem ipsum dolor sit | bar@foo.com | Symfony T-Shirt | product |
|
||||
Background:
|
||||
Given there is default currency configured
|
||||
And there are following taxonomies defined:
|
||||
| code | name |
|
||||
| RTX1 | Category |
|
||||
And taxonomy "Category" has following taxons:
|
||||
| Clothing[TX1] > T-Shirts[TX2] |
|
||||
| Clothing[TX1] > PHP T-Shirts[TX3] |
|
||||
| Clothing[TX1] > Gloves[TX4] |
|
||||
And there are following channels configured:
|
||||
| code | name | currencies | locales | url |
|
||||
| WEB-US | mystore.us | EUR, GBP | en_US | |
|
||||
| WEB-EU | mystore.eu | USD | en_GB, fr_FR, de_DE | localhost |
|
||||
And there are following attributes:
|
||||
| name | type |
|
||||
| T-Shirt fabric | text |
|
||||
And the following products exist:
|
||||
| name | price | taxons | pricing calculator | calculator configuration | attributes |
|
||||
| Super T-Shirt | 19.99 | T-Shirts | channel_based | WEB-EU:15.99 | T-Shirt fabric:Wool |
|
||||
| Black T-Shirt | 18.99 | T-Shirts | | | |
|
||||
| Sylius Tee | 12.99 | PHP T-Shirts | | | |
|
||||
| Symfony T-Shirt | 15.00 | PHP T-Shirts | | | |
|
||||
| Doctrine T-Shirt | 15.00 | PHP T-Shirts | | | |
|
||||
And channel "WEB-EU" has following configuration:
|
||||
| taxonomy |
|
||||
| Category |
|
||||
And channel "WEB-EU" has following products assigned:
|
||||
| product |
|
||||
| Super T-Shirt |
|
||||
| Symfony T-Shirt |
|
||||
And channel "WEB-US" has following products assigned:
|
||||
| product |
|
||||
| Sylius Tee |
|
||||
| Black T-Shirt |
|
||||
| Doctrine T-Shirt |
|
||||
And there are following reviews:
|
||||
| title | rating | comment | author | product | subject type |
|
||||
| Lorem ipsum | 5 | Lorem ipsum dolor sit | bar@foo.com | Symfony T-Shirt | product |
|
||||
|
||||
Scenario: Browsing products by taxon
|
||||
Given I am on the store homepage
|
||||
When I follow "T-Shirts"
|
||||
Then I should see there 1 products
|
||||
And I should see "Super T-Shirt"
|
||||
Scenario: Browsing products by taxon
|
||||
Given I am on the store homepage
|
||||
When I follow "T-Shirts"
|
||||
Then I should see there 1 products
|
||||
And I should see "Super T-Shirt"
|
||||
|
||||
Scenario: Empty index of products
|
||||
Given there are no products
|
||||
And I am on the store homepage
|
||||
When I follow "Gloves"
|
||||
Then I should see "There are no products to display"
|
||||
Scenario: Empty index of products
|
||||
Given there are no products
|
||||
And I am on the store homepage
|
||||
When I follow "Gloves"
|
||||
Then I should see "There are no products to display"
|
||||
|
||||
Scenario: Accessing product page via title
|
||||
Given I am on the store homepage
|
||||
And I follow "PHP T-Shirts"
|
||||
When I click "Symfony T-Shirt"
|
||||
Then I should be on the product page for "Symfony T-Shirt"
|
||||
Scenario: Accessing product page via title
|
||||
Given I am on the store homepage
|
||||
And I follow "PHP T-Shirts"
|
||||
When I click "Symfony T-Shirt"
|
||||
Then I should be on the product page for "Symfony T-Shirt"
|
||||
|
||||
Scenario: Display only products for current channel
|
||||
Given I am on the store homepage
|
||||
Then I should see "Super T-Shirt"
|
||||
But I should not see "Black T-Shirt"
|
||||
Scenario: Display only products for current channel
|
||||
Given I am on the store homepage
|
||||
Then I should see "Super T-Shirt"
|
||||
But I should not see "Black T-Shirt"
|
||||
|
||||
Scenario: Display proper product price for specific channel
|
||||
Given I am on the store homepage
|
||||
Then I should see "Super T-shirt"
|
||||
And I should see "€15.99"
|
||||
Scenario: Display proper product price for specific channel
|
||||
Given I am on the store homepage
|
||||
Then I should see "Super T-shirt"
|
||||
And I should see "€15.99"
|
||||
|
||||
Scenario: Display product attributes
|
||||
Given I am on the product page for "Super T-shirt"
|
||||
Then I should see "Wool"
|
||||
Scenario: Display product attributes
|
||||
Given I am on the product page for "Super T-shirt"
|
||||
Then I should see "Wool"
|
||||
|
||||
Scenario: Receiving exception while entering page for product with empty slug
|
||||
Given I go to page for product with empty slug
|
||||
Then the response status code should be 404
|
||||
Scenario: Receiving exception while entering page for product with empty slug
|
||||
Given I go to page for product with empty slug
|
||||
Then the response status code should be 404
|
||||
|
|
|
|||
129
features/legacy/reviews/reviews.feature
Normal file
129
features/legacy/reviews/reviews.feature
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
@legacy_reviews
|
||||
Feature: Reviews
|
||||
In orders to know customer's opinions about my products
|
||||
As a store owner
|
||||
I want to be able to manage reviews
|
||||
|
||||
Background:
|
||||
Given there are following users:
|
||||
| email |
|
||||
| beth@foo.com |
|
||||
| martha@foo.com |
|
||||
| rick@foo.com |
|
||||
And the following products exist:
|
||||
| name | price | average rating |
|
||||
| Black T-Shirt | 18.99 | 4 |
|
||||
| Sylius Tee | 12.99 | 5 |
|
||||
| Symfony T-Shirt | 15.00 | 1 |
|
||||
And there are following reviews:
|
||||
| title | rating | comment | author | product | subject type | status |
|
||||
| Really bad | 1 | Lorem ipsum dolor sit | beth@foo.com | Symfony T-Shirt | product | |
|
||||
| Very good | 4 | Lorem ipsum dolor sit | martha@foo.com | Black T-Shirt | product | |
|
||||
| Awesome | 5 | Lorem ipsum dolor sit | rick@foo.com | Sylius Tee | product | new |
|
||||
And there is default currency configured
|
||||
And there is default channel configured
|
||||
And I am logged in as administrator
|
||||
|
||||
Scenario: Seeing created reviews in the list
|
||||
Given I am on the dashboard page
|
||||
When I follow "Product reviews"
|
||||
Then I should see 3 reviews in the list
|
||||
|
||||
Scenario: Adding new review with default options
|
||||
Given I am on the product review creation page
|
||||
When I fill in the following:
|
||||
| Title | New review |
|
||||
| Comment | Lorem ipsum dolor |
|
||||
And I select the "5" radio button
|
||||
And I press "Create"
|
||||
Then I should be on the page of product review with title "New review"
|
||||
And I should see "Review has been successfully created."
|
||||
And I should see "Lorem ipsum dolor"
|
||||
|
||||
Scenario: Prevent adding review without required fields
|
||||
Given I am on the product review creation page
|
||||
When I press "Create"
|
||||
Then I should still be on the product review creation page
|
||||
And I should see "You must check review rating."
|
||||
And I should see "Review title should not be blank."
|
||||
|
||||
Scenario: Accessing review edit page from the list
|
||||
Given I am on the product review index page
|
||||
When I press "Edit" near "Very good"
|
||||
Then I should be editing product review with title "Very good"
|
||||
|
||||
Scenario: Accessing review edit page from details page
|
||||
Given I am on the page of product review with title "Very good"
|
||||
When I follow "Edit"
|
||||
Then I should be editing product review with title "Very good"
|
||||
|
||||
Scenario: Updating review
|
||||
Given I am editing product review with title "Very good"
|
||||
When I fill in "Title" with "Very, very good"
|
||||
And I press "Save changes"
|
||||
Then I should be on the page of product review with title "Very, very good"
|
||||
|
||||
@javascript
|
||||
Scenario: Removing review from the list
|
||||
Given I am on the product review index page
|
||||
When I press "Delete" near "Awesome"
|
||||
And I click "Delete" from the confirmation modal
|
||||
Then I should still be on the product review index page
|
||||
And I should see "Review has been successfully deleted."
|
||||
|
||||
@javascript
|
||||
Scenario: Removing review from details page
|
||||
Given I am on the page of product review with title "Awesome"
|
||||
When I press "Delete"
|
||||
And I click "Delete" from the confirmation modal
|
||||
Then I should be on the product review index page
|
||||
And I should see "Review has been successfully deleted."
|
||||
|
||||
Scenario: Showing review details
|
||||
Given I am on the product review index page
|
||||
When I click "Details" near "Awesome"
|
||||
Then I should be on the page of product review with title "Awesome"
|
||||
And I should see "Awesome"
|
||||
And I should see "rick@foo.com"
|
||||
And I should see "Lorem ipsum dolor"
|
||||
|
||||
Scenario: Accepting review from the list
|
||||
Given I am on the product review index page
|
||||
When I press "Accept" near "Awesome"
|
||||
Then I should see "Product review has been successfully updated."
|
||||
When I press "Details" near "Awesome"
|
||||
Then I should see "accepted"
|
||||
|
||||
Scenario: Accepting review from details page
|
||||
Given I am on the page of product review with title "Awesome"
|
||||
When I press "Accept"
|
||||
Then I should see "Product review has been successfully updated."
|
||||
And I should see "accepted"
|
||||
And I should not see "Reject" button
|
||||
And I should not see "Accept" button
|
||||
|
||||
Scenario: Rejecting review from the list
|
||||
Given I am on the product review index page
|
||||
When I press "Reject" near "Awesome"
|
||||
And I press "Details" near "Awesome"
|
||||
Then I should see "rejected"
|
||||
|
||||
Scenario: Rejecting review from details page
|
||||
Given I am on the page of product review with title "Awesome"
|
||||
When I press "Reject"
|
||||
Then I should see "Product review has been successfully updated."
|
||||
And I should see "rejected"
|
||||
And I should not see "Reject" button
|
||||
And I should not see "Accept" button
|
||||
|
||||
Scenario: Seeing reviews list after customer deletion
|
||||
Given customer "beth@foo.com" has been deleted
|
||||
And I am on the product review index page
|
||||
Then I should see 2 reviews in the list
|
||||
And I should not see "Really bad"
|
||||
|
||||
Scenario: Seeing review list after product deletion
|
||||
Given product "Symfony T-Shirt" has been deleted
|
||||
And I am on the product review index page
|
||||
Then I should see 2 reviews in the list
|
||||
And I should not see "Really bad"
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
@reviews
|
||||
Feature: Reviews
|
||||
In orders to know customer's opinions about my products
|
||||
As a store owner
|
||||
I want to be able to manage reviews
|
||||
|
||||
Background:
|
||||
Given there are following users:
|
||||
| email |
|
||||
| beth@foo.com |
|
||||
| martha@foo.com |
|
||||
| rick@foo.com |
|
||||
And there are following taxonomies defined:
|
||||
| code | name |
|
||||
| TRX1 | Category |
|
||||
And taxonomy "Category" has following taxons:
|
||||
| Clothing[TX1] > T-Shirts[TX2] |
|
||||
| Clothing[TX1] > PHP T-Shirts[TX3] |
|
||||
| Clothing[TX1] > PHP T-Gloves[TX4] |
|
||||
And the following products exist:
|
||||
| name | price | taxons | average rating |
|
||||
| Super T-Shirt | 19.99 | T-Shirts | 0 |
|
||||
| Black T-Shirt | 18.99 | T-Shirts | 4 |
|
||||
| Sylius Tee | 12.99 | PHP T-Shirts | 5 |
|
||||
| Symfony T-Shirt | 15.00 | PHP T-Shirts | 1 |
|
||||
| Doctrine T-Shirt | 15.00 | PHP T-Shirts | 0 |
|
||||
And there are following reviews:
|
||||
| title | rating | comment | author | product | subject type | status |
|
||||
| Really bad | 1 | Lorem ipsum dolor sit | beth@foo.com | Symfony T-Shirt | product | |
|
||||
| Very good | 4 | Lorem ipsum dolor sit | martha@foo.com | Black T-Shirt | product | |
|
||||
| Awesome | 5 | Lorem ipsum dolor sit | rick@foo.com | Sylius Tee | product | new |
|
||||
And there is default currency configured
|
||||
And there is default channel configured
|
||||
And I am logged in as administrator
|
||||
|
||||
Scenario: Seeing created reviews in the list
|
||||
Given I am on the dashboard page
|
||||
When I follow "Product reviews"
|
||||
Then I should see 3 reviews in the list
|
||||
|
||||
Scenario: Adding new review with default options
|
||||
Given I am on the product review creation page
|
||||
When I fill in the following:
|
||||
| Title | New review |
|
||||
| Comment | Lorem ipsum dolor |
|
||||
And I select the "5" radio button
|
||||
And I press "Create"
|
||||
Then I should be on the page of product review with title "New review"
|
||||
And I should see "Review has been successfully created."
|
||||
And I should see "Lorem ipsum dolor"
|
||||
|
||||
Scenario: Prevent adding review without required fields
|
||||
Given I am on the product review creation page
|
||||
When I press "Create"
|
||||
Then I should still be on the product review creation page
|
||||
And I should see "You must check review rating."
|
||||
And I should see "Review title should not be blank."
|
||||
|
||||
Scenario: Accessing review edit page from the list
|
||||
Given I am on the product review index page
|
||||
When I press "Edit" near "Very good"
|
||||
Then I should be editing product review with title "Very good"
|
||||
|
||||
Scenario: Accessing review edit page from details page
|
||||
Given I am on the page of product review with title "Very good"
|
||||
When I follow "Edit"
|
||||
Then I should be editing product review with title "Very good"
|
||||
|
||||
Scenario: Updating review
|
||||
Given I am editing product review with title "Very good"
|
||||
When I fill in "Title" with "Very, very good"
|
||||
And I press "Save changes"
|
||||
Then I should be on the page of product review with title "Very, very good"
|
||||
|
||||
@javascript
|
||||
Scenario: Removing review from the list
|
||||
Given I am on the product review index page
|
||||
When I press "Delete" near "Awesome"
|
||||
And I click "Delete" from the confirmation modal
|
||||
Then I should still be on the product review index page
|
||||
And I should see "Review has been successfully deleted."
|
||||
|
||||
@javascript
|
||||
Scenario: Removing review from details page
|
||||
Given I am on the page of product review with title "Awesome"
|
||||
When I press "Delete"
|
||||
And I click "Delete" from the confirmation modal
|
||||
Then I should be on the product review index page
|
||||
And I should see "Review has been successfully deleted."
|
||||
|
||||
Scenario: Showing review details
|
||||
Given I am on the product review index page
|
||||
When I click "Details" near "Awesome"
|
||||
Then I should be on the page of product review with title "Awesome"
|
||||
And I should see "Awesome"
|
||||
And I should see "rick@foo.com"
|
||||
And I should see "Lorem ipsum dolor"
|
||||
|
||||
Scenario: Accepting review from the list
|
||||
Given I am on the product review index page
|
||||
When I press "Accept" near "Awesome"
|
||||
Then I should see "Product review has been successfully updated."
|
||||
When I press "Details" near "Awesome"
|
||||
Then I should see "accepted"
|
||||
|
||||
Scenario: Accepting review from details page
|
||||
Given I am on the page of product review with title "Awesome"
|
||||
When I press "Accept"
|
||||
Then I should see "Product review has been successfully updated."
|
||||
And I should see "accepted"
|
||||
And I should not see "Reject" button
|
||||
And I should not see "Accept" button
|
||||
|
||||
Scenario: Rejecting review from the list
|
||||
Given I am on the product review index page
|
||||
When I press "Reject" near "Awesome"
|
||||
Then I should see "Product review has been successfully updated."
|
||||
When I press "Details" near "Awesome"
|
||||
Then I should see "rejected"
|
||||
|
||||
Scenario: Rejecting review from details page
|
||||
Given I am on the page of product review with title "Awesome"
|
||||
When I press "Reject"
|
||||
Then I should see "Product review has been successfully updated."
|
||||
And I should see "rejected"
|
||||
And I should not see "Reject" button
|
||||
And I should not see "Accept" button
|
||||
|
||||
Scenario: Seeing reviews list after customer deletion
|
||||
Given customer "beth@foo.com" has been deleted
|
||||
And I am on the product review index page
|
||||
Then I should see 2 reviews in the list
|
||||
And I should not see "Really bad"
|
||||
|
||||
Scenario: Seeing review list after product deletion
|
||||
Given product "Symfony T-Shirt" has been deleted
|
||||
And I am on the product review index page
|
||||
Then I should see 2 reviews in the list
|
||||
And I should not see "Really bad"
|
||||
70
phpspec.yml
70
phpspec.yml
|
|
@ -1,70 +0,0 @@
|
|||
suites:
|
||||
Addressing : { namespace: Sylius\Component\Addressing, psr4_prefix: Sylius\Component\Addressing, spec_path: src/Sylius/Component/Addressing, src_path: src/Sylius/Component/Addressing }
|
||||
Archetype : { namespace: Sylius\Component\Archetype, psr4_prefix: Sylius\Component\Archetype, spec_path: src/Sylius/Component/Archetype, src_path: src/Sylius/Component/Archetype }
|
||||
Attribute : { namespace: Sylius\Component\Attribute, psr4_prefix: Sylius\Component\Attribute, spec_path: src/Sylius/Component/Attribute, src_path: src/Sylius/Component/Attribute }
|
||||
Cart : { namespace: Sylius\Component\Cart, psr4_prefix: Sylius\Component\Cart, spec_path: src/Sylius/Component/Cart, src_path: src/Sylius/Component/Cart }
|
||||
Channel : { namespace: Sylius\Component\Channel, psr4_prefix: Sylius\Component\Channel, spec_path: src/Sylius/Component/Channel, src_path: src/Sylius/Component/Channel }
|
||||
Contact : { namespace: Sylius\Component\Contact, psr4_prefix: Sylius\Component\Contact, spec_path: src/Sylius/Component/Contact, src_path: src/Sylius/Component/Contact }
|
||||
Core : { namespace: Sylius\Component\Core, psr4_prefix: Sylius\Component\Core, spec_path: src/Sylius/Component/Core, src_path: src/Sylius/Component/Core }
|
||||
Currency : { namespace: Sylius\Component\Currency, psr4_prefix: Sylius\Component\Currency, spec_path: src/Sylius/Component/Currency, src_path: src/Sylius/Component/Currency }
|
||||
Inventory : { namespace: Sylius\Component\Inventory, psr4_prefix: Sylius\Component\Inventory, spec_path: src/Sylius/Component/Inventory, src_path: src/Sylius/Component/Inventory }
|
||||
Locale : { namespace: Sylius\Component\Locale, psr4_prefix: Sylius\Component\Locale, spec_path: src/Sylius/Component/Locale, src_path: src/Sylius/Component/Locale }
|
||||
Mailer : { namespace: Sylius\Component\Mailer, psr4_prefix: Sylius\Component\Mailer, spec_path: src/Sylius/Component/Mailer, src_path: src/Sylius/Component/Mailer }
|
||||
Order : { namespace: Sylius\Component\Order, psr4_prefix: Sylius\Component\Order, spec_path: src/Sylius/Component/Order, src_path: src/Sylius/Component/Order }
|
||||
Originator : { namespace: Sylius\Component\Originator, psr4_prefix: Sylius\Component\Originator, spec_path: src/Sylius/Component/Originator, src_path: src/Sylius/Component/Originator }
|
||||
Payment : { namespace: Sylius\Component\Payment, psr4_prefix: Sylius\Component\Payment , spec_path: src/Sylius/Component/Payment, src_path: src/Sylius/Component/Payment }
|
||||
Pricing : { namespace: Sylius\Component\Pricing, psr4_prefix: Sylius\Component\Pricing , spec_path: src/Sylius/Component/Pricing, src_path: src/Sylius/Component/Pricing }
|
||||
Product : { namespace: Sylius\Component\Product, psr4_prefix: Sylius\Component\Product , spec_path: src/Sylius/Component/Product, src_path: src/Sylius/Component/Product }
|
||||
Promotion : { namespace: Sylius\Component\Promotion, psr4_prefix: Sylius\Component\Promotion, spec_path: src/Sylius/Component/Promotion, src_path: src/Sylius/Component/Promotion }
|
||||
Rbac : { namespace: Sylius\Component\Rbac, psr4_prefix: Sylius\Component\Rbac, spec_path: src/Sylius/Component/Rbac, src_path: src/Sylius/Component/Rbac }
|
||||
Registry : { namespace: Sylius\Component\Registry, psr4_prefix: Sylius\Component\Registry, spec_path: src/Sylius/Component/Registry, src_path: src/Sylius/Component/Registry }
|
||||
Report : { namespace: Sylius\Component\Report, psr4_prefix: Sylius\Component\Report , spec_path: src/Sylius/Component/Report, src_path: src/Sylius/Component/Report }
|
||||
Review : { namespace: Sylius\Component\Review, psr4_prefix: Sylius\Component\Review , spec_path: src/Sylius/Component/Review, src_path: src/Sylius/Component/Review }
|
||||
Resource : { namespace: Sylius\Component\Resource, psr4_prefix: Sylius\Component\Resource, spec_path: src/Sylius/Component/Resource, src_path: src/Sylius/Component/Resource }
|
||||
Sequence : { namespace: Sylius\Component\Sequence, psr4_prefix: Sylius\Component\Sequence, spec_path: src/Sylius/Component/Sequence, src_path: src/Sylius/Component/Sequence }
|
||||
Shipping : { namespace: Sylius\Component\Shipping, psr4_prefix: Sylius\Component\Shipping, spec_path: src/Sylius/Component/Shipping, src_path: src/Sylius/Component/Shipping }
|
||||
Storage : { namespace: Sylius\Component\Storage, psr4_prefix: Sylius\Component\Storage , spec_path: src/Sylius/Component/Storage, src_path: src/Sylius/Component/Storage }
|
||||
Taxation : { namespace: Sylius\Component\Taxation, psr4_prefix: Sylius\Component\Taxation, spec_path: src/Sylius/Component/Taxation, src_path: src/Sylius/Component/Taxation }
|
||||
Taxonomy : { namespace: Sylius\Component\Taxonomy, psr4_prefix: Sylius\Component\Taxonomy, spec_path: src/Sylius/Component/Taxonomy, src_path: src/Sylius/Component/Taxonomy }
|
||||
Translation : { namespace: Sylius\Component\Translation, psr4_prefix: Sylius\Component\Translation, spec_path: src/Sylius/Component/Translation, src_path: src/Sylius/Component/Translation }
|
||||
User : { namespace: Sylius\Component\User, psr4_prefix: Sylius\Component\User, spec_path: src/Sylius/Component/User, src_path: src/Sylius/Component/User }
|
||||
Variation : { namespace: Sylius\Component\Variation, psr4_prefix: Sylius\Component\Variation, spec_path: src/Sylius/Component/Variation, src_path: src/Sylius/Component/Variation }
|
||||
|
||||
AddressingBundle : { namespace: Sylius\Bundle\AddressingBundle, psr4_prefix: Sylius\Bundle\AddressingBundle, spec_path: src/Sylius/Bundle/AddressingBundle, src_path: src/Sylius/Bundle/AddressingBundle }
|
||||
ApiBundle : { namespace: Sylius\Bundle\ApiBundle, psr4_prefix: Sylius\Bundle\ApiBundle, spec_path: src/Sylius/Bundle/ApiBundle, src_path: src/Sylius/Bundle/ApiBundle }
|
||||
ArchetypeBundle : { namespace: Sylius\Bundle\ArchetypeBundle, psr4_prefix: Sylius\Bundle\ArchetypeBundle, spec_path: src/Sylius/Bundle/ArchetypeBundle, src_path: src/Sylius/Bundle/ArchetypeBundle }
|
||||
AttributeBundle : { namespace: Sylius\Bundle\AttributeBundle, psr4_prefix: Sylius\Bundle\AttributeBundle, spec_path: src/Sylius/Bundle/AttributeBundle, src_path: src/Sylius/Bundle/AttributeBundle }
|
||||
CartBundle : { namespace: Sylius\Bundle\CartBundle, psr4_prefix: Sylius\Bundle\CartBundle, spec_path: src/Sylius/Bundle/CartBundle, src_path: src/Sylius/Bundle/CartBundle }
|
||||
ChannelBundle : { namespace: Sylius\Bundle\ChannelBundle, psr4_prefix: Sylius\Bundle\ChannelBundle, spec_path: src/Sylius/Bundle/ChannelBundle, src_path: src/Sylius/Bundle/ChannelBundle }
|
||||
ContactBundle : { namespace: Sylius\Bundle\ContactBundle, psr4_prefix: Sylius\Bundle\ContactBundle, spec_path: src/Sylius/Bundle/ContactBundle, src_path: src/Sylius/Bundle/ContactBundle }
|
||||
ContentBundle : { namespace: Sylius\Bundle\ContentBundle, psr4_prefix: Sylius\Bundle\ContentBundle, spec_path: src/Sylius/Bundle/ContentBundle, src_path: src/Sylius/Bundle/ContentBundle }
|
||||
CoreBundle : { namespace: Sylius\Bundle\CoreBundle, psr4_prefix: Sylius\Bundle\CoreBundle, spec_path: src/Sylius/Bundle/CoreBundle, src_path: src/Sylius/Bundle/CoreBundle }
|
||||
CurrencyBundle : { namespace: Sylius\Bundle\CurrencyBundle, psr4_prefix: Sylius\Bundle\CurrencyBundle , spec_path: src/Sylius/Bundle/CurrencyBundle, src_path: src/Sylius/Bundle/CurrencyBundle }
|
||||
FlowBundle : { namespace: Sylius\Bundle\FlowBundle, psr4_prefix: Sylius\Bundle\FlowBundle, spec_path: src/Sylius/Bundle/FlowBundle, src_path: src/Sylius/Bundle/FlowBundle }
|
||||
InstallerBundle : { namespace: Sylius\Bundle\InstallerBundle, psr4_prefix: Sylius\Bundle\InstallerBundle, spec_path: src/Sylius/Bundle/InstallerBundle, src_path: src/Sylius/Bundle/InstallerBundle }
|
||||
InventoryBundle : { namespace: Sylius\Bundle\InventoryBundle, psr4_prefix: Sylius\Bundle\InventoryBundle, spec_path: src/Sylius/Bundle/InventoryBundle, src_path: src/Sylius/Bundle/InventoryBundle }
|
||||
LocaleBundle : { namespace: Sylius\Bundle\LocaleBundle, psr4_prefix: Sylius\Bundle\LocaleBundle, spec_path: src/Sylius/Bundle/LocaleBundle, src_path: src/Sylius/Bundle/LocaleBundle }
|
||||
MailerBundle : { namespace: Sylius\Bundle\MailerBundle, psr4_prefix: Sylius\Bundle\MailerBundle, spec_path: src/Sylius/Bundle/MailerBundle, src_path: src/Sylius/Bundle/MailerBundle }
|
||||
MoneyBundle : { namespace: Sylius\Bundle\MoneyBundle, psr4_prefix: Sylius\Bundle\MoneyBundle, spec_path: src/Sylius/Bundle/MoneyBundle, src_path: src/Sylius/Bundle/MoneyBundle }
|
||||
OrderBundle : { namespace: Sylius\Bundle\OrderBundle, psr4_prefix: Sylius\Bundle\OrderBundle, spec_path: src/Sylius/Bundle/OrderBundle, src_path: src/Sylius/Bundle/OrderBundle }
|
||||
PaymentBundle : { namespace: Sylius\Bundle\PaymentBundle, psr4_prefix: Sylius\Bundle\PaymentBundle, spec_path: src/Sylius/Bundle/PaymentBundle, src_path: src/Sylius/Bundle/PaymentBundle }
|
||||
PayumBundle : { namespace: Sylius\Bundle\PayumBundle, psr4_prefix: Sylius\Bundle\PayumBundle, spec_path: src/Sylius/Bundle/PayumBundle, src_path: src/Sylius/Bundle/PayumBundle }
|
||||
PricingBundle : { namespace: Sylius\Bundle\PricingBundle, psr4_prefix: Sylius\Bundle\PricingBundle, spec_path: src/Sylius/Bundle/PricingBundle, src_path: src/Sylius/Bundle/PricingBundle }
|
||||
ProductBundle : { namespace: Sylius\Bundle\ProductBundle, psr4_prefix: Sylius\Bundle\ProductBundle, spec_path: src/Sylius/Bundle/ProductBundle, src_path: src/Sylius/Bundle/ProductBundle }
|
||||
PromotionBundle : { namespace: Sylius\Bundle\PromotionBundle, psr4_prefix: Sylius\Bundle\PromotionBundle, spec_path: src/Sylius/Bundle/PromotionBundle, src_path: src/Sylius/Bundle/PromotionBundle }
|
||||
RbacBundle : { namespace: Sylius\Bundle\RbacBundle, psr4_prefix: Sylius\Bundle\RbacBundle, spec_path: src/Sylius/Bundle/RbacBundle, src_path: src/Sylius/Bundle/RbacBundle }
|
||||
ReportBundle : { namespace: Sylius\Bundle\ReportBundle, psr4_prefix: Sylius\Bundle\ReportBundle , spec_path: src/Sylius/Bundle/ReportBundle, src_path: src/Sylius/Bundle/ReportBundle }
|
||||
ResourceBundle : { namespace: Sylius\Bundle\ResourceBundle, psr4_prefix: Sylius\Bundle\ResourceBundle , spec_path: src/Sylius/Bundle/ResourceBundle, src_path: src/Sylius/Bundle/ResourceBundle }
|
||||
ReviewBundle : { namespace: Sylius\Bundle\ReviewBundle, psr4_prefix: Sylius\Bundle\ReviewBundle , spec_path: src/Sylius/Bundle/ReviewBundle, src_path: src/Sylius/Bundle/ReviewBundle }
|
||||
SearchBundle : { namespace: Sylius\Bundle\SearchBundle, psr4_prefix: Sylius\Bundle\SearchBundle, spec_path: src/Sylius/Bundle/SearchBundle, src_path: src/Sylius/Bundle/SearchBundle }
|
||||
SequenceBundle : { namespace: Sylius\Bundle\SequenceBundle, psr4_prefix: Sylius\Bundle\SequenceBundle , spec_path: src/Sylius/Bundle/SequenceBundle, src_path: src/Sylius/Bundle/SequenceBundle }
|
||||
SettingsBundle : { namespace: Sylius\Bundle\SettingsBundle, psr4_prefix: Sylius\Bundle\SettingsBundle , spec_path: src/Sylius/Bundle/SettingsBundle, src_path: src/Sylius/Bundle/SettingsBundle }
|
||||
ShippingBundle : { namespace: Sylius\Bundle\ShippingBundle, psr4_prefix: Sylius\Bundle\ShippingBundle , spec_path: src/Sylius/Bundle/ShippingBundle, src_path: src/Sylius/Bundle/ShippingBundle }
|
||||
TaxationBundle : { namespace: Sylius\Bundle\TaxationBundle, psr4_prefix: Sylius\Bundle\TaxationBundle , spec_path: src/Sylius/Bundle/TaxationBundle, src_path: src/Sylius/Bundle/TaxationBundle }
|
||||
TaxonomyBundle : { namespace: Sylius\Bundle\TaxonomyBundle, psr4_prefix: Sylius\Bundle\TaxonomyBundle , spec_path: src/Sylius/Bundle/TaxonomyBundle, src_path: src/Sylius/Bundle/TaxonomyBundle }
|
||||
TranslationBundle : { namespace: Sylius\Bundle\TranslationBundle, psr4_prefix: Sylius\Bundle\TranslationBundle , spec_path: src/Sylius/Bundle/TranslationBundle, src_path: src/Sylius/Bundle/TranslationBundle }
|
||||
VariationBundle : { namespace: Sylius\Bundle\VariationBundle, psr4_prefix: Sylius\Bundle\VariationBundle, spec_path: src/Sylius/Bundle/VariationBundle, src_path: src/Sylius/Bundle/VariationBundle }
|
||||
UserBundle : { namespace: Sylius\Bundle\UserBundle, psr4_prefix: Sylius\Bundle\UserBundle, spec_path: src/Sylius/Bundle/UserBundle, src_path: src/Sylius/Bundle/UserBundle }
|
||||
|
||||
extensions:
|
||||
- Akeneo\SkipExampleExtension
|
||||
|
|
@ -21,6 +21,7 @@ suites:
|
|||
Registry: { namespace: Sylius\Component\Registry, psr4_prefix: Sylius\Component\Registry, spec_path: src/Sylius/Component/Registry, src_path: src/Sylius/Component/Registry }
|
||||
Report: { namespace: Sylius\Component\Report, psr4_prefix: Sylius\Component\Report, spec_path: src/Sylius/Component/Report, src_path: src/Sylius/Component/Report }
|
||||
Resource: { namespace: Sylius\Component\Resource, psr4_prefix: Sylius\Component\Resource, spec_path: src/Sylius/Component/Resource, src_path: src/Sylius/Component/Resource }
|
||||
Review: { namespace: Sylius\Component\Review, psr4_prefix: Sylius\Component\Review, spec_path: src/Sylius/Component/Review, src_path: src/Sylius/Component/Review }
|
||||
Sequence: { namespace: Sylius\Component\Sequence, psr4_prefix: Sylius\Component\Sequence, spec_path: src/Sylius/Component/Sequence, src_path: src/Sylius/Component/Sequence }
|
||||
Shipping: { namespace: Sylius\Component\Shipping, psr4_prefix: Sylius\Component\Shipping, spec_path: src/Sylius/Component/Shipping, src_path: src/Sylius/Component/Shipping }
|
||||
Storage: { namespace: Sylius\Component\Storage, psr4_prefix: Sylius\Component\Storage, spec_path: src/Sylius/Component/Storage, src_path: src/Sylius/Component/Storage }
|
||||
|
|
@ -57,6 +58,7 @@ suites:
|
|||
RbacBundle: { namespace: Sylius\Bundle\RbacBundle, psr4_prefix: Sylius\Bundle\RbacBundle, spec_path: src/Sylius/Bundle/RbacBundle, src_path: src/Sylius/Bundle/RbacBundle }
|
||||
ReportBundle: { namespace: Sylius\Bundle\ReportBundle, psr4_prefix: Sylius\Bundle\ReportBundle, spec_path: src/Sylius/Bundle/ReportBundle, src_path: src/Sylius/Bundle/ReportBundle }
|
||||
ResourceBundle: { namespace: Sylius\Bundle\ResourceBundle, psr4_prefix: Sylius\Bundle\ResourceBundle, spec_path: src/Sylius/Bundle/ResourceBundle, src_path: src/Sylius/Bundle/ResourceBundle }
|
||||
ReviewBundle: { namespace: Sylius\Bundle\ReviewBundle, psr4_prefix: Sylius\Bundle\ReviewBundle, spec_path: src/Sylius/Bundle/ReviewBundle, src_path: src/Sylius/Bundle/ReviewBundle }
|
||||
SearchBundle: { namespace: Sylius\Bundle\SearchBundle, psr4_prefix: Sylius\Bundle\SearchBundle, spec_path: src/Sylius/Bundle/SearchBundle, src_path: src/Sylius/Bundle/SearchBundle }
|
||||
SequenceBundle: { namespace: Sylius\Bundle\SequenceBundle, psr4_prefix: Sylius\Bundle\SequenceBundle, spec_path: src/Sylius/Bundle/SequenceBundle, src_path: src/Sylius/Bundle/SequenceBundle }
|
||||
SettingsBundle: { namespace: Sylius\Bundle\SettingsBundle, psr4_prefix: Sylius\Bundle\SettingsBundle, spec_path: src/Sylius/Bundle/SettingsBundle, src_path: src/Sylius/Bundle/SettingsBundle }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\CoreBundle\EventListener;
|
||||
|
||||
use Sylius\Bundle\ReviewBundle\Remover\ReviewerReviewsRemoverInterface;
|
||||
use Sylius\Component\Resource\Exception\UnexpectedTypeException;
|
||||
use Sylius\Component\Review\Model\ReviewerInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.p.zalewski@gmail.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class CustomerReviewsDeleteListener
|
||||
{
|
||||
/**
|
||||
* @var ReviewerReviewsRemoverInterface
|
||||
*/
|
||||
private $reviewerReviewsRemover;
|
||||
|
||||
/**
|
||||
* @param ReviewerReviewsRemoverInterface $reviewerReviewsRemover
|
||||
*/
|
||||
public function __construct(ReviewerReviewsRemoverInterface $reviewerReviewsRemover)
|
||||
{
|
||||
$this->reviewerReviewsRemover = $reviewerReviewsRemover;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GenericEvent $event
|
||||
*/
|
||||
public function removeCustomerReviews(GenericEvent $event)
|
||||
{
|
||||
$author = $event->getSubject();
|
||||
if (!$author instanceof ReviewerInterface) {
|
||||
throw new UnexpectedTypeException($author, ReviewerInterface::class);
|
||||
}
|
||||
|
||||
$this->reviewerReviewsRemover->removeReviewerReviews($author);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ class ProductDeleteListener
|
|||
return;
|
||||
}
|
||||
|
||||
$reviewManager = $args->getEntityManager();
|
||||
$reviewManager = $this->container->get('sylius.manager.product_review');
|
||||
$reviewRepository = $this->container->get('sylius.repository.product_review');
|
||||
$reviews = $reviewRepository->findBy(['reviewSubject' => $product]);
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ class ProductDeleteListener
|
|||
$reviewManager->remove($review);
|
||||
}
|
||||
|
||||
$product->setAverageRating(null);
|
||||
$product->setAverageRating(0);
|
||||
|
||||
$reviewManager->flush();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@
|
|||
|
||||
namespace Sylius\Bundle\CoreBundle\Form\Type;
|
||||
|
||||
use Sylius\Component\Core\Model\Customer;
|
||||
use Sylius\Component\Core\Model\Product;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* @author Daniel Richter <nexyz9@gmail.com>
|
||||
|
|
@ -30,12 +32,12 @@ class ProductReviewAdminType extends ProductReviewType
|
|||
|
||||
$builder
|
||||
->add('reviewSubject', 'entity', [
|
||||
'class' => 'Sylius\Component\Core\Model\Product',
|
||||
'class' => Product::class,
|
||||
'label' => 'sylius.form.review.product',
|
||||
'property' => 'name',
|
||||
])
|
||||
->add('author', 'entity', [
|
||||
'class' => 'Sylius\Component\Core\Model\Customer',
|
||||
'class' => Customer::class,
|
||||
'label' => 'sylius.form.review.author',
|
||||
'property' => 'email',
|
||||
])
|
||||
|
|
@ -45,7 +47,7 @@ class ProductReviewAdminType extends ProductReviewType
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDefaultOptions(OptionsResolverInterface $resolver)
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'rating_steps' => 5,
|
||||
|
|
@ -59,6 +61,6 @@ class ProductReviewAdminType extends ProductReviewType
|
|||
*/
|
||||
public function getName()
|
||||
{
|
||||
return sprintf('sylius_%s_review_admin', $this->subject);
|
||||
return 'sylius_product_review_admin';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ use Sylius\Bundle\ReviewBundle\Form\Type\ReviewType;
|
|||
/**
|
||||
* @author Mateusz Zalewski <mateusz.p.zalewski@gmail.com>
|
||||
*/
|
||||
class ProductReviewType extends ReviewType
|
||||
class ProductReviewType extends ReviewType
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -820,4 +820,4 @@ sylius_review:
|
|||
admin: Sylius\Bundle\CoreBundle\Form\Type\ProductReviewAdminType
|
||||
reviewer:
|
||||
classes:
|
||||
model: Sylius\Component\Core\Model\Customer
|
||||
model: %sylius.model.customer.class%
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<mapped-superclass name="Sylius\Component\Core\Model\Product" table="sylius_product">
|
||||
|
||||
<field name="variantSelectionMethod" column="variant_selection_method" type="string" nullable="false" />
|
||||
<field name="averageRating" column="average_rating" type="float" nullable="true" />
|
||||
<field name="averageRating" column="average_rating" type="float" />
|
||||
|
||||
<many-to-one field="shippingCategory" target-entity="Sylius\Component\Shipping\Model\ShippingCategoryInterface">
|
||||
<join-column name="shipping_category_id" referenced-column-name="id" nullable="true" on-delete="SET NULL" />
|
||||
|
|
@ -56,6 +56,7 @@
|
|||
<many-to-one field="mainTaxon" target-entity="Sylius\Component\Taxonomy\Model\TaxonInterface">
|
||||
<join-column name="main_taxon_id" referenced-column-name="id" nullable="true" />
|
||||
</many-to-one>
|
||||
|
||||
<gedmo:loggable />
|
||||
</mapped-superclass>
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping">
|
||||
|
||||
<mapped-superclass name="Sylius\Component\Core\Model\ProductReview" table="sylius_product_review">
|
||||
</mapped-superclass>
|
||||
<mapped-superclass name="Sylius\Component\Core\Model\ProductReview" table="sylius_product_review" />
|
||||
|
||||
</doctrine-mapping>
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@
|
|||
<parameter key="sylius.form.type.promotion_rule.customer_group_configuration.class">Sylius\Bundle\CoreBundle\Form\Type\Rule\CustomerGroupType</parameter>
|
||||
<parameter key="sylius.form.type.promotion_action.shipping_discount_configuration.class">Sylius\Bundle\CoreBundle\Form\Type\Action\ShippingDiscountConfigurationType</parameter>
|
||||
<parameter key="sylius.form.type.promotion_action.add_product_configuration.class">Sylius\Bundle\CoreBundle\Form\Type\Action\AddProductConfigurationType</parameter>
|
||||
|
||||
<parameter key="sylius.form.type.product_review_admin.class">Sylius\Bundle\CoreBundle\Form\Type\ProductReviewAdminType</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
<parameter key="sylius.listener.channel.class">Sylius\Bundle\CoreBundle\EventListener\ChannelDeletionListener</parameter>
|
||||
<parameter key="sylius.listener.customer_aware.class">Sylius\Bundle\CoreBundle\EventListener\CustomerAwareListener</parameter>
|
||||
<parameter key="sylius.listener.product_delete.class">Sylius\Bundle\CoreBundle\EventListener\ProductDeleteListener</parameter>
|
||||
<parameter key="sylius.listener.customer_delete.class">Sylius\Bundle\CoreBundle\EventListener\CustomerDeleteListener</parameter>
|
||||
<parameter key="sylius.listener.customer_reviews_delete.class">Sylius\Bundle\CoreBundle\EventListener\CustomerReviewsDeleteListener</parameter>
|
||||
|
||||
<parameter key="sylius.active_promotions_by_channel_provider.class">Sylius\Component\Core\Provider\ActivePromotionsByChannelProvider</parameter>
|
||||
|
||||
|
|
@ -394,10 +394,8 @@
|
|||
<tag name="kernel.event_listener" event="sylius.taxonomy.pre_create" method="uploadTaxonomyImage" />
|
||||
<tag name="kernel.event_listener" event="sylius.taxonomy.pre_update" method="uploadTaxonomyImage" />
|
||||
</service>
|
||||
<service id="sylius.listener.customer_delete" class="%sylius.listener.customer_delete.class%">
|
||||
<argument type="service" id="sylius.repository.product_review" />
|
||||
<argument type="service" id="sylius.manager.product_review" />
|
||||
<argument type="service" id="sylius.review.calculator.average_rating" />
|
||||
<service id="sylius.listener.customer_reviews_delete" class="%sylius.listener.customer_reviews_delete.class%">
|
||||
<argument type="service" id="sylius.review.remover.reviewer_reviews" />
|
||||
<tag name="kernel.event_listener" event="sylius.customer.pre_delete" method="removeCustomerReviews" />
|
||||
</service>
|
||||
<service id="sylius.listener.product_delete" class="%sylius.listener.product_delete.class%">
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ winzou_state_machine:
|
|||
to: rejected
|
||||
callbacks:
|
||||
after:
|
||||
update_review_subject_average_price:
|
||||
update_price:
|
||||
on: 'accept'
|
||||
do: [@sylius.review.updater.reviewable_average_rating, updateFromReview]
|
||||
do: [@sylius.review.updater.average_rating, updateFromReview]
|
||||
args: ['object']
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace spec\Sylius\Bundle\CoreBundle\EventListener;
|
||||
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
|
||||
use Sylius\Component\Core\Model\CustomerInterface;
|
||||
use Sylius\Component\Resource\Exception\UnexpectedTypeException;
|
||||
use Sylius\Component\Review\Calculator\AverageRatingCalculatorInterface;
|
||||
use Sylius\Component\Review\Model\ReviewableInterface;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
*/
|
||||
class CustomerDeleteListenerSpec extends ObjectBehavior
|
||||
{
|
||||
function let(EntityRepository $reviewRepository, ObjectManager $reviewManager, AverageRatingCalculatorInterface $averageRatingCalculator)
|
||||
{
|
||||
$this->beConstructedWith($reviewRepository, $reviewManager, $averageRatingCalculator);
|
||||
}
|
||||
|
||||
function it_is_initializable()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\CoreBundle\EventListener\CustomerDeleteListener');
|
||||
}
|
||||
|
||||
function it_removes_soft_deleted_customer_reviews_and_recalculates_their_product_ratings(
|
||||
$averageRatingCalculator,
|
||||
$reviewRepository,
|
||||
$reviewManager,
|
||||
GenericEvent $event,
|
||||
CustomerInterface $author,
|
||||
ReviewableInterface $reviewSubject,
|
||||
ReviewInterface $review
|
||||
) {
|
||||
$event->getSubject()->willReturn($author)->shouldBeCalled();
|
||||
|
||||
$reviewRepository->findBy(['author' => $author])->willReturn([$review])->shouldBeCalled();
|
||||
$review->getReviewSubject()->willReturn($reviewSubject)->shouldBeCalled();
|
||||
|
||||
$reviewManager->remove($review)->shouldBeCalled();
|
||||
$reviewManager->flush()->shouldBeCalled();
|
||||
|
||||
$averageRatingCalculator->calculate($reviewSubject)->willReturn(0)->shouldBeCalled();
|
||||
|
||||
$reviewSubject->setAverageRating(0)->shouldBeCalled();
|
||||
|
||||
$this->removeCustomerReviews($event);
|
||||
}
|
||||
|
||||
function it_throws_exception_if_event_subject_is_not_customer_object(GenericEvent $event)
|
||||
{
|
||||
$event->getSubject()->willReturn('badObject')->shouldBeCalled();
|
||||
|
||||
$this->shouldThrow(new UnexpectedTypeException('badObject', 'Sylius\Component\Core\Model\CustomerInterface'))->during('removeCustomerReviews', [$event]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace spec\Sylius\Bundle\CoreBundle\EventListener;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ReviewBundle\Remover\ReviewerReviewsRemover;
|
||||
use Sylius\Component\Resource\Exception\UnexpectedTypeException;
|
||||
use Sylius\Component\Review\Model\ReviewerInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class CustomerReviewsDeleteListenerSpec extends ObjectBehavior
|
||||
{
|
||||
function let(ReviewerReviewsRemover $reviewerReviewsRemover)
|
||||
{
|
||||
$this->beConstructedWith($reviewerReviewsRemover);
|
||||
}
|
||||
|
||||
function it_is_initializable()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\CoreBundle\EventListener\CustomerReviewsDeleteListener');
|
||||
}
|
||||
|
||||
function it_removes_soft_deleted_customer_reviews_and_recalculates_their_product_ratings(
|
||||
$reviewerReviewsRemover,
|
||||
GenericEvent $event,
|
||||
ReviewerInterface $author
|
||||
) {
|
||||
$event->getSubject()->willReturn($author);
|
||||
$reviewerReviewsRemover->removeReviewerReviews($author)->shouldBeCalled();
|
||||
|
||||
$this->removeCustomerReviews($event);
|
||||
}
|
||||
|
||||
function it_throws_exception_if_event_subject_is_not_customer_object(GenericEvent $event)
|
||||
{
|
||||
$event->getSubject()->willReturn('badObject')->shouldBeCalled();
|
||||
|
||||
$this->shouldThrow(new UnexpectedTypeException('badObject', ReviewerInterface::class))->during('removeCustomerReviews', [$event]);
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ class ProductDeleteListenerSpec extends ObjectBehavior
|
|||
) {
|
||||
$args->getEntity()->willReturn($product)->shouldBeCalled();
|
||||
|
||||
$args->getEntityManager()->willReturn($reviewManager)->shouldBeCalled();
|
||||
$container->get('sylius.manager.product_review')->willReturn($reviewManager)->shouldBeCalled();
|
||||
$container->get('sylius.repository.product_review')->willReturn($reviewRepository)->shouldBeCalled();
|
||||
|
||||
$reviewRepository->findBy(['reviewSubject' => $product])->willReturn([$review])->shouldBeCalled();
|
||||
|
|
@ -53,7 +53,7 @@ class ProductDeleteListenerSpec extends ObjectBehavior
|
|||
$reviewManager->remove($review)->shouldBeCalled();
|
||||
$reviewManager->flush()->shouldBeCalled();
|
||||
|
||||
$product->setAverageRating(null)->shouldBeCalled();
|
||||
$product->setAverageRating(0)->shouldBeCalled();
|
||||
|
||||
$this->postSoftDelete($args);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,13 @@
|
|||
namespace spec\Sylius\Bundle\CoreBundle\Form\Type;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Prophecy\Argument;
|
||||
use Sylius\Bundle\CoreBundle\Form\Type\ProductReviewType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class ProductReviewAdminTypeSpec extends ObjectBehavior
|
||||
{
|
||||
|
|
@ -31,62 +34,43 @@ class ProductReviewAdminTypeSpec extends ObjectBehavior
|
|||
|
||||
function it_extends_product_review_admin_type()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\CoreBundle\Form\Type\ProductReviewType');
|
||||
$this->shouldHaveType(ProductReviewType::class);
|
||||
}
|
||||
|
||||
function it_builds_form(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('rating', 'choice', [
|
||||
'choices' => [1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5],
|
||||
'label' => 'sylius.form.review.rating',
|
||||
'expanded' => true,
|
||||
'multiple' => false,
|
||||
])
|
||||
->add('rating', 'choice', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$builder
|
||||
->add('author', 'sylius_customer_guest', [
|
||||
'label' => false,
|
||||
])
|
||||
->add('author', 'sylius_customer_guest', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$builder
|
||||
->add('title', 'text', [
|
||||
'label' => 'sylius.form.review.title',
|
||||
])
|
||||
->add('title', 'text', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$builder
|
||||
->add('comment', 'textarea', [
|
||||
'label' => 'sylius.form.review.comment',
|
||||
])
|
||||
->add('comment', 'textarea', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$builder
|
||||
->add('author', 'entity', [
|
||||
'class' => 'Sylius\Component\Core\Model\Customer',
|
||||
'label' => 'sylius.form.review.author',
|
||||
'property' => 'email',
|
||||
])
|
||||
->add('author', 'entity', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$builder
|
||||
->add('reviewSubject', 'entity', [
|
||||
'class' => 'Sylius\Component\Core\Model\Product',
|
||||
'label' => 'sylius.form.review.product',
|
||||
'property' => 'name',
|
||||
])
|
||||
->add('reviewSubject', 'entity', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
namespace spec\Sylius\Bundle\CoreBundle\Form\Type;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ReviewBundle\Form\Type\ReviewType;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
|
|
@ -30,7 +31,7 @@ class ProductReviewTypeSpec extends ObjectBehavior
|
|||
|
||||
function it_extends_review_type()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\Form\Type\ReviewType');
|
||||
$this->shouldHaveType(ReviewType::class);
|
||||
}
|
||||
|
||||
function it_has_name()
|
||||
|
|
|
|||
|
|
@ -94,10 +94,6 @@ class ProductContext extends DefaultContext
|
|||
$this->configureProductPricingCalculator($product, $data);
|
||||
}
|
||||
|
||||
if (isset($data['average rating'])) {
|
||||
$product->setAverageRating($data['average rating']);
|
||||
}
|
||||
|
||||
$manager->persist($product);
|
||||
}
|
||||
|
||||
|
|
@ -383,6 +379,7 @@ class ProductContext extends DefaultContext
|
|||
$manager->persist($product);
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^product "([^"]*)" has been deleted$/
|
||||
*/
|
||||
|
|
@ -391,7 +388,7 @@ class ProductContext extends DefaultContext
|
|||
$this->getSession()->visit($this->generatePageUrl('sylius_backend_product_index'));
|
||||
|
||||
$tr = $this->assertSession()->elementExists('css', sprintf('table tbody tr:contains("%s")', $productName));
|
||||
$locator = sprintf('button:contains("%s")', 'Delete');
|
||||
$locator = 'button:contains("Delete")';
|
||||
$tr->find('css', $locator)->press();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,27 +22,9 @@
|
|||
<parameter key="sylius.generator.product_variant.class">Sylius\Bundle\ProductBundle\Generator\VariantGenerator</parameter>
|
||||
|
||||
<parameter key="sylius.validator.product.unique.class">Sylius\Bundle\ProductBundle\Validator\ProductUniqueValidator</parameter>
|
||||
<parameter key="sylius.form.type.product_translation.class">Sylius\Bundle\ProductBundle\Form\Type\ProductTranslationType</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<!--Forms-->
|
||||
<service id="sylius.form.type.product" class="%sylius.form.type.product.class%">
|
||||
<argument>%sylius.model.product.class%</argument>
|
||||
<argument>%sylius.validation_groups.product%</argument>
|
||||
<tag name="form.type" alias="sylius_product" />
|
||||
</service>
|
||||
<service id="sylius.form.type.product_archetype" class="%sylius.form.type.product_archetype.class%">
|
||||
<argument>%sylius.model.product_archetype.class%</argument>
|
||||
<argument>%sylius.validation_groups.product_archetype%</argument>
|
||||
<tag name="form.type" alias="sylius_product_archetype" />
|
||||
</service>
|
||||
<service id="sylius.form.type.product_translation" class="%sylius.form.type.product_translation.class%">
|
||||
<argument>%sylius.model.product.class%</argument>
|
||||
<argument>%sylius.validation_groups.product%</argument>
|
||||
<tag name="form.type" alias="sylius_product_translation" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.set_builder.cartesian" class="%sylius.set_builder.cartesian.class%" />
|
||||
<service id="sylius.generator.product_variant" class="%sylius.generator.product_variant.class%">
|
||||
<argument type="service" id="sylius.factory.product_variant" />
|
||||
|
|
|
|||
|
|
@ -102,11 +102,6 @@ class ResourceController extends Controller
|
|||
*/
|
||||
protected $eventDispatcher;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $stateMachineGraph;
|
||||
|
||||
/**
|
||||
* @param MetadataInterface $metadata
|
||||
* @param RequestConfigurationFactoryInterface $requestConfigurationFactory
|
||||
|
|
@ -466,15 +461,11 @@ class ResourceController extends Controller
|
|||
*
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function updateStateAction(Request $request, $transition, $graph = null)
|
||||
public function updateStateAction(Request $request, $transition, $graph)
|
||||
{
|
||||
$configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
|
||||
$resource = $this->findOr404($configuration);
|
||||
|
||||
if (null === $graph) {
|
||||
$graph = $this->stateMachineGraph;
|
||||
}
|
||||
|
||||
$stateMachine = $this->get('sm.factory')->get($resource, $graph);
|
||||
if (!$stateMachine->can($transition)) {
|
||||
throw new NotFoundHttpException(sprintf(
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
language: php
|
||||
|
||||
sudo: false
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 7.0
|
||||
- 5.6
|
||||
- 5.5
|
||||
|
||||
before_script: composer install --prefer-source --no-interaction
|
||||
before_install:
|
||||
- echo "memory_limit=2048M" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
|
||||
- phpenv config-rm xdebug.ini || true
|
||||
|
||||
script: bin/phpspec run -fpretty --verbose
|
||||
install:
|
||||
- composer install --no-interaction --prefer-source
|
||||
|
||||
notifications:
|
||||
email: "travis-ci@sylius.org"
|
||||
irc: "irc.freenode.org#sylius-dev"
|
||||
script:
|
||||
- bin/phpspec run -fpretty --verbose
|
||||
|
|
|
|||
|
|
@ -61,6 +61,11 @@ class ReviewContext extends DefaultContext
|
|||
|
||||
$review->setStatus((isset($reviewHash['status']) && '' !== $reviewHash['status']) ? $reviewHash['status'] : ReviewInterface::STATUS_ACCEPTED);
|
||||
|
||||
if (ReviewInterface::STATUS_ACCEPTED === $review->getStatus()) {
|
||||
$averageRatingCalculator = $this->getService('sylius.review.calculator.average_rating');
|
||||
$product->setAverageRating($averageRatingCalculator->calculate($product));
|
||||
}
|
||||
|
||||
return $review;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
### v0.16.0
|
||||
### v0.17.0
|
||||
|
||||
* Initial dev release.
|
||||
* Initial dev release.
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\ReviewBundle\Controller;
|
||||
|
||||
use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
*/
|
||||
class ReviewController extends ResourceController
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $stateMachineGraph = ReviewInterface::REVIEW_STATE_MACHINE_GRAPH;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\ReviewBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Sylius\Component\Review\Factory\ReviewFactory;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
/**
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class RegisterReviewFactoryPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getParameter('sylius.review.subjects') as $subject => $configuration) {
|
||||
$factory = $container->findDefinition('sylius.factory.'.$subject.'_review');
|
||||
$reviewFactoryDefinition = new Definition(ReviewFactory::class);
|
||||
|
||||
$reviewFactory = $container->setDefinition(sprintf('sylius.factory.'.$subject.'_review'), $reviewFactoryDefinition);
|
||||
$reviewFactory->addArgument($factory);
|
||||
$reviewFactory->addArgument($container->findDefinition('sylius.repository.'.$subject));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,13 @@
|
|||
|
||||
namespace Sylius\Bundle\ReviewBundle\DependencyInjection;
|
||||
|
||||
use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
|
||||
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
|
||||
use Sylius\Bundle\ReviewBundle\Doctrine\ORM\ReviewRepository;
|
||||
use Sylius\Bundle\ReviewBundle\Form\Type\ReviewType;
|
||||
use Sylius\Component\Resource\Factory\Factory;
|
||||
use Sylius\Component\Review\Model\ReviewerInterface;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
|
@ -38,7 +44,7 @@ class Configuration implements ConfigurationInterface
|
|||
$rootNode
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('driver')->isRequired()->cannotBeEmpty()->end()
|
||||
->scalarNode('driver')->defaultValue(SyliusResourceBundle::DRIVER_DOCTRINE_ORM)->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
|
|
@ -67,14 +73,14 @@ class Configuration implements ConfigurationInterface
|
|||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('model')->isRequired()->end()
|
||||
->scalarNode('interface')->defaultValue('Sylius\Component\Review\Model\ReviewInterface')->end()
|
||||
->scalarNode('controller')->defaultValue('Sylius\Bundle\ResourceBundle\Controller\ResourceController')->end()
|
||||
->scalarNode('repository')->cannotBeEmpty()->end()
|
||||
->scalarNode('factory')->defaultValue(Factory::class)->end()
|
||||
->scalarNode('interface')->defaultValue(ReviewInterface::class)->cannotBeEmpty()->end()
|
||||
->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
|
||||
->scalarNode('repository')->defaultValue(ReviewRepository::class)->cannotBeEmpty()->end()
|
||||
->scalarNode('factory')->defaultValue(Factory::class)->cannotBeEmpty()->end()
|
||||
->arrayNode('form')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('default')->defaultValue('Sylius\Bundle\ReviewBundle\Form\Type\ReviewType')->cannotBeEmpty()->end()
|
||||
->scalarNode('default')->defaultValue(ReviewType::class)->cannotBeEmpty()->end()
|
||||
->scalarNode('admin')->isRequired()->end()
|
||||
->end()
|
||||
->end()
|
||||
|
|
@ -102,7 +108,9 @@ class Configuration implements ConfigurationInterface
|
|||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('model')->isRequired()->end()
|
||||
->scalarNode('factory')->defaultValue(Factory::class)->end()
|
||||
->scalarNode('interface')->defaultValue(ReviewerInterface::class)->cannotBeEmpty()->end()
|
||||
->scalarNode('repository')->cannotBeEmpty()->end()
|
||||
->scalarNode('factory')->defaultValue(Factory::class)->cannotBeEmpty()->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('validation_groups')
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ class SyliusReviewExtension extends AbstractResourceExtension
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $parameters
|
||||
* @param string $name
|
||||
* @param array $parameters
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
private function addRequiredArgumentsToForms($name, array $parameters, ContainerBuilder $container)
|
||||
|
|
@ -100,7 +100,7 @@ class SyliusReviewExtension extends AbstractResourceExtension
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $resourceName
|
||||
* @param string $resourceName
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
private function addProperTagToReviewDeleteListener($resourceName, ContainerBuilder $container)
|
||||
|
|
@ -110,6 +110,6 @@ class SyliusReviewExtension extends AbstractResourceExtension
|
|||
}
|
||||
|
||||
$listenerDefinition = $container->getDefinition('sylius.listener.review_delete');
|
||||
$listenerDefinition->addTag('kernel.event_listener', ['event' => 'sylius.'.$resourceName.'_review.post_delete', 'method' => 'recalculateSubjectRating']);
|
||||
$listenerDefinition->addTag('doctrine.event_listener', ['event' => 'postRemove', 'method' => 'recalculateSubjectRating']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\ReviewBundle\Doctrine\ORM;
|
||||
|
||||
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
|
||||
/**
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class ReviewRepository extends EntityRepository
|
||||
{
|
||||
/**
|
||||
* @param int $reviewSubjectId
|
||||
*
|
||||
* @return ReviewInterface[]
|
||||
*/
|
||||
public function findAcceptedBySubjectId($reviewSubjectId)
|
||||
{
|
||||
return $this
|
||||
->getCollectionQueryBuilder()
|
||||
->andWhere('o.reviewSubject = :reviewSubject')
|
||||
->andWhere('o.status = :status')
|
||||
->setParameter('reviewSubject', $reviewSubjectId)
|
||||
->setParameter('status', ReviewInterface::STATUS_ACCEPTED)
|
||||
->getQuery()
|
||||
->getResult()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
namespace Sylius\Bundle\ReviewBundle\EventListener;
|
||||
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||
|
||||
/**
|
||||
|
|
@ -38,7 +39,9 @@ class LoadMetadataSubscriber implements EventSubscriber
|
|||
*/
|
||||
public function getSubscribedEvents()
|
||||
{
|
||||
return ['loadClassMetadata'];
|
||||
return [
|
||||
'loadClassMetadata',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -56,48 +59,75 @@ class LoadMetadataSubscriber implements EventSubscriber
|
|||
$reviewableEntityMetadata = $metadataFactory->getMetadataFor($reviewableEntity);
|
||||
$reviewerEntityMetadata = $metadataFactory->getMetadataFor($reviewerEntity);
|
||||
|
||||
$subjectMapping = [
|
||||
'fieldName' => 'reviewSubject',
|
||||
'targetEntity' => $reviewableEntity,
|
||||
'inversedBy' => 'reviews',
|
||||
'joinColumns' => [
|
||||
[
|
||||
'name' => $subject.'_id',
|
||||
'referencedColumnName' => $reviewableEntityMetadata->fieldMappings['id']['columnName'],
|
||||
'nullable' => false,
|
||||
'onDelete' => 'CASCADE',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$reviewerMapping = [
|
||||
'fieldName' => 'author',
|
||||
'targetEntity' => $reviewerEntity,
|
||||
'joinColumn' => [
|
||||
'name' => 'customer_id',
|
||||
'referencedColumnName' => $reviewerEntityMetadata->fieldMappings['id']['columnName'],
|
||||
'nullable' => false,
|
||||
'onDelete' => 'CASCADE',
|
||||
],
|
||||
'cascade' => ['persist'],
|
||||
];
|
||||
|
||||
$metadata->mapManyToOne($subjectMapping);
|
||||
$metadata->mapManyToOne($reviewerMapping);
|
||||
$metadata->mapManyToOne($this->createSubjectMapping($reviewableEntity, $subject, $reviewableEntityMetadata));
|
||||
$metadata->mapManyToOne($this->createReviewerMapping($reviewerEntity, $reviewerEntityMetadata));
|
||||
}
|
||||
|
||||
if ($class['subject'] === $metadata->getName()) {
|
||||
$reviewEntity = $class['review']['classes']['model'];
|
||||
|
||||
$reviewsMapping = [
|
||||
'fieldName' => 'reviews',
|
||||
'targetEntity' => $reviewEntity,
|
||||
'mappedBy' => 'reviewSubject',
|
||||
'cascade' => ['all'],
|
||||
];
|
||||
|
||||
$metadata->mapOneToMany($reviewsMapping);
|
||||
$metadata->mapOneToMany($this->createReviewsMapping($reviewEntity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $reviewableEntity
|
||||
* @param string $subject
|
||||
* @param ClassMetadata $reviewableEntityMetadata
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createSubjectMapping($reviewableEntity, $subject, ClassMetadata $reviewableEntityMetadata)
|
||||
{
|
||||
return [
|
||||
'fieldName' => 'reviewSubject',
|
||||
'targetEntity' => $reviewableEntity,
|
||||
'inversedBy' => 'reviews',
|
||||
'joinColumns' => [
|
||||
[
|
||||
'name' => $subject.'_id',
|
||||
'referencedColumnName' => $reviewableEntityMetadata->fieldMappings['id']['columnName'],
|
||||
'nullable' => false,
|
||||
'onDelete' => 'CASCADE',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $reviewerEntity
|
||||
* @param ClassMetadata $reviewerEntityMetadata
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createReviewerMapping($reviewerEntity, ClassMetadata $reviewerEntityMetadata)
|
||||
{
|
||||
return [
|
||||
'fieldName' => 'author',
|
||||
'targetEntity' => $reviewerEntity,
|
||||
'joinColumn' => [
|
||||
'name' => 'author_id',
|
||||
'referencedColumnName' => $reviewerEntityMetadata->fieldMappings['id']['columnName'],
|
||||
'nullable' => false,
|
||||
'onDelete' => 'CASCADE',
|
||||
],
|
||||
'cascade' => ['persist'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $reviewEntity
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createReviewsMapping($reviewEntity)
|
||||
{
|
||||
return [
|
||||
'fieldName' => 'reviews',
|
||||
'targetEntity' => $reviewEntity,
|
||||
'mappedBy' => 'reviewSubject',
|
||||
'cascade' => ['all'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class ReviewCreateListener
|
|||
public function ensureReviewHasAuthor(GenericEvent $event)
|
||||
{
|
||||
if (!($subject = $event->getSubject()) instanceof ReviewInterface) {
|
||||
throw new UnexpectedTypeException($subject, 'Sylius\Component\Review\Model\ReviewInterface');
|
||||
throw new UnexpectedTypeException($subject, ReviewInterface::class);
|
||||
}
|
||||
|
||||
if (null !== $subject->getAuthor()) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
namespace Sylius\Bundle\ReviewBundle\EventListener;
|
||||
|
||||
use Sylius\Bundle\ReviewBundle\Updater\ReviewableAverageRatingUpdaterInterface;
|
||||
use Sylius\Bundle\ReviewBundle\Updater\ReviewableRatingUpdaterInterface;
|
||||
use Sylius\Component\Resource\Exception\UnexpectedTypeException;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
|
|
@ -22,16 +22,16 @@ use Symfony\Component\EventDispatcher\GenericEvent;
|
|||
class ReviewDeleteListener
|
||||
{
|
||||
/**
|
||||
* @var ReviewableAverageRatingUpdaterInterface
|
||||
* @var ReviewableRatingUpdaterInterface
|
||||
*/
|
||||
private $reviewableAverageRatingUpdater;
|
||||
private $averageRatingUpdater;
|
||||
|
||||
/**
|
||||
* @param ReviewableAverageRatingUpdaterInterface $reviewableAverageRatingUpdater
|
||||
* @param ReviewableRatingUpdaterInterface $averageRatingUpdater
|
||||
*/
|
||||
public function __construct(ReviewableAverageRatingUpdaterInterface $reviewableAverageRatingUpdater)
|
||||
public function __construct(ReviewableRatingUpdaterInterface $averageRatingUpdater)
|
||||
{
|
||||
$this->reviewableAverageRatingUpdater = $reviewableAverageRatingUpdater;
|
||||
$this->averageRatingUpdater = $averageRatingUpdater;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -39,12 +39,13 @@ class ReviewDeleteListener
|
|||
*/
|
||||
public function recalculateSubjectRating(GenericEvent $event)
|
||||
{
|
||||
if (!(($subject = $event->getSubject()) instanceof ReviewInterface)) {
|
||||
throw new UnexpectedTypeException($subject, 'Sylius\Component\Review\Model\ReviewInterface');
|
||||
$subject = $event->getSubject();
|
||||
if (!$subject instanceof ReviewInterface) {
|
||||
throw new UnexpectedTypeException($subject, ReviewInterface::class);
|
||||
}
|
||||
|
||||
if (ReviewInterface::STATUS_ACCEPTED === $subject->getStatus()) {
|
||||
$this->reviewableAverageRatingUpdater->update($subject->getReviewSubject());
|
||||
$this->averageRatingUpdater->update($subject->getReviewSubject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\ReviewBundle\Form\Transformer;
|
||||
|
||||
use Sylius\Component\Core\Model\Customer;
|
||||
use Sylius\Component\Review\Model\ReviewerInterface;
|
||||
use Symfony\Component\Form\DataTransformerInterface;
|
||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.p.zalewski@gmail.com>
|
||||
*/
|
||||
class ReviewerTransformer implements DataTransformerInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value)
|
||||
{
|
||||
if (null === $value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$value instanceof ReviewerInterface) {
|
||||
throw new UnexpectedTypeException($value, 'Sylius\Component\Review\Model\ReviewerInterface');
|
||||
}
|
||||
|
||||
return $value->getEmail();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function reverseTransform($value)
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//this is temporary, after implementing proper form from UserBundle in ReviewType, it's going to be Reviewer object, as it's default review author class
|
||||
$reviewer = new Customer();
|
||||
$reviewer->setEmail($value);
|
||||
|
||||
return $reviewer;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,11 +13,12 @@ namespace Sylius\Bundle\ReviewBundle\Form\Type;
|
|||
|
||||
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* @author Daniel Richter <nexyz9@gmail.com>
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class ReviewType extends AbstractResourceType
|
||||
{
|
||||
|
|
@ -33,9 +34,9 @@ class ReviewType extends AbstractResourceType
|
|||
*/
|
||||
public function __construct($dataClass, array $validationGroups = [], $subject)
|
||||
{
|
||||
$this->subject = $subject;
|
||||
|
||||
parent::__construct($dataClass, $validationGroups);
|
||||
|
||||
$this->subject = $subject;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -65,7 +66,7 @@ class ReviewType extends AbstractResourceType
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDefaultOptions(OptionsResolverInterface $resolver)
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'rating_steps' => 5,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
SyliusReviewBundle [](http://travis-ci.org/Sylius/SyliusReportBundle)
|
||||
SyliusReviewBundle [](http://travis-ci.org/Sylius/SyliusReviewBundle)
|
||||
====================
|
||||
|
||||
Sylius
|
||||
|
|
@ -21,18 +21,7 @@ Documentation
|
|||
Contributing
|
||||
------------
|
||||
|
||||
All informations about contributing to Sylius can be found on [this page](http://docs.sylius.org/en/latest/contributing/index.html).
|
||||
|
||||
Mailing lists
|
||||
-------------
|
||||
|
||||
### Users
|
||||
|
||||
Questions? Feel free to ask on [users mailing list](http://groups.google.com/group/sylius).
|
||||
|
||||
### Developers
|
||||
|
||||
To contribute and develop this bundle, use the [developers mailing list](http://groups.google.com/group/sylius-dev).
|
||||
All information's about contributing to Sylius can be found on [this page](http://docs.sylius.org/en/latest/contributing/index.html).
|
||||
|
||||
Sylius twitter account
|
||||
----------------------
|
||||
|
|
@ -62,10 +51,10 @@ This versioning method is same for all **Sylius** bundles and applications.
|
|||
MIT License
|
||||
-----------
|
||||
|
||||
License can be found [here](https://github.com/Sylius/SyliusReportBundle/blob/master/Resources/meta/LICENSE).
|
||||
License can be found [here](https://github.com/Sylius/SyliusReviewBundle/blob/master/Resources/meta/LICENSE).
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
The bundle was originally created by [Mateusz Zalewski](mateusz.zalewski@lakion.com), based on [Daniel Richter](nexyz9@gmail.com) work.
|
||||
The bundle was originally created by [Mateusz Zalewski](mateusz.zalewski@lakion.com) and [Grzegorz Sadowski](grzegorz.sadowski@lakion.com), based on [Daniel Richter](nexyz9@gmail.com) work.
|
||||
See the list of [contributors](https://github.com/Sylius/SyliusReviewBundle/contributors).
|
||||
|
|
|
|||
|
|
@ -9,21 +9,19 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\CoreBundle\EventListener;
|
||||
namespace Sylius\Bundle\ReviewBundle\Remover;
|
||||
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
|
||||
use Sylius\Component\Core\Model\CustomerInterface;
|
||||
use Sylius\Component\Resource\Exception\UnexpectedTypeException;
|
||||
use Sylius\Component\Review\Calculator\AverageRatingCalculatorInterface;
|
||||
use Sylius\Component\Review\Calculator\ReviewableRatingCalculatorInterface;
|
||||
use Sylius\Component\Review\Model\ReviewableInterface;
|
||||
use Sylius\Component\Review\Model\ReviewerInterface;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.p.zalewski@gmail.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class CustomerDeleteListener
|
||||
class ReviewerReviewsRemover implements ReviewerReviewsRemoverInterface
|
||||
{
|
||||
/**
|
||||
* @var EntityRepository
|
||||
|
|
@ -36,32 +34,30 @@ class CustomerDeleteListener
|
|||
private $reviewManager;
|
||||
|
||||
/**
|
||||
* @var AverageRatingCalculatorInterface
|
||||
* @var ReviewableRatingCalculatorInterface
|
||||
*/
|
||||
private $averageRatingCalculator;
|
||||
|
||||
/**
|
||||
* @param EntityRepository $reviewRepository
|
||||
* @param ObjectManager $reviewManager
|
||||
* @param AverageRatingCalculatorInterface $averageRatingCalculator
|
||||
* @param EntityRepository $reviewRepository
|
||||
* @param ObjectManager $reviewManager
|
||||
* @param ReviewableRatingCalculatorInterface $averageRatingCalculator
|
||||
*/
|
||||
public function __construct(EntityRepository $reviewRepository, ObjectManager $reviewManager, AverageRatingCalculatorInterface $averageRatingCalculator)
|
||||
{
|
||||
public function __construct(
|
||||
EntityRepository $reviewRepository,
|
||||
ObjectManager $reviewManager,
|
||||
ReviewableRatingCalculatorInterface $averageRatingCalculator
|
||||
) {
|
||||
$this->reviewRepository = $reviewRepository;
|
||||
$this->reviewManager = $reviewManager;
|
||||
$this->averageRatingCalculator = $averageRatingCalculator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GenericEvent $event
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeCustomerReviews(GenericEvent $event)
|
||||
public function removeReviewerReviews(ReviewerInterface $author)
|
||||
{
|
||||
$author = $event->getSubject();
|
||||
if (!$author instanceof CustomerInterface) {
|
||||
throw new UnexpectedTypeException($author, 'Sylius\Component\Core\Model\CustomerInterface');
|
||||
}
|
||||
|
||||
$reviewSubjectsToRecalculate = [];
|
||||
|
||||
foreach ($this->reviewRepository->findBy(['author' => $author]) as $review) {
|
||||
|
|
@ -75,7 +71,7 @@ class CustomerDeleteListener
|
|||
}
|
||||
|
||||
/**
|
||||
* @param ReviewInterface $review
|
||||
* @param ReviewInterface $review
|
||||
* @param ReviewableInterface[] $reviewSubjectsToRecalculate
|
||||
*
|
||||
* @return array
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\ReviewBundle\Remover;
|
||||
|
||||
use Sylius\Component\Review\Model\ReviewerInterface;
|
||||
|
||||
/**
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
interface ReviewerReviewsRemoverInterface
|
||||
{
|
||||
/**
|
||||
* @param ReviewerInterface $author
|
||||
*/
|
||||
public function removeReviewerReviews(ReviewerInterface $author);
|
||||
}
|
||||
|
|
@ -16,17 +16,17 @@
|
|||
|
||||
<mapped-superclass name="Sylius\Component\Review\Model\Review" table="sylius_review">
|
||||
<id name="id" type="integer" column="id">
|
||||
<generator strategy="AUTO"/>
|
||||
<generator strategy="AUTO" />
|
||||
</id>
|
||||
<field name="title" type="string" column="title"/>
|
||||
<field name="rating" type="integer" column="rating"/>
|
||||
<field name="title" type="string" column="title" />
|
||||
<field name="rating" type="integer" column="rating" />
|
||||
<field name="comment" type="text" column="comment" nullable="true" />
|
||||
<field name="status" type="string" column="status" length="255"/>
|
||||
<field name="status" type="string" column="status" length="255" />
|
||||
<field name="createdAt" column="created_at" type="datetime">
|
||||
<gedmo:timestampable on="create"/>
|
||||
<gedmo:timestampable on="create" />
|
||||
</field>
|
||||
<field name="updatedAt" column="updated_at" type="datetime" nullable="true">
|
||||
<gedmo:timestampable on="update"/>
|
||||
<gedmo:timestampable on="update" />
|
||||
</field>
|
||||
</mapped-superclass>
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@
|
|||
|
||||
<mapped-superclass name="Sylius\Component\Review\Model\Reviewer" table="sylius_reviewer">
|
||||
<id name="id" type="integer" column="id">
|
||||
<generator strategy="AUTO"/>
|
||||
<generator strategy="AUTO" />
|
||||
</id>
|
||||
<field name="email" type="string" column="email"/>
|
||||
<field name="firstName" type="string" column="first_name"/>
|
||||
<field name="lastName" type="string" column="last_name"/>
|
||||
<field name="email" type="string" column="email" />
|
||||
<field name="firstName" type="string" column="first_name" />
|
||||
<field name="lastName" type="string" column="last_name" />
|
||||
</mapped-superclass>
|
||||
|
||||
</doctrine-mapping>
|
||||
|
|
|
|||
|
|
@ -14,34 +14,50 @@
|
|||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="sylius.event_subscriber.review.load_metadata.class">Sylius\Bundle\ReviewBundle\EventListener\LoadMetadataSubscriber</parameter>
|
||||
<parameter key="sylius.review.validator.unique_reviewer_email.class">Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueReviewerEmailValidator</parameter>
|
||||
<parameter key="sylius.listener.review_create.class">Sylius\Bundle\ReviewBundle\EventListener\ReviewCreateListener</parameter>
|
||||
<parameter key="sylius.listener.review_delete.class">Sylius\Bundle\ReviewBundle\EventListener\ReviewDeleteListener</parameter>
|
||||
<parameter key="sylius.review.calculator.average_rating.class">Sylius\Component\Review\Calculator\AverageRatingCalculator</parameter>
|
||||
<parameter key="sylius.review.updater.average_rating.class">Sylius\Bundle\ReviewBundle\Updater\AverageRatingUpdater</parameter>
|
||||
<parameter key="sylius.review.remover.reviewer_reviews.class">Sylius\Bundle\ReviewBundle\Remover\ReviewerReviewsRemover</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<!--Subscribers-->
|
||||
<service id="sylius.event_subscriber.review.load_metadata" class="Sylius\Bundle\ReviewBundle\EventListener\LoadMetadataSubscriber">
|
||||
<service id="sylius.event_subscriber.review.load_metadata" class="%sylius.event_subscriber.review.load_metadata.class%">
|
||||
<argument>%sylius.review.subjects%</argument>
|
||||
<tag name="doctrine.event_subscriber" />
|
||||
</service>
|
||||
|
||||
<!--Validators-->
|
||||
<service id="sylius.review.validator.unique_user_email" class="Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueUserEmailValidator">
|
||||
<service id="sylius.review.validator.unique_reviewer_email" class="%sylius.review.validator.unique_reviewer_email.class%">
|
||||
<argument type="service" id="sylius.repository.user" />
|
||||
<argument type="service" id="security.token_storage" />
|
||||
<argument type="service" id="security.authorization_checker" />
|
||||
<tag name="validator.constraint_validator" alias="unique_user_email_validator" />
|
||||
<tag name="validator.constraint_validator" alias="sylius_unique_reviewer_email_validator" />
|
||||
</service>
|
||||
|
||||
<!--Listeners-->
|
||||
<service id="sylius.listener.review_create" class="Sylius\Bundle\ReviewBundle\EventListener\ReviewCreateListener">
|
||||
<service id="sylius.listener.review_create" class="%sylius.listener.review_create.class%">
|
||||
<argument type="service" id="sylius.context.customer" />
|
||||
<tag name="kernel.event_listener" event="sylius.product_review.pre_create" method="ensureReviewHasAuthor" />
|
||||
</service>
|
||||
<service id="sylius.listener.review_delete" class="Sylius\Bundle\ReviewBundle\EventListener\ReviewDeleteListener">
|
||||
<argument type="service" id="sylius.review.updater.reviewable_average_rating" />
|
||||
<service id="sylius.listener.review_delete" class="%sylius.listener.review_delete.class%">
|
||||
<argument type="service" id="sylius.review.updater.average_rating" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.review.calculator.average_rating" class="Sylius\Component\Review\Calculator\AverageRatingCalculator" />
|
||||
<service id="sylius.review.updater.reviewable_average_rating" class="Sylius\Bundle\ReviewBundle\Updater\ReviewableAverageRatingUpdater">
|
||||
<service id="sylius.review.calculator.average_rating" class="%sylius.review.calculator.average_rating.class%" />
|
||||
<service id="sylius.review.updater.average_rating" class="%sylius.review.updater.average_rating.class%">
|
||||
<argument type="service" id="sylius.review.calculator.average_rating" />
|
||||
<argument type="service" id="doctrine.orm.default_entity_manager" />
|
||||
</service>
|
||||
<service id="sylius.review.remover.reviewer_reviews" class="%sylius.review.remover.reviewer_reviews.class%">
|
||||
<argument type="service" id="sylius.repository.product_review" />
|
||||
<argument type="service" id="sylius.manager.product_review" />
|
||||
<argument type="service" id="sylius.review.calculator.average_rating" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
</option>
|
||||
</constraint>
|
||||
</property>
|
||||
<constraint name="Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueUserEmail" >
|
||||
<constraint name="Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueReviewerEmail" >
|
||||
<option name="groups">sylius_review</option>
|
||||
</constraint>
|
||||
</class>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2011-2015 Paweł Jędrzejewski
|
||||
Copyright (c) 2011-2016 Paweł Jędrzejewski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -7,40 +7,57 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#reviewForm").submit(function(e){
|
||||
function initializeAjaxForm(successMessage) {
|
||||
$("#reviewForm").submit(function(e) {
|
||||
e.preventDefault();
|
||||
var form = $(this);
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: location.href+"/product_review",
|
||||
data: $(this).serialize(),
|
||||
url: form.attr('action'),
|
||||
data: parseFormToJson(form),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
if (data == 'success') {
|
||||
location.reload();
|
||||
} else {
|
||||
renderErrorsOnProperFields(data, form);
|
||||
}
|
||||
accept: "application/json",
|
||||
success: function(data, textStatus, xhr) {
|
||||
completeRequest(form);
|
||||
appendFlash(successMessage);
|
||||
},
|
||||
error: function(xhr, textStatus, errorThrown) {
|
||||
renderErrors(xhr, form);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderErrorsOnProperFields(data, form) {
|
||||
function renderErrors(xhr, form) {
|
||||
clearErrors(form);
|
||||
|
||||
$.each(data, function(key, value){
|
||||
var element = form.find('#sylius_product_review_'+key.replace('data.', ''));
|
||||
|
||||
element.siblings('.form-error').remove();
|
||||
element.parent().append('<span class="help-block form-error">'+value+'</span>');
|
||||
element.parents('.form-group').addClass('has-error');
|
||||
$.each(xhr.responseJSON.errors.errors, function(key, value) {
|
||||
$('div.panel-body').addClass('has-error').prepend('<span class="help-block form-error">' + value + '</span>');
|
||||
});
|
||||
}
|
||||
|
||||
function clearErrors(form) {
|
||||
form.find('.form-error').remove();
|
||||
form.find('.has-error').removeClass('has-error');
|
||||
}
|
||||
}
|
||||
|
||||
function parseFormToJson(form) {
|
||||
var formJson = {};
|
||||
$.each(form.serializeArray(), function(index, field) {
|
||||
var name = field.name.replace('sylius_product_review[', '').replace(']', '');
|
||||
formJson[name] = field.value || '';
|
||||
});
|
||||
|
||||
return formJson;
|
||||
}
|
||||
|
||||
function appendFlash(successMessage) {
|
||||
$('<div class="alert alert-success"><a class="close" data-dismiss="alert" href="#">×</a>' + successMessage + '</div>').insertAfter('h1.logo');
|
||||
}
|
||||
|
||||
function completeRequest(form) {
|
||||
form[0].reset();
|
||||
clearErrors(form);
|
||||
$("html, body").animate({ scrollTop: 0 }, "slow");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
# (c) Paweł Jędrzejewski
|
||||
|
||||
sylius:
|
||||
review:
|
||||
header: Product reviews
|
||||
no_results: There are no reviews for this product.
|
||||
form:
|
||||
review:
|
||||
header: Add a review
|
||||
|
|
@ -18,4 +15,3 @@ sylius:
|
|||
approved: Approved
|
||||
rejected: Rejected
|
||||
submit: Submit
|
||||
product: Product
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ sylius:
|
|||
rating:
|
||||
not_blank: You must check review rating.
|
||||
author:
|
||||
already_exists: This email is already registered. Please log in.
|
||||
already_exists: This email is already registered, please login or use forgotten password.
|
||||
|
|
|
|||
|
|
@ -13,9 +13,12 @@ namespace Sylius\Bundle\ReviewBundle;
|
|||
|
||||
use Sylius\Bundle\ResourceBundle\AbstractResourceBundle;
|
||||
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
|
||||
use Sylius\Bundle\ReviewBundle\DependencyInjection\Compiler\RegisterReviewFactoryPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class SyliusReviewBundle extends AbstractResourceBundle
|
||||
{
|
||||
|
|
@ -29,6 +32,16 @@ class SyliusReviewBundle extends AbstractResourceBundle
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build(ContainerBuilder $container)
|
||||
{
|
||||
parent::build($container);
|
||||
|
||||
$container->addCompilerPass(new RegisterReviewFactoryPass());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -12,17 +12,18 @@
|
|||
namespace Sylius\Bundle\ReviewBundle\Updater;
|
||||
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Sylius\Component\Review\Calculator\AverageRatingCalculatorInterface;
|
||||
use Sylius\Component\Review\Calculator\ReviewableRatingCalculatorInterface;
|
||||
use Sylius\Component\Review\Model\ReviewableInterface;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.p.zalewski@gmail.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class ReviewableAverageRatingUpdater implements ReviewableAverageRatingUpdaterInterface
|
||||
class AverageRatingUpdater implements ReviewableRatingUpdaterInterface
|
||||
{
|
||||
/**
|
||||
* @var AverageRatingCalculatorInterface
|
||||
* @var ReviewableRatingCalculatorInterface
|
||||
*/
|
||||
private $averageRatingCalculator;
|
||||
|
||||
|
|
@ -32,10 +33,10 @@ class ReviewableAverageRatingUpdater implements ReviewableAverageRatingUpdaterIn
|
|||
private $reviewSubjectManager;
|
||||
|
||||
/**
|
||||
* @param AverageRatingCalculatorInterface $averageRatingCalculator
|
||||
* @param ObjectManager $reviewSubjectManager
|
||||
* @param ReviewableRatingCalculatorInterface $averageRatingCalculator
|
||||
* @param ObjectManager $reviewSubjectManager
|
||||
*/
|
||||
public function __construct(AverageRatingCalculatorInterface $averageRatingCalculator, ObjectManager $reviewSubjectManager)
|
||||
public function __construct(ReviewableRatingCalculatorInterface $averageRatingCalculator, ObjectManager $reviewSubjectManager)
|
||||
{
|
||||
$this->averageRatingCalculator = $averageRatingCalculator;
|
||||
$this->reviewSubjectManager = $reviewSubjectManager;
|
||||
|
|
@ -16,8 +16,9 @@ use Sylius\Component\Review\Model\ReviewInterface;
|
|||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
interface ReviewableAverageRatingUpdaterInterface
|
||||
interface ReviewableRatingUpdaterInterface
|
||||
{
|
||||
/**
|
||||
* @param ReviewableInterface $reviewSubject
|
||||
|
|
@ -15,8 +15,9 @@ use Symfony\Component\Validator\Constraint;
|
|||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.p.zalewski@gmail.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class UniqueUserEmail extends Constraint
|
||||
class UniqueReviewerEmail extends Constraint
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
|
|
@ -28,7 +29,7 @@ class UniqueUserEmail extends Constraint
|
|||
*/
|
||||
public function validatedBy()
|
||||
{
|
||||
return 'unique_user_email_validator';
|
||||
return 'sylius_unique_reviewer_email_validator';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -11,9 +11,10 @@
|
|||
|
||||
namespace Sylius\Bundle\ReviewBundle\Validator\Constraints;
|
||||
|
||||
use Sylius\Bundle\UserBundle\Doctrine\ORM\UserRepository;
|
||||
use Sylius\Component\User\Model\UserInterface;
|
||||
use Sylius\Component\User\Repository\UserRepositoryInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
|
@ -22,7 +23,7 @@ use Symfony\Component\Validator\ConstraintValidator;
|
|||
* @author Mateusz Zalewski <mateusz.p.zalewski@gmail.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class UniqueUserEmailValidator extends ConstraintValidator
|
||||
class UniqueReviewerEmailValidator extends ConstraintValidator
|
||||
{
|
||||
/**
|
||||
* @var UserRepository
|
||||
|
|
@ -40,12 +41,15 @@ class UniqueUserEmailValidator extends ConstraintValidator
|
|||
private $authorizationChecker;
|
||||
|
||||
/**
|
||||
* @param UserRepository $userRepository
|
||||
* @param UserRepositoryInterface $userRepository
|
||||
* @param TokenStorageInterface $tokenStorage
|
||||
* @param AuthorizationCheckerInterface $authorizationChecker
|
||||
*/
|
||||
public function __construct(UserRepository $userRepository, TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authorizationChecker)
|
||||
{
|
||||
public function __construct(
|
||||
UserRepositoryInterface $userRepository,
|
||||
TokenStorageInterface $tokenStorage,
|
||||
AuthorizationCheckerInterface $authorizationChecker
|
||||
) {
|
||||
$this->userRepository = $userRepository;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->authorizationChecker = $authorizationChecker;
|
||||
|
|
@ -59,7 +63,7 @@ class UniqueUserEmailValidator extends ConstraintValidator
|
|||
$customer = $review->getAuthor();
|
||||
|
||||
$token = $this->tokenStorage->getToken();
|
||||
if (null !== $token && $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED') && $token->getUser() instanceof UserInterface) {
|
||||
if ($this->checkIfUserIsAuthenticated($token)) {
|
||||
if (null !== $customer && $token->getUser()->getCustomer()->getEmail() === $customer->getEmail()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -74,4 +78,18 @@ class UniqueUserEmailValidator extends ConstraintValidator
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TokenInterface $token
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function checkIfUserIsAuthenticated(TokenInterface $token)
|
||||
{
|
||||
return
|
||||
null !== $token &&
|
||||
$this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED') &&
|
||||
$token->getUser() instanceof UserInterface
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,36 +7,42 @@
|
|||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paweł Jędrzejewski",
|
||||
"name": "Paweł Jędrzejewski",
|
||||
"homepage": "http://pjedrzejewski.com"
|
||||
},
|
||||
{
|
||||
"name": "Mateusz Zalewski",
|
||||
"email": "mateusz.zalewski@lakion.com"
|
||||
"name": "Mateusz Zalewski",
|
||||
"email": "mateusz.zalewski@lakion.com"
|
||||
},
|
||||
{
|
||||
"name": "Daniel Richter",
|
||||
"email": "nexyz9@gmail.com"
|
||||
"name": "Grzegorz Sadowski",
|
||||
"email": "grzegorz.sadowski@lakion.com"
|
||||
},
|
||||
{
|
||||
"name": "Sylius project",
|
||||
"name": "Daniel Richter",
|
||||
"email": "nexyz9@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sylius project",
|
||||
"homepage": "http://sylius.org"
|
||||
},
|
||||
{
|
||||
"name": "Community contributions",
|
||||
"name": "Community contributions",
|
||||
"homepage": "http://github.com/Sylius/Sylius/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"symfony/framework-bundle": "^2.7",
|
||||
"php": "^5.5.9|^7.0",
|
||||
|
||||
"symfony/framework-bundle": "^2.7.7",
|
||||
"stof/doctrine-extensions-bundle": "~1.1",
|
||||
"sylius/resource-bundle": "0.16.*",
|
||||
"sylius/review": "0.16.*"
|
||||
"sylius/review": "0.17.*",
|
||||
"sylius/user-bundle": "0.17.*",
|
||||
"sylius/resource-bundle": "0.17.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "~2.1",
|
||||
"symfony/form": "^2.7",
|
||||
"phpspec/phpspec": "^2.4",
|
||||
"symfony/form": "^2.7",
|
||||
"symfony/validator": "^2.7"
|
||||
},
|
||||
"config": {
|
||||
|
|
@ -48,9 +54,10 @@
|
|||
"autoload-dev": {
|
||||
"psr-4": { "Sylius\\Bundle\\ReviewBundle\\spec\\": "spec/" }
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.16-dev"
|
||||
"dev-master": "0.17-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
namespace spec\Sylius\Bundle\ReviewBundle\EventListener;
|
||||
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
|
|
@ -50,7 +51,7 @@ class LoadMetadataSubscriberSpec extends ObjectBehavior
|
|||
|
||||
function it_implements_event_subscriber()
|
||||
{
|
||||
$this->shouldImplement('Doctrine\Common\EventSubscriber');
|
||||
$this->shouldImplement(EventSubscriber::class);
|
||||
}
|
||||
|
||||
function it_has_subscribed_events()
|
||||
|
|
@ -93,7 +94,7 @@ class LoadMetadataSubscriberSpec extends ObjectBehavior
|
|||
'fieldName' => 'author',
|
||||
'targetEntity' => 'AcmeBundle\Entity\ReviewerModel',
|
||||
'joinColumn' => [
|
||||
'name' => 'customer_id',
|
||||
'name' => 'author_id',
|
||||
'referencedColumnName' => 'id',
|
||||
'nullable' => false,
|
||||
'onDelete' => 'CASCADE',
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ class ReviewCreateListenerSpec extends ObjectBehavior
|
|||
GenericEvent $event,
|
||||
ReviewInterface $review
|
||||
) {
|
||||
$event->getSubject()->willReturn($review)->shouldBeCalled();
|
||||
$customerContext->getCustomer()->willReturn($customer)->shouldBeCalled();
|
||||
$event->getSubject()->willReturn($review);
|
||||
$customerContext->getCustomer()->willReturn($customer);
|
||||
$review->getAuthor()->willReturn(null);
|
||||
|
||||
$review->setAuthor($customer)->shouldBeCalled();
|
||||
|
|
@ -53,7 +53,7 @@ class ReviewCreateListenerSpec extends ObjectBehavior
|
|||
{
|
||||
$event->getSubject()->willReturn('badObject')->shouldBeCalled();
|
||||
|
||||
$this->shouldThrow(new UnexpectedTypeException('badObject', 'Sylius\Component\Review\Model\ReviewInterface'))->during('ensureReviewHasAuthor', [$event]);
|
||||
$this->shouldThrow(new UnexpectedTypeException('badObject', ReviewInterface::class))->during('ensureReviewHasAuthor', [$event]);
|
||||
}
|
||||
|
||||
function it_does_nothing_if_review_already_has_author(
|
||||
|
|
@ -62,8 +62,8 @@ class ReviewCreateListenerSpec extends ObjectBehavior
|
|||
GenericEvent $event,
|
||||
ReviewInterface $review
|
||||
) {
|
||||
$event->getSubject()->willReturn($review)->shouldBeCalled();
|
||||
$review->getAuthor()->willReturn($existingAuthor)->shouldBeCalled();
|
||||
$event->getSubject()->willReturn($review);
|
||||
$review->getAuthor()->willReturn($existingAuthor);
|
||||
|
||||
$customerContext->getCustomer()->shouldNotBeCalled();
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace spec\Sylius\Bundle\ReviewBundle\EventListener;
|
|||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Prophecy\Argument;
|
||||
use Sylius\Bundle\ReviewBundle\Updater\ReviewableAverageRatingUpdaterInterface;
|
||||
use Sylius\Bundle\ReviewBundle\Updater\ReviewableRatingUpdaterInterface;
|
||||
use Sylius\Component\Resource\Exception\UnexpectedTypeException;
|
||||
use Sylius\Component\Review\Model\ReviewableInterface;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
|
|
@ -24,9 +24,9 @@ use Symfony\Component\EventDispatcher\GenericEvent;
|
|||
*/
|
||||
class ReviewDeleteListenerSpec extends ObjectBehavior
|
||||
{
|
||||
function let(ReviewableAverageRatingUpdaterInterface $reviewableAverageRatingUpdater)
|
||||
function let(ReviewableRatingUpdaterInterface $averageRatingUpdater)
|
||||
{
|
||||
$this->beConstructedWith($reviewableAverageRatingUpdater);
|
||||
$this->beConstructedWith($averageRatingUpdater);
|
||||
}
|
||||
|
||||
function it_is_initializable()
|
||||
|
|
@ -34,33 +34,37 @@ class ReviewDeleteListenerSpec extends ObjectBehavior
|
|||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\EventListener\ReviewDeleteListener');
|
||||
}
|
||||
|
||||
function it_recalculates_subject_rating_on_accepted_review_deletion($reviewableAverageRatingUpdater, GenericEvent $event, ReviewInterface $review, ReviewableInterface $reviewSubject)
|
||||
{
|
||||
$event->getSubject()->willReturn($review)->shouldBeCalled();
|
||||
$review->getStatus()->willReturn(ReviewInterface::STATUS_ACCEPTED)->shouldBeCalled();
|
||||
$review->getReviewSubject()->willReturn($reviewSubject)->shouldBeCalled();
|
||||
function it_recalculates_subject_rating_on_accepted_review_deletion(
|
||||
$averageRatingUpdater,
|
||||
GenericEvent $event,
|
||||
ReviewInterface $review,
|
||||
ReviewableInterface $reviewSubject
|
||||
) {
|
||||
$event->getSubject()->willReturn($review);
|
||||
$review->getStatus()->willReturn(ReviewInterface::STATUS_ACCEPTED);
|
||||
$review->getReviewSubject()->willReturn($reviewSubject);
|
||||
|
||||
$reviewableAverageRatingUpdater->update($reviewSubject)->shouldBeCalled();
|
||||
$averageRatingUpdater->update($reviewSubject)->shouldBeCalled();
|
||||
|
||||
$this->recalculateSubjectRating($event);
|
||||
}
|
||||
|
||||
function it_does_nothing_if_review_was_new($reviewableAverageRatingUpdater, GenericEvent $event, ReviewInterface $review)
|
||||
function it_does_nothing_if_review_was_new($averageRatingUpdater, GenericEvent $event, ReviewInterface $review)
|
||||
{
|
||||
$event->getSubject()->willReturn($review)->shouldBeCalled();
|
||||
$review->getStatus()->willReturn(ReviewInterface::STATUS_NEW)->shouldBeCalled();
|
||||
$event->getSubject()->willReturn($review);
|
||||
$review->getStatus()->willReturn(ReviewInterface::STATUS_NEW);
|
||||
|
||||
$reviewableAverageRatingUpdater->update(Argument::type('Sylius\Component\Review\Model\ReviewableInterface'))->shouldNotBeCalled();
|
||||
$averageRatingUpdater->update(Argument::type(ReviewableInterface::class))->shouldNotBeCalled();
|
||||
|
||||
$this->recalculateSubjectRating($event);
|
||||
}
|
||||
|
||||
function it_does_nothing_if_review_was_rejected($reviewableAverageRatingUpdater, GenericEvent $event, ReviewInterface $review)
|
||||
function it_does_nothing_if_review_was_rejected($averageRatingUpdater, GenericEvent $event, ReviewInterface $review)
|
||||
{
|
||||
$event->getSubject()->willReturn($review)->shouldBeCalled();
|
||||
$review->getStatus()->willReturn(ReviewInterface::STATUS_REJECTED)->shouldBeCalled();
|
||||
$event->getSubject()->willReturn($review);
|
||||
$review->getStatus()->willReturn(ReviewInterface::STATUS_REJECTED);
|
||||
|
||||
$reviewableAverageRatingUpdater->update(Argument::type('Sylius\Component\Review\Model\ReviewableInterface'))->shouldNotBeCalled();
|
||||
$averageRatingUpdater->update(Argument::type(ReviewableInterface::class))->shouldNotBeCalled();
|
||||
|
||||
$this->recalculateSubjectRating($event);
|
||||
}
|
||||
|
|
@ -70,7 +74,7 @@ class ReviewDeleteListenerSpec extends ObjectBehavior
|
|||
$event->getSubject()->willReturn('badObject');
|
||||
|
||||
$this
|
||||
->shouldThrow(new UnexpectedTypeException('badObject', 'Sylius\Component\Review\Model\ReviewInterface'))
|
||||
->shouldThrow(new UnexpectedTypeException('badObject', ReviewInterface::class))
|
||||
->during('recalculateSubjectRating', [$event])
|
||||
;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace spec\Sylius\Bundle\ReviewBundle\Form\Transformer;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Component\Review\Model\ReviewerInterface;
|
||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
*/
|
||||
class ReviewerTransformerSpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_initializable()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\Form\Transformer\ReviewerTransformer');
|
||||
}
|
||||
|
||||
function it_implements_data_transformer_interface()
|
||||
{
|
||||
$this->shouldImplement('Symfony\Component\Form\DataTransformerInterface');
|
||||
}
|
||||
|
||||
function it_transforms_form_data(ReviewerInterface $author)
|
||||
{
|
||||
$author->getEmail()->willReturn('john.doe@example.com');
|
||||
|
||||
$this->transform($author)->shouldReturn('john.doe@example.com');
|
||||
}
|
||||
|
||||
function it_returns_null_if_given_value_is_null()
|
||||
{
|
||||
$this->transform(null)->shouldReturn(null);
|
||||
}
|
||||
|
||||
function it_throws_exception_if_given_value_is_not_reviewer_interface_object()
|
||||
{
|
||||
$this->shouldThrow(new UnexpectedTypeException('badObject', 'Sylius\Component\Review\Model\ReviewerInterface'))->during('transform', ['badObject']);
|
||||
}
|
||||
|
||||
function it_reverse_transforms_form_data(ReviewerInterface $author)
|
||||
{
|
||||
$author->getEmail()->willReturn('john.doe@example.com');
|
||||
|
||||
$this->reverseTransform('john.doe@example.com')->shouldBeSameAs($author);
|
||||
}
|
||||
|
||||
function it_returns_null_if_given_value_is_incorrect(\DateTime $wrongObject)
|
||||
{
|
||||
$this->reverseTransform(null)->shouldReturn(null);
|
||||
$this->reverseTransform($wrongObject)->shouldReturn(null);
|
||||
}
|
||||
|
||||
public function getMatchers()
|
||||
{
|
||||
return [
|
||||
'beSameAs' => function ($subject, $key) {
|
||||
if (!$subject instanceof ReviewerInterface || !$key instanceof ReviewerInterface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $subject->getEmail() === $key->getEmail();
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -12,11 +12,14 @@
|
|||
namespace spec\Sylius\Bundle\ReviewBundle\Form\Type;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Prophecy\Argument;
|
||||
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class ReviewTypeSpec extends ObjectBehavior
|
||||
{
|
||||
|
|
@ -32,42 +35,31 @@ class ReviewTypeSpec extends ObjectBehavior
|
|||
|
||||
function it_is_abstract_type_object()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType');
|
||||
$this->shouldHaveType(AbstractResourceType::class);
|
||||
}
|
||||
|
||||
function it_builds_form(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('rating', 'choice', [
|
||||
'choices' => [1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5],
|
||||
'label' => 'sylius.form.review.rating',
|
||||
'expanded' => true,
|
||||
'multiple' => false,
|
||||
])
|
||||
->add('rating', 'choice', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$builder
|
||||
->add('author', 'sylius_customer_guest', [
|
||||
'label' => false,
|
||||
])
|
||||
->add('author', 'sylius_customer_guest', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$builder
|
||||
->add('title', 'text', [
|
||||
'label' => 'sylius.form.review.title',
|
||||
])
|
||||
->add('title', 'text', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$builder
|
||||
->add('comment', 'textarea', [
|
||||
'label' => 'sylius.form.review.comment',
|
||||
])
|
||||
->add('comment', 'textarea', Argument::cetera())
|
||||
->willReturn($builder)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
|
@ -75,7 +67,7 @@ class ReviewTypeSpec extends ObjectBehavior
|
|||
$this->buildForm($builder, ['rating_steps' => 5]);
|
||||
}
|
||||
|
||||
function it_sets_default_options(OptionsResolverInterface $resolver)
|
||||
function it_configures_options(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults(
|
||||
[
|
||||
|
|
@ -84,7 +76,7 @@ class ReviewTypeSpec extends ObjectBehavior
|
|||
]
|
||||
)->shouldBeCalled();
|
||||
|
||||
$this->setDefaultOptions($resolver);
|
||||
$this->configureOptions($resolver);
|
||||
}
|
||||
|
||||
function it_has_name()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace spec\Sylius\Bundle\ReviewBundle\Remover;
|
||||
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
|
||||
use Sylius\Bundle\ReviewBundle\Remover\ReviewerReviewsRemoverInterface;
|
||||
use Sylius\Component\Review\Calculator\ReviewableRatingCalculatorInterface;
|
||||
use Sylius\Component\Review\Model\ReviewableInterface;
|
||||
use Sylius\Component\Review\Model\ReviewerInterface;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
|
||||
/**
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class ReviewerReviewsRemoverSpec extends ObjectBehavior
|
||||
{
|
||||
function let(
|
||||
EntityRepository $reviewRepository,
|
||||
ObjectManager $reviewManager,
|
||||
ReviewableRatingCalculatorInterface $averageRatingCalculator
|
||||
) {
|
||||
$this->beConstructedWith($reviewRepository, $reviewManager, $averageRatingCalculator);
|
||||
}
|
||||
|
||||
function it_is_initializable()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\Remover\ReviewerReviewsRemover');
|
||||
}
|
||||
|
||||
function it_implements_reviewer_reviews_remover_interface()
|
||||
{
|
||||
$this->shouldImplement(ReviewerReviewsRemoverInterface::class);
|
||||
}
|
||||
|
||||
function it_removes_soft_deleted_customer_reviews_and_recalculates_their_product_ratings(
|
||||
$averageRatingCalculator,
|
||||
$reviewRepository,
|
||||
$reviewManager,
|
||||
ReviewerInterface $author,
|
||||
ReviewableInterface $reviewSubject,
|
||||
ReviewInterface $review
|
||||
) {
|
||||
$reviewRepository->findBy(['author' => $author])->willReturn([$review]);
|
||||
$review->getReviewSubject()->willReturn($reviewSubject);
|
||||
|
||||
$reviewManager->remove($review)->shouldBeCalled();
|
||||
$reviewManager->flush()->shouldBeCalled();
|
||||
|
||||
$averageRatingCalculator->calculate($reviewSubject)->willReturn(0);
|
||||
|
||||
$reviewSubject->setAverageRating(0)->shouldBeCalled();
|
||||
|
||||
$this->removeReviewerReviews($author);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,28 +13,29 @@ namespace spec\Sylius\Bundle\ReviewBundle\Updater;
|
|||
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Component\Review\Calculator\AverageRatingCalculatorInterface;
|
||||
use Sylius\Bundle\ReviewBundle\Updater\ReviewableRatingUpdaterInterface;
|
||||
use Sylius\Component\Review\Calculator\ReviewableRatingCalculatorInterface;
|
||||
use Sylius\Component\Review\Model\ReviewableInterface;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
*/
|
||||
class ReviewableAverageRatingUpdaterSpec extends ObjectBehavior
|
||||
class AverageRatingUpdaterSpec extends ObjectBehavior
|
||||
{
|
||||
function let(AverageRatingCalculatorInterface $averageRatingCalculator, ObjectManager $reviewSubjectManager)
|
||||
function let(ReviewableRatingCalculatorInterface $averageRatingCalculator, ObjectManager $reviewSubjectManager)
|
||||
{
|
||||
$this->beConstructedWith($averageRatingCalculator, $reviewSubjectManager);
|
||||
}
|
||||
|
||||
function it_is_initializable()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\Updater\ReviewableAverageRatingUpdater');
|
||||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\Updater\AverageRatingUpdater');
|
||||
}
|
||||
|
||||
function it_implements_product_average_rating_updater_interface()
|
||||
{
|
||||
$this->shouldImplement('Sylius\Bundle\ReviewBundle\Updater\ReviewableAverageRatingUpdaterInterface');
|
||||
$this->shouldImplement(ReviewableRatingUpdaterInterface::class);
|
||||
}
|
||||
|
||||
function it_updates_review_subject_average_rating(
|
||||
|
|
@ -42,7 +43,7 @@ class ReviewableAverageRatingUpdaterSpec extends ObjectBehavior
|
|||
$reviewSubjectManager,
|
||||
ReviewableInterface $reviewSubject
|
||||
) {
|
||||
$averageRatingCalculator->calculate($reviewSubject)->willReturn(4.5)->shouldBeCalled();
|
||||
$averageRatingCalculator->calculate($reviewSubject)->willReturn(4.5);
|
||||
|
||||
$reviewSubject->setAverageRating(4.5)->shouldBeCalled();
|
||||
$reviewSubjectManager->flush($reviewSubject)->shouldBeCalled();
|
||||
|
|
@ -56,8 +57,8 @@ class ReviewableAverageRatingUpdaterSpec extends ObjectBehavior
|
|||
ReviewableInterface $reviewSubject,
|
||||
ReviewInterface $review
|
||||
) {
|
||||
$review->getReviewSubject()->willReturn($reviewSubject)->shouldBeCalled();
|
||||
$averageRatingCalculator->calculate($reviewSubject)->willReturn(4.5)->shouldBeCalled();
|
||||
$review->getReviewSubject()->willReturn($reviewSubject);
|
||||
$averageRatingCalculator->calculate($reviewSubject)->willReturn(4.5);
|
||||
|
||||
$reviewSubject->setAverageRating(4.5)->shouldBeCalled();
|
||||
$reviewSubjectManager->flush($reviewSubject)->shouldBeCalled();
|
||||
|
|
@ -18,16 +18,16 @@ use Symfony\Component\Validator\Constraint;
|
|||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class UniqueUserEmailSpec extends ObjectBehavior
|
||||
class UniqueReviewerEmailSpec extends ObjectBehavior
|
||||
{
|
||||
function it_is_initializable()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueUserEmail');
|
||||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueReviewerEmail');
|
||||
}
|
||||
|
||||
function it_extends_contraint_class()
|
||||
{
|
||||
$this->shouldHaveType('Symfony\Component\Validator\Constraint');
|
||||
$this->shouldHaveType(Constraint::class);
|
||||
}
|
||||
|
||||
function it_has_message()
|
||||
|
|
@ -37,7 +37,7 @@ class UniqueUserEmailSpec extends ObjectBehavior
|
|||
|
||||
function it_is_validate_by_unique_user_email_validator()
|
||||
{
|
||||
$this->validatedBy()->shouldReturn('unique_user_email_validator');
|
||||
$this->validatedBy()->shouldReturn('sylius_unique_reviewer_email_validator');
|
||||
}
|
||||
|
||||
function it_has_targets()
|
||||
|
|
@ -12,35 +12,40 @@
|
|||
namespace spec\Sylius\Bundle\ReviewBundle\Validator\Constraints;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueUserEmail;
|
||||
use Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueReviewerEmail;
|
||||
use Sylius\Bundle\UserBundle\Doctrine\ORM\UserRepository;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
use Sylius\Component\User\Model\CustomerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Symfony\Component\Validator\ExecutionContext;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class UniqueUserEmailValidatorSpec extends ObjectBehavior
|
||||
class UniqueReviewerEmailValidatorSpec extends ObjectBehavior
|
||||
{
|
||||
function let(UserRepository $userRepository, TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authorizationChecker, ExecutionContext $context)
|
||||
{
|
||||
function let(
|
||||
UserRepository $userRepository,
|
||||
TokenStorageInterface $tokenStorage,
|
||||
AuthorizationCheckerInterface $authorizationChecker,
|
||||
ExecutionContext $context
|
||||
) {
|
||||
$this->beConstructedWith($userRepository, $tokenStorage, $authorizationChecker);
|
||||
$this->initialize($context);
|
||||
}
|
||||
|
||||
function it_is_initializable()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueUserEmailValidator');
|
||||
$this->shouldHaveType('Sylius\Bundle\ReviewBundle\Validator\Constraints\UniqueReviewerEmailValidator');
|
||||
}
|
||||
|
||||
function it_extends_contraint_validator_class()
|
||||
{
|
||||
$this->shouldHaveType('Symfony\Component\Validator\ConstraintValidator');
|
||||
$this->shouldHaveType(ConstraintValidator::class);
|
||||
}
|
||||
|
||||
function it_validates_if_user_with_given_email_is_already_registered(
|
||||
|
|
@ -49,7 +54,7 @@ class UniqueUserEmailValidatorSpec extends ObjectBehavior
|
|||
$authorizationChecker,
|
||||
$context,
|
||||
TokenInterface $token,
|
||||
UniqueUserEmail $constraint,
|
||||
UniqueReviewerEmail $constraint,
|
||||
ReviewInterface $review,
|
||||
CustomerInterface $customer,
|
||||
CustomerInterface $existingUser
|
||||
|
|
@ -59,7 +64,7 @@ class UniqueUserEmailValidatorSpec extends ObjectBehavior
|
|||
|
||||
$review->getAuthor()->willReturn($customer);
|
||||
$customer->getEmail()->willReturn('john.doe@example.com');
|
||||
$userRepository->findOneByEmail('john.doe@example.com')->willReturn($existingUser)->shouldBeCalled();
|
||||
$userRepository->findOneByEmail('john.doe@example.com')->willReturn($existingUser);
|
||||
$constraint->message = 'This email is already registered. Please log in.';
|
||||
|
||||
$context->addViolationAt('author', 'This email is already registered. Please log in.', [], null)->shouldBeCalled();
|
||||
|
|
@ -28,8 +28,8 @@ class CustomerGuestType extends AbstractResourceType
|
|||
private $guestCustomerSubscriber;
|
||||
|
||||
/**
|
||||
* @param string $dataClass
|
||||
* @param array $validationGroups
|
||||
* @param string $dataClass
|
||||
* @param array $validationGroups
|
||||
* @param EventSubscriberInterface $guestCustomerSubscriber
|
||||
*/
|
||||
public function __construct($dataClass, array $validationGroups, EventSubscriberInterface $guestCustomerSubscriber)
|
||||
|
|
|
|||
|
|
@ -33,4 +33,4 @@ sylius:
|
|||
not_blank: Please enter your email.
|
||||
invalid: This email is invalid.
|
||||
unique: This email is already used.
|
||||
registered: This email is already registered, please login or reset your password.
|
||||
registered: This email is already registered, please login or use forgotten password.
|
||||
|
|
|
|||
|
|
@ -1,194 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\WebBundle\Controller\Frontend\Review;
|
||||
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use FOS\RestBundle\Controller\FOSRestController;
|
||||
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
|
||||
use Sylius\Component\Core\Model\ProductInterface;
|
||||
use Sylius\Component\Resource\Factory\FactoryInterface;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* @author Justin Hilles <justin@1011i.com>
|
||||
* @author Daniel Richter <nexyz9@gmail.com>
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class ProductReviewController extends FOSRestController
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function indexAction(Request $request)
|
||||
{
|
||||
$product = $this->findProductOr404($request->attributes->get('slug'));
|
||||
$reviews = $this->getProductReviewRepository()->findBy([
|
||||
'reviewSubject' => $product,
|
||||
'status' => ReviewInterface::STATUS_ACCEPTED,
|
||||
]);
|
||||
|
||||
$view = $this
|
||||
->view()
|
||||
->setTemplate('SyliusWebBundle:Frontend/Review:_list.html.twig')
|
||||
->setData([
|
||||
'product_reviews' => $reviews,
|
||||
])
|
||||
;
|
||||
|
||||
return $this->handleView($view);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
$review = $this->getProductReviewFactory()->createNew();
|
||||
$form = $this->getReviewForm($review);
|
||||
|
||||
$view = $this
|
||||
->view()
|
||||
->setTemplate('SyliusWebBundle:Frontend/Review:_form.html.twig')
|
||||
->setData([
|
||||
'product_review' => $review,
|
||||
'form' => $form->createView(),
|
||||
])
|
||||
;
|
||||
|
||||
return $this->handleView($view);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function createWithAjaxAction(Request $request)
|
||||
{
|
||||
$review = $this->getProductReviewFactory()->createNew();
|
||||
$form = $this->getReviewForm($review);
|
||||
|
||||
if ($form->submit($request)->isValid()) {
|
||||
$manager = $this->getProductReviewManager();
|
||||
$review = $form->getData();
|
||||
$product = $this->findProductOr404($request->attributes->get('slug'));
|
||||
$review->setReviewSubject($product);
|
||||
|
||||
$manager->persist($review);
|
||||
$manager->flush();
|
||||
|
||||
$this->addFlashMessage('success', 'sylius.resource.create', ['%resource%' => 'Product review']);
|
||||
|
||||
return new JsonResponse('success');
|
||||
}
|
||||
|
||||
return new JsonResponse($this->getFormErrorsAsArray($form));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $slug
|
||||
*
|
||||
* @return ProductInterface
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
private function findProductOr404($slug)
|
||||
{
|
||||
if (!$product = $this->getProductRepository()->findOneBy(['slug' => $slug])) {
|
||||
throw new NotFoundHttpException(sprintf('Product with slug "%s" not found', $slug));
|
||||
}
|
||||
|
||||
return $product;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FormInterface $form
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getFormErrorsAsArray(FormInterface $form)
|
||||
{
|
||||
$errors = [];
|
||||
foreach ($form->getErrors(true) as $error) {
|
||||
$errors[$error->getCause()->getPropertyPath()] = $error->getMessage();
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FactoryInterface
|
||||
*/
|
||||
private function getProductReviewFactory()
|
||||
{
|
||||
return $this->get('sylius.factory.product_review');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityRepository
|
||||
*/
|
||||
private function getProductReviewRepository()
|
||||
{
|
||||
return $this->get('sylius.repository.product_review');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityRepository
|
||||
*/
|
||||
private function getProductRepository()
|
||||
{
|
||||
return $this->get('sylius.repository.product');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReviewInterface $review
|
||||
*
|
||||
* @return FormInterface
|
||||
*/
|
||||
private function getReviewForm(ReviewInterface $review)
|
||||
{
|
||||
return $this->get('form.factory')->create('sylius_product_review', $review);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ObjectManager
|
||||
*/
|
||||
private function getProductReviewManager()
|
||||
{
|
||||
return $this->get('sylius.manager.product_review');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param string $message
|
||||
* @param array $parameters
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
private function addFlashMessage($type, $message, array $parameters)
|
||||
{
|
||||
if (!$this->container->has('session')) {
|
||||
throw new \LogicException('You can not use the addFlash method if sessions are disabled.');
|
||||
}
|
||||
|
||||
$translator = $this->container->get('translator');
|
||||
$this->container->get('session')->getFlashBag()->add($type, $translator->trans($message, $parameters, 'flashes'));
|
||||
}
|
||||
}
|
||||
|
|
@ -374,8 +374,8 @@ class BackendMenuBuilder extends MenuBuilder
|
|||
|
||||
/**
|
||||
* @param ItemInterface $menu
|
||||
* @param array $childOptions
|
||||
* @param string $section
|
||||
* @param array $childOptions
|
||||
* @param string $section
|
||||
*/
|
||||
public function addReviewsMenu(ItemInterface $menu, array $childOptions, $section)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -183,6 +183,6 @@ sylius_backend_metadata_container:
|
|||
resource: @SyliusWebBundle/Resources/config/routing/backend/metadata_container.yml
|
||||
prefix: /metadata
|
||||
|
||||
sylius_backend_review:
|
||||
resource: @SyliusWebBundle/Resources/config/routing/backend/review.yml
|
||||
prefix: /reviews
|
||||
sylius_backend_product_review:
|
||||
resource: @SyliusWebBundle/Resources/config/routing/backend/product_review.yml
|
||||
prefix: /product-reviews
|
||||
|
|
|
|||
|
|
@ -48,3 +48,4 @@ sylius_backend_product_review_update_state:
|
|||
defaults:
|
||||
_controller: sylius.controller.product_review:updateStateAction
|
||||
graph: sylius_product_review
|
||||
|
||||
|
|
@ -29,8 +29,8 @@ sylius_user_account:
|
|||
resource: @SyliusUserBundle/Resources/config/routing/account.yml
|
||||
prefix: /account
|
||||
|
||||
sylius_review:
|
||||
resource: @SyliusWebBundle/Resources/config/routing/frontend/review.yml
|
||||
sylius_product_review:
|
||||
resource: @SyliusWebBundle/Resources/config/routing/frontend/product_review.yml
|
||||
|
||||
sylius_cart:
|
||||
resource: @SyliusCartBundle/Resources/config/routing.yml
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
# This file is part of the Sylius package.
|
||||
# (c) Paweł Jędrzejewski
|
||||
|
||||
sylius_product_review:
|
||||
path: /products/{productId}/reviews/new
|
||||
methods: [POST]
|
||||
defaults:
|
||||
_controller: sylius.controller.product_review:createAction
|
||||
_sylius:
|
||||
template: 'SyliusWebBundle:Frontend/Review:_form.html.twig'
|
||||
factory:
|
||||
method: createForSubject
|
||||
arguments: [$productId]
|
||||
permission: false
|
||||
form: sylius_product_review
|
||||
_format: json
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
sylius_review_product:
|
||||
pattern: /p/{slug}/product_review
|
||||
methods: [POST]
|
||||
defaults:
|
||||
_controller: sylius.controller.frontend.product_review:createWithAjaxAction
|
||||
_sylius:
|
||||
permission: false
|
||||
|
|
@ -6,5 +6,5 @@ sylius_product:
|
|||
prefix: /product
|
||||
|
||||
sylius_review:
|
||||
resource: @SyliusWebBundle/Resources/config/routing/partial/review.yml
|
||||
prefix: /reviews
|
||||
resource: @SyliusWebBundle/Resources/config/routing/partial/product-review.yml
|
||||
prefix: /product-reviews
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
# This file is part of the Sylius package.
|
||||
# (c) Paweł Jędrzejewski
|
||||
|
||||
sylius_product_reviews:
|
||||
path: /products/{productId}/reviews/
|
||||
defaults:
|
||||
_controller: sylius.controller.product_review:indexAction
|
||||
_sylius:
|
||||
template: 'SyliusWebBundle:Frontend/Review:_list.html.twig'
|
||||
repository:
|
||||
method: findAcceptedBySubjectId
|
||||
arguments: [$productId]
|
||||
permission: false
|
||||
|
||||
sylius_product_review_create:
|
||||
path: /products/{productId}/reviews/new
|
||||
methods: [GET]
|
||||
defaults:
|
||||
_controller: sylius.controller.product_review:createAction
|
||||
_sylius:
|
||||
template: 'SyliusWebBundle:Frontend/Review:_form.html.twig'
|
||||
factory:
|
||||
method: createForSubject
|
||||
arguments: [$productId]
|
||||
permission: false
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
# This file is part of the Sylius package.
|
||||
# (c) Paweł Jędrzejewski
|
||||
|
||||
sylius_partial_product_review_list:
|
||||
pattern: /{slug}
|
||||
defaults:
|
||||
_controller: sylius.controller.frontend.product_review:indexAction
|
||||
_sylius:
|
||||
paginate: false
|
||||
limit: $limit
|
||||
sorting:
|
||||
createdAt: desc
|
||||
filterable: true
|
||||
criteria: { 'reviewSubject': $product, 'status': 'accepted' }
|
||||
template: 'SyliusWebBundle:Frontend/Review:_list.html.twig'
|
||||
permission: false
|
||||
|
||||
sylius_partial_product_review_form:
|
||||
pattern: /{slug}/new
|
||||
methods: [GET]
|
||||
defaults:
|
||||
_controller: sylius.controller.frontend.product_review:createAction
|
||||
_sylius:
|
||||
template: 'SyliusWebBundle:Frontend/Review:_form.html.twig'
|
||||
permission: false
|
||||
|
|
@ -20,7 +20,6 @@
|
|||
<parameter key="sylius.controller.frontend.homepage.class">Sylius\Bundle\WebBundle\Controller\Frontend\HomepageController</parameter>
|
||||
<parameter key="sylius.controller.frontend.account.address.class">Sylius\Bundle\WebBundle\Controller\Frontend\Account\AddressController</parameter>
|
||||
<parameter key="sylius.controller.frontend.account.order.class">Sylius\Bundle\WebBundle\Controller\Frontend\Account\OrderController</parameter>
|
||||
<parameter key="sylius.controller.frontend.product_review.class">Sylius\Bundle\WebBundle\Controller\Frontend\Review\ProductReviewController</parameter>
|
||||
|
||||
<parameter key="sylius.controller.backend.dashboard.class">Sylius\Bundle\WebBundle\Controller\Backend\DashboardController</parameter>
|
||||
<parameter key="sylius.controller.backend.security.class">Sylius\Bundle\WebBundle\Controller\Backend\SecurityController</parameter>
|
||||
|
|
@ -32,7 +31,6 @@
|
|||
</parameters>
|
||||
|
||||
<services>
|
||||
|
||||
<service id="sylius.controller.frontend.homepage" class="%sylius.controller.frontend.homepage.class%">
|
||||
<call method="setContainer">
|
||||
<argument type="service" id="service_container" />
|
||||
|
|
@ -48,11 +46,6 @@
|
|||
<argument type="service" id="service_container" />
|
||||
</call>
|
||||
</service>
|
||||
<service id="sylius.controller.frontend.product_review" class="%sylius.controller.frontend.product_review.class%">
|
||||
<call method="setContainer">
|
||||
<argument type="service" id="service_container" />
|
||||
</call>
|
||||
</service>
|
||||
<service id="sylius.controller.backend.dashboard" class="%sylius.controller.backend.dashboard.class%">
|
||||
<call method="setContainer">
|
||||
<argument type="service" id="service_container" />
|
||||
|
|
|
|||
|
|
@ -675,52 +675,6 @@ sylius:
|
|||
taxes: Taxes
|
||||
total: Total
|
||||
update_header: Editing order
|
||||
customer: customer
|
||||
currency: Currency
|
||||
state: State
|
||||
immutable_warning: Already shipped orders are immutable.
|
||||
promotion_coupons: Coupons
|
||||
no_promotion: No coupons were used.order:
|
||||
adjustments:
|
||||
manage: Manage adjustments
|
||||
type: Type
|
||||
description: Description
|
||||
amount: Amount
|
||||
locked: Locked?
|
||||
lock: Lock
|
||||
unlock: Unlock
|
||||
lock_all: Lock all adjustments
|
||||
unlock_all: Unlock all adjustments
|
||||
comment:
|
||||
header: Order comments
|
||||
comment: Comment
|
||||
author: Author
|
||||
created_at: Created at
|
||||
notify: Notification
|
||||
state: State
|
||||
customer:
|
||||
notified: Customer notified
|
||||
not_notified: Customer not notified
|
||||
no_comment: No comment
|
||||
route:
|
||||
create: Create route
|
||||
create_header: Creating route
|
||||
id: ID
|
||||
index_header: Routes
|
||||
name: Name
|
||||
no_results: There are no routes to display.
|
||||
page: Page
|
||||
title: Title
|
||||
update_header: Editing route
|
||||
view: View
|
||||
redirect_route:
|
||||
create: Create redirect route
|
||||
create_header: Creating redirect route
|
||||
id: ID
|
||||
index_header: Redirect route
|
||||
no_results: There are no redirect routes to display.
|
||||
title: Title
|
||||
update_header: Editing redirect route
|
||||
review:
|
||||
create: New review
|
||||
index: Product reviews
|
||||
|
|
@ -736,43 +690,9 @@ sylius:
|
|||
created_at: Created at
|
||||
details: Review details
|
||||
editing: Editing review
|
||||
shipment:
|
||||
ship: Ship
|
||||
created_at: Created at
|
||||
id: ID
|
||||
index_header: Shipments
|
||||
inventory_state: Inventory state
|
||||
manage: Manage shipments
|
||||
method: Method
|
||||
modified: Modified
|
||||
name: Name
|
||||
no_items: There are no items to display.
|
||||
no_results: There are no shipments to display.
|
||||
order: Order
|
||||
show_header: Shipment details
|
||||
sku: SKU
|
||||
state: State
|
||||
tracking_code: Tracking Code
|
||||
update: Edit
|
||||
update_header: Editing shipment
|
||||
updated_at: Last update
|
||||
channel:
|
||||
create: Add channel
|
||||
created_at: Created at
|
||||
code: Code
|
||||
currency_default: Default currency
|
||||
enabled: Enabled
|
||||
id: ID
|
||||
index_header: Channels
|
||||
locale_default: Default locale
|
||||
manage: Manage channels
|
||||
create_header: Add channel
|
||||
name: Name
|
||||
url: Url
|
||||
no_results: There are no channels configured.
|
||||
update: Edit
|
||||
update_header: Editing channel
|
||||
updated_at: Last update
|
||||
header: Product reviews
|
||||
product_review: Product review
|
||||
no_results: There are no reviews for this product.
|
||||
order_item:
|
||||
product: Item
|
||||
quantity: Qty
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if product.averageRating is not null and product.averageRating != 0 %}
|
||||
{% if 0 != product.averageRating %}
|
||||
<tr>
|
||||
<td>{{ 'sylius.product.rating'|trans }}</td>
|
||||
<td>{{ product.averageRating|round(2, 'floor') }}</td>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
{{ form_errors(form) }}
|
||||
|
||||
<form action="{{ path('sylius_backend_product_review_create') }}" method="post" class="form-horizontal" {{ form_enctype(form) }} novalidate>nie zbywa
|
||||
<form action="{{ path('sylius_backend_product_review_create') }}" method="post" class="form-horizontal" {{ form_enctype(form) }} novalidate>
|
||||
{% include 'SyliusWebBundle:Backend/Review:_form.html.twig' %}
|
||||
{{ create() }}
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -141,9 +141,9 @@
|
|||
|
||||
<div>
|
||||
<h3>{{ 'sylius.review.header'|trans }}</h3>
|
||||
{% render(url("sylius_partial_product_review_list", { 'slug': product.slug, limit: 3 })) %}
|
||||
{% render(url('sylius_product_reviews', { 'productId': product.id, limit: 3 })) %}
|
||||
<hr />
|
||||
{% render(url("sylius_partial_product_review_form", { 'slug': product.slug })) %}
|
||||
{% render(url('sylius_product_review_create', { 'productId': product.id })) %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -153,5 +153,11 @@
|
|||
'bundles/syliusreview/js/sylius-review.js'
|
||||
%}
|
||||
<script type="text/javascript" src="{{ asset_url }}"></script>
|
||||
<script>
|
||||
var createMessage = "{{ 'sylius.resource.create'|trans({'%resource%': 'sylius.review.product_review'|trans}, 'flashes') }}";
|
||||
$(document).ready(function() {
|
||||
initializeAjaxForm(createMessage);
|
||||
});
|
||||
</script>
|
||||
{% endjavascripts %}
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{{ form_start(form, { 'attr': { 'class': 'form-horizontal', 'id': 'reviewForm' }, 'action': path('sylius_review_product', { 'slug': app.request.attributes.get('slug') }) }) }}
|
||||
{{ form_start(form, { 'attr': { 'class': 'form-horizontal', 'id': 'reviewForm' }, 'action': path('sylius_product_review', { 'productId': app.request.attributes.get('productId') }) }) }}
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
|
|
@ -28,4 +28,4 @@
|
|||
<div class="panel-footer">
|
||||
<button type="submit" class="btn btn-primary">{{ 'sylius.form.review.submit'|trans }}</button>
|
||||
</div>
|
||||
{{ form_row(form._token) }}
|
||||
{{ form_end(form, {'render_rest': false}) }}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class Product extends BaseProduct implements ProductInterface, ReviewableProduct
|
|||
/**
|
||||
* @var float
|
||||
*/
|
||||
protected $averageRating;
|
||||
protected $averageRating = 0;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
|
@ -368,7 +368,7 @@ class Product extends BaseProduct implements ProductInterface, ReviewableProduct
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Collection|ReviewInterface[]
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReviews()
|
||||
{
|
||||
|
|
@ -376,15 +376,7 @@ class Product extends BaseProduct implements ProductInterface, ReviewableProduct
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Collection $reviews
|
||||
*/
|
||||
public function setReviews(Collection $reviews)
|
||||
{
|
||||
$this->reviews = $reviews;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReviewInterface $review
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addReview(ReviewInterface $review)
|
||||
{
|
||||
|
|
@ -392,7 +384,7 @@ class Product extends BaseProduct implements ProductInterface, ReviewableProduct
|
|||
}
|
||||
|
||||
/**
|
||||
* @param ReviewInterface $review
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeReview(ReviewInterface $review)
|
||||
{
|
||||
|
|
@ -400,7 +392,7 @@ class Product extends BaseProduct implements ProductInterface, ReviewableProduct
|
|||
}
|
||||
|
||||
/**
|
||||
* @param float $averageRating
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setAverageRating($averageRating)
|
||||
{
|
||||
|
|
@ -408,7 +400,7 @@ class Product extends BaseProduct implements ProductInterface, ReviewableProduct
|
|||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAverageRating()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
namespace spec\Sylius\Component\Core\Model;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Component\Review\Model\Review;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
|
|
@ -25,6 +26,6 @@ class ProductReviewSpec extends ObjectBehavior
|
|||
|
||||
function it_extends_review()
|
||||
{
|
||||
$this->shouldHaveType('Sylius\Component\Review\Model\Review');
|
||||
$this->shouldHaveType(Review::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
language: php
|
||||
|
||||
sudo: false
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 7.0
|
||||
- 5.6
|
||||
- 5.5
|
||||
|
||||
before_script: composer install --dev --prefer-source
|
||||
before_install:
|
||||
- echo "memory_limit=2048M" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
|
||||
- phpenv config-rm xdebug.ini || true
|
||||
|
||||
script: bin/phpspec run -fpretty --verbose
|
||||
install:
|
||||
- composer install --no-interaction --prefer-source
|
||||
|
||||
notifications:
|
||||
email: "travis-ci@sylius.org"
|
||||
irc: "irc.freenode.org#sylius-dev"
|
||||
|
||||
script:
|
||||
- bin/phpspec run -fpretty --verbose
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
### v0.16.0
|
||||
### v0.17.0
|
||||
|
||||
* Initial dev release.
|
||||
|
|
|
|||
|
|
@ -17,28 +17,25 @@ use Sylius\Component\Review\Model\ReviewInterface;
|
|||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
*/
|
||||
class AverageRatingCalculator implements AverageRatingCalculatorInterface
|
||||
class AverageRatingCalculator implements ReviewableRatingCalculatorInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculate(ReviewableInterface $reviewable)
|
||||
{
|
||||
if (0 === count($reviews = $reviewable->getReviews())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$sum = 0.0;
|
||||
$sum = 0;
|
||||
$reviewsNumber = 0;
|
||||
$reviews = $reviewable->getReviews();
|
||||
|
||||
foreach ($reviews as $review) {
|
||||
if (ReviewInterface::STATUS_ACCEPTED === $review->getStatus()) {
|
||||
++$reviewsNumber;
|
||||
|
||||
$sum = $sum + $review->getRating();
|
||||
$sum += $review->getRating();
|
||||
}
|
||||
}
|
||||
|
||||
return $sum / $reviewsNumber;
|
||||
return 0 !== $reviewsNumber ? $sum / $reviewsNumber : 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ use Sylius\Component\Review\Model\ReviewableInterface;
|
|||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
interface AverageRatingCalculatorInterface
|
||||
interface ReviewableRatingCalculatorInterface
|
||||
{
|
||||
/**
|
||||
* @param ReviewableInterface $reviewable
|
||||
64
src/Sylius/Component/Review/Factory/ReviewFactory.php
Normal file
64
src/Sylius/Component/Review/Factory/ReviewFactory.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Component\Review\Factory;
|
||||
|
||||
use Sylius\Component\Resource\Factory\FactoryInterface;
|
||||
use Sylius\Component\Resource\Repository\RepositoryInterface;
|
||||
|
||||
/**
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class ReviewFactory implements ReviewFactoryInterface
|
||||
{
|
||||
/**
|
||||
* @var FactoryInterface
|
||||
*/
|
||||
private $factory;
|
||||
|
||||
/**
|
||||
* @var RepositoryInterface
|
||||
*/
|
||||
private $subjectRepository;
|
||||
|
||||
/**
|
||||
* @param FactoryInterface $factory
|
||||
* @param RepositoryInterface $subjectRepository
|
||||
*/
|
||||
public function __construct(FactoryInterface $factory, RepositoryInterface $subjectRepository)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->subjectRepository = $subjectRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createNew()
|
||||
{
|
||||
return $this->factory->createNew();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createForSubject($subjectId)
|
||||
{
|
||||
if (null === $subject = $this->subjectRepository->find($subjectId)) {
|
||||
throw new \InvalidArgumentException(sprintf('Review subject with id "%s" does not exist.', $subjectId));
|
||||
}
|
||||
|
||||
$review = $this->factory->createNew();
|
||||
$review->setReviewSubject($subject);
|
||||
|
||||
return $review;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Component\Review\Factory;
|
||||
|
||||
use Sylius\Component\Resource\Factory\FactoryInterface;
|
||||
use Sylius\Component\Review\Model\ReviewableInterface;
|
||||
use Sylius\Component\Review\Model\ReviewInterface;
|
||||
|
||||
/**
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
interface ReviewFactoryInterface extends FactoryInterface
|
||||
{
|
||||
/**
|
||||
* @param ReviewableInterface $subjectId
|
||||
*
|
||||
* @return ReviewInterface
|
||||
*/
|
||||
public function createForSubject($subjectId);
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2011-2015 Paweł Jędrzejewski
|
||||
Copyright (c) 2011-2016 Paweł Jędrzejewski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -11,12 +11,17 @@
|
|||
|
||||
namespace Sylius\Component\Review\Model;
|
||||
|
||||
use Sylius\Component\Resource\Model\TimestampableTrait;
|
||||
|
||||
/**
|
||||
* @author Daniel Richter <nexyz9@gmail.com>
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class Review implements ReviewInterface
|
||||
{
|
||||
use TimestampableTrait;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
|
@ -52,19 +57,6 @@ class Review implements ReviewInterface
|
|||
*/
|
||||
protected $reviewSubject;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*/
|
||||
protected $createdAt;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*/
|
||||
protected $updatedAt;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->createdAt = new \DateTime();
|
||||
|
|
@ -173,36 +165,4 @@ class Review implements ReviewInterface
|
|||
{
|
||||
$this->reviewSubject = $reviewSubject;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setCreatedAt(\DateTime $createdAt)
|
||||
{
|
||||
$this->createdAt = $createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCreatedAt()
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUpdatedAt(\DateTime $updatedAt)
|
||||
{
|
||||
$this->updatedAt = $updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUpdatedAt()
|
||||
{
|
||||
return $this->updatedAt;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ use Sylius\Component\Resource\Model\TimestampableInterface;
|
|||
*/
|
||||
interface ReviewInterface extends TimestampableInterface, ResourceInterface
|
||||
{
|
||||
const REVIEW_STATE_MACHINE_GRAPH = 'sylius_review';
|
||||
|
||||
const STATUS_NEW = 'new';
|
||||
const STATUS_ACCEPTED = 'accepted';
|
||||
const STATUS_REJECTED = 'rejected';
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
namespace Sylius\Component\Review\Model;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
*/
|
||||
|
|
@ -24,7 +22,7 @@ interface ReviewableInterface
|
|||
public function getName();
|
||||
|
||||
/**
|
||||
* @return Collection|ReviewInterface[]
|
||||
* @return ReviewInterface[]
|
||||
*/
|
||||
public function getReviews();
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,12 @@
|
|||
|
||||
namespace Sylius\Component\Review\Model;
|
||||
|
||||
use Sylius\Component\Resource\Model\ResourceInterface;
|
||||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
*/
|
||||
interface ReviewerInterface
|
||||
interface ReviewerInterface extends ResourceInterface
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Review Component [](http://travis-ci.org/Sylius/Report)
|
||||
Review Component [](http://travis-ci.org/Sylius/Review)
|
||||
=================
|
||||
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Modern ecommerce for PHP and Symfony2. Visit [Sylius.org](http://sylius.org).
|
|||
Documentation
|
||||
-------------
|
||||
|
||||
Documentation is available on [**docs.sylius.org**](http://docs.sylius.org/en/latest/components/Report/index.html).
|
||||
Documentation is available on [**docs.sylius.org**](http://docs.sylius.org/en/latest/components/Review/index.html).
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
|
@ -37,10 +37,10 @@ If you find a bug, please refer to the [Reporting a Bug](http://docs.sylius.org/
|
|||
MIT License
|
||||
-----------
|
||||
|
||||
License can be found [here](https://github.com/Sylius/Report/blob/master/LICENSE).
|
||||
License can be found [here](https://github.com/Sylius/Review/blob/master/LICENSE).
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
The component was originally created by [Paweł Jędrzejewski](http://pjedrzejewski.com).
|
||||
See the list of [contributors](https://github.com/Sylius/Report/contributors).
|
||||
The component was originally created by [Mateusz Zalewski](mateusz.zalewski@lakion.com) and [Grzegorz Sadowski](grzegorz.sadowski@lakion.com), based on [Daniel Richter](nexyz9@gmail.com) work.
|
||||
See the list of [contributors](https://github.com/Sylius/Review/contributors).
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
"name": "Mateusz Zalewski",
|
||||
"email": "mateusz.zalewski@lakion.com"
|
||||
},
|
||||
{
|
||||
"name": "Grzegorz Sadowski",
|
||||
"email": "grzegorz.sadowski@lakion.com"
|
||||
},
|
||||
{
|
||||
"name": "Daniel Richter",
|
||||
"email": "nexyz9@gmail.com"
|
||||
|
|
@ -28,10 +32,10 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
"php": "^5.5.9|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "~2.1"
|
||||
"phpspec/phpspec": "^2.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Sylius\\Component\\Review\\": "" }
|
||||
|
|
@ -39,9 +43,10 @@
|
|||
"autoload-dev": {
|
||||
"psr-4": { "Sylius\\Component\\Review\\spec\\": "spec/" }
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.16-dev"
|
||||
"dev-master": "0.17-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue