chameleon-system-private/review-bundle
A generic bundle for reviewing things (e.g. products or articles)
Requires
- ext-json: *
- chameleon-system/chameleon-base: ~8.0.0
- thecodingmachine/safe: ^1.3
- 8.47.1
- 8.47.0
- 8.0.x-dev
- 8.0.51
- 8.0.50
- 8.0.48
- 8.0.46
- 8.0.45
- 8.0.44
- 8.0.43
- 8.0.42
- 8.0.41
- 8.0.40
- 8.0.39
- 8.0.38
- 8.0.37
- 8.0.36
- 8.0.35
- 8.0.34
- 8.0.33
- 8.0.32
- 8.0.31
- 8.0.30
- 8.0.29
- 8.0.28
- 8.0.27
- 8.0.26
- 8.0.25
- 8.0.24
- 8.0.23
- 8.0.22
- 8.0.21
- 8.0.20
- 8.0.19
- 8.0.18
- 8.0.17
- 8.0.16
- 8.0.15
- 8.0.14
- 8.0.13
- 8.0.12
- 8.0.11
- 8.0.10
- 8.0.9
- 8.0.8
- 8.0.7
- 8.0.6
- 8.0.5
- 8.0.4
- 8.0.3
- 8.0.2
- 8.0.1
- 7.1.x-dev
- 7.1.140
- 7.1.139
- 7.1.138
- 7.1.137
- 7.1.136
- 7.1.135
- 7.1.134
- 7.1.133
- 7.1.132
- 7.1.131
- 7.1.130
- 7.1.129
- 7.1.128
- 7.1.127
- 7.1.126
- 7.1.125
- 7.1.124
- 7.1.123
- 7.1.122
- 7.1.121
- 7.1.120
- 7.1.119
- 7.1.118
- 7.1.117
- 7.1.116
- 7.1.115
- 7.1.114
- 7.1.113
- 7.1.112
- 7.1.111
- 7.1.110
- 7.1.109
- 7.1.108
- 7.1.107
- 7.1.106
- 7.1.105
- 7.1.104
- 7.1.103
- 7.1.102
- 7.1.101
- 7.1.100
- 7.1.99
- 7.1.98
- 7.1.97
- 7.1.96
- 7.1.95
- 7.1.94
- 7.1.93
- 7.1.92
- 7.1.91
- 7.1.90
- 7.1.89
- 7.1.88
- 7.1.87
- 7.1.86
- 7.1.85
- 7.1.84
- 7.1.83
- 7.1.82
- 7.1.81
- 7.1.80
- 7.1.79
- 7.1.78
- 7.1.77
- 7.1.76
- 7.1.75
- 7.1.74
- 7.1.73
- 7.1.72
- 7.1.71
- 7.1.70
- 7.1.69
- 7.1.68
- 7.1.67
- 7.1.66
- 7.1.65
- 7.1.64
- 7.1.63
- 7.1.62
- 7.1.61
- 7.1.60
- 7.1.59
- 7.1.58
- 7.1.57
- 7.1.56
- 7.1.55
- 7.1.54
- 7.1.53
- 7.1.52
- 7.1.51
- 7.1.50
- 7.1.49
- 7.1.48
- 7.1.47
- 7.1.46
- 7.1.45
- 7.1.44
- 7.1.43
- 7.1.42
- 7.1.41
- 7.1.40
- 7.1.39
- 7.1.38
- 7.1.37
- 7.1.36
- 7.1.35
- 7.1.34
- 7.1.33
- 7.1.32
- 7.1.31
- 7.1.30
- 7.1.29
- 7.1.28
- 7.1.27
- 7.1.26
- 7.1.25
- 7.1.24
- 7.1.23
- 7.1.22
- 7.1.21
- 7.1.20
- 7.1.19
- 7.1.18
- 7.1.17
- 7.1.16
- 7.0.23
- 7.0.22
- 7.0.21
- dev-main
- dev-66480-paypal-button-integration-wip
- dev-65797-paypal-checkout-7.1.x
- dev-65797-paypal-button-integration
- dev-64992-campaign-tracking-bundle
- dev-64817-update-tag-manager-bundle
README
Allows for reviewing arbitrary things. In order to review something,
one has to create a review_configuration in the backend, consisting
of a ReviewTargetHandler (handles what should be reviewed),
a PublicationStrategy (how a review should be published) and
some optional rendering information.
This bundle exposes 3 endpoints:
GET /api/reviews/{configurationId}/{reviewTargetId}lists existing reviews- Use
Accept: application/jsonheader to get the information as JSON
- Use
POST /api/reviews/{configurationId}/{reviewTargetId}creates a new reviewGET /api/reviews/{configurationId}/publication-hook/{encryptedArguments}- Calls the
handlePublicationHookmethod on the publication strategy of the given configuration. Useful in order to delay publication of a review (e.g. by sending a 'confirm' link to an admin)
- Calls the
In the URLs above, {configurationId} is the id of the review_configuration
record created in the backed. {reviewTargetId} can be an arbitrary string that
is a valid review target according to the configured ReviewTargetHandler.
A publication strategy can create hook urls by using PublicationStrategyHookService
Including Reviews
The bundle is built in a way to maximize flexibility when including reviews. For this reason, multiple ways of including reviews on multiple different levels of abstraction exist:
1. As a template module in a module spot
TODO (Does not exist yet)
2. As a template include
In the template for your review target, you can include ChameleonSystemReview/include.html.twig
and pass it a configurationId and targetId in order to render the reviews there.
{% include 'ChameleonSystemReview/include.html.twig' with {
'configurationId': '89fa5164-3e28-454e-a296-d43c606afed2',
'targetId': product.id
} %}
Behind the scenes, this template does very little: It defines a single div and loads some javascript
that will asynchronously fetch the reviews. As such, this should not be impacted by caching.
3. Custom rendering
If you have a more complex use case (e.g. integrating reviews into a larger AJAX response), then you can
use ReviewService::renderAsHtml in order to get the rendered HTML. After inserting the rendered HTML into
the DOM, be sure to fire the chameleon_system_review.inserted event on the container in order to
initialize the form correctly.
<!-- Ensure this script is loaded somewhere -->
<script
src="/assets/bundles/chameleonsystemreview/main.js"
type="module"
></script>
<script>
fetchMoreInvolvedData(html => {
const container = document.querySelector('#container');
container.innerHTML = html;
container.dispatchEvent(new Event(chameleon_system_review.inserted', {
bubbles: true
}))
})
</script>
This method can also be used in order to statically embed reviews into the template.
4. Manually via JSON API
If you want full custom rendering, as may be the case in a single page application (SPA), you can fetch reviews from
the /api/reviews/{configurationId}/{reviewTargetId} using a GET request and submit
reviews using a POST request.
- When you specify the
Accept: application/jsonheader, the endpoint will respond with JSON - When you specify the
Content-Type: application/jsonheader, the POST endpoint will accept a JSON body
Make sure you specify credentials: 'same-origin' when submitting the data in order to
ensure that the session cookie is transmitted with the request. It is required to validate
that a user is logged in.
Extending
Adding review target handler
In order to add a target handler, implement the ReviewTargetHandlerInterface and
tag the resulting service with chameleon_system_review.review_target_handler
in the dependency injection container. Additionally, a label and help may be
specified while tagging.
When implementing a target handler that is based on database contents, the
AbstractDatabaseReviewTargetHandler may be a good base class to use.
Implementation:
class BandTargetHandler implements ReviewTargetHandlerInterface {
public function isIdentifierValid(string $identifier): bool
{
return null !== $this->getReviewTarget($identifier);
}
public function getReviewTarget(string $identifier)
{
return $this->bandApi->get($identifier);
}
}
Registering:
<service
id="esono_customer.review.band_target_handler"
class="Esono\Customer\Review\BandTargetHandler"
>
<!--
Translations for label & help can be defined in
@YourBundle/Resources/translations/admin.{LANG}.xlf
-->
<tag
name="chameleon_system_review.review_target_handler"
label="esono_customer.review.band_target_handler.label"
help="esono_customer.review.band_target_handler.help"
/>
</service>
Adding a publication strategy
In order to add a publication strategy, implement the PublicationStrategyInterface and
tag the resulting service with chameleon_system_review.publication_strategy
in the dependency injection container. Additionally, a label and help may be specified
while tagging.
class NotifyModeratorViaTelegram implements PublicationStrategyInterface {
public function handleNewReview(Configuration $configuration, ReviewDataModelInterface $review): void
{
$review->setPublic(true);
$deleteUrl = $this->hookService->generatePublicationStrategyHookUrl($configuration, [
'action' => 'delete',
'review' => $review->getId(),
]);
$this->telegramService->sendToModerator(sprintf(
"New review: \n%s\n\n Delete: %s\nn",
$review->getText(),
$deleteUrl
));
}
public function handlePublicationHook(array $arguments): string
{
switch ($arguments['action']) {
case 'delete':
$this->dataAccess->deleteReview($arguments['review']);
break;
default:
throw new PublicationHookNotAllowedException('Cannot handle hook');
}
}
}
<service
id="esono_customer.review.notify_moderator_via_telegram"
class="Esono\Customer\Review\NotifyModeratorViaTelegram"
>
<!--
Translations for label & help can be defined in
@YourBundle/Resources/translations/admin.{LANG}.xlf
-->
<tag
name="chameleon_system_review.publication_strategy"
label="esono_customer.review.notify_moderator_via_telegram.label"
help="esono_customer.review.notify_moderator_via_telegram.help"
/>
</service>
When implementing a publication strategy that accepts hooks, the PublicationStrategyHookService may be of
interest in order to generate hook URLs.