411 lines
14 KiB
PHP
411 lines
14 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the package thucke/th-rating.
|
|
*
|
|
* For the full copyright and license information, please read the
|
|
* LICENSE file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace WapplerSystems\BookmarksLikesRatings\Domain\Model;
|
|
|
|
use WapplerSystems\BookmarksLikesRatings\Domain\Repository\VoteRepository;
|
|
use WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService;
|
|
use WapplerSystems\BookmarksLikesRatings\Service\JsonService;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
use TYPO3\CMS\Extbase\Annotation as Extbase;
|
|
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
|
|
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
|
|
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
|
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
|
|
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
|
|
|
/**
|
|
* Model for object rating
|
|
*
|
|
* @copyright Copyright belongs to the respective authors
|
|
* @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
|
|
* @entity
|
|
*/
|
|
class Rating extends AbstractEntity
|
|
{
|
|
//TODO check deleted referenced records
|
|
|
|
/**
|
|
* @Extbase\Validate("\WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingobjectValidator")
|
|
* @Extbase\Validate("NotEmpty")
|
|
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject
|
|
*/
|
|
protected $ratingobject;
|
|
|
|
/**
|
|
* The ratings uid of this object
|
|
*
|
|
* @Extbase\Validate("NumberRange", options={"minimum": 1})
|
|
* @Extbase\Validate("NotEmpty")
|
|
* @var int
|
|
*/
|
|
protected $ratedobjectuid;
|
|
|
|
/**
|
|
* The ratings of this object
|
|
*
|
|
* @Extbase\ORM\Lazy
|
|
* @Extbase\ORM\Cascade("remove")
|
|
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote>
|
|
*/
|
|
protected $votes;
|
|
|
|
/**
|
|
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
|
*/
|
|
protected $objectManager;
|
|
/**
|
|
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
|
|
*/
|
|
/** @noinspection PhpUnused */
|
|
public function injectObjectManager(ObjectManagerInterface $objectManager)
|
|
{
|
|
$this->objectManager = $objectManager;
|
|
}
|
|
|
|
/**
|
|
* @var \WapplerSystems\BookmarksLikesRatings\Service\JsonService
|
|
*/
|
|
protected $jsonService;
|
|
/**
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Service\JsonService $jsonService
|
|
*/
|
|
public function injectJsonService(JsonService $jsonService)
|
|
{
|
|
$this->jsonService = $jsonService;
|
|
}
|
|
|
|
/**
|
|
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\VoteRepository
|
|
*/
|
|
protected $voteRepository;
|
|
/**
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\VoteRepository $voteRepository
|
|
*/
|
|
public function injectVoteRepository(VoteRepository $voteRepository)
|
|
{
|
|
$this->voteRepository = $voteRepository;
|
|
}
|
|
|
|
/**
|
|
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
|
|
*/
|
|
protected $extensionHelperService;
|
|
|
|
/**
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService $extensionHelperService
|
|
*/
|
|
/** @noinspection PhpUnused */
|
|
public function injectExtensionHelperService(ExtensionHelperService $extensionHelperService)
|
|
{
|
|
$this->extensionHelperService = $extensionHelperService;
|
|
}
|
|
|
|
/**
|
|
* The current calculated rates
|
|
*
|
|
* Redundant information to enhance performance in displaying calculated information
|
|
* This is a JSON encoded string with the following keys
|
|
* - votecounts(1...n) vote counts of the specific ratingstep
|
|
* It be updated every time a vote is created, changed or deleted.
|
|
* Specific handling must be defined when ratingsteps are added or removed or stepweights are changed
|
|
* Calculation of ratings:
|
|
* currentrate = ( sum of all ( stepweight(n) * votecounts(n) ) ) / number of all votes
|
|
* currentwidth = round (currentrate * 100 / number of ratingsteps, 1)
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $currentrates;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $settings;
|
|
|
|
/**
|
|
* Constructs a new rating object
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject|null $ratingobject
|
|
* @param int|null $ratedobjectuid
|
|
* @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
|
|
*/
|
|
public function __construct(Ratingobject $ratingobject = null, $ratedobjectuid = null)
|
|
{
|
|
if ($ratingobject) {
|
|
$this->setRatingobject($ratingobject);
|
|
}
|
|
if ($ratedobjectuid) {
|
|
$this->setRatedobjectuid($ratedobjectuid);
|
|
}
|
|
$this->initializeObject();
|
|
}
|
|
|
|
/**
|
|
* Initializes a new rating object
|
|
* @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
|
|
*/
|
|
public function initializeObject()
|
|
{
|
|
if (empty($this->objectManager)) {
|
|
$this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
|
}
|
|
$this->settings = $this->objectManager
|
|
->get(ConfigurationManager::class)
|
|
->getConfiguration('Settings', 'thRating', 'pi1');
|
|
|
|
//Initialize vote storage if rating is new
|
|
if (!is_object($this->votes)) {
|
|
$this->votes = new ObjectStorage();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the ratingobject this rating is part of
|
|
*
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject $ratingobject The Rating
|
|
*/
|
|
public function setRatingobject(Ratingobject $ratingobject)
|
|
{
|
|
$this->ratingobject = $ratingobject;
|
|
$this->setPid($ratingobject->getPid());
|
|
}
|
|
|
|
/**
|
|
* Returns the ratingobject this rating is part of
|
|
*
|
|
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject The ratingobject this rating is part of
|
|
*/
|
|
public function getRatingobject(): Ratingobject
|
|
{
|
|
return $this->ratingobject;
|
|
}
|
|
|
|
/**
|
|
* Sets the rating object uid
|
|
*
|
|
* @param int $ratedobjectuid
|
|
*/
|
|
public function setRatedobjectuid($ratedobjectuid)
|
|
{
|
|
$this->ratedobjectuid = $ratedobjectuid;
|
|
}
|
|
|
|
/**
|
|
* Gets the rating object uid
|
|
*
|
|
* @return int Rating object row uid field value
|
|
*/
|
|
public function getRatedobjectuid()
|
|
{
|
|
return $this->ratedobjectuid;
|
|
}
|
|
|
|
/**
|
|
* Adds a vote to this rating
|
|
*
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote
|
|
*/
|
|
public function addVote(Vote $vote)
|
|
{
|
|
$this->votes->attach($vote);
|
|
$this->addCurrentrate($vote);
|
|
$this->extensionHelperService->persistRepository(VoteRepository::class, $vote);
|
|
}
|
|
|
|
/**
|
|
* Updates an existing vote to this rating
|
|
*
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $existingVote
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $newVote
|
|
*/
|
|
public function updateVote(Vote $existingVote, Vote $newVote)
|
|
{
|
|
$this->removeCurrentrate($existingVote);
|
|
$existingVote->setVote($newVote->getVote());
|
|
$this->addCurrentrate($existingVote);
|
|
$this->extensionHelperService->persistRepository(VoteRepository::class, $existingVote);
|
|
}
|
|
|
|
/**
|
|
* Remove a vote from this rating
|
|
*
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $voteToRemove The vote to be removed
|
|
*/
|
|
/** @noinspection PhpUnused */
|
|
public function removeVote(Vote $voteToRemove)
|
|
{
|
|
$this->removeCurrentrate($voteToRemove);
|
|
$this->votes->detach($voteToRemove);
|
|
}
|
|
|
|
/**
|
|
* Remove all votes from this rating
|
|
*/
|
|
/** @noinspection PhpUnused */
|
|
public function removeAllVotes()
|
|
{
|
|
$this->votes = new ObjectStorage();
|
|
unset($this->currentrates);
|
|
}
|
|
|
|
/**
|
|
* Returns all votes in this rating
|
|
*
|
|
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote>
|
|
*/
|
|
public function getVotes()
|
|
{
|
|
return clone $this->votes;
|
|
}
|
|
|
|
/**
|
|
* Checks all votes of this rating and sets currentrates accordingly
|
|
*
|
|
* This method is used for maintenance to assure consistency
|
|
*/
|
|
public function checkCurrentrates()
|
|
{
|
|
$currentratesDecoded['weightedVotes'] = [];
|
|
$currentratesDecoded['sumWeightedVotes'] = [];
|
|
$numAllVotes = 0;
|
|
$numAllAnonymousVotes = 0;
|
|
foreach ($this->getRatingobject()->getStepconfs() as $stepConf) {
|
|
$stepOrder = $stepConf->getSteporder();
|
|
$voteCount = $this->voteRepository->countByMatchingRatingAndVote($this, $stepConf);
|
|
$anonymousCount = $this->voteRepository->countAnonymousByMatchingRatingAndVote(
|
|
$this,
|
|
$stepConf,
|
|
$this->settings['mapAnonymous']
|
|
);
|
|
$currentratesDecoded['weightedVotes'][$stepOrder] = $voteCount * $stepConf->getStepweight();
|
|
$currentratesDecoded['sumWeightedVotes'][$stepOrder] =
|
|
$currentratesDecoded['weightedVotes'][$stepOrder] * $stepOrder;
|
|
$numAllVotes += $voteCount;
|
|
$numAllAnonymousVotes += $anonymousCount;
|
|
}
|
|
$currentratesDecoded['numAllVotes'] = $numAllVotes;
|
|
$currentratesDecoded['anonymousVotes'] = $numAllAnonymousVotes;
|
|
$this->currentrates = $this->jsonService->encodeToJson($currentratesDecoded);
|
|
}
|
|
|
|
/**
|
|
* Adds a vote to the calculations of this rating
|
|
*
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $voting The vote to be added
|
|
*/
|
|
public function addCurrentrate(Vote $voting)
|
|
{
|
|
if (empty($this->currentrates)) {
|
|
$this->checkCurrentrates(); //initialize entry
|
|
}
|
|
$currentratesDecoded = $this->jsonService->decodeJsonToArray($this->currentrates);
|
|
$currentratesDecoded['numAllVotes']++;
|
|
if ($voting->isAnonymous()) {
|
|
$currentratesDecoded['anonymousVotes']++;
|
|
}
|
|
$votingStep = $voting->getVote();
|
|
/** @noinspection NullPointerExceptionInspection */
|
|
$votingSteporder = $votingStep->getSteporder();
|
|
/** @noinspection NullPointerExceptionInspection */
|
|
$votingStepweight = $votingStep->getStepweight();
|
|
$currentratesDecoded['weightedVotes'][$votingSteporder] += $votingStepweight;
|
|
$currentratesDecoded['sumWeightedVotes'][$votingSteporder] += $votingStepweight * $votingSteporder;
|
|
$this->currentrates = $this->jsonService->encodeToJson($currentratesDecoded);
|
|
}
|
|
|
|
/**
|
|
* Adds a vote to the calculations of this rating
|
|
*
|
|
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $voting The vote to be removed
|
|
*/
|
|
public function removeCurrentrate(Vote $voting)
|
|
{
|
|
if (empty($this->currentrates)) {
|
|
$this->checkCurrentrates(); //initialize entry
|
|
}
|
|
$currentratesDecoded = $this->jsonService->decodeJsonToArray($this->currentrates);
|
|
$currentratesDecoded['numAllVotes']--;
|
|
if ($voting->isAnonymous()) {
|
|
$currentratesDecoded['anonymousVotes']--;
|
|
}
|
|
$votingStep = $voting->getVote();
|
|
/** @noinspection NullPointerExceptionInspection */
|
|
$votingSteporder = $votingStep->getSteporder();
|
|
/** @noinspection NullPointerExceptionInspection */
|
|
$votingStepweight = $votingStep->getStepweight();
|
|
$currentratesDecoded['weightedVotes'][$votingSteporder] -= $votingStepweight;
|
|
$currentratesDecoded['sumWeightedVotes'][$votingSteporder] -= $votingStepweight * $votingSteporder;
|
|
$this->currentrates = $this->jsonService->encodeToJson($currentratesDecoded);
|
|
}
|
|
|
|
/**
|
|
* Returns the calculated rating
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getCurrentrates(): array
|
|
{
|
|
$currentratesDecoded = $this->jsonService->decodeJsonToArray($this->currentrates);
|
|
if (empty($currentratesDecoded['numAllVotes'])) {
|
|
$this->checkCurrentrates();
|
|
$currentratesDecoded = $this->jsonService->decodeJsonToArray($this->currentrates);
|
|
}
|
|
$numAllVotes = $currentratesDecoded['numAllVotes'];
|
|
if (!empty($numAllVotes)) {
|
|
$currentrate = array_sum($currentratesDecoded['sumWeightedVotes']) / $numAllVotes;
|
|
} else {
|
|
$currentrate = 0;
|
|
$numAllVotes = 0;
|
|
}
|
|
|
|
$sumAllWeightedVotes = array_sum($currentratesDecoded['weightedVotes']);
|
|
|
|
//initialize array to handle missing stepconfs correctly
|
|
$currentPollDimensions = [];
|
|
|
|
foreach ($this->getRatingobject()->getStepconfs() as $stepConf) {
|
|
if (empty($sumAllWeightedVotes)) {
|
|
//set current polling styles to zero percent and prevent division by zero error in lower formula
|
|
$currentPollDimensions[$stepConf->getStepOrder()]['pctValue'] = 0;
|
|
} else {
|
|
/* calculate current polling styles -> holds a percent value for usage in CSS
|
|
to display polling relations */
|
|
$currentPollDimensions[$stepConf->getStepOrder()]['pctValue'] =
|
|
round(
|
|
($currentratesDecoded['weightedVotes'][$stepConf->getStepOrder()] * 100) /
|
|
$sumAllWeightedVotes,
|
|
1
|
|
);
|
|
}
|
|
}
|
|
|
|
return ['currentrate' => $currentrate,
|
|
'weightedVotes' => $currentratesDecoded['weightedVotes'],
|
|
'sumWeightedVotes' => $currentratesDecoded['sumWeightedVotes'],
|
|
'anonymousVotes' => $currentratesDecoded['anonymousVotes'],
|
|
'currentPollDimensions' => $currentPollDimensions,
|
|
'numAllVotes' => $numAllVotes, ];
|
|
}
|
|
|
|
/**
|
|
* Returns the calculated rating in percent
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getCalculatedRate(): int
|
|
{
|
|
$currentrate = $this->getCurrentrates();
|
|
if (!empty($currentrate['weightedVotes'])) {
|
|
$calculatedRate = round(($currentrate['currentrate'] * 100) / count($currentrate['weightedVotes']), 1);
|
|
} else {
|
|
$calculatedRate = 0;
|
|
}
|
|
return $calculatedRate;
|
|
}
|
|
}
|