Zwischenstand

This commit is contained in:
Sven Wappler
2021-08-17 19:45:38 +02:00
parent fde2759722
commit ce6b9e38dc
71 changed files with 7886 additions and 809 deletions

View File

@@ -7,10 +7,10 @@
* LICENSE file that was distributed with this source code.
*/
namespace WapplerSystems\BookmarkPages\Controller;
namespace WapplerSystems\BookmarksLikesRatings\Controller;
use WapplerSystems\BookmarkPages\Model\Bookmark;
use WapplerSystems\BookmarkPages\Model\Bookmarks;
use WapplerSystems\BookmarksLikesRatings\Model\Bookmark;
use WapplerSystems\BookmarksLikesRatings\Model\Bookmarks;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
* LICENSE file that was distributed with this source code.
*/
namespace WapplerSystems\BookmarkPages\Model;
namespace WapplerSystems\BookmarksLikesRatings\Domain\Model;
use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -47,7 +47,7 @@ class Bookmark
* @param null $pid page id
* @param null $parameter
*/
public function __construct($url, $title=null, $pid=null, $parameter=null)
public function __construct($url, $title = null, $pid = null, $parameter = null)
{
if (is_array($url)) {
$this->id = $url['id'];
@@ -223,7 +223,7 @@ class Bookmark
*/
protected static function getCurrentPageTitle()
{
return self::getFrontend()->altPageTitle? self::getFrontend()->altPageTitle : self::getFrontend()->page['title'];
return self::getFrontend()->altPageTitle ? self::getFrontend()->altPageTitle : self::getFrontend()->page['title'];
}
/**

View File

@@ -7,7 +7,7 @@
* LICENSE file that was distributed with this source code.
*/
namespace WapplerSystems\BookmarkPages\Model;
namespace WapplerSystems\BookmarksLikesRatings\Domain\Model;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;

View File

@@ -0,0 +1,410 @@
<?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;
}
}

View File

@@ -0,0 +1,196 @@
<?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 TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Frontend\Imaging\GifBuilder;
/**
* Model for rating votes
*
* @copyright Copyright belongs to the respective authors
* @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
* @entity
*/
class RatingImage extends AbstractEntity
{
/**
* @var bool
*/
protected $isBuilderObject = false;
/**
* The filename of the final image
*
* @var string
*/
protected $imageFile;
/**
* The typoscript image configuration array
* Only the top level node ['GIFBUILDER'] will be used for building the image
*
* @var array
*/
protected $conf;
/**
* @var GifBuilder
*/
protected $gifBuilder;
/**
* @param GifBuilder $gifBuilder
*/
public function injectGifBuilder(GifBuilder $gifBuilder)
{
$this->gifBuilder = $gifBuilder;
}
/**
* Constructs a new image object
*
* @param mixed $conf either an array consisting of GIFBUILDER typoscript or a plain string having the filename
*/
public function __construct($conf = null)
{
$this->initializeObject();
if (!empty($conf)) {
$this->setConf($conf);
}
}
/**
* Initializes the new vote object
*/
public function initializeObject()
{
if (empty($this->gifBuilder)) {
$this->injectGifBuilder(GeneralUtility::makeInstance(GifBuilder::class));
}
}
/**
* Sets the typoscript configuration for the GIFBUILDER object
*
* @param mixed $conf either an array consisting of GIFBUILDER typoscript or a plain string having the filename
*/
public function setConf($conf)
{
switch (gettype($conf)) {
case 'string':
$this->setImageFile($conf);
break;
case 'array':
$this->conf = $conf;
$this->generateImage();
break;
default:
//TODO: Error message
}
}
/**
* Returns the current typoscript configuration of the GIFBUILDER object
*
* @return array
*/
public function getConf(): array
{
if (empty($this->conf)) {
return [];
}
return $this->conf;
}
/**
* Sets the filename of the image
*
* @param string $imageFile
*/
public function setImageFile($imageFile)
{
$fullImagePath = Environment::getPublicPath() . '/' . $imageFile;
if (file_exists($fullImagePath)) {
$this->imageFile = $imageFile;
$this->isBuilderObject = false;
} else {
//clear path if given file is invalid
unset($this->imageFile, $this->isBuilderObject);
//TODO: error handling
}
}
/**
* Returns the filename of the image
*
* @param mixed $fullPath
* @return string
*/
public function getImageFile($fullPath = false)
{
$checkedFile = $this->gifBuilder->checkFile($this->imageFile);
if (empty($checkedFile)) {
//clear image if file doe not exist
$this->setImageFile('xxx');
}
return $fullPath ? Environment::getPublicPath() . '/' . $this->imageFile : $this->imageFile;
}
/**
* Generates the image using the given typoscript
*
* @return bool The result; true if the given the image has been created successfully; otherwise false
*/
public function generateImage()
{
if (!empty($this->conf)) {
$this->gifBuilder->start($this->getConf(), []);
$genImageFile = $this->gifBuilder->gifBuild();
if (!file_exists($genImageFile)) {
//TODO: error handling
return false;
}
$this->setImageFile($genImageFile);
$this->isBuilderObject = true;
return true;
}
return false;
}
/**
* Returns the filename of the image
*
* @var bool switch if absolute path should be returned
* @return array('width','height')
*/
public function getImageDimensions()
{
if ($this->isBuilderObject) {
[$width, $height] = $this->gifBuilder->getImageDimensions($this->imageFile);
} else {
[$width, $height] = getimagesize($this->getImageFile(true));
}
return ['width' => $width, 'height' => $height, 'builderObject' => $this->isBuilderObject];
}
/**
* Method to use Object as plain string
*
* @return string
*/
public function __toString()
{
return $this->imageFile;
}
}

View File

@@ -0,0 +1,257 @@
<?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\RatingRepository;
use WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepconfRepository;
use WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService;
use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/**
* Aggregate object for rating of content objects
*
* @version $Id:$
* @copyright Copyright belongs to the respective authors
* @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
* @entity
*/
class Ratingobject extends AbstractEntity
{
/**
* Table name of the cObj
* Defaults to Typo3 tablename of pages
*
* @Extbase\Validate("StringLength", options={"minimum": 3})
* @Extbase\Validate("StringLength", options={"maximum": 60})
* @Extbase\Validate("NotEmpty")
* @var string
*/
protected $ratetable;
/**
* Fieldname within the table of the cObj
* Defaults to the field 'uid'
*
* @Extbase\Validate("StringLength", options={"minimum": 3})
* @Extbase\Validate("StringLength", options={"maximum": 60})
* @Extbase\Validate("NotEmpty")
* @var string
*/
protected $ratefield;
/**
* The stepconfs of this object
*
* @Extbase\ORM\Lazy
* @Extbase\ORM\Cascade("remove")
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf>
*/
protected $stepconfs;
/**
* The ratings of this object
*
* @Extbase\ORM\Lazy
* @Extbase\ORM\Cascade("remove")
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating>
*/
protected $ratings;
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepconfRepository
*/
protected $stepconfRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepconfRepository $stepconfRepository
*/
public function injectStepconfRepository(StepconfRepository $stepconfRepository)
{
$this->stepconfRepository = $stepconfRepository;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected $extensionHelperService;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService $extensionHelperService
*/
/** @noinspection PhpUnused */
public function injectExtensionHelperService(ExtensionHelperService $extensionHelperService)
{
$this->extensionHelperService = $extensionHelperService;
}
/**
* Constructs a new rating object
* @param string $ratetable The rating objects table name
* @param string $ratefield The rating objects field name
* @Extbase\Validate("StringLength", options={"minimum": 3}, param="ratetable")
* @Extbase\Validate("StringLength", options={"maximum": 60}, param="ratetable")
* @Extbase\Validate("StringLength", options={"minimum": 3}, param="ratefield")
* @Extbase\Validate("StringLength", options={"maximum": 60}, param="ratefield")
*/
public function __construct($ratetable = null, $ratefield = null)
{
if ($ratetable) {
$this->setRatetable($ratetable);
}
if ($ratefield) {
$this->setRatefield($ratefield);
}
$this->initializeObject();
}
/**
* Initializes a new ratingobject
*/
public function initializeObject()
{
//Initialize rating storage if ratingobject is new
if (!is_object($this->ratings)) {
$this->ratings = new ObjectStorage();
}
//Initialize stepconf storage if ratingobject is new
if (!is_object($this->stepconfs)) {
$this->stepconfs = new ObjectStorage();
}
}
/**
* Sets the rating table name
*
* @param string $ratetable
*/
public function setRatetable($ratetable)
{
$this->ratetable = $ratetable;
}
/**
* Gets the rating table name
*
* @return string Rating object table name
*/
public function getRatetable()
{
return $this->ratetable;
}
/**
* Sets the rating field name
*
* @param string $ratefield
*/
public function setRatefield($ratefield)
{
$this->ratefield = $ratefield;
}
/**
* Sets the rating field name
*
* @return string Rating object field name
*/
public function getRatefield()
{
return $this->ratefield;
}
/**
* Adds a rating to this object
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating $rating
*/
/** @noinspection PhpUnused */
public function addRating(Rating $rating)
{
$this->ratings->attach($rating);
$this->extensionHelperService->persistRepository(RatingRepository::class, $rating);
$this->extensionHelperService->clearDynamicCssFile();
}
/**
* Remove a rating from this object
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating $rating The rating to be removed
*/
public function removeRating(Rating $rating): void
{
$this->ratings->detach($rating);
}
/**
* Remove all ratings from this object
*/
public function removeAllRatings(): void
{
$this->ratings = new ObjectStorage();
}
/**
* Adds a stepconf to this object
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf
*/
public function addStepconf(Stepconf $stepconf): void
{
if (!$this->stepconfRepository->existStepconf($stepconf)) {
$this->stepconfs->attach($stepconf);
$this->extensionHelperService->persistRepository(StepconfRepository::class, $stepconf);
$this->extensionHelperService->clearDynamicCssFile();
}
}
/**
* Sets all ratings of this ratingobject
*
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf> $stepconfs
* The step configurations for this ratingobject
*/
public function setStepconfs(ObjectStorage $stepconfs)
{
$this->stepconfs = $stepconfs;
}
/**
* Returns all ratings in this object
*
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf>
*/
public function getStepconfs()
{
return clone $this->stepconfs;
}
/**
* Sets all ratings of this ratingobject
*
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating> $ratings
* The ratings of the organization
*/
public function setRatings(ObjectStorage $ratings)
{
$this->ratings = $ratings;
}
/**
* Returns all ratings in this object
*
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating>
*/
public function getRatings()
{
return clone $this->ratings;
}
}

View File

@@ -0,0 +1,271 @@
<?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\StepconfRepository;
use WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository;
use WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService;
use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/**
* Model for ratingstep configuration
*
* @copyright Copyright belongs to the respective authors
* @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
* @entity
*/
class Stepconf extends AbstractEntity
{
/**
* @Extbase\Validate("\WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingobjectValidator")
* @Extbase\Validate("NotEmpty")
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject
*/
protected $ratingobject;
/**
* The order of this config entry
*
* @Extbase\Validate("NumberRange", options={"minimum": 1})
* @Extbase\Validate("NotEmpty")
* @var int discrete order of ratingsteps
*/
protected $steporder;
/**
* The weight of this config entry
*
* @Extbase\Validate("Integer")
* @Extbase\Validate("NumberRange", options={"minimum": 1})
* @var int default is 1 which is equal weight
*/
protected $stepweight;
/**
* The value of this config entry
*
* @Extbase\ORM\Lazy
* @Extbase\ORM\Cascade("remove")
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname
*/
protected $stepname;
/**
* 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 $objectManager
*/
protected $objectManager;
/**
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
*/
public function injectObjectManager(ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository $stepnameRepository
*/
protected $stepnameRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository $stepnameRepository
*/
public function injectStepnameRepository(StepnameRepository $stepnameRepository)
{
$this->stepnameRepository = $stepnameRepository;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected $extensionHelperService;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService $extensionHelperService
*/
public function injectExtensionHelperService(ExtensionHelperService $extensionHelperService)
{
$this->extensionHelperService = $extensionHelperService;
}
/**
* Constructs a new stepconfig object
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject|null $ratingobject
* @param int|null $steporder
*/
public function __construct(Ratingobject $ratingobject = null, $steporder = null)
{
if ($ratingobject) {
$this->setRatingobject($ratingobject);
}
if ($steporder) {
$this->setSteporder($steporder);
}
$this->initializeObject();
}
/**
* Initializes a new stepconf object
*/
public function initializeObject()
{
//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|null
*/
public function getRatingobject()
{
return $this->ratingobject;
}
/**
* Sets the stepconfig order
*
* @param int $steporder
*/
public function setSteporder($steporder)
{
$this->steporder = $steporder;
}
/**
* Gets the stepconfig order
*
* @return int stepconfig position
*/
public function getSteporder(): int
{
return $this->steporder;
}
/**
* Sets the stepconfig value
*
* @param int $stepweight
*/
public function setStepweight($stepweight)
{
$this->stepweight = $stepweight;
}
/**
* Gets the stepconfig value
* If not set steporder is copied
*
* @return int Stepconfig value
*/
public function getStepweight()
{
empty($this->stepweight) && $this->stepweight = $this->steporder;
return $this->stepweight;
}
/**
* Adds a localized stepname to this stepconf
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname $stepname
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
* @return bool
*/
public function addStepname(Stepname $stepname): bool
{
$success = true;
$stepname->setStepconf($this);
if (!$this->stepnameRepository->existStepname($stepname)) {
$defaultLanguageObject = $this->stepnameRepository->findDefaultStepname($stepname);
if (is_object($defaultLanguageObject)) {
//handle localization if an entry for the default language exists
$stepname->setL18nParent($defaultLanguageObject->getUid());
}
$this->stepnameRepository->add($stepname);
$this->extensionHelperService->persistRepository(StepnameRepository::class, $stepname);
$stepname->getStepconf()->getStepname();
$this->extensionHelperService->persistRepository(StepconfRepository::class, $this);
$this->extensionHelperService->clearDynamicCssFile();
$this->stepname = $stepname;
} else {
//warning - existing stepname entry for a language will not be overwritten
$success = false;
}
return $success;
}
/**
* Returns the localized stepname object of this stepconf
*
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname|null
*/
public function getStepname(): ?Stepname
{
/* @phpstan-ignore-next-line */
if ($this->stepname instanceof LazyLoadingProxy) {
$this->stepname = $this->stepname->_loadRealInstance();
}
return $this->stepname;
}
/**
* Returns all votes in this rating
*
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote>
*/
public function getVotes()
{
return clone $this->votes;
}
/**
* Method to use Object as plain string
*
* @return string
*/
public function __toString()
{
$stepnameText = $this->getStepname();
if (!$stepnameText) {
$stepnameText = $this->getSteporder();
}
return (string)$stepnameText;
}
}

View File

@@ -0,0 +1,158 @@
<?php
declare(strict_types = 1);
/*
* 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 TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* Model for ratingstep configuration names
*
* @copyright Copyright belongs to the respective authors
* @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
* @entity
*/
class Stepname extends AbstractEntity
{
/**
* @Extbase\Validate("\WapplerSystems\BookmarksLikesRatings\Domain\Validator\StepconfValidator")
* @Extbase\Validate("NotEmpty")
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf
*/
protected $stepconf;
/**
* The name of this config entry
*
* @var string Name or description to display
*/
protected $stepname;
/**
* Localization entry
* workaround to help avoiding bug in Typo 4.7 handling localized objects
*
* @var int
*/
protected $l18nParent;
/**
* @var int
*/
protected $sysLanguageUid;
/**
* Sets the stepconf this rating is part of
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf The Rating
*/
public function setStepconf(Stepconf $stepconf): void
{
$this->stepconf = $stepconf;
$this->setPid($stepconf->getPid());
}
/**
* Returns the stepconf this rating is part of
*
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf The stepconf this rating is part of
*/
public function getStepconf(): Stepconf
{
return $this->stepconf;
}
/**
* Sets the stepconfig name
*
* @param string $stepname
*/
public function setStepname($stepname): void
{
$this->stepname = $stepname;
}
/**
* Gets the stepconfig name
* If not set stepweight is copied
*
* @return string Stepconfig name
*/
public function getStepname(): string
{
$value = $this->stepname;
if (stripos($value, 'LLL:') === 0) {
$value = 'stepnames.' . substr($value, 4);
$value = LocalizationUtility::translate($value, 'ThRating');
}
if (empty($value)) {
$value = (string)$this->getStepconf()->getSteporder();
}
return $value;
}
/**
* @return int
*/
/** @noinspection PhpUnused */
public function getL18nParent(): int
{
return $this->l18nParent;
}
/**
* @param int $l18nParent
*/
public function setL18nParent($l18nParent): void
{
$this->l18nParent = $l18nParent;
}
/**
* Get sys language
*
* @return int
*/
public function getSysLanguageUid(): int
{
return $this->_languageUid;
}
/**
* Set sys language
*
* @param int $sysLanguageUid language uid
*/
public function setSysLanguageUid($sysLanguageUid): void
{
$this->_languageUid = $sysLanguageUid;
}
/**
* @return bool
*/
public function isValid(): bool
{
return !empty($this->stepconf);
}
/**
* Method to use Object as plain string
*
* @return string
*/
public function __toString(): string
{
return $this->getStepname();
}
}

View File

@@ -0,0 +1,242 @@
<?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\Service\ExtensionHelperService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
use TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
/**
* Model for rating votes
*
* @copyright Copyright belongs to the respective authors
* @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
* @entity
*/
class Vote extends AbstractEntity
{
/**
* @Extbase\Validate("\WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingValidator")
* @Extbase\Validate("NotEmpty")
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating
*/
protected $rating;
/**
* The voter of this object
*
* @Extbase\Validate("NotEmpty")
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter
*/
protected $voter;
/**
* The actual voting of this object
*
* @Extbase\Validate("\WapplerSystems\BookmarksLikesRatings\Domain\Validator\StepconfValidator")
* @Extbase\Validate("NotEmpty")
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf
*/
protected $vote;
/**
* @var array
*/
protected $settings;
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
*/
protected $objectManager;
/**
* @var \TYPO3\CMS\Core\Log\Logger
*/
protected $logger;
/**
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
*/
public function injectObjectManager(ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected $extensionHelperService;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService $extensionHelperService
*/
public function injectExtensionHelperService(ExtensionHelperService $extensionHelperService): void
{
$this->extensionHelperService = $extensionHelperService;
}
/**
* Constructs a new rating object
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating|null $rating
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter|null $voter
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf|null $vote
* @throws InvalidConfigurationTypeException
*/
/** @noinspection PhpUnused */
public function __construct(
Rating $rating = null,
Voter $voter = null,
Stepconf $vote = null
) {
if ($rating) {
$this->setRating($rating);
}
if ($voter) {
$this->setVoter($voter);
}
if ($vote) {
$this->setVote($vote);
}
$this->initializeObject();
}
/**
* Initializes the new vote object
* @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
*/
public function initializeObject()
{
if (empty($this->objectManager)) {
$this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
}
if (empty($this->extensionHelperService)) {
$this->extensionHelperService = GeneralUtility::makeInstance(ExtensionHelperService::class);
}
$this->logger = $this->extensionHelperService->getLogger(__CLASS__);
$this->settings = $this->objectManager->get(ConfigurationManager::class)->getConfiguration(
'Settings',
'thRating',
'pi1'
);
//\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($this,get_class($this).' initializeObject');
}
/**
* Sets the rating this vote is part of
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating $rating The Rating
*/
public function setRating(Rating $rating)
{
$this->rating = $rating;
$this->setPid($rating->getPid());
}
/**
* Returns the rating this vote is part of
*
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating The rating this vote is part of
*/
public function getRating(): Rating
{
return $this->rating;
}
/**
* Sets the frontenduser of this vote
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter $voter The frontenduser
*/
public function setVoter(Voter $voter)
{
$this->voter = $voter;
}
/**
* Returns the frontenduser of this vote
*
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter|null
*/
public function getVoter(): ?Voter
{
return $this->voter;
}
/**
* Sets the choosen stepconfig
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $vote
*/
public function setVote($vote)
{
$this->vote = $vote;
}
/**
* Gets the rating object uid
*
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf|null Reference to selected stepconfig
*/
public function getVote()
{
return $this->vote;
}
/**
* Sets the rating this vote is part of
*
* @return bool
*/
/** @noinspection PhpUnused */
public function hasRated()
{
return $this->getVote() !== null && ($this->getVote() instanceof Stepconf);
}
/**
* Checks if vote is done by anonymous user
*
* @return bool
*/
public function isAnonymous(): bool
{
return !empty($this->settings['mapAnonymous']) && !empty($this->getVoter()) &&
$this->getVoter()->getUid() === (int)$this->settings['mapAnonymous'];
}
/**
* Checks cookie if anonymous vote is already done
* always false if cookie checks is deactivated
*
* @param string $prefixId Extension prefix to identify cookie
* @return bool
*/
public function hasAnonymousVote($prefixId = 'DummyPrefix'): bool
{
$anonymousRating = GeneralUtility::makeInstance(\WapplerSystems\BookmarksLikesRatings\Service\JsonService::class)
->decodeJsonToArray($_COOKIE[$prefixId . '_AnonymousRating_' . $this->getRating()->getUid()]);
return !empty($anonymousRating['voteUid']);
}
/**
* Method to use Object as plain string
*
* @return string
*/
public function __toString(): string
{
return (string)$this->getVote();
}
}

View File

@@ -0,0 +1,17 @@
<?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;
/**
* The voter
*/
class Voter extends \TYPO3\CMS\Extbase\Domain\Model\FrontendUser
{
}

View File

@@ -0,0 +1,89 @@
<?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\Repository;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject;
use WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingValidator;
use WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService;
use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException;
use TYPO3\CMS\Extbase\Persistence\Repository;
/**
* A repository for ratings
*/
class RatingRepository extends Repository
{
/**
* Defines name for function parameter
*/
public const ADD_IF_NOT_FOUND = true;
/**
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected $extensionHelperService;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService $extensionHelperService
*/
public function injectExtensionHelperService(ExtensionHelperService $extensionHelperService): void
{
$this->extensionHelperService = $extensionHelperService;
}
/**
* Finds the specific rating by giving the object and row uid
*
* @Extbase\Validate("\WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingobjectValidator", param="ratingobject")
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject $ratingobject The concerned ratingobject
* @Extbase\Validate("NumberRange", options={"minimum": 1}, param="ratedobjectuid")
* @param int $ratedobjectuid The Uid of the rated row
* @param bool $addIfNotFound Set to true if new objects should instantly be added
* @return Rating
* @throws IllegalObjectTypeException
*/
public function findMatchingObjectAndUid(
Ratingobject $ratingobject,
int $ratedobjectuid,
$addIfNotFound = false
): Rating {
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating $foundRow */
$foundRow = $this->objectManager->get(Rating::class);
$query = $this->createQuery();
$query->matching($query->logicalAnd(
[
$query->equals('ratingobject', $ratingobject->getUid()),
$query->equals('ratedobjectuid', $ratedobjectuid)
]
))->setLimit(1);
/*$queryParser = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getSQL(), get_class($this).' SQL');
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getParameters(), get_class($this).' SQL Parameter');*/
$queryResult = $query->execute();
if ($queryResult->count() > 0) {
$foundRow = $queryResult->getFirst();
} elseif ($addIfNotFound) {
$foundRow->setRatingobject($ratingobject);
$foundRow->setRatedobjectuid($ratedobjectuid);
$validator = $this->objectManager->get(RatingValidator::class);
if (!$validator->validate($foundRow)->hasErrors()) {
$this->add($foundRow);
}
$this->extensionHelperService->persistRepository(__CLASS__, $foundRow);
$foundRow = $this->findMatchingObjectAndUid($ratingobject, $ratedobjectuid);
}
return $foundRow;
}
}

View File

@@ -0,0 +1,114 @@
<?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\Repository;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject;
use WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingobjectValidator;
use WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException;
use WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Repository;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* A repository for rating objects
*/
class RatingobjectRepository extends Repository
{
/**
* Defines name for function parameter
*/
public const ADD_IF_NOT_FOUND = true;
/**
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected $extensionHelperService;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService $extensionHelperService
*/
public function injectExtensionHelperService(ExtensionHelperService $extensionHelperService): void
{
$this->extensionHelperService = $extensionHelperService;
}
/**
* @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
*/
protected $configurationManager;
/**
* @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
*/
public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager): void
{
$this->configurationManager = $configurationManager;
}
/**
* Finds the specific ratingobject by giving table and fieldname
*
* @param string $ratetable The tablename of the ratingobject
* @param string $ratefield The fieldname of the ratingobject
* @param bool $addIfNotFound Set to true if new objects should instantly be added
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject The ratingobject
* @throws RecordNotFoundException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
*/
public function findMatchingTableAndField(string $ratetable, string $ratefield, bool $addIfNotFound = false): Ratingobject
{
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject $foundRow */
$foundRow = $this->objectManager->get(Ratingobject::class);
$query = $this->createQuery();
$query->matching($query->logicalAnd([
$query->equals('ratetable', $ratetable),
$query->equals('ratefield', $ratefield),
]))->setLimit(1);
/*$queryParser = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getSQL(), get_class($this).' SQL');
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getParameters(), get_class($this).' SQL Parameter');*/
/** @var \TYPO3\CMS\Extbase\Persistence\QueryResultInterface $queryResult */
$queryResult = $query->execute();
if ($queryResult->count() > 0) {
$foundRow = $queryResult->getFirst();
} elseif ($addIfNotFound) {
$foundRow->setRatetable($ratetable);
$foundRow->setRatefield($ratefield);
if (!$this->objectManager->get(RatingobjectValidator::class)->validate($foundRow)->hasErrors()) {
$this->add($foundRow);
}
$this->extensionHelperService->persistRepository(self::class, $foundRow);
$foundRow = $this->findMatchingTableAndField($ratetable, $ratefield);
} else {
throw new RecordNotFoundException(LocalizationUtility::translate('recordNotFound', 'ThRating'), 1567962473);
}
return $foundRow;
}
/**
* Finds the specific ratingobject by giving table and fieldname
*
* @param bool Switch to fetch ALL entries regardless of their pid
* @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array All ratingobjects of the site
*/
/** @noinspection PhpMissingParentCallCommonInspection */
public function findAll($ignoreStoragePage = false)
{
$query = $this->createQuery();
$query->getQuerySettings()->setRespectStoragePage(!$ignoreStoragePage);
return $query->execute();
}
}

View File

@@ -0,0 +1,78 @@
<?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\Repository;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf;
use WapplerSystems\BookmarksLikesRatings\Domain\Validator\StepconfValidator;
use TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
use TYPO3\CMS\Extbase\Persistence\Repository;
/**
* A repository for ratingstep configurations
* @method findByRatingobject(Ratingobject $getRatingobject)
*/
class StepconfRepository extends Repository
{
protected $defaultOrderings = ['steporder' => QueryInterface::ORDER_ASCENDING];
/**
* Initialize this repository
*/
public function initializeObject(): void
{
//disable RespectStoragePage as pid is always bound to parent objects pid
/** @var \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $defaultQuerySettings */
$defaultQuerySettings = $this->objectManager->get(QuerySettingsInterface::class);
$defaultQuerySettings->setRespectStoragePage(false);
$this->setDefaultQuerySettings($defaultQuerySettings);
}
/**
* Finds the given stepconf object in the repository
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf The ratingobject to look for
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf
*/
public function findStepconfObject(Stepconf $stepconf): Stepconf
{
$query = $this->createQuery();
/** @noinspection NullPointerExceptionInspection */
$query->matching($query->logicalAnd([
$query->equals('ratingobject', $stepconf->getRatingobject()->getUid()),
$query->equals('steporder', $stepconf->getSteporder()),
]))->setLimit(1);
$queryResult = $query->execute();
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $foundRow */
$foundRow = $this->objectManager->get(Stepconf::class);
if (count($queryResult) !== 0) {
$foundRow = $queryResult->getFirst();
}
return $foundRow;
}
/**
* Finds the ratingstep entry by giving ratingobjectUid
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf The uid of the ratingobject
* @return bool true if stepconf object exists in repository
*/
public function existStepconf(Stepconf $stepconf): bool
{
$foundRow = $this->findStepconfObject($stepconf);
$stepconfValidator = $this->objectManager->get(StepconfValidator::class);
return !$stepconfValidator->validate($foundRow)->hasErrors();
}
}

View File

@@ -0,0 +1,255 @@
<?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\Repository;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname;
use WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService;
use TYPO3\CMS\Core\Site\Entity\Site;
use TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use TYPO3\CMS\Extbase\Persistence\Repository;
/**
* A repository for ratingstep configurations
*/
class StepnameRepository extends Repository
{
protected const TABLE_NAME = 'tx_thrating_domain_model_stepname';
protected const STEPCONF_NAME = 'stepconf';
/**
* @var string $syslangUidLiteral
*/
protected $syslangUidLiteral;
/**
* @var array
*/
protected $defaultOrderings;
/**
* Initialize this repository
*/
public function initializeObject(): void
{
$this->syslangUidLiteral = $GLOBALS['TCA'][self::TABLE_NAME]['ctrl']['languageField'];
$this->defaultOrderings = [ $this->syslangUidLiteral => QueryInterface::ORDER_ASCENDING];
}
/**
* Checks if stepname got a valid language code
*
* @param Stepname $stepname The stepname object
* @return bool
*/
public function checkStepnameLanguage(Stepname $stepname): bool
{
$stepnameLang = $stepname->getSysLanguageUid();
if ($stepnameLang > 0) {
//check if given language exist
try {
// only get language and do not assign the result to check if it exists
$this->objectManager
->get(ExtensionHelperService::class)
->getStaticLanguageById($stepnameLang);
} catch (InvalidArgumentException $exception) {
//invalid language code -> NOK
return false;
}
}
//language code found -> OK
return true;
}
/**
* Finds the given stepconf object in the repository
*
* @param Stepname $stepname The ratingname to look for
* @return Stepname|null
*/
public function findStepnameObject(Stepname $stepname): ?Stepname
{
$query = $this->createQuery();
$query->getQuerySettings()->setRespectSysLanguage(false);
$query->getQuerySettings()->setLanguageOverlayMode(false);
$query->matching(
$query->logicalAnd(
[
$query->equals(self::STEPCONF_NAME, $stepname->getStepconf()),
$query->equals($this->syslangUidLiteral, $stepname->getSysLanguageUid()),
]
)
)->setLimit(1);
/** @var \TYPO3\CMS\Extbase\Persistence\QueryResultInterface $queryResult */
$queryResult = $query->execute();
/*
$queryParser = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getSQL(), get_class($this).' SQL');
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getParameters(), get_class($this).' SQL Parameter');
*/
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname $foundRow */
$foundRow = null;
if ($queryResult->count() > 0) {
$foundRow = $queryResult->getFirst();
}
return $foundRow;
}
/**
* Finds the given stepname object in the repository
*
* @param int $uid
* @return Stepname|null
*/
public function findStrictByUid(int $uid): ?Stepname
{
$query = $this->createQuery();
$query->getQuerySettings()->setRespectSysLanguage(false);
$query->getQuerySettings()->setRespectStoragePage(false);
$query->getQuerySettings()->setLanguageOverlayMode(false);
$query->matching(
$query->logicalAnd(
[$query->equals('uid', $uid)]
)
)->setLimit(1);
$queryResult = $query->execute();
/** @var Stepname $foundRow */
$foundRow = null;
if ($queryResult->count() > 0) {
$foundRow = $queryResult->getFirst();
}
return $foundRow;
}
/**
* Check on double language entries
*
* @param Stepname $stepname The ratingname to look for
* @return array return values false says OK
*/
public function checkConsistency(Stepname $stepname): array
{
$query = $this->createQuery();
$query ->getQuerySettings()->setRespectSysLanguage(false);
$query ->matching(
$query->equals(self::STEPCONF_NAME, $stepname->getStepconf()->getUid())
);
$queryResult = $query
->execute(true);
$checkConsistency = [];
if (count($queryResult) > 1) {
$websiteLanguagesArray = [];
$allWebsiteLanguages = $this->getCurrentSite()->getAllLanguages();
/** @var \TYPO3\CMS\Core\Site\Entity\SiteLanguage $language */
foreach (array_values($allWebsiteLanguages) as $language) {
$websiteLanguagesArray[] = $language->getLanguageId();
}
$languageCounter = [];
foreach (array_values($queryResult) as $value) {
$languageUid = $value[$this->syslangUidLiteral];
$languageCounter[$languageUid]++;
if ($languageCounter[$languageUid] > 1) {
$checkConsistency['doubleLang'] = true;
}
//check if language flag exists in current website
if (($languageUid > 0) && in_array($languageUid, $websiteLanguagesArray, true)) {
$checkConsistency['existLang'] = true;
}
}
}
return $checkConsistency;
}
/**
* Finds the default language stepconf by giving ratingobject and steporder
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname $stepname The ratingname to look for
* @throws InvalidQueryException
* @return Stepname|null The stepname in default language
* @var Stepname $foundRow
*/
public function findDefaultStepname(Stepname $stepname): ?Stepname
{
$foundRow = $this->objectManager->get(Stepname::class);
$query = $this->createQuery();
$query->getQuerySettings()->setRespectSysLanguage(false);
$query->getQuerySettings()->setLanguageOverlayMode(false);
$query->matching(
$query->logicalAnd(
[
$query->equals(self::STEPCONF_NAME, $stepname->getStepconf()),
$query->in($this->syslangUidLiteral, [0, -1])
]
)
)->setLimit(1);
/** @var QueryResultInterface $queryResult */
$queryResult = $query->execute();
/*
$queryParser = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getSQL(), get_class($this).' SQL');
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getParameters(), get_class($this).' SQL Parameter');
*/
/** @var Stepname $foundRow */
$foundRow = null;
if ($queryResult->count() > 0) {
$foundRow = $queryResult->getFirst();
}
return $foundRow;
}
/**
* Finds the localized ratingstep entry by giving ratingobjectUid
*
* @param Stepname $stepname The ratingname to look for
* @return bool true if stepconf having same steporder and _languageUid exists
*/
public function existStepname(Stepname $stepname): bool
{
$lookForStepname = $this->findStepnameObject($stepname);
return !is_null($lookForStepname);
}
/**
* Set default query settings to find ALL records
*/
public function clearQuerySettings(): void
{
$querySettings = $this->createQuery()->getQuerySettings();
$querySettings->setRespectSysLanguage(true);
$querySettings->setIgnoreEnableFields(true);
$querySettings->setLanguageOverlayMode(false);
$this->setDefaultQuerySettings($querySettings);
}
protected function getCurrentSite(): ?Site
{
if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface
&& $GLOBALS['TYPO3_REQUEST']->getAttribute('site') instanceof Site) {
return $GLOBALS['TYPO3_REQUEST']->getAttribute('site');
}
return null;
}
}

View File

@@ -0,0 +1,105 @@
<?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\Repository;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter;
use TYPO3\CMS\Extbase\Persistence\Repository;
/**
* A repository for votes
*/
class VoteRepository extends Repository
{
/**
* Defines name for function parameter
*/
public const /** @noinspection PhpUnused */
ADD_IF_NOT_FOUND = true;
/**
* Initialize this repository
*/
/** @noinspection PhpUnused */
public function initializeObject(): void
{
}
/**
* Finds the voting by giving the rating and voter objects
*
* @param Rating|null $rating The concerned ratingobject
* @param Voter|null $voter The Uid of the rated row
* @return Vote|object The voting
*/
public function findMatchingRatingAndVoter($rating = null, $voter = null)
{
/** @var \TYPO3\CMS\Extbase\Persistence\QueryInterface $query */
$query = $this->createQuery();
return $query->matching(
$query->logicalAnd(
[
$query->equals('rating', $rating),
$query->equals('voter', $voter)
]
)
)->execute()->getFirst();
}
/**
* Counts all votings by giving the rating and ratingstep
*
* @param Rating $rating The concerned ratingobject
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf The stepconf object
* @return int
*/
public function countByMatchingRatingAndVote($rating = null, $stepconf = null): int
{
$query = $this->createQuery();
$query->matching($query->logicalAnd(
[
$query->equals('rating', $rating->getUid()),
$query->equals('vote', $stepconf->getUid())
]
));
return count($query->execute());
}
/**
* Counts all anonymous votings by giving the rating and ratingstep
*
* @param Rating $rating The concerned ratingobject
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf The stepconf object
* @param int $anonymousVoter UID of the anonymous account
* @return int
*/
public function countAnonymousByMatchingRatingAndVote($rating = null, $stepconf = null, $anonymousVoter = null): int
{
/** @var int $count */
$count = 0;
if ($anonymousVoter !== null) {
$query = $this->createQuery();
$query->matching(
$query->logicalAnd([
$query->equals('rating', $rating->getUid()),
$query->equals('vote', $stepconf->getUid()),
$query->equals('voter', $anonymousVoter),
])
);
$count = count($query->execute());
}
return $count;
}
}

View File

@@ -0,0 +1,31 @@
<?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\Repository;
use TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository;
use TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface;
/**
* A repository for votes
*/
class VoterRepository extends FrontendUserRepository
{
/**
* Initialze this repository
*/
public function initializeObject()
{
//Even hidden or deleted FE Users should be found
/** @var \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings */
$querySettings = $this->objectManager->get(QuerySettingsInterface::class);
$querySettings->setIgnoreEnableFields(true);
$this->setDefaultQuerySettings($querySettings);
}
}

View File

@@ -0,0 +1,60 @@
<?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\Validator;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
/**
* A validator for Ratings
*
* @copyright Copyright belongs to the respective authors
* @scope singleton
*/
class RatingValidator extends AbstractValidator
{
/**
* This validator always needs to be executed even if the given value is empty.
* See AbstractValidator::validate()
*
* @var bool
*/
protected $acceptsEmptyValues = false;
/**
* If the given Rating is valid
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating $rating
* @noinspection PhpUnnecessaryFullyQualifiedNameInspection
*/
protected function isValid($rating): void
{
/** @noinspection NotOptimalIfConditionsInspection */
if (!$this->isEmpty($rating) && $rating instanceof Rating) {
$ratedobjectuid = $rating->getRatedobjectuid();
if (empty($ratedobjectuid)) {
$this->addError(
LocalizationUtility::translate('error.validator.rating.ratedobjectuid', 'ThRating'),
1283536994
);
}
if (!$rating->getRatingobject() instanceof Ratingobject) {
$this->addError(
LocalizationUtility::translate('error.validator.rating.ratingobject', 'ThRating'),
1283538549
);
}
} else {
$this->addError(LocalizationUtility::translate('error.validator.rating.empty', 'ThRating'), 1568138421);
}
}
}

View File

@@ -0,0 +1,54 @@
<?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\Validator;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
/**
* A validator for Ratingobjects
*
* @copyright Copyright belongs to the respective author
* @scope singleton
*/
class RatingobjectValidator extends AbstractValidator
{
/**
* If the given Ratingobject is valid
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject $ratingobject The ratingobject
*/
protected function isValid($ratingobject)
{
/** @var string $ratetable */
$ratetable = $ratingobject->getRatetable();
/** @var string $ratefield */
$ratefield = $ratingobject->getRatefield();
if (empty($ratetable)) {
$this->addError(
LocalizationUtility::translate(
'error.validator.ratingobject_table_extbase',
'ThRating'
),
1283528638
);
}
if (empty($ratefield)) {
$this->addError(
LocalizationUtility::translate(
'error.validator.ratingobject_field_extbase',
'ThRating'
),
1283536038
);
}
}
}

View File

@@ -0,0 +1,185 @@
<?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.
*/
/** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */
namespace WapplerSystems\BookmarksLikesRatings\Domain\Validator;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf;
use WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepconfRepository;
use WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository;
use TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
/**
* A validator for Ratings
*
* @copyright Copyright belongs to the respective authors
* @scope singleton
*/
class StepconfValidator extends AbstractValidator
{
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepconfRepository
*/
protected $stepconfRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepconfRepository $stepconfRepository
*/
public function injectStepconfRepository(StepconfRepository $stepconfRepository)
{
$this->stepconfRepository = $stepconfRepository;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository
*/
protected $stepnameRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository $stepnameRepository
*/
public function injectStepnameRepository(StepnameRepository $stepnameRepository)
{
$this->stepnameRepository = $stepnameRepository;
}
/**
* If the given step is valid
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf
* @throws InvalidQueryException
*/
protected function isValid($stepconf): void
{
/** @noinspection NotOptimalIfConditionsInspection */
if (!$this->isEmpty($stepconf) && $stepconf instanceof Stepconf) {
$this->checkRatingobject($stepconf);
if (!$this->result->hasErrors()) {
$this->checkSteporder($stepconf);
}
if (!$this->result->hasErrors()) {
$this->validateStepnames($stepconf);
}
} else {
$this->addError(LocalizationUtility::translate('error.validator.stepconf.empty', 'ThRating'), 1568139528);
}
}
/**
* A stepconf object must have a ratingobject
* @param Stepconf $stepconf
*/
protected function checkRatingobject(Stepconf $stepconf): void
{
if (!$stepconf->getRatingobject() instanceof Ratingobject) {
$this->addError(
LocalizationUtility::translate('error.validator.stepconf.ratingobject', 'ThRating'),
1284700846
);
}
}
/**
* At least a steporder value must be set and a positive integer ( >0 ) and valid regaing existing values
* @param Stepconf $stepconf
*/
protected function checkSteporder(Stepconf $stepconf): void
{
$steporder = $stepconf->getSteporder();
if (empty($steporder)) {
$this->addError(
LocalizationUtility::translate('error.validator.stepconf.steps', 'ThRating'),
1284700903
);
return;
}
if (!is_int($stepconf->getSteporder()) || $stepconf->getSteporder() < 1) {
$this->addError(
LocalizationUtility::translate(
'error.validator.stepconf.invalidSteporderNumber',
'ThRating'
),
1368123953
);
}
//check if given steporder is valid (integer, maximum +1)
/** @var object $maxSteporderStepconfobject */
$maxSteporderStepconfobject = $this->stepconfRepository->findByRatingobject($stepconf->getRatingobject());
$maxSteporder = $maxSteporderStepconfobject[$maxSteporderStepconfobject->count() - 1]->getSteporder();
if ($stepconf->getSteporder() > $maxSteporder + 1) {
$this->addError(
LocalizationUtility::translate('error.validator.stepconf.maxSteporder', 'ThRating'),
1368123970
);
}
}
/**
* If the given step is valid
*
* @param Stepconf $stepconf
* @throws InvalidQueryException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/
protected function validateStepnames($stepconf): void
{
//check if a stepname is given that at least has the default language definition
//TODO move to query on stepname repository
$stepname = $stepconf->getStepname();
$countNames = 0;
if ($stepname instanceof ObjectStorage) {
$countNames = $stepname->count();
}
if ($countNames != 0) {
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname $firstStepname */
$firstStepname = $stepname->current();
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname|object $defaultName */
$defaultName = $this->stepnameRepository->findDefaultStepname($firstStepname);
if (!$defaultName->isValid()) {
$this->addError(
LocalizationUtility::translate(
'error.validator.stepconf.defaultStepname',
'ThRating',
[$firstStepname->getStepconf()->getUid()]
),
1384374165
);
} else {
//Finally check on language consistency
$checkConsistency = $this->stepnameRepository->checkConsistency($firstStepname);
if ($checkConsistency['doubleLang']) {
$this->addError(
LocalizationUtility::translate(
'error.validator.stepconf.doubleLangEntry',
'ThRating',
[$firstStepname->getStepconf()->getUid()]
),
1384374589
);
} elseif ($checkConsistency['existLang']) {
$this->addError(
LocalizationUtility::translate(
'error.validator.stepconf.notExistingLanguage',
'ThRating',
[$firstStepname->getUid()]
),
1384374589
);
}
}
}
}
}

View File

@@ -0,0 +1,72 @@
<?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.
*/
/** @noinspection PhpFullyQualifiedNameUsageInspection */
namespace WapplerSystems\BookmarksLikesRatings\Domain\Validator;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
/**
* A validator for Ratings
*
* @copyright Copyright belongs to the respective authors
* @scope singleton
*/
class StepnameValidator extends AbstractValidator
{
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository
*/
protected $stepnameRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository $stepnameRepository
*/
public function injectStepnameRepository(\WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository $stepnameRepository)
{
$this->stepnameRepository = $stepnameRepository;
}
/**
* If the given step is valid
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname $stepname
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/
protected function isValid($stepname): void
{
//a stepname object must have a stepconf
if (!$stepname->getStepconf() instanceof Stepconf) {
$this->addError(
LocalizationUtility::translate('error.validator.stepname.stepconf', 'ThRating'),
1382895072
);
}
//check if given languagecode exists in website
if (!$this->stepnameRepository->checkStepnameLanguage($stepname)) {
$this->addError(LocalizationUtility::translate('error.validator.stepname.sysLang', 'ThRating'), 1382895089);
}
//now check if entry for default language exists
$langUid = $stepname->getSysLanguageUid();
if (!empty($langUid)) {
$defaultStepname = $this->stepnameRepository->findDefaultStepname($stepname);
if (get_class($defaultStepname) !== Stepname::class || $this->validate($defaultStepname)->hasErrors()) {
$this->addError(
LocalizationUtility::translate('error.validator.stepname.defaultLang', 'ThRating'),
1382895097
);
}
}
}
}

View File

@@ -0,0 +1,79 @@
<?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\Validator;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
/**
* A validator for Votes
*
* @copyright Copyright belongs to the respective authors
* @scope singleton
*/
class VoteValidator extends AbstractValidator
{
/**
* This validator always needs to be executed even if the given value is empty.
* See AbstractValidator::validate()
*
* @var bool
*/
protected $acceptsEmptyValues = false;
/**
* If the given Vote is valid
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote The vote
*/
protected function isValid($vote)
{
/** @noinspection NotOptimalIfConditionsInspection */
if (!$this->isEmpty($vote) && $vote instanceof Vote) {
//a vote object must have a vote
if (!$vote->getVote() instanceof Stepconf) {
$this->addError(LocalizationUtility::translate('error.validator.vote.vote', 'ThRating'), 1283537235);
} else {
//a vote must have a valid voter
if (!$vote->getVoter() instanceof Voter) {
$this->addError(
LocalizationUtility::translate('error.validator.vote.voter', 'ThRating'),
1283540684
);
}
//check if the given vote is a valid step for this ratingobject
if (!$vote->getRating()->getRatingobject()->getStepconfs()->contains($vote->getVote())) {
$this->addError(
LocalizationUtility::translate('error.validator.vote.stepconf', 'ThRating'),
1283612492
);
}
}
} else {
$this->addError(LocalizationUtility::translate('error.validator.vote.empty', 'ThRating'), 1568141014);
}
}
/**
* If the given Vote is set
*
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote The vote
* @return bool
*/
public function isObjSet($vote)
{
$result = !$this->isEmpty($vote) && $vote instanceof Vote;
return $result;
}
}

View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types = 1);
/*
* 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\Service;
use TYPO3\CMS\Core\SingletonInterface;
/**
* An access control service
*
* @version $Id:$
* @license http://opensource.org/licenses/gpl-license.php GNU protected License, version 2
*/
class AbstractExtensionService implements SingletonInterface
{
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
*/
protected $objectManager;
/**
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
*/
public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Service\LoggingService
*/
protected $loggingService;
/**
* @var \TYPO3\CMS\Core\Log\Logger
*/
protected $logger;
/**
* Constructor
* @param \WapplerSystems\BookmarksLikesRatings\Service\LoggingService $loggingService
*/
public function __construct(LoggingService $loggingService)
{
$this->loggingService = $loggingService;
$this->logger = $loggingService->getLogger(get_class($this));
}
}

View File

@@ -0,0 +1,187 @@
<?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.
*/
/** @noinspection PhpFullyQualifiedNameUsageInspection */
namespace WapplerSystems\BookmarksLikesRatings\Service;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter;
use WapplerSystems\BookmarksLikesRatings\Exception\FeUserNotFoundException;
use TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* An access control service
*
* @version $Id:$
* @license http://opensource.org/licenses/gpl-license.php GNU protected License, version 2
*/
class AccessControlService extends AbstractExtensionService
{
/**
* @var \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository $frontendUserRepository
*/
protected $frontendUserRepository;
/**
* @param \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository $frontendUserRepository
* @noinspection PhpUnused
*/
public function injectFrontendUserRepository(FrontendUserRepository $frontendUserRepository): void
{
$this->frontendUserRepository = $frontendUserRepository;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\VoterRepository $voterRepository
*/
protected $voterRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\VoterRepository $voterRepository
*/
public function injectVoterRepository(\WapplerSystems\BookmarksLikesRatings\Domain\Repository\VoterRepository $voterRepository): void
{
$this->voterRepository = $voterRepository;
}
/**
* @var \TYPO3\CMS\Core\Context\Context $context
*/
protected $context;
/**
* @param \TYPO3\CMS\Core\Context\Context $context
*/
public function injectContext(\TYPO3\CMS\Core\Context\Context $context): void
{
$this->context = $context;
}
/**
* Tests, if the given person is logged into the frontend
*
* @param \TYPO3\CMS\Extbase\Domain\Model\FrontendUser|null $person The person
* @return bool The result; true if the given person is logged in; otherwise false
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
*/
public function isLoggedIn(\TYPO3\CMS\Extbase\Domain\Model\FrontendUser $person = null): bool
{
if (is_object($person)) {
if ($person->getUid() &&
($person->getUid() === $this->getFrontendUserUid())) {
return true; //treat anonymous user also as logged in
}
}
return false;
}
/**
* @return bool
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
*/
public function backendAdminIsLoggedIn(): bool
{
return $this->context->getPropertyFromAspect('backend.user', 'isLoggedIn');
}
/**
* @return bool
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
*/
public function hasLoggedInFrontendUser(): bool
{
return $this->context->getPropertyFromAspect('frontend.user', 'isLoggedIn');
}
/**
* @return array
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
*/
public function getFrontendUserGroups(): array
{
if ($this->hasLoggedInFrontendUser()) {
return $this->context->getPropertyFromAspect('frontend.user', 'groupIds');
}
return [];
}
/**
* @return int|null
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
*/
public function getFrontendUserUid(): ?int
{
if ($this->hasLoggedInFrontendUser()) {
return $this->context->getPropertyFromAspect('frontend.user', 'id');
}
return null;
}
/**
* Loads objects from repositories
*
* @param mixed $voter
* @return \TYPO3\CMS\Extbase\Domain\Model\FrontendUser
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
*/
public function getFrontendUser($voter = null): ?\TYPO3\CMS\Extbase\Domain\Model\FrontendUser
{
//set userobject
if (!$voter instanceof \TYPO3\CMS\Extbase\Domain\Model\FrontendUser) {
//TODO Errorhandling if no user is logged in
if ((int)$voter === 0) {
//get logged in fe-user
$voter = $this->frontendUserRepository->findByUid($this->getFrontendUserUid());
} else {
$voter = $this->frontendUserRepository->findByUid((int)$voter);
}
}
return $voter;
}
/**
* Loads objects from repositories
*
* @param int|null $voter
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter
* @throws FeUserNotFoundException
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
*/
public function getFrontendVoter(?int $voter = 0): Voter
{
$exceptionMessageArray = [];
/** @var Voter $voterObject */
$voterObject = null;
//TODO Errorhandling if no user is logged in
if ((int)$voter === 0) {
//get logged in fe-user
$voterObject = $this->voterRepository->findByUid($this->getFrontendUserUid());
$exceptionMessageArray = [$this->getFrontendUserUid()];
$exceptionMessageType = 'feUser';
} else {
$voterObject = $this->voterRepository->findByUid((int)$voter);
$exceptionMessageArray = [(int)$voter];
$exceptionMessageType = 'anonymousUser';
}
if (empty($voterObject)) {
throw new FeUserNotFoundException(
LocalizationUtility::translate(
'flash.pluginConfiguration.missing.' . $exceptionMessageType,
'ThRating',
$exceptionMessageArray
),
1602095329
);
}
return $voterObject;
}
}

View File

@@ -0,0 +1,21 @@
<?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\Service;
use TYPO3\CMS\Extbase\Exception;
/**
* An access exception
*
* @version $ID: $
*/
class AccessException extends Exception
{
}

View File

@@ -0,0 +1,139 @@
<?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\Service;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Service for setting cookies like Typo3 does
*
* @version $Id:$
* @license http://opensource.org/licenses/gpl-license.php GNU protected License, version 2
*/
class CookieService extends AbstractExtensionService
{
/**
* Indicator for cookieProtection has been set
* @var bool
*/
protected $cookieProtection = false;
/**
* Gets the domain to be used on setting cookies.
* The information is taken from the value in $GLOBALS['TYPO3_CONF_VARS']['SYS']['cookieDomain'].
* Protected function taken from t3lib_userAuth (t3 4.7.7)
*
* @return string The domain to be used on setting cookies
*/
protected function getCookieDomain()
{
$result = '';
$cookieDomain = $GLOBALS['TYPO3_CONF_VARS']['SYS']['cookieDomain'];
// If a specific cookie domain is defined for a given TYPO3_MODE,
// use that domain
if (!empty($GLOBALS['TYPO3_CONF_VARS']['FE']['cookieDomain'])) {
$cookieDomain = $GLOBALS['TYPO3_CONF_VARS']['FE']['cookieDomain'];
}
if ($cookieDomain) {
if ($cookieDomain[0] === '/') {
$match = [];
/** @noinspection PhpUsageOfSilenceOperatorInspection */
$matchCnt = @preg_match(
$cookieDomain,
GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY'),
$match
);
if ($matchCnt === false) {
$this->logger->log(
LogLevel::ERROR,
'getCookieDomain: The regular expression for the cookie domain contains errors.' .
'The session is not shared across sub-domains.',
['cookieDomain' => $cookieDomain, 'errorCode' => 1399137882]
);
} elseif ($matchCnt) {
$result = $match[0];
}
} else {
$result = $cookieDomain;
}
}
return $result;
}
/**
* Sets the cookie
* Protected function taken from t3lib_userAuth (t3 4.7.7)
*
* @param string $cookieName identifier for the cookie
* @param string $cookieValue cookie value
* @param int $cookieExpire expire time for the cookie (UNIX timestamp)
*
* @throws Exception
*/
public function setVoteCookie($cookieName, $cookieValue, $cookieExpire = 0): void
{
// do not set session cookies
if (!empty($cookieExpire)) {
$settings = $GLOBALS['TYPO3_CONF_VARS']['SYS'];
// Get the domain to be used for the cookie (if any):
$cookieDomain = $this->getCookieDomain();
// If no cookie domain is set, use the base path:
$cookiePath = ($cookieDomain ? '/' : GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'));
// Use the secure option when the current request is served by a secure connection:
$cookieSecure = (bool)$settings['cookieSecure'] && GeneralUtility::getIndpEnv('TYPO3_SSL');
// Deliver cookies only via HTTP and prevent possible XSS by JavaScript:
$cookieHttpOnly = (bool)$settings['cookieHttpOnly'];
// Do not set cookie if cookieSecure is set to "1" (force HTTPS) and no secure channel is used:
if ((int)$settings['cookieSecure'] !== 1 || GeneralUtility::getIndpEnv('TYPO3_SSL')) {
setcookie(
$cookieName,
$cookieValue,
(int)$cookieExpire,
$cookiePath,
$cookieDomain,
$cookieSecure,
$cookieHttpOnly
);
$this->cookieProtection = true;
$this->logger->log(
LogLevel::INFO,
'setVoteCookie: Cookie set',
[
'cookieName' => $cookieName,
'cookieValue' => $cookieValue,
'cookieExpire' => $cookieExpire,
'cookiePath' => $cookiePath,
'cookieDomain' => $cookieDomain,
'cookieSecure' => $cookieSecure,
'cookieHttpOnly' => $cookieHttpOnly,
]
);
} else {
throw new Exception(
"Cookie was not set since HTTPS was forced in \$GLOBALS['TYPO3_CONF_VARS'][SYS][cookieSecure].",
1254325546
);
}
}
}
/**
* Return if cookie protection has been set
*
* @return bool
*/
public function isProtected()
{
return $this->cookieProtection;
}
}

View File

@@ -0,0 +1,19 @@
<?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\Service;
/**
* A ViewHelper Exception
*
* @api
*/
class Exception extends \TYPO3Fluid\Fluid\Core\Exception
{
}

View File

@@ -0,0 +1,233 @@
<?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\Service;
use WapplerSystems\BookmarksLikesRatings\Exception\FeUserStoragePageException;
use WapplerSystems\BookmarksLikesRatings\Exception\InvalidStoragePageException;
use TYPO3\CMS\Core\Log\Logger;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* Factory for model objects
*
* @version $Id:$
* @license http://opensource.org/licenses/gpl-license.php GNU protected License, version 2
*/
class ExtensionConfigurationService extends AbstractExtensionService
{
/**
* Contains configuration of the calling extension
*
* @var array
*/
protected $originalConfiguration;
/**
* Calling extension query settings
*
* @var \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface
*/
protected $originalTypo3QuerySettings;
/**
* @var int
*/
protected $cookieLifetime;
/**
* @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
*/
protected $configurationManager;
/**
* @var QuerySettingsInterface
*/
private $extDefaultQuerySettings;
/**
* @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
*/
public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager): void
{
$this->configurationManager = $configurationManager;
}
/**
* Contains the settings of the current extension
*
* @var array
*/
protected $settings;
/**
* Contains configuration of th_rating
*
* @var array
*/
protected $thRatingConfiguration;
/**
* Contains configuration of the current extension
*
* @var array
*/
protected $frameworkConfiguration;
/**
* Constructor
*/
public function initializeObject(): void
{
// store calling extension configuration
$this->originalConfiguration = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
);
$this->thRatingConfiguration = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
'thrating',
'pi1'
);
if (!empty($this->thRatingConfiguration['ratings'])) {
//Merge extension ratingConfigurations with customer added ones
ArrayUtility::mergeRecursiveWithOverrule(
$this->thRatingConfiguration['settings']['ratingConfigurations'],
$this->thRatingConfiguration['ratings']
);
}
$this->frameworkConfiguration = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT,
'thrating',
'pi1'
);
//\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($this->frameworkConfiguration,get_class($this).' frameworkConfiguration');
//\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($this->thRatingConfiguration,get_class($this).' thRatingConfiguration');
//\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($this->originalConfiguration,get_class($this).' originalConfiguration');
}
/**
* Get a logger instance
* The configuration of the logger is modified by extension typoscript config
*
* @param string|null $name the class name which this logger is for
* @return \TYPO3\CMS\Core\Log\Logger
*/
public function getLogger(string $name = null): Logger
{
if (empty($name)) {
return $this->loggingService->getLogger(__CLASS__);
}
return $this->loggingService->getLogger($name);
}
/**
* Set default query settings to those of th_rating
* (could be different if services are called from other extensions
* @throws FeUserStoragePageException
* @throws InvalidStoragePageException
*/
public function setExtDefaultQuerySettings(): void
{
$this->mergeStoragePids();
$this->extDefaultQuerySettings = $this->objectManager->get(QuerySettingsInterface::class);
$this->extDefaultQuerySettings->setStoragePageIds(
explode(',', $this->thRatingConfiguration['persistence']['storagePid'])
);
}
/**
* @return bool
*/
protected function getCookieProtection(): bool
{
$this->cookieLifetime = abs((int)$this->thRatingConfiguration['settings']['cookieLifetime']);
$this->logger->log(
LogLevel::DEBUG,
'Cookielifetime set to ' . $this->cookieLifetime . ' days',
['errorCode' => 1465728751]
);
return empty($this->cookieLifetime);
}
/**
* Checks storagePid settings of th_rating and tx_felogin_pi1 and
* concatenates them to the new storagePid setting
*
* @throws InvalidStoragePageException if plugin.tx_thrating.storagePid has not been set
* @throws FeUserStoragePageException if plugin.tx_felogin_pi1.storagePid has not been set
*/
private function mergeStoragePids(): void
{
$storagePids = GeneralUtility::intExplode(',', $this->thRatingConfiguration['storagePid'], true);
if (empty($storagePids[0])) {
throw new InvalidStoragePageException(
LocalizationUtility::translate('flash.vote.general.invalidStoragePid', 'ThRating'),
1403203519
);
}
$storagePids[] = $this->getFeUserStoragePage();
$this->thRatingConfiguration['persistence.']['storagePid'] = implode(',', $storagePids);
}
/**
* Check and return the first configured storage page for website users
* @return int
* @throws FeUserStoragePageException
*/
private function getFeUserStoragePage(): int
{
$feUserStoragePid = array_merge(
GeneralUtility::intExplode(
',',
$this->frameworkConfiguration['plugin.']['tx_felogin_pi1.']['storagePid'],
true
),
GeneralUtility::intExplode(',', $this->thRatingConfiguration['feUsersStoragePid'], true)
);
if (empty($feUserStoragePid[0])) {
throw new FeUserStoragePageException(
LocalizationUtility::translate('flash.pluginConfiguration.missing.feUserStoragePid', 'ThRating'),
1403190539
);
}
return $feUserStoragePid[0];
}
/**
* Change the current extbase configuration to the one of th_rating
*/
public function prepareExtensionConfiguration(): void
{
if ($this->originalConfiguration['extensionName'] !== 'ThRating') {
//Set default storage pids
$this->setExtDefaultQuerySettings();
}
$this->configurationManager->setConfiguration($this->thRatingConfiguration);
}
/**
* Change the current extbase configuration to the one of th_rating
*/
public function restoreCallingExtensionConfiguration(): void
{
if ($this->originalConfiguration['extensionName'] !== 'ThRating') {
$this->configurationManager->setConfiguration($this->originalConfiguration);
}
}
}

View File

@@ -0,0 +1,720 @@
<?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.
*/
/** @noinspection PhpFullyQualifiedNameUsageInspection */
namespace WapplerSystems\BookmarksLikesRatings\Service;
use Psr\Http\Message\ServerRequestInterface;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\RatingImage;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote;
use WapplerSystems\BookmarksLikesRatings\Domain\Repository\RatingobjectRepository;
use WapplerSystems\BookmarksLikesRatings\Domain\Repository\RatingRepository;
use WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository;
use WapplerSystems\BookmarksLikesRatings\Domain\Repository\VoteRepository;
use WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingobjectValidator;
use WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingValidator;
use WapplerSystems\BookmarksLikesRatings\Domain\Validator\StepconfValidator;
use WapplerSystems\BookmarksLikesRatings\Domain\Validator\VoteValidator;
use WapplerSystems\BookmarksLikesRatings\Evaluation\DynamicCssEvaluator;
use WapplerSystems\BookmarksLikesRatings\Exception\LanguageNotFoundException;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Log\Logger;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Site\Entity\Site;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
* Factory for model objects
*
* @version $Id:$
* @license http://opensource.org/licenses/gpl-license.php GNU protected License, version 2
*/
class ExtensionHelperService extends AbstractExtensionService
{
protected const DYN_CSS_FILENAME = 'typo3temp/thratingDyn.css';
/**
* The current request.
*
* @var \TYPO3\CMS\Extbase\Mvc\Request
*/
protected $request;
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\RatingobjectRepository
*/
protected $ratingobjectRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\RatingobjectRepository $ratingobjectRepository
*/
public function injectRatingobjectRepository(RatingobjectRepository $ratingobjectRepository): void
{
$this->ratingobjectRepository = $ratingobjectRepository;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\RatingRepository
*/
protected $ratingRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\RatingRepository $ratingRepository
*/
public function injectRatingRepository(RatingRepository $ratingRepository): void
{
$this->ratingRepository = $ratingRepository;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository
*/
protected $stepnameRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepnameRepository $stepnameRepository
*/
public function injectStepnameRepository(StepnameRepository $stepnameRepository): void
{
$this->stepnameRepository = $stepnameRepository;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Repository\VoteRepository
*/
protected $voteRepository;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\VoteRepository $voteRepository
*/
public function injectVoteRepository(VoteRepository $voteRepository): void
{
$this->voteRepository = $voteRepository;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Service\AccessControlService
*/
protected $accessControllService;
/**
* @param AccessControlService $accessControllService
*/
public function injectAccessControlService(AccessControlService $accessControllService): void
{
$this->accessControllService = $accessControllService;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Validator\StepconfValidator
*/
protected $stepconfValidator;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Validator\StepconfValidator $stepconfValidator
*/
public function injectStepconfValidator(StepconfValidator $stepconfValidator): void
{
$this->stepconfValidator = $stepconfValidator;
}
/**
* @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
*/
protected $configurationManager;
/**
* @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
*/
public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager): void
{
$this->configurationManager = $configurationManager;
}
/**
* Contains the settings of the current extension
*
* @var array
*/
protected $settings;
/**
* @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\RatingImage
*/
protected $ratingImage;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface
*/
protected $extDefaultQuerySettings;
/**
* Constructor
*/
public function initializeObject(): void
{
$this->settings = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'thrating',
'pi1'
);
$frameworkConfiguration = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
'thrating',
'pi1'
);
if (!empty($frameworkConfiguration['ratings'])) {
//Merge extension ratingConfigurations with customer added ones
ArrayUtility::mergeRecursiveWithOverrule(
$this->settings['ratingConfigurations'],
$frameworkConfiguration['ratings']
);
}
}
/**
* @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
*/
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
{
global $TSFE;
return $TSFE;
}
/**
* Returns the completed settings array
*
* @param array $settings
* @return array
*/
private function completeConfigurationSettings(array $settings): array
{
$cObj = $this->configurationManager->getContentObject();
if (!empty($cObj->currentRecord)) {
/* build array [0=>cObj tablename, 1=> cObj uid] - initialize with content information
(usage as normal content) */
$currentRecord = explode(':', $cObj->currentRecord);
} else {
//build array [0=>cObj tablename, 1=> cObj uid] - initialize with page info if used by typoscript
$currentRecord = ['pages', $GLOBALS['TSFE']->page['uid']];
}
if (empty($settings['ratetable'])) {
$settings['ratetable'] = $currentRecord[0];
}
if (empty($settings['ratefield'])) {
$settings['ratefield'] = 'uid';
}
if (empty($settings['ratedobjectuid'])) {
$settings['ratedobjectuid'] = $currentRecord[1];
}
return $settings;
}
/**
* Returns a new or existing ratingobject
*
* @param array $settings
* @throws \WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject
*/
public function getRatingobject(array $settings): Ratingobject
{
$ratingobject = null;
//check whether a dedicated ratingobject is configured
if (!empty($settings['ratingobject'])) {
$ratingobject = $this->ratingobjectRepository->findByUid($settings['ratingobject']);
} else {
if (empty($settings['ratetable']) || empty($settings['ratefield'])) {
//fallback to default configuration
$settings = $settings['defaultObject'] + $settings;
}
$settings = $this->completeConfigurationSettings($settings);
$ratingobject = $this->ratingobjectRepository->findMatchingTableAndField(
$settings['ratetable'],
$settings['ratefield'],
RatingobjectRepository::ADD_IF_NOT_FOUND
);
}
return $ratingobject;
}
/**
* Returns a new or existing ratingobject
*
* @param array $stepconfArray
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf
*/
public function createStepconf(array $stepconfArray): Stepconf
{
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf */
$stepconf = $this->objectManager->get(Stepconf::class);
$stepconf->setRatingobject($stepconfArray['ratingobject']);
$stepconf->setSteporder($stepconfArray['steporder']);
$stepconf->setStepweight($stepconfArray['stepweight']);
return $stepconf;
}
/**
* Returns a new or existing ratingobject
*
* @param Stepconf $stepconf
* @param array $stepnameArray
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname
* @throws LanguageNotFoundException
* @throws \TYPO3\CMS\Core\Exception\SiteNotFoundException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/
public function createStepname(Stepconf $stepconf, array $stepnameArray): Stepname
{
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname $stepname */
$stepname = $this->objectManager->get(Stepname::class);
$stepname->setStepconf($stepconf);
$stepname->setStepname($stepnameArray['stepname']);
$stepname->setPid($stepnameArray['pid']);
$stepname->setSysLanguageUid(
$this->getStaticLanguageByIsoCode(
$stepname->getPid(),
$stepnameArray['twoLetterIsoCode'] ?: null
)->getLanguageId()
);
$defaultStepname = $this->stepnameRepository->findDefaultStepname($stepname);
$l18nParent = is_null($defaultStepname) ? 0 : $defaultStepname->getUid();
$stepname->setL18nParent($l18nParent);
return $stepname;
}
/**
* Returns a new or existing rating
*
* @param array $settings
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject|null $ratingobject
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @throws \WapplerSystems\BookmarksLikesRatings\Service\Exception
*/
public function getRating(array $settings, ?Ratingobject $ratingobject): Rating
{
$settings = $this->completeConfigurationSettings($settings);
if (!empty($settings['rating'])) {
//fetch rating when it is configured
$rating = $this->ratingRepository->findByUid($settings['rating']);
} elseif ($settings['ratedobjectuid'] && !$this->objectManager->get(RatingobjectValidator::class)
->validate($ratingobject)->hasErrors()) {
//get rating according to given row
/** @noinspection NullPointerExceptionInspection */
$rating = $this->ratingRepository->findMatchingObjectAndUid(
$ratingobject,
$settings['ratedobjectuid'],
RatingRepository::ADD_IF_NOT_FOUND
);
} else {
throw new \WapplerSystems\BookmarksLikesRatings\Service\Exception(
'Incomplete configuration setting. Either \'rating\' or \'ratedobjectuid\' are missing.',
1398351336
);
}
return $rating;
}
/**
* Returns a new or existing vote
*
* @param string $prefixId
* @param array $settings
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Rating $rating
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote
* @throws \WapplerSystems\BookmarksLikesRatings\Exception\FeUserNotFoundException
*/
public function getVote(string $prefixId, array $settings, Rating $rating): Vote
{
// initialize variables
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote */
$vote = null;
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter $voter */
$voter = null;
//first fetch real voter or anonymous
/** @var int $frontendUserUid */
$frontendUserUid = $this->accessControllService->getFrontendUserUid();
if (!$frontendUserUid && !empty($settings['mapAnonymous'])) {
//set anonymous vote
$voter = $this->accessControllService->getFrontendVoter($settings['mapAnonymous']);
$anonymousRating = GeneralUtility::makeInstance(\WapplerSystems\BookmarksLikesRatings\Service\JsonService::class)
->decodeJsonToArray($_COOKIE[$prefixId . '_AnonymousRating_' . $rating->getUid()]);
if (!empty($anonymousRating['voteUid'])) {
$vote = $this->voteRepository->findByUid($anonymousRating['voteUid']);
}
} elseif ($frontendUserUid) {
//set FEUser if one is logged on
$voter = $this->accessControllService->getFrontendVoter($frontendUserUid);
if ($voter instanceof \WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter) {
$vote = $this->voteRepository->findMatchingRatingAndVoter($rating, $voter);
}
}
//voting not found in database or anonymous vote? - create new one
$voteValidator = $this->objectManager->get(VoteValidator::class);
if ($voteValidator->validate($vote)->hasErrors()) {
$vote = $this->objectManager->get(Vote::class);
$ratingValidator = $this->objectManager->get(RatingValidator::class);
if (!$ratingValidator->validate($rating)->hasErrors()) {
$vote->setRating($rating);
}
if ($voter instanceof \WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter) {
$vote->setVoter($voter);
}
}
return $vote;
}
/**
* Get a logger instance
* The configuration of the logger is modified by extension typoscript config
*
* @param string|null $name the class name which this logger is for
* @return \TYPO3\CMS\Core\Log\Logger
*/
public function getLogger(?string $name): Logger
{
if (empty($name)) {
return $this->loggingService->getLogger(__CLASS__);
}
return $this->loggingService->getLogger($name);
}
/**
* Update and persist attached objects to the repository
*
* @param string $repository
* @param \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $objectToPersist
*/
public function persistRepository(string $repository, AbstractEntity $objectToPersist): void
{
$objectUid = $objectToPersist->getUid();
if (!is_int($objectUid)) {
$this->objectManager->get($repository)->add($objectToPersist);
} else {
$this->objectManager->get($repository)->update($objectToPersist);
}
$this->objectManager->get(PersistenceManager::class)->persistAll();
}
/**
* Clear the dynamic CSS file for recreation
*/
public function clearDynamicCssFile(): void
{
$this->objectManager->get(DynamicCssEvaluator::class)->clearCachePostProc([]);
}
/**
* Render CSS-styles for ratings and ratingsteps
* Only called by singeltonAction to render styles once per page.
* The file self::DYN_CSS_FILENAME will be created if it doesn<73>t exist
*
* @return array
*/
public function renderDynCSS(): array
{
$messageArray = [];
$cssFile = '';
//create file if it does not exist
if (file_exists(Environment::getPublicPath() . '/' . self::DYN_CSS_FILENAME)) {
$fstat = stat(Environment::getPublicPath() . '/' . self::DYN_CSS_FILENAME);
//do not recreate file if it has greater than zero length
if ($fstat[7] !== 0) {
$this->logger->log(LogLevel::DEBUG, 'Dynamic CSS file exists - exiting');
return $messageArray;
}
}
//now walk through all ratingobjects to calculate stepwidths
$allRatingobjects = $this->ratingobjectRepository->findAll(true);
foreach ($allRatingobjects as $ratingobject) {
$ratingobjectUid = $ratingobject->getUid();
/** @var ObjectStorage<\WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf> $stepconfObjects */
$stepconfObjects = $ratingobject->getStepconfs();
$stepcount = count($stepconfObjects);
if (!$stepcount) {
if ($this->settings['showMissingStepconfError']) {
//show error message in GUI
$messageArray[] = [
'messageText' => LocalizationUtility::translate(
'flash.renderCSS.noStepconf',
'ThRating',
[
1 => $ratingobject->getUid(),
2 => $ratingobject->getPid()
]
),
'messageTitle' => LocalizationUtility::translate(
'flash.configuration.error',
'ThRating'
),
'severity' => 'ERROR',
'additionalInfo' => [
'errorCode' => 1384705470,
'ratingobject UID' => $ratingobject->getUid(),
'ratingobject PID' => $ratingobject->getPid(),
],
];
} else {
//only log message
$this->logger->log(
LogLevel::ERROR,
LocalizationUtility::translate(
'flash.renderCSS.noStepconf',
'ThRating',
[
1 => $ratingobject->getUid(),
2 => $ratingobject->getPid()
]
),
[
'errorCode' => 1384705470,
'ratingobject UID' => $ratingobject->getUid(),
'ratingobject PID' => $ratingobject->getPid(),
]
);
}
}
$stepWeights = [];
$sumStepWeights = 0;
$stepconfs = $stepconfObjects->toArray();
foreach ($stepconfs as $stepconf) { //stepconfs are already sorted by steporder
//just do checks here that all steps are OK
if (!$this->stepconfValidator->validate($stepconf)->hasErrors()) {
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf */
$stepWeights[] = $stepconf->getStepweight();
$sumStepWeights += $stepconf->getStepweight();
} else {
foreach ($this->stepconfValidator->validate($stepconf)->getErrors() as $errorMessage) {
$messageArray[] = [
'messageText' => $errorMessage->getMessage(),
'messageTitle' => LocalizationUtility::translate('flash.configuration.error', 'ThRating'),
'severity' => 'ERROR',
'additionalInfo' => ['errorCode' => $errorMessage->getCode(),
'errorMessage' => $errorMessage->getMessage(), ], ];
}
}
}
$this->logger->log(
LogLevel::INFO,
'Ratingobject data',
[
'ratingobject UID' => $ratingobject->getUid(),
'ratingobject PID' => $ratingobject->getPid(),
'stepcount' => $stepcount,
'stepWeights' => $stepWeights,
'sumStepWeights' => $sumStepWeights,
'messageCount' => count($messageArray)
]
);
//generate CSS for all ratings out of TSConfig
foreach ($this->settings['ratingConfigurations'] as $ratingName => $ratingConfig) {
if ($ratingName === 'default') {
continue;
}
$subURI = substr(Environment::getPublicPath() . '/', strlen($_SERVER['DOCUMENT_ROOT']) + 1);
$basePath = $this->getTypoScriptFrontendController()->baseUrl ?: '//' .
$_SERVER['HTTP_HOST'] . '/' . $subURI;
$this->ratingImage = $this->objectManager->get(RatingImage::class);
$this->ratingImage->setConf($ratingConfig['imagefile']);
$filename = $this->ratingImage->getImageFile();
if (empty($filename)) {
$messageArray[] = [
'messageText' => LocalizationUtility::translate(
'flash.vote.renderCSS.defaultImage',
'ThRating'
),
'messageTitle' => LocalizationUtility::translate(
'flash.heading.warning',
'ThRating'
),
'severity' => 'WARNING',
'additionalInfo' => ['errorCode' => 1403192702,
'ratingName' => $ratingName,
'ratingConfig' => $ratingConfig, ], ];
$defaultRatingName = $this->settings['ratingConfigurations']['default'];
$ratingConfig = $this->settings['ratingConfigurations'][$defaultRatingName];
$this->ratingImage->setConf($ratingConfig['imagefile']);
$filename = $this->ratingImage->getImageFile();
}
$filenameUri = $basePath . '/' . $filename; //prepend host basepath if no URL is given
$imageDimensions = $this->ratingImage->getImageDimensions();
$height = $imageDimensions['height'];
$width = $imageDimensions['width'];
$mainId = '.thRating-RObj' . $ratingobjectUid . '-' . $ratingName;
$this->logger->log(
LogLevel::DEBUG,
'Main CSS info',
[
'mainId' => $mainId,
'filenameUri' => $filenameUri,
'image width' => $width,
'image height' => $height, ]
);
//calculate overall rating size depending on rating direction
if ($ratingConfig['tilt']) {
$width = round($width / 3, 1);
if (!$ratingConfig['barimage']) {
$height *= $sumStepWeights;
}
$cssFile .= $mainId . ' { width:' . $width . 'px; height:' . $height . 'px; }' . chr(10);
$cssFile .= $mainId . ', ' . $mainId . ' span:hover, ' . $mainId . ' span:active, ' . $mainId .
' span:focus, ' . $mainId . ' .current-rating { background:url(' . $filenameUri .
') right bottom repeat-y; }' . chr(10);
$cssFile .= $mainId . ' span, ' . $mainId . ' .current-rating { width:' . $width . 'px; }' .
chr(10);
} else {
$height = round($height / 3, 1);
if (!$ratingConfig['barimage']) {
$width *= $sumStepWeights;
}
$cssFile .= $mainId . ' { width:' . $width . 'px; height:' . $height . 'px; }' . chr(10);
$cssFile .= $mainId . ', ' . $mainId . ' span:hover, ' . $mainId . ' span:active, ' . $mainId .
' span:focus, ' . $mainId . ' .current-rating { background:url(' . $filenameUri .
') 0 0 repeat-x; }' . chr(10);
$cssFile .= $mainId . ' span, ' . $mainId . ' .current-rating { height:' . $height .
'px; line-height:' . $height . 'px; }' . chr(10);
//calculate widths/heights related to stepweights
}
$cssFile .= $mainId . ' .current-poll { background:url(' . $filenameUri . '); }' . chr(10);
}
//calculate widths/heights related to stepweights
$i = 1;
$stepPart = 0;
$sumWeights = 0;
foreach ($stepWeights as $stepWeight) {
$sumWeights += $stepWeight;
$zIndex = $stepcount - $i + 2; //add 2 to override .current-poll and .currentPollText
//configure rating and polling styles for steps
$oneStepPart = round($stepWeight * 100 / $sumStepWeights, 1); //calculate single width of ratingstep
$cssFile .= 'span.RObj' . $ratingobjectUid . '-StpOdr' . $i . '-ratingpoll-normal { width:' .
$oneStepPart . '%; z-index:' . $zIndex . '; margin-left:' . $stepPart . '%;}' . chr(10);
$cssFile .= 'span.RObj' . $ratingobjectUid . '-StpOdr' . $i . '-ratingpoll-tilt { height:' .
$oneStepPart . '%; z-index:' . $zIndex . '; margin-bottom:' . $stepPart . '%; }' . chr(10);
$cssFile .= 'li.RObj' . $ratingobjectUid . '-StpOdr' . $i . '-currentpoll-normal { width:' .
$oneStepPart . '%; margin-left:' . $stepPart . '%; }' . chr(10);
$cssFile .= 'li.RObj' . $ratingobjectUid . '-StpOdr' . $i . '-currentpoll-normal span { width:100%; }' .
chr(10);
$cssFile .= 'li.RObj' . $ratingobjectUid . '-StpOdr' . $i . '-currentpoll-tilt { height:' .
$oneStepPart . '%; margin-bottom:' . $stepPart . '%; }' . chr(10);
$cssFile .= 'li.RObj' . $ratingobjectUid . '-StpOdr' . $i . '-currentpoll-tilt span { height:100%; }' .
chr(10);
$stepPart = round($sumWeights * 100 / $sumStepWeights, 1); //calculate sum of widths to this ratingstep
$cssFile .= 'span.RObj' . $ratingobjectUid . '-StpOdr' . $i . '-ratingstep-normal { width:' .
$stepPart . '%; z-index:' . $zIndex . '; }' . chr(10);
$cssFile .= 'span.RObj' . $ratingobjectUid . '-StpOdr' . $i . '-ratingstep-tilt { height:' .
$stepPart . '%; z-index:' . $zIndex . '; }' . chr(10);
$i++;
}
//reset variables for next iteration
unset($stepWeights, $sumWeights, $sumStepWeights);
$this->logger->log(LogLevel::DEBUG, 'CSS finished for ratingobject');
}
$this->logger->log(LogLevel::DEBUG, 'Saving CSS file', ['cssFile' => $cssFile]);
$fp = fopen(Environment::getPublicPath() . '/' . self::DYN_CSS_FILENAME, 'wb');
fwrite($fp, $cssFile);
fclose($fp);
return $messageArray;
}
/**
* Returns the language object
* If not ISO code is provided the default language is returned
*
* @param int $pid page id to which is part of the site
* @param string|null $twoLetterIsoCode iso-639-1 string (e.g. en, de, us)
* @return \TYPO3\CMS\Core\Site\Entity\SiteLanguage
* @throws LanguageNotFoundException
*/
public function getStaticLanguageByIsoCode(int $pid, string $twoLetterIsoCode = null): SiteLanguage
{
/** @var Site $site */
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pid);
if (!is_null($twoLetterIsoCode)) {
foreach ($site->getAllLanguages() as $language) {
if ($language->getTwoLetterIsoCode() === $twoLetterIsoCode) {
return $language;
}
}
throw new LanguageNotFoundException(LocalizationUtility::translate(
'flash.general.languageNotFound',
'ThRating'
), 1582980369);
}
return $site->getDefaultLanguage();
}
/**
* Returns the language object
* If not ISO code is provided the default language is returned
*
* @param int $pid page id to which is part of the site
* @param int|null $languageId iso-639-1 string (e.g. en, de, us)
* @return \TYPO3\CMS\Core\Site\Entity\SiteLanguage
* @throws \TYPO3\CMS\Core\Exception\SiteNotFoundException
*/
public function getStaticLanguageById(int $pid, int $languageId = null): ?SiteLanguage
{
/** @var Site $site */
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pid);
if ($languageId) {
return $site->getLanguageById($languageId);
}
return $site->getDefaultLanguage();
}
/**
* @return ServerRequestInterface
*/
public function getRequest(): ServerRequestInterface
{
return $GLOBALS['TYPO3_REQUEST'];
}
/**
* Sets the current request object
*
* @param \TYPO3\CMS\Extbase\Mvc\Request $request
*/
public function setRequest(\TYPO3\CMS\Extbase\Mvc\Request $request): void
{
$this->request = $request;
}
}

View File

@@ -0,0 +1,185 @@
<?php
declare(strict_types = 1);
/*
* 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\Service;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject;
use WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf;
use TYPO3\CMS\Core\Log\LogLevel;
/**
* Factory for model objects
*
* @version $Id:$
* @license http://opensource.org/licenses/gpl-license.php GNU protected License, version 2
*/
class ExtensionManagementService extends AbstractExtensionService
{
/**
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionConfigurationService
*/
protected $extensionConfigurationService;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionConfigurationService $extensionConfigurationService
*/
public function injectExtensionConfigurationService(ExtensionConfigurationService $extensionConfigurationService): void
{
$this->extensionConfigurationService = $extensionConfigurationService;
}
/**
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected $extensionHelperService;
/**
* @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService $extensionHelperService
*/
public function injectExtensionHelperService(ExtensionHelperService $extensionHelperService)
{
$this->extensionHelperService = $extensionHelperService;
}
/**
* Prepares an object for ratings
*
* @api
* @param string $tablename
* @param string $fieldname
* @param int $stepcount
* @return \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @throws \WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException
*/
public function makeRatable(string $tablename, string $fieldname, int $stepcount): Ratingobject
{
$this->logger->log(
LogLevel::INFO,
'makeRatable called',
['tablename' => $tablename, 'fieldname' => $fieldname, 'stepcount' => $stepcount]
);
$this->extensionConfigurationService->prepareExtensionConfiguration();
$ratingobject = $this->extensionHelperService->getRatingobject(
['ratetable' => $tablename, 'ratefield' => $fieldname]
);
//create a new default stepconf having stepweight 1 for each step
for ($i = 1; $i <= $stepcount; $i++) {
$stepconfArray = ['ratingobject' => $ratingobject, 'steporder' => $i, 'stepweight' => 1];
$stepconf = $this->extensionHelperService->createStepconf($stepconfArray);
$ratingobject->addStepconf($stepconf);
}
//Full reload of newly created object
$ratingobject = $this->extensionHelperService->getRatingobject(
['ratetable' => $tablename, 'ratefield' => $fieldname]
);
// CREATE NEW DYNCSS FILE
$this->extensionHelperService->clearDynamicCssFile();
$this->extensionHelperService->renderDynCSS();
$this->extensionConfigurationService->restoreCallingExtensionConfiguration();
return $ratingobject;
}
/**
* Prepares an object for ratings
*
* @api
* @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf
* @param string $stepname
* @param string|null $twoLetterIsoCode
* @param bool $allStepconfs Take stepname for all steps and add steporder number at the end
* @return bool
* @throws \TYPO3\CMS\Core\Exception\SiteNotFoundException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
* @throws \WapplerSystems\BookmarksLikesRatings\Exception\Exception
*/
public function setStepname(
Stepconf $stepconf,
string $stepname,
string $twoLetterIsoCode=null,
bool $allStepconfs = false
): bool {
$this->logger->log(
LogLevel::INFO,
'setStepname called',
[
'stepconf' => $stepconf->getUid(),
'steporder' => $stepconf->getSteporder(),
'stepname' => $stepname,
'twoLetterIsoCode' => $twoLetterIsoCode,
'allStepconfs' => $allStepconfs
]
);
$this->extensionConfigurationService->prepareExtensionConfiguration();
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject $ratingobject */
$ratingobject = $stepconf->getRatingobject();
$success = true;
if (!$allStepconfs) {
//only add the one specific stepname
$stepnameArray = [
'stepname' => $stepname,
'twoLetterIsoCode' => $twoLetterIsoCode,
'pid' => $stepconf->getPid()
];
/** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepname $stepname */
$stepnameObject = $this->extensionHelperService->createStepname($stepconf, $stepnameArray);
if (!$stepconf->addStepname($stepnameObject)) {
$this->logger->log(
LogLevel::WARNING,
'Stepname entry for language already exists',
[
'stepconf' => $stepconf->getUid(),
'steporder' => $stepconf->getSteporder(),
'stepname' => $stepnameObject,
'twoLetterIsoCode' => $twoLetterIsoCode,
'errorCode' => 1398972827
]
);
$success = false;
}
} else {
//add stepnames to every stepconf
foreach ($ratingobject->getStepconfs() as $loopStepConf) {
$stepnameArray = [
'stepname' => $stepname . $loopStepConf->getSteporder(),
'twoLetterIsoCode' => $twoLetterIsoCode,
'pid' => $ratingobject->getPid()
];
$stepnameObject = $this->extensionHelperService->createStepname($loopStepConf, $stepnameArray);
if ($success && !$loopStepConf->addStepname($stepnameObject)) {
$this->logger->log(
LogLevel::WARNING,
'Stepname entry for language already exists',
[
'stepconf' => $stepconf->getUid(),
'steporder' => $stepconf->getSteporder(),
'stepname' => $stepname,
'twoLetterIsoCode' => $twoLetterIsoCode,
'errorCode' => 1398972331
]
);
$success = false;
}
}
}
$this->extensionConfigurationService->restoreCallingExtensionConfiguration();
return $success;
}
}

View File

@@ -0,0 +1,81 @@
<?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\Service;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* Service for setting cookies like Typo3 does
*
* @version $Id:$
* @license http://opensource.org/licenses/gpl-license.php GNU protected License, version 2
*/
class JsonService extends AbstractExtensionService
{
/**
* Encode a string to JSON
* Log a warning on error
*
* @param mixed $content
* @return string|false The domain to be used on setting cookies
*/
public function encodeToJson($content)
{
if (!empty($content)) {
try {
return json_encode($content, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
$this->logger->log(
LogLevel::WARNING,
LocalizationUtility::translate('system.warning.json.encode', 'ThRating', [
1 => $content,
]),
[
'errorCode' => 1615051494,
'JSON' => $content,
'Exception' => $e,
]
);
}
}
return false;
}
/**
* Encode a string to JSON
* Log a warning on error
*
* @param string|null $content
* @return array|false The domain to be used on setting cookies
*/
public function decodeJsonToArray(string $content=null)
{
if (!empty($content)) {
try {
return json_decode($content, true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
$this->logger->log(
LogLevel::WARNING,
LocalizationUtility::translate('system.warning.json.encode', 'ThRating', [
1 => $content,
]),
[
'errorCode' => 1615051494,
'JSON' => $content,
'Exception' => $e,
]
);
}
}
return false;
}
}

View File

@@ -0,0 +1,83 @@
<?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\Service;
use TYPO3\CMS\Core\Log\Logger;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Log\Writer\DatabaseWriter;
use TYPO3\CMS\Core\Log\Writer\FileWriter;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
/**
* Factory for model objects
*
* @version $Id:$
* @license http://opensource.org/licenses/gpl-license.php GNU protected License, version 2
*/
class LoggingService
{
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
*/
protected $objectManager;
/**
* @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
*/
protected $configurationManager;
/**
* Constructor
* Must overrule the abstract class method to avoid self referencing
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
* @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager,
*/
public function __construct(
ObjectManagerInterface $objectManager,
ConfigurationManagerInterface $configurationManager
) {
$this->objectManager = $objectManager;
$this->configurationManager = $configurationManager;
}
/**
* Get a logger instance
* The configuration of the logger is modified by extension typoscript config
*
* @param string $name the class name which this logger is for
* @return \TYPO3\CMS\Core\Log\Logger
*/
public function getLogger(string $name): Logger
{
/** @var array $writerConfiguration */
$writerConfiguration = $GLOBALS['TYPO3_CONF_VARS']['LOG']['Thucke']['ThRating']['writerConfiguration'];
$settings = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'thRating',
'pi1'
);
if (is_array($settings['logging'])) {
foreach ($settings['logging'] as $logLevel => $logConfig) {
$levelUppercase = strtoupper($logLevel);
if (!empty($logConfig['file'])) {
$writerConfiguration[constant('\TYPO3\CMS\Core\Log\LogLevel::' . $levelUppercase)][FileWriter::class] = ['logFile' => $logConfig['file']];
}
if (!empty($logConfig['database'])) {
$writerConfiguration[constant('\TYPO3\CMS\Core\Log\LogLevel::' . $levelUppercase)][DatabaseWriter::class] = ['table' => $logConfig['table']];
}
}
}
if (!empty($writerConfiguration)) {
$GLOBALS['TYPO3_CONF_VARS']['LOG']['Thucke']['ThRating']['writerConfiguration'] = $writerConfiguration;
}
return $this->objectManager->get(LogManager::class)->getLogger($name);
}
}

View File

@@ -0,0 +1,442 @@
<?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\Service;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* The voter
*/
class RichSnippetService extends AbstractExtensionService
{
/**
* Instances of AggregateRating may appear as properties of the following types
* This list derives from Google's information about supported types in aggregateRating (20 May 2021)
* (see https://developers.google.com/search/docs/data-types/review-snippet#aggregated-rating-type-definition)
* @const array
*/
protected const VALID_AGGREGATE_RATING_SCHEMA_TYPES = [
'Book',
'Audiobook',
'Course',
'CreativeWorkSeason',
'PodcastSeason',
'RadioSeason',
'TVSeason',
'CreativeWorkSeries',
'BookSeries',
'MovieSeries',
'Periodical',
'ComicSeries',
'Newspaper',
'PodcastSeries',
'RadioSeries',
'TVSeries',
'VideoGameSeries',
'Episode',
'PodcastEpisode',
'RadioEpisode',
'TVEpisode',
'Event',
'BusinessEvent',
'ChildrensEvent',
'ComedyEvent',
'CourseInstance',
'DanceEvent',
'DeliveryEvent',
'EducationEvent',
'EventSeries',
'ExhibitionEvent',
'Festival',
'FoodEvent',
'Hackathon',
'LiteraryEvent',
'MusicEvent',
'PublicationEvent',
'BroadcastEvent',
'OnDemandEvent',
'SaleEvent',
'ScreeningEvent',
'SocialEvent',
'SportsEvent',
'TheaterEvent',
'VisualArtsEvent',
'Game',
'VideoGame',
'HowTo',
'Recipe',
'AnimalShelter',
'ArchiveOrganization',
'AutomotiveBusiness',
'AutoBodyShop',
'AutoDealer',
'AutoRental',
'AutoRepair',
'AutoWash',
'GasStation',
'MotorcycleDealer',
'MotorcycleRepair',
'ChildCare',
'DryCleaningOrLaundry',
'EmergencyService',
'FireStation',
'Hospital',
'PoliceStation',
'EmploymentAgency',
'EntertainmentBusiness',
'AdultEntertainment',
'AmusementPark',
'ArtGallery',
'Casino',
'ComedyClub',
'MovieTheater',
'NightClub',
'FinancialService',
'AccountingService',
'AutomatedTeller',
'BankOrCreditUnion',
'InsuranceAgency',
'FoodEstablishment',
'Bakery',
'BarOrPub',
'Brewery',
'CafeOrCoffeeShop',
'Distillery',
'FastFoodRestaurant',
'IceCreamShop',
'Restaurant',
'Winery',
'GovernmentOffice',
'PostOffice',
'HealthAndBeautyBusiness',
'BeautySalon',
'DaySpa',
'HairSalon',
'NailSalon',
'TattooParlor',
'HomeAndConstructionBusiness',
'Electrician',
'GeneralContractor',
'HVACBusiness',
'HousePainter',
'Locksmith',
'MovingCompany',
'Plumber',
'RoofingContractor',
'InternetCafe',
'LegalService',
'Attorney',
'Notary',
'Library',
'LodgingBusiness',
'BedAndBreakfast',
'Campground',
'Hostel',
'Hotel',
'Motel',
'Resort',
'MedicalBusiness',
'CovidTestingFacility',
'Optician',
'Pharmacy',
'Physician',
'ProfessionalService',
'RadioStation',
'RealEstateAgent',
'RecyclingCenter',
'SelfStorage',
'ShoppingCenter',
'SportsActivityLocation',
'BowlingAlley',
'ExerciseGym',
'GolfCourse',
'HealthClub',
'PublicSwimmingPool',
'SkiResort',
'SportsClub',
'StadiumOrArena',
'TennisComplex',
'Store',
'AutoPartsStore',
'BikeStore',
'BookStore',
'ClothingStore',
'ComputerStore',
'ConvenienceStore',
'DepartmentStore',
'ElectronicsStore',
'Florist',
'FurnitureStore',
'GardenStore',
'GroceryStore',
'HardwareStore',
'HobbyShop',
'HomeGoodsStore',
'JewelryStore',
'LiquorStore',
'MensClothingStore',
'MobilePhoneStore',
'MovieRentalStore',
'MusicStore',
'OfficeEquipmentStore',
'OutletStore',
'PawnShop',
'PetStore',
'ShoeStore',
'SportingGoodsStore',
'TireShop',
'ToyStore',
'WholesaleStore',
'TelevisionStation',
'TouristInformationCenter',
'TravelAgency',
'MediaObject',
'3DModel',
'AudioObject',
'DataDownload',
'ImageObject',
'Barcode',
'LegislationObject',
'MusicVideoObject',
'VideoObject',
'Movie',
'MusicPlaylist',
'MusicAlbum',
'MusicRelease',
'MusicRecording',
'Organization',
'Airline',
'Consortium',
'Corporation',
'EducationalOrganization',
'CollegeOrUniversity',
'ElementarySchool',
'HighSchool',
'MiddleSchool',
'Preschool',
'School',
'FundingScheme',
'GovernmentOrganization',
'LibrarySystem',
'LocalBusiness',
'MedicalOrganization',
'NGO',
'NewsMediaOrganization',
'Dentist',
'DiagnosticLab',
'MedicalClinic',
'VeterinaryCare',
'PerformingGroup',
'DanceGroup',
'MusicGroup',
'TheaterGroup',
'Project',
'FundingAgency',
'ResearchProject',
'SportsOrganization',
'SportsTeam',
'WorkersUnion',
'Product',
'IndividualProduct',
'ProductCollection',
'ProductGroup',
'ProductModel',
'SomeProducts',
'Vehicle',
'BusOrCoach',
'Car',
'Motorcycle',
'MotorizedBicycle',
'SoftwareApplication',
'MobileApplication',
'WebApplication'
];
/**
* @var string
*/
protected $schema = 'Product';
/**
* @var string
*/
protected $anchor;
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $description;
/**
* @var array
*/
protected $richSnippetConfig;
/**
* @param array $settings
* @return bool
*/
public function setRichSnippetConfig(array $settings): bool
{
$this->logger->log(LogLevel::DEBUG, 'setRichSnippetConfig Entry point', $settings);
$this->richSnippetConfig['tablename'] = $settings['ratetable'];
$this->richSnippetConfig['richSnippetFields'] = $settings['richSnippetFields'];
if (is_array($this->richSnippetConfig['richSnippetFields'])) {
$this->logger->log(
LogLevel::DEBUG,
'setRichSnippetConfig Exit point',
$this->richSnippetConfig['richSnippetFields']
);
return true;
}
$this->logger->log(LogLevel::DEBUG, 'setRichSnippetConfig Exit point');
return false;
}
/**
* @return string|false
*/
public function getRichSnippetConfig()
{
return GeneralUtility::makeInstance(\WapplerSystems\BookmarksLikesRatings\Service\JsonService::class)
->encodeToJson($this->richSnippetConfig);
}
/**
* @return string
*/
public function getSchema(): string
{
return $this->schema;
}
/**
* @param string|null $schema
* @throws \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException if parameter is invalid
*/
public function setSchema(?string $schema): void
{
if (!empty($schema)) {
if (in_array($schema, self::VALID_AGGREGATE_RATING_SCHEMA_TYPES, true)) {
$this->schema = $schema;
} else {
throw new \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException(
LocalizationUtility::translate(
'error.richSnippetConfiguration.AggregateRatingPropertySchema',
'ThRating'
),
1521487362
);
}
}
}
/**
* @return string
*/
public function getAnchor(): string
{
return $this->anchor;
}
/**
* @param string $anchor
*/
public function setAnchor(string $anchor): void
{
$this->anchor = $anchor;
}
/**
* @param string|null $name
*/
public function setName(?string $name): void
{
$this->name = $name;
}
/**
* @return string|null
*/
public function getName(): ?string
{
return $this->name;
}
/**
* @return string|null
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* @param string|null $description
*/
public function setDescription(?string $description): void
{
$this->description = $description;
}
/**
* @param int $uid
* @return RichSnippetService
*@throws \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException
*/
public function getRichSnippetObject(int $uid): self
{
$this->logger->log(LogLevel::DEBUG, 'getRichSnippetObject Entry point');
$this->setSchema($this->richSnippetConfig['richSnippetFields']['aggregateRatingSchemaType']);
if (empty($this->richSnippetConfig['richSnippetFields']['name'])) {
$this->logger->log(LogLevel::INFO, 'No name field defined - skipping database access');
unset($this->name, $this->description);
throw new \TYPO3\CMS\Core\Exception();
} else {
/** @var QueryBuilder $queryBuilder */
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable($this->richSnippetConfig['tablename']);
//fetch whole row from database
/** @var array $row */
$row = $queryBuilder
->select('*')
->from($this->richSnippetConfig['tablename'])
->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid)))
->execute()
->fetch();
$this->logger->log(LogLevel::DEBUG, 'Data fetched', $row);
$this->setName($row[$this->richSnippetConfig['richSnippetFields']['name']]);
$contentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class);
$this->setDescription($row[$this->richSnippetConfig['richSnippetFields']['description']]);
//$this->setDescription($contentObjectRenderer->cObjGetSingle('TEXT', $this->richSnippetConfig['richSnippetFields']['description']));
//$this->setDescription($contentObjectRenderer->render($this->richSnippetConfig['richSnippetFields']['description']));
}
$this->logger->log(LogLevel::DEBUG, 'getRichSnippetObject Exit point', (array)$this);
return $this;
}
}

View File

@@ -0,0 +1,245 @@
<?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\ViewHelpers;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
/**
*
*
*/
class BookmarkViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* Disable escaping of this node's output
*
* @var bool
*/
protected $escapeOutput = false;
/**
* @noinspection PhpUnnecessaryFullyQualifiedNameInspection
* @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
* contains a backup of the current['TSFE'] if used in BE mode
*/
protected static $tsfeBackup;
/**
* @noinspection PhpFullyQualifiedNameUsageInspection
* @var \TYPO3\CMS\Core\Log\Logger $logger
*/
protected $logger;
/**
* @var array
*/
protected $typoScriptSetup;
/**
* @noinspection PhpUnnecessaryFullyQualifiedNameInspection
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected $extensionHelperService;
public function initializeArguments(): void
{
$this->registerArgument('action', 'string', 'The rating action');
$this->registerArgument('ratetable', 'string', 'The rating tablename');
$this->registerArgument('ratefield', 'string', 'The rating fieldname');
$this->registerArgument('ratedobjectuid', 'integer', 'The ratingobject uid', true);
$this->registerArgument('ratingobject', 'integer', 'The ratingobject');
$this->registerArgument('display', 'string', 'The display configuration');
}
/**
* Renders the ratingView
*
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
* @return mixed
* @throws \TYPO3Fluid\Fluid\Core\ViewHelper\Exception
* @noinspection PhpFullyQualifiedNameUsageInspection
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$typoscriptObjectPath = 'plugin.tx_thrating';
$ratedobjectuid = $arguments['ratedobjectuid'];
$action = $arguments['action'];
$ratingobject = $arguments['ratingobject'];
$ratetable = $arguments['ratetable'];
$ratefield = $arguments['ratefield'];
$display = $arguments['display'];
$extensionHelperService = static::getExtensionHelperService();
$contentObjectRenderer = static::getContentObjectRenderer();
//instantiate the logger
$logger = $extensionHelperService->getLogger(__CLASS__);
$logger->log(
LogLevel::DEBUG,
'Entry point',
[
'Viewhelper parameters' => [
'action' => $action,
'ratingobject' => $ratingobject,
'ratetable' => $ratetable,
'ratefield' => $ratefield,
'ratedobjectuid' => $ratedobjectuid,
'display' => $display, ],
'typoscript' => static::getConfigurationManager()
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT),
]
);
if (TYPO3_MODE === 'BE') {
static::simulateFrontendEnvironment();
}
$contentObjectRenderer->start([]);
$pathSegments = GeneralUtility::trimExplode('.', $typoscriptObjectPath);
$lastSegment = array_pop($pathSegments);
$setup = static::getConfigurationManager()
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
foreach ($pathSegments as $segment) {
if (!array_key_exists($segment . '.', $setup)) {
$logger->log(
LogLevel::CRITICAL,
'TypoScript object path does not exist',
[
'Typoscript object path' => htmlspecialchars($typoscriptObjectPath),
'Setup' => $setup,
'errorCode' => 1253191023, ]
);
throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception(
'TypoScript object path "' . $typoscriptObjectPath . '" does not exist',
1549388144
);
}
$setup = $setup[$segment . '.'];
}
if (!isset($setup[$lastSegment])) {
throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception(
'No Content Object definition found at TypoScript object path "' . $typoscriptObjectPath . '"',
1549388123
);
}
if (!empty($action)) {
$setup[$lastSegment . '.']['action'] = $action;
$setup[$lastSegment . '.']['switchableControllerActions.']['Vote.']['1'] = $action;
}
if (!empty($ratingobject)) {
$setup[$lastSegment . '.']['settings.']['ratingobject'] = $ratingobject;
} elseif (!empty($ratetable) && !empty($ratefield)) {
$setup[$lastSegment . '.']['settings.']['ratetable'] = $ratetable;
$setup[$lastSegment . '.']['settings.']['ratefield'] = $ratefield;
} else {
$logger->log(
LogLevel::CRITICAL,
'ratingobject not specified or ratetable/ratfield not set',
['errorCode' => 1399727698]
);
throw new Exception('ratingobject not specified or ratetable/ratfield not set', 1399727698);
}
if (!empty($ratedobjectuid)) {
$setup[$lastSegment . '.']['settings.']['ratedobjectuid'] = $ratedobjectuid;
} else {
$logger->log(LogLevel::CRITICAL, 'ratedobjectuid not set', ['errorCode' => 1304624408]);
throw new Exception('ratedobjectuid not set', 1304624408);
}
if (!empty($display)) {
$setup[$lastSegment . '.']['settings.']['display'] = $display;
}
$logger->log(
LogLevel::DEBUG,
'Single contentObjectRenderer to get',
[
'contentObjectRenderer type' => $setup[$lastSegment],
'cOjb config' => $setup[$lastSegment . '.'], ]
);
$content = $contentObjectRenderer->cObjGetSingle($setup[$lastSegment], $setup[$lastSegment . '.'] ?? []);
if (TYPO3_MODE === 'BE') {
static::resetFrontendEnvironment();
}
$logger->log(LogLevel::INFO, 'Generated content', ['content' => $content]);
$logger->log(LogLevel::DEBUG, 'Exit point');
return $content;
}
/**
* @return \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected static function getExtensionHelperService(): ExtensionHelperService
{
return GeneralUtility::makeInstance(ObjectManager::class)->get(ExtensionHelperService::class);
}
/**
* @return object|\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
*/
protected static function getConfigurationManager()
{
return GeneralUtility::makeInstance(ObjectManager::class)->get(ConfigurationManagerInterface::class);
}
/**
* @return \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
protected static function getContentObjectRenderer(): ContentObjectRenderer
{
return GeneralUtility::makeInstance(
ContentObjectRenderer::class,
$GLOBALS['TSFE'] ?? GeneralUtility::makeInstance(TypoScriptFrontendController::class, null, 0, 0)
);
}
/**
* Sets the $TSFE->cObjectDepthCounter in Backend mode
* This somewhat hacky work around is currently needed because the cObjGetSingle() function
* of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer relies on this setting
*/
protected static function simulateFrontendEnvironment(): void
{
static::$tsfeBackup = $GLOBALS['TSFE'] ?? null;
/** @noinspection PhpFullyQualifiedNameUsageInspection */
$GLOBALS['TSFE'] = new \stdClass();
$GLOBALS['TSFE']->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
$GLOBALS['TSFE']->cObjectDepthCounter = 100;
}
/**
* Resets $GLOBALS['TSFE'] if it was previously changed by simulateFrontendEnvironment()
*
* @see simulateFrontendEnvironment()
*/
protected static function resetFrontendEnvironment(): void
{
$GLOBALS['TSFE'] = static::$tsfeBackup;
}
}

View File

@@ -0,0 +1,245 @@
<?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\ViewHelpers;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
/**
*
*
*/
class LikeViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* Disable escaping of this node's output
*
* @var bool
*/
protected $escapeOutput = false;
/**
* @noinspection PhpUnnecessaryFullyQualifiedNameInspection
* @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
* contains a backup of the current['TSFE'] if used in BE mode
*/
protected static $tsfeBackup;
/**
* @noinspection PhpFullyQualifiedNameUsageInspection
* @var \TYPO3\CMS\Core\Log\Logger $logger
*/
protected $logger;
/**
* @var array
*/
protected $typoScriptSetup;
/**
* @noinspection PhpUnnecessaryFullyQualifiedNameInspection
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected $extensionHelperService;
public function initializeArguments(): void
{
$this->registerArgument('action', 'string', 'The rating action');
$this->registerArgument('ratetable', 'string', 'The rating tablename');
$this->registerArgument('ratefield', 'string', 'The rating fieldname');
$this->registerArgument('ratedobjectuid', 'integer', 'The ratingobject uid', true);
$this->registerArgument('ratingobject', 'integer', 'The ratingobject');
$this->registerArgument('display', 'string', 'The display configuration');
}
/**
* Renders the ratingView
*
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
* @return mixed
* @throws \TYPO3Fluid\Fluid\Core\ViewHelper\Exception
* @noinspection PhpFullyQualifiedNameUsageInspection
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$typoscriptObjectPath = 'plugin.tx_thrating';
$ratedobjectuid = $arguments['ratedobjectuid'];
$action = $arguments['action'];
$ratingobject = $arguments['ratingobject'];
$ratetable = $arguments['ratetable'];
$ratefield = $arguments['ratefield'];
$display = $arguments['display'];
$extensionHelperService = static::getExtensionHelperService();
$contentObjectRenderer = static::getContentObjectRenderer();
//instantiate the logger
$logger = $extensionHelperService->getLogger(__CLASS__);
$logger->log(
LogLevel::DEBUG,
'Entry point',
[
'Viewhelper parameters' => [
'action' => $action,
'ratingobject' => $ratingobject,
'ratetable' => $ratetable,
'ratefield' => $ratefield,
'ratedobjectuid' => $ratedobjectuid,
'display' => $display, ],
'typoscript' => static::getConfigurationManager()
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT),
]
);
if (TYPO3_MODE === 'BE') {
static::simulateFrontendEnvironment();
}
$contentObjectRenderer->start([]);
$pathSegments = GeneralUtility::trimExplode('.', $typoscriptObjectPath);
$lastSegment = array_pop($pathSegments);
$setup = static::getConfigurationManager()
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
foreach ($pathSegments as $segment) {
if (!array_key_exists($segment . '.', $setup)) {
$logger->log(
LogLevel::CRITICAL,
'TypoScript object path does not exist',
[
'Typoscript object path' => htmlspecialchars($typoscriptObjectPath),
'Setup' => $setup,
'errorCode' => 1253191023, ]
);
throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception(
'TypoScript object path "' . $typoscriptObjectPath . '" does not exist',
1549388144
);
}
$setup = $setup[$segment . '.'];
}
if (!isset($setup[$lastSegment])) {
throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception(
'No Content Object definition found at TypoScript object path "' . $typoscriptObjectPath . '"',
1549388123
);
}
if (!empty($action)) {
$setup[$lastSegment . '.']['action'] = $action;
$setup[$lastSegment . '.']['switchableControllerActions.']['Vote.']['1'] = $action;
}
if (!empty($ratingobject)) {
$setup[$lastSegment . '.']['settings.']['ratingobject'] = $ratingobject;
} elseif (!empty($ratetable) && !empty($ratefield)) {
$setup[$lastSegment . '.']['settings.']['ratetable'] = $ratetable;
$setup[$lastSegment . '.']['settings.']['ratefield'] = $ratefield;
} else {
$logger->log(
LogLevel::CRITICAL,
'ratingobject not specified or ratetable/ratfield not set',
['errorCode' => 1399727698]
);
throw new Exception('ratingobject not specified or ratetable/ratfield not set', 1399727698);
}
if (!empty($ratedobjectuid)) {
$setup[$lastSegment . '.']['settings.']['ratedobjectuid'] = $ratedobjectuid;
} else {
$logger->log(LogLevel::CRITICAL, 'ratedobjectuid not set', ['errorCode' => 1304624408]);
throw new Exception('ratedobjectuid not set', 1304624408);
}
if (!empty($display)) {
$setup[$lastSegment . '.']['settings.']['display'] = $display;
}
$logger->log(
LogLevel::DEBUG,
'Single contentObjectRenderer to get',
[
'contentObjectRenderer type' => $setup[$lastSegment],
'cOjb config' => $setup[$lastSegment . '.'], ]
);
$content = $contentObjectRenderer->cObjGetSingle($setup[$lastSegment], $setup[$lastSegment . '.'] ?? []);
if (TYPO3_MODE === 'BE') {
static::resetFrontendEnvironment();
}
$logger->log(LogLevel::INFO, 'Generated content', ['content' => $content]);
$logger->log(LogLevel::DEBUG, 'Exit point');
return $content;
}
/**
* @return \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected static function getExtensionHelperService(): ExtensionHelperService
{
return GeneralUtility::makeInstance(ObjectManager::class)->get(ExtensionHelperService::class);
}
/**
* @return object|\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
*/
protected static function getConfigurationManager()
{
return GeneralUtility::makeInstance(ObjectManager::class)->get(ConfigurationManagerInterface::class);
}
/**
* @return \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
protected static function getContentObjectRenderer(): ContentObjectRenderer
{
return GeneralUtility::makeInstance(
ContentObjectRenderer::class,
$GLOBALS['TSFE'] ?? GeneralUtility::makeInstance(TypoScriptFrontendController::class, null, 0, 0)
);
}
/**
* Sets the $TSFE->cObjectDepthCounter in Backend mode
* This somewhat hacky work around is currently needed because the cObjGetSingle() function
* of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer relies on this setting
*/
protected static function simulateFrontendEnvironment(): void
{
static::$tsfeBackup = $GLOBALS['TSFE'] ?? null;
/** @noinspection PhpFullyQualifiedNameUsageInspection */
$GLOBALS['TSFE'] = new \stdClass();
$GLOBALS['TSFE']->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
$GLOBALS['TSFE']->cObjectDepthCounter = 100;
}
/**
* Resets $GLOBALS['TSFE'] if it was previously changed by simulateFrontendEnvironment()
*
* @see simulateFrontendEnvironment()
*/
protected static function resetFrontendEnvironment(): void
{
$GLOBALS['TSFE'] = static::$tsfeBackup;
}
}

View File

@@ -0,0 +1,257 @@
<?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\ViewHelpers;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
/**
* The Rating Viewhelper
*
* Renders the rating view based upon plugin.tx_thrating
* Only the argument ratedobjectuid is required.
* Others could be used to configure the output
*
* = Example =
*
* <code title="Render rating view">
* <thr:rating ratetable="some_tablename" ratefield="one_field_of_the_table" ratedobjectuid="UID integer" ></thr:rating>
* </code>
* <output>
* rendered rating
* </output>
*/
class RatingViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* Disable escaping of this node's output
*
* @var bool
*/
protected $escapeOutput = false;
/**
* @noinspection PhpUnnecessaryFullyQualifiedNameInspection
* @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
* contains a backup of the current['TSFE'] if used in BE mode
*/
protected static $tsfeBackup;
/**
* @noinspection PhpFullyQualifiedNameUsageInspection
* @var \TYPO3\CMS\Core\Log\Logger $logger
*/
protected $logger;
/**
* @var array
*/
protected $typoScriptSetup;
/**
* @noinspection PhpUnnecessaryFullyQualifiedNameInspection
* @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected $extensionHelperService;
public function initializeArguments(): void
{
$this->registerArgument('action', 'string', 'The rating action');
$this->registerArgument('ratetable', 'string', 'The rating tablename');
$this->registerArgument('ratefield', 'string', 'The rating fieldname');
$this->registerArgument('ratedobjectuid', 'integer', 'The ratingobject uid', true);
$this->registerArgument('ratingobject', 'integer', 'The ratingobject');
$this->registerArgument('display', 'string', 'The display configuration');
}
/**
* Renders the ratingView
*
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
* @return mixed
* @throws \TYPO3Fluid\Fluid\Core\ViewHelper\Exception
* @noinspection PhpFullyQualifiedNameUsageInspection
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$typoscriptObjectPath = 'plugin.tx_thrating';
$ratedobjectuid = $arguments['ratedobjectuid'];
$action = $arguments['action'];
$ratingobject = $arguments['ratingobject'];
$ratetable = $arguments['ratetable'];
$ratefield = $arguments['ratefield'];
$display = $arguments['display'];
$extensionHelperService = static::getExtensionHelperService();
$contentObjectRenderer = static::getContentObjectRenderer();
//instantiate the logger
$logger = $extensionHelperService->getLogger(__CLASS__);
$logger->log(
LogLevel::DEBUG,
'Entry point',
[
'Viewhelper parameters' => [
'action' => $action,
'ratingobject' => $ratingobject,
'ratetable' => $ratetable,
'ratefield' => $ratefield,
'ratedobjectuid' => $ratedobjectuid,
'display' => $display, ],
'typoscript' => static::getConfigurationManager()
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT),
]
);
if (TYPO3_MODE === 'BE') {
static::simulateFrontendEnvironment();
}
$contentObjectRenderer->start([]);
$pathSegments = GeneralUtility::trimExplode('.', $typoscriptObjectPath);
$lastSegment = array_pop($pathSegments);
$setup = static::getConfigurationManager()
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
foreach ($pathSegments as $segment) {
if (!array_key_exists($segment . '.', $setup)) {
$logger->log(
LogLevel::CRITICAL,
'TypoScript object path does not exist',
[
'Typoscript object path' => htmlspecialchars($typoscriptObjectPath),
'Setup' => $setup,
'errorCode' => 1253191023, ]
);
throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception(
'TypoScript object path "' . $typoscriptObjectPath . '" does not exist',
1549388144
);
}
$setup = $setup[$segment . '.'];
}
if (!isset($setup[$lastSegment])) {
throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception(
'No Content Object definition found at TypoScript object path "' . $typoscriptObjectPath . '"',
1549388123
);
}
if (!empty($action)) {
$setup[$lastSegment . '.']['action'] = $action;
$setup[$lastSegment . '.']['switchableControllerActions.']['Vote.']['1'] = $action;
}
if (!empty($ratingobject)) {
$setup[$lastSegment . '.']['settings.']['ratingobject'] = $ratingobject;
} elseif (!empty($ratetable) && !empty($ratefield)) {
$setup[$lastSegment . '.']['settings.']['ratetable'] = $ratetable;
$setup[$lastSegment . '.']['settings.']['ratefield'] = $ratefield;
} else {
$logger->log(
LogLevel::CRITICAL,
'ratingobject not specified or ratetable/ratfield not set',
['errorCode' => 1399727698]
);
throw new Exception('ratingobject not specified or ratetable/ratfield not set', 1399727698);
}
if (!empty($ratedobjectuid)) {
$setup[$lastSegment . '.']['settings.']['ratedobjectuid'] = $ratedobjectuid;
} else {
$logger->log(LogLevel::CRITICAL, 'ratedobjectuid not set', ['errorCode' => 1304624408]);
throw new Exception('ratedobjectuid not set', 1304624408);
}
if (!empty($display)) {
$setup[$lastSegment . '.']['settings.']['display'] = $display;
}
$logger->log(
LogLevel::DEBUG,
'Single contentObjectRenderer to get',
[
'contentObjectRenderer type' => $setup[$lastSegment],
'cOjb config' => $setup[$lastSegment . '.'], ]
);
$content = $contentObjectRenderer->cObjGetSingle($setup[$lastSegment], $setup[$lastSegment . '.'] ?? []);
if (TYPO3_MODE === 'BE') {
static::resetFrontendEnvironment();
}
$logger->log(LogLevel::INFO, 'Generated content', ['content' => $content]);
$logger->log(LogLevel::DEBUG, 'Exit point');
return $content;
}
/**
* @return \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService
*/
protected static function getExtensionHelperService(): ExtensionHelperService
{
return GeneralUtility::makeInstance(ObjectManager::class)->get(ExtensionHelperService::class);
}
/**
* @return object|\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
*/
protected static function getConfigurationManager()
{
return GeneralUtility::makeInstance(ObjectManager::class)->get(ConfigurationManagerInterface::class);
}
/**
* @return \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
protected static function getContentObjectRenderer(): ContentObjectRenderer
{
return GeneralUtility::makeInstance(
ContentObjectRenderer::class,
$GLOBALS['TSFE'] ?? GeneralUtility::makeInstance(TypoScriptFrontendController::class, null, 0, 0)
);
}
/**
* Sets the $TSFE->cObjectDepthCounter in Backend mode
* This somewhat hacky work around is currently needed because the cObjGetSingle() function
* of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer relies on this setting
*/
protected static function simulateFrontendEnvironment(): void
{
static::$tsfeBackup = $GLOBALS['TSFE'] ?? null;
/** @noinspection PhpFullyQualifiedNameUsageInspection */
$GLOBALS['TSFE'] = new \stdClass();
$GLOBALS['TSFE']->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
$GLOBALS['TSFE']->cObjectDepthCounter = 100;
}
/**
* Resets $GLOBALS['TSFE'] if it was previously changed by simulateFrontendEnvironment()
*
* @see simulateFrontendEnvironment()
*/
protected static function resetFrontendEnvironment(): void
{
$GLOBALS['TSFE'] = static::$tsfeBackup;
}
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace WapplerSystems\BookmarksLikesRatings\Widgets\Provider;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Dashboard\Widgets\ListDataProviderInterface;
class TopLikesDataProvider implements ListDataProviderInterface
{
public function __construct()
{
}
public function getItems(): array
{
/** @var QueryBuilder $queryBuilder */
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_users');
return $queryBuilder
->count('*')
->from('be_users')
->where(
$queryBuilder->expr()->eq(
'admin',
$queryBuilder->createNamedParameter(0, Connection::PARAM_INT)
)
)
->execute();
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace WapplerSystems\BookmarksLikesRatings\Widgets;
use TYPO3\CMS\Dashboard\Widgets\ButtonProviderInterface;
use TYPO3\CMS\Dashboard\Widgets\ListDataProviderInterface;
use TYPO3\CMS\Dashboard\Widgets\WidgetConfigurationInterface;
use TYPO3\CMS\Dashboard\Widgets\WidgetInterface;
use TYPO3\CMS\Fluid\View\StandaloneView;
use WapplerSystems\BookmarksLikesRatings\Widgets\Provider\TopLikesDataProvider;
class TopLikesWidget implements WidgetInterface
{
/**
* @var WidgetConfigurationInterface
*/
private $configuration;
/**
* @var StandaloneView
*/
private $view;
/**
* @var array
*/
private $options;
/**
* @var ButtonProviderInterface|null
*/
private $buttonProvider;
/**
* @var TopLikesDataProvider
*/
private $dataProvider;
public function __construct(
WidgetConfigurationInterface $configuration,
TopLikesDataProvider $dataProvider,
StandaloneView $view,
$buttonProvider = null,
array $options = []
)
{
$this->configuration = $configuration;
$this->view = $view;
$this->options = $options;
$this->buttonProvider = $buttonProvider;
$this->dataProvider = $dataProvider;
}
public function renderWidgetContent(): string
{
$this->view->setTemplate('Widget/ListWidget');
$this->view->assignMultiple([
'items' => $this->getItems(),
'options' => $this->options,
'button' => $this->buttonProvider,
'configuration' => $this->configuration,
]);
return $this->view->render();
}
protected function getItems(): array
{
return $this->dataProvider->getTopLikes();
}
}