Commit ea5a6b25 authored by Tino Goratsch's avatar Tino Goratsch

add the actual rating logic

parent 3fdfce69
<?php
/**
* Copyright (c) by the ACP3 Developers.
* See the LICENCE file at the top-level module directory for licencing details.
*/
namespace ACP3\Modules\ACP3\Share\Controller\Frontend\Index;
use ACP3\Core\Controller\Context\FrontendContext;
use ACP3\Core\Controller\Exception\ResultNotExistsException;
use ACP3\Modules\ACP3\Comments\Controller\Frontend\Index\AbstractFrontendAction;
use ACP3\Modules\ACP3\Share\Model\Repository\ShareRatingsRepository;
use ACP3\Modules\ACP3\Share\Model\Repository\ShareRepository;
use ACP3\Modules\ACP3\Share\Model\ShareRatingModel;
class Rate extends AbstractFrontendAction
{
/**
* @var \ACP3\Modules\ACP3\Share\Model\Repository\ShareRepository
*/
private $shareRepository;
/**
* @var \ACP3\Modules\ACP3\Share\Model\Repository\ShareRatingsRepository
*/
private $shareRatingsRepository;
/**
* @var \ACP3\Modules\ACP3\Share\Model\ShareRatingModel
*/
private $shareRatingModel;
/**
* Rate constructor.
* @param \ACP3\Core\Controller\Context\FrontendContext $context
* @param \ACP3\Modules\ACP3\Share\Model\Repository\ShareRepository $shareRepository
* @param \ACP3\Modules\ACP3\Share\Model\Repository\ShareRatingsRepository $shareRatingsRepository
* @param \ACP3\Modules\ACP3\Share\Model\ShareRatingModel $shareRatingModel
*/
public function __construct(
FrontendContext $context,
ShareRepository $shareRepository,
ShareRatingsRepository $shareRatingsRepository,
ShareRatingModel $shareRatingModel)
{
parent::__construct($context);
$this->shareRepository = $shareRepository;
$this->shareRatingsRepository = $shareRatingsRepository;
$this->shareRatingModel = $shareRatingModel;
}
/**
* @param int $id
* @param int $stars
* @return array
* @throws \ACP3\Core\Controller\Exception\ResultNotExistsException
* @throws \Doctrine\DBAL\DBALException
*/
public function execute(int $id, int $stars): array
{
if (!($stars >= 1 && $stars <= 5)) {
throw new ResultNotExistsException();
}
if ($this->shareRepository->resultExistsById($id) === false) {
throw new ResultNotExistsException();
}
$this->shareRatingModel->save([
'share_id' => $id,
'stars' => $stars
]);
return [
'rating' => $this->shareRatingsRepository->getRatingStatistics($id)
];
}
}
......@@ -72,8 +72,8 @@ class AddSocialSharingListener
$this->view->assign('sharing', [
'path' => $this->request->getUriWithoutPages(),
'services' => $this->socialServices->getActiveServices(),
'ratings_active' => ((int)$sharingInfo['ratings_active']) === 1,
'rating_stats' => $this->shareRatingsRepository->getRatingsStats($sharingInfo['id'])
'ratings_active' => ((int) $sharingInfo['ratings_active']) === 1,
'rating' => $this->shareRatingsRepository->getRatingStatistics($sharingInfo['id']),
]);
$this->view->displayTemplate('Share/Partials/add_social_sharing.tpl');
......
......@@ -28,6 +28,7 @@ class Migration implements Modules\Installer\MigrationInterface
INDEX(`share_id`),
FOREIGN KEY (`share_id`) REFERENCES `{pre}share` (`id`) ON DELETE CASCADE
) {ENGINE} {CHARSET};',
"INSERT INTO `{pre}acl_resources` (`id`, `module_id`, `area`, `controller`, `page`, `params`, `privilege_id`) VALUES('', '{moduleId}', 'frontend', 'index', 'rate', '', 1);",
],
];
}
......
......@@ -32,6 +32,7 @@ class Schema implements Modules\Installer\SchemaInterface
'frontend' => [
'index' => [
'index' => PrivilegeEnum::FRONTEND_VIEW,
'rate' => PrivilegeEnum::FRONTEND_VIEW,
],
],
'widget' => [
......
......@@ -13,10 +13,17 @@ class ShareRatingsRepository extends AbstractRepository
{
const TABLE_NAME = 'share_ratings';
public function getRatingsStats(int $shareId): array
/**
* @param int $shareId
*
* @return array
*
* @throws \Doctrine\DBAL\DBALException
*/
public function getRatingStatistics(int $shareId): array
{
return $this->db->fetchAssoc(
"SELECT COUNT(*) AS total_ratings, AVG(`stars`) AS average_rating FROM {$this->getTableName()} WHERE `share_id` = :shareId GROUP BY `share_id`;",
"SELECT `share_id`, COUNT(*) AS total_ratings, AVG(`stars`) AS average_rating FROM {$this->getTableName()} WHERE `share_id` = :shareId GROUP BY `share_id`;",
['shareId' => $shareId]
) ?: [];
}
......
......@@ -13,11 +13,22 @@ class ShareRepository extends Core\Model\Repository\AbstractRepository
{
const TABLE_NAME = 'share';
/**
* @param int $id
* @return bool
* @throws \Doctrine\DBAL\DBALException
*/
public function resultExistsById(int $id): bool
{
return $this->db->fetchColumn(
"SELECT COUNT(*) FROM {$this->getTableName()} WHERE `id` = :id",
['id' => $id]
) > 0;
}
/**
* @param string $uri
*
* @return array
*
* @throws \Doctrine\DBAL\DBALException
*/
public function getOneByUri(string $uri): array
......@@ -27,7 +38,6 @@ class ShareRepository extends Core\Model\Repository\AbstractRepository
/**
* @return array
*
* @throws \Doctrine\DBAL\DBALException
*/
public function getAll(): array
......
......@@ -21,17 +21,22 @@
}
.rating__star:hover,
.rating__star:focus,
.rating__star:active,
.rating__star.rating__star_active {
.rating__star:active {
text-decoration: none;
}
.rating__star:hover::before,
.rating__star:focus::before,
.rating__star:active::before,
.rating__star.rating__star_active::before,
.rating__star:hover ~ .rating__star::before,
.rating__star:focus ~ .rating__star::before,
.rating__star:active ~ .rating__star::before,
.rating__star:active ~ .rating__star::before {
content: "\f006" !important;
color: #e3cf7a !important;
}
.rating__star.rating__star_active {
text-decoration: none;
}
.rating__star.rating__star_active::before,
.rating__star.rating__star_active ~ .rating__star::before {
content: "\f005";
color: #e3cf7a;
......
......@@ -24,7 +24,16 @@
&:hover,
&:focus,
&:active,
&:active {
text-decoration: none;
&::before,
& ~ .rating__star::before {
content: "\f006" !important;
color: #e3cf7a !important;;
}
}
&.rating__star_active {
text-decoration: none;
......
{include file="asset:Share/Partials/rating.tpl" rating=$rating}
......@@ -2,9 +2,15 @@
{load_module module="widget/share/index/index" path=$sharing.path}
{js_libraries enable='shariff'}
{/if}
{if $sharing.ratings_active === true && !empty($sharing.rating_stats)}
{if $sharing.ratings_active === true && !empty($sharing.rating)}
{if !empty($sharing.services)}
<hr>
{/if}
{include file="asset:Share/Partials/ratings.tpl" sharing=$sharing}
<div id="rating-wrapper">
{include file="asset:Share/Partials/rating.tpl" rating=$sharing.rating}
</div>
{javascripts}
{js_libraries enable='font-awesome'}
{include_js module="system" file="ajax-form"}
{/javascripts}
{/if}
<span class="rating">
{$rating_rounded=$rating.average_rating|round:0}
{for $i=5 to 1 step -1}
<a href="{uri args="share/index/rate/stars_`$i`/id_`$rating.share_id`"}"
data-ajax-form="true"
data-ajax-form-target-element="#rating-wrapper"
data-ajax-form-loading-overlay="false"
title="{lang t="share|rate_with_x_stars" args=['%stars%' => $i]}"
class="rating__star{if $i == $rating_rounded} rating__star_active{/if}"></a>
{/for}
</span>
<div class="rating-summary">
{if $rating.total_ratings > 0}
{$rating.average_rating|string_format:"%.2f"} / 5
({lang t="share|total_x_ratings" args=['%ratings%' => $rating.total_ratings]})
{else}
{lang t="share|no_ratings_yet"}
{/if}
</div>
<span class="rating">
{$rating_rounded=$sharing.rating_stats.average_rating|round:0}
{for $i=5 to 1 step -1}
<a href="#"
title="{lang t="share|rate_with_x_stars" args=['%stars%' => $i]}"
class="rating__star{if $i == $rating_rounded} rating__star_active{/if}"></a>
{/for}
</span>
{if $sharing.rating_stats.total_ratings > 0}
<div class="rating-summary">
{$sharing.rating_stats.average_rating|round:2} / 5 ({lang t="share|total_x_ratings" args=['%ratings%' => $sharing.rating_stats.total_ratings]})
</div>
{/if}
......@@ -45,6 +45,14 @@ services:
- '@core.context.frontend'
- '@shariff.backend'
share.controller.frontend.index.rate:
class: ACP3\Modules\ACP3\Share\Controller\Frontend\Index\Rate
arguments:
- '@core.context.frontend'
- '@share.model.share_repository'
- '@share.model.share_ratings_repository'
- '@share.model.share_rating_model'
share.controller.widget.index.index:
class: ACP3\Modules\ACP3\Share\Controller\Widget\Index\Index
arguments:
......
......@@ -17,6 +17,7 @@
<item key="fb_app_id">Facebook App-ID</item>
<item key="fb_secret">Facebook Secret</item>
<item key="mod_description">Ermöglicht die Einbindung diverser sozialer Netzwerke zum Teilen von Inhalten, etc.</item>
<item key="no_ratings_yet">Noch keine Bewertungen</item>
<item key="rate_with_x_stars">Mit %stars% Sternen bewerten</item>
<item key="select_active">Bitte wählen aus, ob dieser Datensatz bei sozialen Netzwerken geteilt werden können soll oder nicht.</item>
<item key="select_customize_services">Bitte wählen aus ob Sie die verfügbaren sozialen Netzwerke für diesen Datensatz anpassen möchten oder nicht.</item>
......
......@@ -9,6 +9,8 @@
var pluginName = 'formSubmit',
defaults = {
targetElement: '#content',
loadingOverlay: true,
loadingText: '',
customFormData: null
};
......@@ -26,6 +28,7 @@
init: function () {
var that = this;
this.mergeSettings();
this.findSubmitButton();
this.element.noValidate = true;
......@@ -52,6 +55,22 @@
}
});
},
mergeSettings: function () {
var data = $(this.element).data();
for (var key in data) {
if (data.hasOwnProperty(key)) {
var keyStripped = this.lowerCaseFirstLetter(key.replace('ajaxForm', ''));
if (keyStripped.length > 0 && this.settings[keyStripped]) {
this.settings[keyStripped] = data[key];
}
}
}
},
lowerCaseFirstLetter(string) {
return string.charAt(0).toLowerCase() + string.slice(1);
},
findSubmitButton: function () {
$(this.element).find(':submit').click(function () {
$(':submit', $(this).closest('form')).removeAttr('data-clicked');
......@@ -190,11 +209,14 @@
});
},
showLoadingLayer: function ($submitButton) {
var $loadingLayer = $('#loading-layer');
if (this.settings.loadingOverlay === false) {
return;
}
var $loadingLayer = $('#loading-layer');
if ($loadingLayer.length === 0) {
var $body = $('body'),
loadingText = $(this.element).data('ajax-form-loading-text') || '',
loadingText = this.settings.loadingText || '',
html = '<div id="loading-layer" class="loading-layer"><h1><span class="glyphicon glyphicon-cog"></span>' + loadingText + '</h1></div>';
$(html).appendTo($body);
......@@ -242,6 +264,7 @@
$(this.settings.targetElement).html(responseData);
}
// Rebind the submit/click handlers
this.findSubmitButton();
},
hideLoadingLayer: function ($submitButton) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment